#!BPY
"""
Name: 'MOSAIC RenderMan(R) System'
Blender: 245
Group: 'Render'
Tooltip: 'RenderMan(R) developement tool for blender'
"""
####################################################################### AUTHOR BLOCK
# MOSAIC RenderMan(R) System
# by Eric Nathen Back, 02-02-2007
# This plugin is protected by the GPL: Gnu Public Licence
# GPL - http://www.gnu.org/copyleft/gpl.html
####################################################################### GPL LICENSE BLOCK
# Script Copyright (C) Eric Nathen Back
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
####################################################################### COPYRIGHT BLOCK
# The RenderMan(R) Interface Procedures and Protocol are:
# Copyright 1988, 1989, 2000, 2005 Pixar
# All Rights Reserved
# RenderMan(R) is a registered trademark of Pixar
####################################################################### END BLOCKS

__author__	= "Eric Nathen Back AKA >WHiTeRaBBiT<"
__url__		= ["Project page, http://www.sourceforge.net/projects/ribmosaic/",
		   "Wiki documentation, http://ribmosaic.wiki.sourceforge.net/",
		   "GPL Licence, http://www.gnu.org/copyleft/gpl.html"]
__version__	= "Beta-0.2"
__bpydoc__	= """\
Welcome to MOSAIC<br>

Follow the links above to find the latest versions, news, tutorials and reference materials.

MOSAIC is protected by the GPL: Gnu Public Licence<br>
The RenderMan(R) Interface Procedures and Protocol are:<br>
Copyright 1988, 1989, 2000, 2005 Pixar<br>
All Rights Reserved<br>
RenderMan(R) is a registered trademark of Pixar<br>
"""

import os
import time
import math
import gzip
import Blender
from Blender		import *
from Blender.BGL	import *
from Blender.Draw	import *
from Blender.Mathutils	import *
from Blender.Window	import *
from math		import pi
from math		import atan
from time 		import localtime
from time		import strftime
from time		import time

print "Welcome to MOSAIC "+__version__+"!"

####################################################################### SETUP REGISTRY HANDELING
#This list contains the supported renderers in the preset list in menu format for dropdown menu
RendererList		= ["Renderer Presets:%t|CUSTOM|3Delight|Air|Angel|Aqsis|BMRT|Gelato|JrMan|Lucille|Pixie|PRMan|RenderDotC", "CUSTOM", "3Delight", "Air", "Angel", "Aqsis", "BMRT", "Gelato", "JrMan", "Lucille", "Pixie", "PRMan", "RenderDotC"]

#This array contains data used by the render binary preset system in the following format:
#[preset[renderer,compiler,texoptimizer,envoptimizer,info,shaderext,ribext,textureext,SourceExt,HeaderExt,RibFrames,RibWorlds,RibScreen,RibProjection,RibClipping,RibColor,RibOpacity,RibSides,RibBound,RibVertexCols,RibNormals,RibVertexUVs,RibComments,tracedisplace,vistransmission,visspecular,visdiffuse,visphoton,viscamera,hittransmission,hitspecular,paraclass],...]
PresetList		= [["renderdl", "shaderdl", "tdlmake -smode periodic -tmode periodic", "tdlmake -envlatl", "shaderinfo", ".sdl", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1],					#3Delight
			   ["air", "shaded", "mktex -smode periodic -tmode periodic", "mktex -envlatl", "slbtell -o", ".slb", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 6, 5, 1, 1, 1, 1, 1, 1],						#Air
			   ["angel", "slc", "mkmip -smode periodic -tmode periodic", "mkmip -envlatl", "slctell", ".slc", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],						#Angel
			   ["aqsis", "aqsl", "teqser -wrap periodic", "teqser -envlatl", "aqsltell", ".slx", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],								#Aqsis
			   ["rendrib", "slc", "mkmip -smode periodic -tmode periodic", "mkmip -envlatl", "slctell", ".slc", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],						#BMRT
			   ["gelato", "gslc", "maketx -smode periodic -tmode periodic -o <TEXOUT> <TEXIN>", "maketx -envlatl -o <TEXOUT> <TEXIN>", "gsoinfo -v", ".gso", ".rib", ".tx", ".gsl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 5, 1, 1, 1, 1, 1, 1],#Gelato
			   ["jrman", "slc", "mkmip -smode periodic -tmode periodic", "mkmip -envlatl", "slctell", ".slc", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3],						#JrMan
			   ["lsh", "NONE", "NONE", "NONE", "NONE", ".lc", ".rib", ".tx", ".sl", ".h", 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3],												#Lucille
			   ["rndr", "sdrc", "texmake -smode periodic -tmode periodic", "texmake -envlatl", "sdrinfo", ".sdr", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1],						#Pixie
			   ["prman", "shader", "txmake -smode periodic -tmode periodic", "txmake -envlatl", "sloinfo", ".slo", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1],						#PrMan
			   ["renderdc", "shaderdc", "texdc -m periodic", "texdc -l", "soinfo", ".so", ".rib", ".tx", ".sl", ".h", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]									#RenderDotC

#Registry Vars
RenderDir		= "/tmp/"					#Assume standard Blender export directory if none is set
ProjectDir		= ""						#Final export directory which is RenderDir+Users Project Folder
ShaderDir		= []						#Directory where pre-compiled shaders are located
ShaderExt		= ""						#The file extension of compiled shaders
TextureExt		= ""						#The file extension of exported and optimized textures
RibExt			= ""						#The file extension of RIB files
RenderPreset		= 1						#Keeps track of last user renderer preset
RenderBin		= ""						#Renderman renderer binary
CompilerBin		= ""						#Shader compiler
TexmakeBin		= ""						#Texture Optimizer
EnvmakeBin		= ""						#Lat/Long Environment Optimizer
InfoBin			= ""						#Shader info binary
RibOutput		= ""						#Main rib file name
RibCompress		= 0						#Rib compression
RibFrames		= 1						#Use frame blocks in RIB
RibWorlds		= 1						#Use world blocks in RIB
RibScreen		= 1						#Use RiScreenWindow in RIB
RibProjection		= 1						#Use RiProjection in RIB
RibClipping		= 1						#Use RiClipping in RIB
RibColor		= 1						#Use RiColor in RIB
RibOpacity		= 1						#Use RiOpacity in RIB
RibSides		= 1						#Use RiSides in RIB
RibBound		= 1						#Use RiBound in RIB
RibVertexCols		= 1						#Use vertex colors in RIB
RibNormals		= 1						#Use face normals in RIB
RibVertexUVs		= 1						#Use vertex uv in RIB
RibComments		= 1						#Use comments in RIB
PresetEmbed		= 0						#Is preset embeded?
VertexNormals		= 0						#Are we using vertex normals?

#Text file name filters: [code, shader source, surface, displacement, volume, imager, light, shader include]
Filters			= ["cf_", ".sl", "ss_", "ds_", "vs_", "is_", "ls_", ".h"]


#### Show a error
def ErrorPopup(errortext):
	print "ERROR: "+errortext
	PupMenu("ERROR: "+errortext)


#### Update settings to registry cache
def UpdateRegistry(type = 0):
	global RenderPreset, RenderDir, ShaderDir, ShaderExt, RibExt, RenderBin, CompilerBin, TexmakeBin, InfoBin, Filters, PresetEmbed, RendererList, TextureExt
	global RibFrames, RibWorlds, RibScreen, RibClipping, RibColor, RibOpacity, RibVertexCols, RibNormals, RibVertexUVs, RibComments, RibProjection, RibSides, RibBound
	if ((not type and not PresetEmbed) or type == 1):		#This block is for handling traditional Blender registry
		data				= {} #Registry data
		data['RenderPreset']		= RendererList[RenderPreset]
		data['ShaderExt']		= ShaderExt
		data['RibExt']			= RibExt
		data['TextureExt']		= TextureExt
		data['RenderBin']		= RenderBin
		data['CompilerBin']		= CompilerBin
		data['TexmakeBin']		= TexmakeBin
		data['EnvmakeBin']		= EnvmakeBin
		data['InfoBin']			= InfoBin
		data['RibFrames']		= RibFrames
		data['RibWorlds']		= RibWorlds
		data['RibScreen']		= RibScreen
		data['RibProjection']		= RibProjection
		data['RibClipping']		= RibClipping
		data['RibColor']		= RibColor
		data['RibOpacity']		= RibOpacity
		data['RibSides']		= RibSides
		data['RibBound']		= RibBound
		data['RibVertexCols']		= RibVertexCols
		data['RibNormals']		= RibNormals
		data['RibVertexUVs']		= RibVertexUVs
		data['RibComments']		= RibComments
		data['CodeFilter']		= Filters[0]
		data['SourceFilter']		= Filters[1]
		data['SurfaceFilter']		= Filters[2]
		data['DisplacementFilter']	= Filters[3]
		data['VolumeFilter']		= Filters[4]
		data['ImagerFilter']		= Filters[5]
		data['LightFilter']		= Filters[6]
		data['IncludeFilter']		= Filters[7]
		data['RenderDir']		= RenderDir
		data['ShaderDir']		= ShaderDir
		Blender.Registry.SetKey('Mosaic', data, True)
	elif ((not type and PresetEmbed) or type == 2):			#This block is for handling the embeded text registry
		PresetEmbed	= 1
		if ([True for text in Blender.Text.Get() if text.name == "MOSAIC Preset"]):
			preset	= Blender.Text.Get("MOSAIC Preset")
			preset.clear()
		else: preset = Blender.Text.New("MOSAIC Preset")
		preset.write("RenderPreset,"+str(RendererList[RenderPreset])+"\n")
		preset.write("ShaderExt,"+str(ShaderExt)+"\n")
		preset.write("RibExt,"+str(RibExt)+"\n")
		preset.write("TextureExt,"+str(TextureExt)+"\n")
		preset.write("RenderBin,"+str(RenderBin)+"\n")
		preset.write("CompilerBin,"+str(CompilerBin)+"\n")
		preset.write("TexmakeBin,"+str(TexmakeBin)+"\n")
		preset.write("EnvmakeBin,"+str(EnvmakeBin)+"\n")
		preset.write("InfoBin,"+str(InfoBin)+"\n")
		preset.write("RibFrames,"+str(RibFrames)+"\n")
		preset.write("RibWorlds,"+str(RibWorlds)+"\n")
		preset.write("RibScreen,"+str(RibScreen)+"\n")
		preset.write("RibProjection,"+str(RibProjection)+"\n")
		preset.write("RibClipping,"+str(RibClipping)+"\n")
		preset.write("RibColor,"+str(RibColor)+"\n")
		preset.write("RibOpacity,"+str(RibOpacity)+"\n")
		preset.write("RibSides,"+str(RibSides)+"\n")
		preset.write("RibBound,"+str(RibBound)+"\n")
		preset.write("RibVertexCols,"+str(RibVertexCols)+"\n")
		preset.write("RibNormals,"+str(RibNormals)+"\n")
		preset.write("RibVertexUVs,"+str(RibVertexUVs)+"\n")
		preset.write("RibComments,"+str(RibComments)+"\n")
		preset.write("CodeFilter,"+str(Filters[0])+"\n")
		preset.write("SourceFilter,"+str(Filters[1])+"\n")
		preset.write("SurfaceFilter,"+str(Filters[2])+"\n")
		preset.write("DisplacementFilter,"+str(Filters[3])+"\n")
		preset.write("VolumeFilter,"+str(Filters[4])+"\n")
		preset.write("ImagerFilter,"+str(Filters[5])+"\n")
		preset.write("LightFilter,"+str(Filters[6])+"\n")
		preset.write("IncludeFilter,"+str(Filters[7])+"\n")
		data				= Registry.GetKey('Mosaic', True) #Get current registry
		if (data):
			data['RenderDir']	= RenderDir
			data['ShaderDir']	= ShaderDir
			Blender.Registry.SetKey('Mosaic', data, True)	#Save data to registry


#### Check if registry cache is available and if so load it
def GetRegistry():
	global RenderPreset, RenderDir, ShaderDir, ShaderExt, RibExt, RenderBin, CompilerBin, TexmakeBin, EnvmakeBin, InfoBin, Filters, PresetEmbed, RendererList, TextureExt
	global RibFrames, RibWorlds, RibScreen, RibClipping, RibColor, RibOpacity, RibVertexCols, RibNormals, RibVertexUVs, RibComments, RibProjection, RibSides, RibBound
	registry	= Registry.GetKey('Mosaic', True)
	if (registry):
		try:
			ShaderDir		= registry['ShaderDir']
			if (type(ShaderDir) != list): ShaderDir = [ShaderDir] #Fix for ealier versions
			renderer		= registry['RenderPreset'] #If old style registry just pass value through
			if (type(renderer) == str):  #if new style get index of preset string in renderers list
				if (RendererList.count(renderer)):	RenderPreset = RendererList.index(renderer)
				else:					RenderPreset = 1 #If not in list then tag as CUSTOM
			else:
				ErrorPopup("Your registry is using older syle MOSAIC settings, you may need to re-apply your renderer preset!")
				RenderPreset	= renderer
			RenderDir		= registry['RenderDir']
			ShaderExt		= registry['ShaderExt']
			RibExt			= registry['RibExt']
			TextureExt		= registry['TextureExt']
			RenderBin		= registry['RenderBin']
			CompilerBin		= registry['CompilerBin']
			TexmakeBin		= registry['TexmakeBin']
			EnvmakeBin		= registry['EnvmakeBin']
			InfoBin			= registry['InfoBin']
			RibFrames		= registry['RibFrames']
			RibWorlds		= registry['RibWorlds']
			RibScreen		= registry['RibScreen']
			RibProjection		= registry['RibProjection']
			RibClipping		= registry['RibClipping']
			RibColor		= registry['RibColor']
			RibOpacity		= registry['RibOpacity']
			RibSides		= registry['RibSides']
			RibBound		= registry['RibBound']
			RibVertexCols		= registry['RibVertexCols']
			RibNormals		= registry['RibNormals']
			RibVertexUVs		= registry['RibVertexUVs']
			RibComments		= registry['RibComments']
			Filters[0]		= registry['CodeFilter']
			Filters[1]		= registry['SourceFilter']
			Filters[2]		= registry['SurfaceFilter']
			Filters[3]		= registry['DisplacementFilter']
			Filters[4]		= registry['VolumeFilter']
			Filters[5]		= registry['ImagerFilter']
			Filters[6]		= registry['LightFilter']
			Filters[7]		= registry['IncludeFilter']
		except: UpdateRegistry(1)				#If registry does not exist make one from defaults


#### Check if embeded preset text is available and if so load it
def GetTextPreset():
	global RenderPreset, RenderDir, ShaderDir, ShaderExt, RibExt, RenderBin, CompilerBin, TexmakeBin, EnvmakeBin, InfoBin, Filters, PresetEmbed, RendererList, TextureExt
	global RibFrames, RibWorlds, RibScreen, RibClipping, RibColor, RibOpacity, RibVertexCols, RibNormals, RibVertexUVs, RibComments, RibProjection, RibSides, RibBound
	preset = [text.asLines() for text in Blender.Text.Get() if text.name == "MOSAIC Preset"]
	if (preset):
		try:
			PresetEmbed			= 1
			unknownLine			= False
			for line in preset[0]:
				if (line.count("RenderPreset")):
					renderer					= line.split(',')[1]
					if (RendererList.count(renderer)):		RenderPreset = RendererList.index(renderer)
					else:						RenderPreset = 1 #If not in list then tag as CUSTOM
				elif (line.count("ShaderExt")):		ShaderExt	= line.split(',')[1]
				elif (line.count("RibExt")):		RibExt		= line.split(',')[1]
				elif (line.count("TextureExt")):	TextureExt	= line.split(',')[1]
				elif (line.count("RenderBin")):		RenderBin	= line.split(',')[1]
				elif (line.count("CompilerBin")):	CompilerBin	= line.split(',')[1]
				elif (line.count("TexmakeBin")):	TexmakeBin	= line.split(',')[1]
				elif (line.count("EnvmakeBin")):	EnvmakeBin	= line.split(',')[1]
				elif (line.count("InfoBin")):		InfoBin		= line.split(',')[1]
				elif (line.count("RibFrames")):		RibFrames	= int(line.split(',')[1])
				elif (line.count("RibWorlds")):		RibWorlds	= int(line.split(',')[1])
				elif (line.count("RibScreen")):		RibScreen	= int(line.split(',')[1])
				elif (line.count("RibProjection")):	RibProjection	= int(line.split(',')[1])
				elif (line.count("RibClipping")):	RibClipping	= int(line.split(',')[1])
				elif (line.count("RibColor")):		RibColor	= int(line.split(',')[1])
				elif (line.count("RibOpacity")):	RibOpacity	= int(line.split(',')[1])
				elif (line.count("RibSides")):		RibSides	= int(line.split(',')[1])
				elif (line.count("RibBound")):		RibBound	= int(line.split(',')[1])
				elif (line.count("RibVertexCols")):	RibVertexCols	= int(line.split(',')[1])
				elif (line.count("RibNormals")):	RibNormals	= int(line.split(',')[1])
				elif (line.count("RibVertexUVs")):	RibVertexUVs	= int(line.split(',')[1])
				elif (line.count("RibComments")):	RibComments	= int(line.split(',')[1])
				elif (line.count("CodeFilter")):	Filters[0]	= line.split(',')[1]
				elif (line.count("SourceFilter")):	Filters[1]	= line.split(',')[1]
				elif (line.count("SurfaceFilter")):	Filters[2]	= line.split(',')[1]
				elif (line.count("DisplacementFilter")):Filters[3]	= line.split(',')[1]
				elif (line.count("VolumeFilter")):	Filters[4]	= line.split(',')[1]
				elif (line.count("ImagerFilter")):	Filters[5]	= line.split(',')[1]
				elif (line.count("LightFilter")):	Filters[6]	= line.split(',')[1]
				elif (line.count("IncludeFilter")):	Filters[7]	= line.split(',')[1]
				elif (line):				unknownLine	= True
			if (unknownLine): ErrorPopup("Some lines of embeded preset could not be read, some settings may not be updated!")
		except: ErrorPopup("Could not parse embeded preset, it could be corrupted or of an older format!")


#### Apply presets into appropriate globals such as render binaries and GUI
def ApplyPresetGlobals():
	global RenderPreset, PresetList, RenderBin, CompilerBin, TexmakeBin, EnvmakeBin, InfoBin, ShaderExt, RibExt, ButtonData, RendererList, TextureExt
	global RibFrames, RibWorlds, RibScreen, RibClipping, RibColor, RibOpacity, RibVertexCols, RibNormals, RibVertexUVs, RibComments, RibProjection, RibSides, RibBound
	if (RenderPreset > 1):
		RenderBin								= PresetList[RenderPreset-2][0]
		CompilerBin								= PresetList[RenderPreset-2][1]
		TexmakeBin								= PresetList[RenderPreset-2][2]
		EnvmakeBin								= PresetList[RenderPreset-2][3]
		InfoBin									= PresetList[RenderPreset-2][4]
		ShaderExt								= PresetList[RenderPreset-2][5]
		RibExt									= PresetList[RenderPreset-2][6]
		TextureExt								= PresetList[RenderPreset-2][7]
		Filters[1]								= PresetList[RenderPreset-2][8]
		Filters[7]								= PresetList[RenderPreset-2][9]
		RibFrames								= PresetList[RenderPreset-2][10]
		RibWorlds								= PresetList[RenderPreset-2][11]
		RibScreen								= PresetList[RenderPreset-2][12]
		RibProjection								= PresetList[RenderPreset-2][13]
		RibClipping								= PresetList[RenderPreset-2][14]
		RibColor								= PresetList[RenderPreset-2][15]
		RibOpacity								= PresetList[RenderPreset-2][16]
		RibSides								= PresetList[RenderPreset-2][17]
		RibBound								= PresetList[RenderPreset-2][18]
		RibVertexCols								= PresetList[RenderPreset-2][19]
		RibNormals								= PresetList[RenderPreset-2][20]
		RibVertexUVs								= PresetList[RenderPreset-2][21]
		RibComments								= PresetList[RenderPreset-2][22]
		ButtonData[GEOMETRY][WIN_BUTS][GEO_TRACE_DISPLACE][BUT_DEFAULT]		= PresetList[RenderPreset-2][23]
		ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_TRANS][BUT_DEFAULT]		= PresetList[RenderPreset-2][24]
		ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_SPECULAR][BUT_DEFAULT]		= PresetList[RenderPreset-2][25]
		ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_DIFFUSE][BUT_DEFAULT]		= PresetList[RenderPreset-2][26]
		ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_PHOTON][BUT_DEFAULT]		= PresetList[RenderPreset-2][27]
		ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_CAMERA][BUT_DEFAULT]		= PresetList[RenderPreset-2][28]
		ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_TRANS][BUT_DEFAULT]		= PresetList[RenderPreset-2][29]
		ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_SPECULAR][BUT_DEFAULT]	= PresetList[RenderPreset-2][30]
		ButtonData[GEOMETRY][WIN_BUTS][GEO_PARA_CLASS][BUT_DEFAULT]		= PresetList[RenderPreset-2][31]
		for index, item in enumerate(Filters): DialogData[DIALOG_FILE_FILTER][index][1].val = Filters[index]


#### Updates settings buttons and dialogs with global presets
def UpdatePresetControls():
	global ButtonData, DialogData, Filters, RenderBin, CompilerBin, RenderDir, TexmakeBin, EnvmakeBin, InfoBin, RenderPreset, ShaderExt, ShaderDir, RibExt
	global RibFrames, RibWorlds, RibScreen, RibClipping, RibColor, RibOpacity, RibVertexCols, RibNormals, RibVertexUVs, RibComments, RibProjection, RibSides, RibBound, TextureExt
	if (not ShaderExt.count('.')): ShaderExt = "."+ShaderExt
	if (not RibExt.count('.')): RibExt = "."+RibExt
	if (not TextureExt.count('.')): TextureExt = "."+TextureExt
	DialogData[DIALOG_RENDER_BIN][0][1].val				= RenderBin
	DialogData[DIALOG_COMPILER_BIN][0][1].val			= CompilerBin
	DialogData[DIALOG_TEX_OPT][0][1].val				= TexmakeBin
	DialogData[DIALOG_INFO_BIN][0][1].val				= InfoBin
	DialogData[DIALOG_SL_EXT][0][1].val				= ShaderExt
	DialogData[DIALOG_RIB_EXT][0][1].val				= RibExt
	DialogData[DIALOG_TEX_EXT][0][1].val				= TextureExt
	DialogData[DIALOG_ENV_OPT][0][1].val 				= EnvmakeBin
	DialogData[DIALOG_EXPORTER_SW][0][1].val			= RibFrames
	DialogData[DIALOG_EXPORTER_SW][1][1].val			= RibWorlds
	DialogData[DIALOG_EXPORTER_SW][2][1].val			= RibScreen
	DialogData[DIALOG_EXPORTER_SW][3][1].val			= RibProjection
	DialogData[DIALOG_EXPORTER_SW][4][1].val			= RibClipping
	DialogData[DIALOG_EXPORTER_SW][5][1].val			= RibColor
	DialogData[DIALOG_EXPORTER_SW][6][1].val			= RibOpacity
	DialogData[DIALOG_EXPORTER_SW][7][1].val			= RibSides
	DialogData[DIALOG_EXPORTER_SW][8][1].val			= RibBound
	DialogData[DIALOG_EXPORTER_SW][9][1].val			= RibVertexCols
	DialogData[DIALOG_EXPORTER_SW][10][1].val			= RibVertexUVs
	DialogData[DIALOG_EXPORTER_SW][11][1].val			= RibNormals
	DialogData[DIALOG_EXPORTER_SW][12][1].val			= RibComments
	ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT]	= RenderPreset
	ButtonData[SETTINGS][WIN_BUTS][SET_RENDER_BIN][BUT_DEFAULT]	= RenderBin
	ButtonData[SETTINGS][WIN_BUTS][SET_SHADER_BIN][BUT_DEFAULT]	= CompilerBin
	ButtonData[SETTINGS][WIN_BUTS][SET_TEXMAKE_BIN][BUT_DEFAULT]	= TexmakeBin
	ButtonData[SETTINGS][WIN_BUTS][SET_ENVMAKE_BIN][BUT_DEFAULT]	= EnvmakeBin
	ButtonData[SETTINGS][WIN_BUTS][SET_INFO_BIN][BUT_DEFAULT]	= InfoBin
	ButtonData[SETTINGS][WIN_BUTS][SET_SHADER_EXT][BUT_DEFAULT]	= ShaderExt
	ButtonData[SETTINGS][WIN_BUTS][SET_RIB_EXT][BUT_DEFAULT]	= RibExt
	ButtonData[SETTINGS][WIN_BUTS][SET_TEX_EXT][BUT_DEFAULT]	= TextureExt
	ButtonData[SETTINGS][WIN_BUTS][SET_RENDER_BIN][BUT_TIP]		= "Renderer: "+RenderBin
	ButtonData[SETTINGS][WIN_BUTS][SET_SHADER_BIN][BUT_TIP]		= "Compiler: "+CompilerBin
	ButtonData[SETTINGS][WIN_BUTS][SET_TEXMAKE_BIN][BUT_TIP]	= "Texture Optimizer: "+TexmakeBin
	ButtonData[SETTINGS][WIN_BUTS][SET_ENVMAKE_BIN][BUT_TIP]	= "LatEnv Optimizer: "+EnvmakeBin
	ButtonData[SETTINGS][WIN_BUTS][SET_INFO_BIN][BUT_TIP]		= "Shader Info: "+InfoBin
	ButtonData[SETTINGS][WIN_BUTS][SET_SHADER_EXT][BUT_TIP]		= "Shader Extension: "+ShaderExt
	ButtonData[SETTINGS][WIN_BUTS][SET_RIB_EXT][BUT_TIP]		= "RIB Extension: "+RibExt
	ButtonData[SETTINGS][WIN_BUTS][SET_TEX_EXT][BUT_TIP]		= "Texture Export Extension: "+TextureExt
	for index, item in enumerate(Filters): DialogData[DIALOG_FILE_FILTER][index][1].val = Filters[index]


GetRegistry()
GetTextPreset()


#### Looks for Object[Property][SubProperty1] and return property value or OnError value
def GetProperty(Object, Property, SubProperty1 = "", SubProperty2 = "", SubProperty3 = "", OnError = False):
	try:
		if (SubProperty3):	return Object.properties[Property][SubProperty1][SubProperty2][SubProperty3]
		elif (SubProperty2):	return Object.properties[Property][SubProperty1][SubProperty2]
		elif (SubProperty1):	return Object.properties[Property][SubProperty1]
		else:			return Object.properties[Property]
	except: return OnError


#### Create a filtered and sorted string of names suitable for PupMenu, type determines what blender objects are listed or pass Array of items through List, if Object is passed it is used for RIBset data collection otherwise object is found according to Type
#### also returns each name in order in array for position/name reference later. Type info: (-1=nothing, 0=Texts, 1=Scenes, 2=Cameras, 3=Groups, 4=Geometry, 5=Lamps, 6=Materials, 7=SceneSet, 8=CameraSet, 9=GeoSet, 10=LampSet, 11=MaterialSet)
def CreateMenu(Title="Menu Title", Filters=[""], Type=-1, manualList=[], FirstItems=[""], Sort=True, Object=""):
	Title = Title + ":%t"
	List = []
	menu = []
	
	if (Type == 0):	  						#List TEXT FILES
		List = [item.name for item in Blender.Text.Get() if not FirstItems.count(item.name)]
	elif (Type == 1): 						#List SCENES
		List = [item.name for item in Blender.Scene.Get() if not FirstItems.count(item.name)]
	elif (Type == 2): 						#List CAMERAS
		List = [item.name for item in Blender.Scene.GetCurrent().objects if item.getType() == "Camera" and not FirstItems.count(item.name)]
	elif (Type == 3): 						#List GROUPS
		List = [item.name for item in Blender.Group.Get() if not FirstItems.count(item.name)]
	elif (Type == 4): 						#list EXPORTABLE GEOMETRY
		List = [item.name for item in Blender.Scene.GetCurrent().objects if (item.getType() == "Mesh" or item.getType() == "Curve" or item.getType() == "Surf") and not FirstItems.count(item.name)]
	elif (Type == 5): 						#List LAMPS
		List = [item.name for item in Blender.Scene.GetCurrent().objects if item.getType() == "Lamp" and not FirstItems.count(item.name)]
	elif (Type == 6): 						#List MATERIALS
		List = [item.name for item in Blender.Material.Get() if not FirstItems.count(item.name)]
	elif (Type == 7): 						#List SCENES SETS
		if (Object):	currentScene = Object
		else:		currentScene = Blender.Scene.GetCurrent()
		if (currentScene.properties.has_key("MOSAICData")):	List = [k for k, v in currentScene.properties["MOSAICData"].iteritems() if not FirstItems.count(k)]
	elif (Type == 8): 						#List CAMERA SETS
		if (Object):	currentCamera = Object
		else:		currentCamera = Blender.Object.Get(ButtonData[CAMERAS][WIN_BUTS][CAM_SELECT][BUT_MENU][ButtonData[CAMERAS][WIN_BUTS][CAM_SELECT][BUTTON].val])
		if (currentCamera.properties.has_key("MOSAICData")):	List = [k for k, v in currentCamera.properties["MOSAICData"].iteritems() if not FirstItems.count(k)]
	elif (Type == 9): 						#List GEOMETRY SETS
		if (Object):	currentGeo = Object
		else:		currentGeo = Blender.Object.Get(ButtonData[GEOMETRY][WIN_BUTS][GEO_SELECT][BUT_MENU][ButtonData[GEOMETRY][WIN_BUTS][GEO_SELECT][BUTTON].val])
		if (currentGeo.properties.has_key("MOSAICData")):	List = [k for k, v in currentGeo.properties["MOSAICData"].iteritems() if not FirstItems.count(k)]
	elif (Type == 10): 						#List LAMP SETS
		if (Object):	currentLight = Object
		else:		currentLight = Blender.Object.Get(ButtonData[LIGHTS][WIN_BUTS][LIGHT_SELECT][BUT_MENU][ButtonData[LIGHTS][WIN_BUTS][LIGHT_SELECT][BUTTON].val])
		if (currentLight.properties.has_key("MOSAICData")):	List = [k for k, v in currentLight.properties["MOSAICData"].iteritems() if not FirstItems.count(k)]
	elif (Type == 11): 						#List MATERIAL SETS
		if (Object):	currentMat = Object
		else:		currentMat = Blender.Material.Get(ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUTTON].val])
		if (currentMat.properties.has_key("MOSAICData")):	List = [k for k, v in currentMat.properties["MOSAICData"].iteritems() if not FirstItems.count(k)]
	
	for Filter in Filters: menu.extend([item for item in List if not Filter or item.count(Filter)]) #Get filtered names in list	
	if (Sort == True):
		menu.sort()						#Sort list
		manualList.sort()
	menu.extend(manualList)
	for item in FirstItems:
		if (item): menu.insert(0, item)				#Insert manual first item if present
	Title = Title+'|'+'|'.join(menu)
	menu.insert(0, Title)						#Put menu string at top of list
	return menu


#### Clears specified count number of items from list starting at index, if count is not specified it defaults to end of list
def ClearList(List, index = 0, count = 0):
	if (List):
		length = len(List)
		if (count < 1): count = length-index
		if (index >= 0 and index+1 <= length):
			for popCount in range(count):
				List.pop(index)


#### Builds a list of [[use pass, scene, ribset, start frame, end frame],[ect...]] for use in renderpasses and scene exports
def BuildPassList(rootScene):
	renderPasses	= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_PASSES][BUT_PROP], "", "", "") #Get current scene passes
	passList	= []
	
	if (renderPasses and renderPasses.strip()):			#If theres custom render passes and its not whitespace then proceed
		for passString in renderPasses.split(','):		#Split pass string by scene separators
			try:
				passParameters	= passString.split(':') #Split scene string by parameter separator
				sceneParameters	= passParameters[0].split('@') #Split scene by RIBset separator
				passScene	= sceneParameters[0].strip() #Split parameter string by scene name
				passRIBset	= sceneParameters[1].strip() #Split parameter string by scene RIBset
				passRange	= passParameters[1].split('-') #Split parameter string by range separator (always assume a range is given)
				if (passScene[0] == '#'):
					usePass		= False
					passScene	= passScene[1:]	#Strip use token
				else:
					usePass		= True
				if (passScene != "NONE"):
					scene = Blender.Scene.Get(passScene)
					if (passRIBset != "DEFAULT" and passRIBset != "RIBSETPASSES" and (not scene.properties.has_key("MOSAICData") or not scene.properties["MOSAICData"].has_key(passRIBset))): passRIBset = "DEFAULT"
				else:
					scene		= passScene
					if (passRIBset != "DEFAULT" and passRIBset != "RIBSETPASSES"): passRIBset = "DEFAULT"
				if (len(passRange) == 1): passRange.extend(passRange) #If only one range then set to as from
				passList.append([usePass, scene, passRIBset, int(passRange[0]), int(passRange[1])]) #Put it all in pass list
			except: passList.append([False, "NONE", "DEFAULT", 1, 1]) #If something is wrong just make a default scene
	return passList


#### Builds the passes buttons in ButtonData for current project
def BuildPassesButtons(rootScene):
	global ButtonData
	passList = BuildPassList(rootScene)
	ClearList(ButtonData[PROJECT][WIN_BUTS], PROJECT_DIVIDER3+1)	#Clear existing render pass buttons from interface
	if (passList):
		for passData in passList:
			sceneMenu		= CreateMenu("SceneF", [""], 1, [], ["NONE"])
			if (passData[1] != "NONE"):
				sceneName	= passData[1].name
				ribsetMenu	= CreateMenu("Select RIBset", [""], 7, [], ["DEFAULT", "RIBSETPASSES"], True, passData[1])
			else:
				sceneName	= passData[1]
				ribsetMenu	= CreateMenu("Select RIBset", [""], -1, [], ["DEFAULT", "RIBSETPASSES"])
			if (not ribsetMenu.count(passData[2])): passData[2] = "DEFAULT"
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 3, 30.0, 0, "Use", "Whether or not to use this render pass", "", passData[0], 0, 1])
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), sceneMenu, True, 1, 0.175, 0, "SceneF", "Select scene to render for this pass: "+sceneName, "Select Scene", sceneMenu.index(sceneName), 0, 1])
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 1, 0.175, 0, ribsetMenu, "Select scenes RIBset for this pass (\"RIBSETPASSES\" exports all RIBsets alphabetically into separate passes except DEFAULT): "+passData[2], "RIBset", ribsetMenu.index(passData[2]), 0, 1])
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 2, 0.15, 0, "Sta", "Select animation starting frame, if 0 then use scenes Sta", "", passData[3], 0, 300000])
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 2, 0.15, 0, "End", "Select animation ending frame, if 0 then use scenes End", "", passData[4], 0, 300000])
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 0.075, 0, "Up", "Move this render pass up the stack", "", 1, 0, 1])
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 0.075, 0, "Dn", "Move this render pass down the stack", "", 1, 0, 1])
			ButtonData[PROJECT][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 100.0, 0, "Del", "Delete this render pass", "", 1, 0, 1])


#### Builds the shader library directory buttons in ButtonData
def BuildPathsButtons():
	global ButtonData, ShaderDir
	ClearList(ButtonData[SETTINGS][WIN_BUTS], SET_CREATE_SHDIR+1)	#Clear existing render pass buttons from interface
	if (type(ShaderDir) == list):	libDir = ShaderDir
	else:				libDir = [ShaderDir]
	if (libDir):
		for passData in libDir:
			if (type(passData) == str): 
				if (passData[0] == '#'):	usePath = 0
				else:				usePath = 1
				ButtonData[SETTINGS][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 3, 30.0, 0, "Use", "Whether or not to use this library path", "", usePath, 0, 1])
				ButtonData[SETTINGS][WIN_BUTS].append([Blender.Draw.Create(""), "", True, 4, 0.6, 0, "", "Shader Path: "+passData, "", passData, 0, 255])
				ButtonData[SETTINGS][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 0.2, 0, "Compile", "Compile all shader sources in this path", "", 1, 0, 1])
				ButtonData[SETTINGS][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 100.0, 0, "Del", "Delete this shader path", "", 1, 0, 1])


#### Builds the display drivers list in current scene
def BuildDisplaysButtons(currentScene):
	global ButtonData
	RIBset		= ButtonData[SCENES][WIN_BUTS][SCENE_SELECT_SET][BUT_MENU][ButtonData[SCENES][WIN_BUTS][SCENE_SELECT_SET][BUTTON].val]
	displayList	= GetProperty(currentScene, "MOSAICData", RIBset, "DisplayList", "", ButtonData[SCENES][WIN_BUTS][SCENE_ADD_DISPLAY][BUT_DEFAULT])
	ClearList(ButtonData[SCENES][WIN_BUTS], SCENE_ADD_DISPLAY+1)	#Clear existing display driver buttons from interface
	if (displayList):
		for displayData in displayList.split("<DIVIDER>"):
			if (displayData[0] == '#'):	useDisplay = 0
			else:				useDisplay = 1
			ButtonData[SCENES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 3, 30.0, 0, "Use", "Whether or not to use this display driver", "", useDisplay, 0, 1])
			ButtonData[SCENES][WIN_BUTS].append([Blender.Draw.Create(""), "", True, 4, 0.8, 0, "", "RiDisplay \"name\" \"type\" \"mode\" ...parameters (common types: \"file\", \"zfile\", \"framebuffer\") (common modes: \"rgb\", \"rgba\", \"z\") blank to reset", "", displayData, 0, 255])
			ButtonData[SCENES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 100.0, 0, "Del", "Delete this display driver", "", 1, 0, 1])


#### Builds the shader parameters buttons in ButtonData for current project
def BuildParamButtons(fragment):
	global ButtonData, DialogData
	shaderTypes	= ["Surface ", "Displacement ", "Atmosphere ", "Interior ", "Exterior ", "Imager ", "AreaLightSource ", "LightSource "]
	paraClasses	= ["constant ", "uniform ", "varying "]
	paraTypes	= ["integer", "float", "color", "point", "vector", "normal", "matrix", "hpoint", "string"]
	shaderTypeMenu	= ["Shader Type:%t|Surface|Displacement|Atmosphere|Interior|Exterior|Imager|AreaLightSource|LightSource", "Surface ", "Displacement ", "Atmosphere ", "Interior ", "Exterior ", "Imager ", "AreaLightSource ", "LightSource "]
	paraClassMenu	= ["Parameter Class:%t|NONE|constant|uniform|varying", "NONE", "constant ", "uniform ", "varying "]
	paraTypeMenu	= ["Parameter Type:%t|NONE|integer|float|color|point|vector|normal|matrix|hpoint|string", "NONE", "integer", "float", "color", "point", "vector", "normal", "matrix", "hpoint", "string"]
	paraName	= ""
	paraValue	= ""
	paraType	= ""
	paraArray	= ""
	paraDefault	= ""
	paraUse		= True
	shaderType	= []
	shaderName	= ""
	gotHeader	= False
	
	ClearList(ButtonData[UTILITIES][WIN_BUTS], UTIL_DIVIDER3+1)	#Clear existing parameter buttons from interface
	try:
		text = Blender.Text.Get(fragment).asLines()
		for lineIndex, line in enumerate(text):
			if (line.strip()):				#Make sure theres something in this line
				if (lineIndex == 0 and line[0] == '#'):	DialogData[DIALOG_COMMENTS][0][1].val = line.lstrip('#') #Add first line comment to usage comment dialog
				elif (not gotHeader and line.lstrip()[0] == '#'): continue #If theres other full line comments before the header then just ignore them
				elif (not gotHeader):
					shaderType	= [foundType for foundType in shaderTypes if line.count(foundType)]
					shaderName	= line.split("\"")[1]
					if (shaderType and shaderName):
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 1, 0.3, 0, shaderTypeMenu, "Shader type", "", shaderTypeMenu.index(shaderType[0]), 0, 1])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(""), "", True, 4, 0.5, 0, "", "Shader name", "", shaderName, 0, 255])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 100.0, 1, "NOTES", "Shader usage notes (can be viewed next to all shader selection controls)", "", 1, 0, 1])
						gotHeader = True
				elif (gotHeader and line.count("\"") >= 2):
					if (line[0] == '#'):	paraUse = False
					else:			paraUse = True
					paraClass	= [foundClass for foundClass in paraClasses if line.count(foundClass)]
					paraType	= [foundType for foundType in paraTypes if line.count(foundType+" ") or line.count(foundType+"[")]
					paraName	= line.lstrip().split("\"")[1].split().pop().strip()
					valueStart	= line.find("\"", line.find("\"")+1)+1
					valueEnd	= line.rfind('#')
					if (line.rfind('#>') == valueEnd): valueEnd = -1 #If the last '#' belongs to a frame token then theres no default
					if (not paraType):
						paraType	= ["NONE"]
						paraArray	= ""
					else:
						paraArray	= line[line.find(paraType[0])+len(paraType[0]):line.find(paraName+"\"")].strip()
					if (not paraClass):	paraClass	= ["NONE"]
					if (valueStart < 0):	valueStart	= 0
					if (valueEnd < 0):
						valueEnd = len(line)
						if (paraType[0] == paraTypes[0]):	paraDefault = "[ 1 ]"
						elif (paraType[0] == paraTypes[1]):	paraDefault = "[ 1.0 ]"
						elif (paraType[0] == paraTypes[2]
						      or paraType[0] == paraTypes[3]
						      or paraType[0] == paraTypes[4]
						      or paraType[0] == paraTypes[5]):	paraDefault = "[ 1 1 1 ]"
						elif (paraType[0] == paraTypes[6]):	paraDefault = "[ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ]"
						elif (paraType[0] == paraTypes[7]):	paraDefault = "[ 1 1 1 1 ]"
						else:					paraDefault = "[ \"\" ]"
					else:	paraDefault	= line[line.rfind('#')+1:].strip()
					paraValue		= line[valueStart:valueEnd].strip()
					if (paraClass and paraType and paraName):
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 3, 30.0, 0, "Use", "Whether or not to use this parameter", "", paraUse, 0, 1])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 1, 0.15, 0, paraClassMenu, "Parameter class", "", paraClassMenu.index(paraClass[0]), 0, 1])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 1, 0.15, 0, paraTypeMenu, "Parameter type", "", paraTypeMenu.index(paraType[0]), 0, 1])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(""), "", True, 4, 25.0, 0, "", "Parameter array (blank for none): "+paraArray, "", paraArray, 0, 255])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(""), "", True, 4, 0.2, 0, "", "Parameter name: "+paraName, "", paraName, 0, 255])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(""), "", True, 4, 0.2, 0, "", "Parameter value: "+paraValue, "", paraValue, 0, 255])
						ButtonData[UTILITIES][WIN_BUTS].append([Blender.Draw.Create(1), "", True, 0, 100.0, 0, "TW", "Start token wizard to hook this parameter to a Blender control", paraDefault, 1, 0, 1])
		if (not gotHeader):
			ErrorPopup("Could not parse shader fragment, check syntax or re-generate fragment")
			return 1
	except: return 1
	return 0


####################################################################### SETUP USER GLOBAL VARIABLES
#These are a list of tokens used to plug blender control values into shader and/or custom code parameter values, there format is as follows:
#This array of tokens is separated according to object types and then parameter types so...
#first by objects: lamps(light shader), materials(surface, displace, area), cameras(imager), world/scene(atmosphere)
#and then by parameters: numbers integer, float, color, point, vector, normal, matrix, hpoint, string
#also tokens can have parameters, they are: _I=integer, _F=float, _C=color, _P=point, _V=vector, _N=normal, _M=matrix, _H=hpoint, _S=string, _X#=texture index, _A#=range adjust adder, _M#=range adjust multiplier
			    #Lamp tokens (light shaders/code)
Tokens			= [[["LampIsSphere", "LampIsRaytrace", "LampIsQuad", "LampType", "LampEnergy", "LampDist", "LampSpotSi", "LampSpotBl", "LampShadBufSize", "LampSamples", "LampHaloInt", "LampBias", "LampSoft", "LampClipStart", "LampClipEnd", "LampSizeX", "LampSizeY", "LampSamplesX", "LampSamplesY", "LampHaloStep", "LampQuad1", "LampQuad2", "LampNoDiffuse", "LampNoSpec"], #Integers
			    ["LampIsSphere", "LampIsRaytrace", "LampIsQuad", "LampType", "LampEnergy", "LampDist", "LampSpotSi", "LampSpotBl", "LampShadBufSize", "LampSamples", "LampHaloInt", "LampBias", "LampSoft", "LampClipStart", "LampClipEnd", "LampSizeX", "LampSizeY", "LampSamplesX", "LampSamplesY", "LampHaloStep", "LampQuad1", "LampQuad2", "LampNoDiffuse", "LampNoSpec"], #Floats
			    ["LampLightColor"], #Colors
			    ["TO", "FROM"], #Points
			    ["TO"], #Vectors
			    ["TO"], #Normals
			    ["FROM"], #Matrices
			    [], #Hpoints
			    []], #Strings
			    #Material tokens (surface/displace/area shaders/code)
			   [["MatHaloAdd", "MatIsRayMirror", "MatIsRayTransp", "MatIsShadeless", "MatAlpha", "MatAmb", "MatDiffuseDark", "MatDiffuseSize", "MatDiffuseSmooth", "MatEmit", "MatRayFilt", "MatFlareBoost", "MatFlareSeed", "MatFlareSize", "MatMirrorFresnel", "MatMirrorFac", "MatRayFresnel", "MatRayFac", "MatHaloSeed",
			     "MatHaloSize", "MatHard", "MatRayIOR", "MatFlares", "MatLines", "MatRings", "MatStar", "MatRayMir", "MatMirrorDepth", "MatRef", "MatRefr", "Matrms", "MatRough", "MatShadA", "MatSpec", "MatSpecSize", "MatSpecSmooth", "MatSpecTra", "MatSSSBack", "MatSSSColBlend",
			     "MatSSSError", "MatSSSIOR", "MatSSSRadiusB", "MatSSSRadiusR", "MatSSSRadiusG", "MatSSSTex", "MatHaloSubSize", "MatRayDepth", "MatTranslu", "MatZoffs", "MatMapCol_X", "MatMapDisp_X", "MatMapDVar_X", "MatMapNor_X", "MatMapOfsX_X", "MatMapOfsY_X", "MatMapOfsZ_X",
			     "MatMapOfSzXY_X", "MatMapSizeX_X", "MatMapSizeY_X", "MatMapSizeZ_X", "MatMapVar_X", "MatTexFrames_X", "MatTexOffs_X", "MatTexStartFr_X", "MatTexBright_X", "MatTexContr_X", "MatTexMinX_X", "MatTexMaxX_X", "MatTexMinY_X", "MatTexMaxY_X", "MatTexFieIma_X", "MatTexFilter_X",
			     "MatTexXrepeat_X", "MatTexYrepeat_X", "MatTexDistAmnt_X", "MatTexExp_X", "MatTexiScale_X", "MatTexH_X", "MatTexLacu_X", "MatTexNDepth_X", "MatTexNSize_X", "MatTexOcts_X", "MatTexTurb_X", "MatTexW1_X", "MatTexW2_X", "MatTexW3_X", "MatTexW4_X", "MatImageSizeX_X",
			     "MatImageSizeY_X", "MatImageStart_X", "MatImageEnd_X", "MatImageDepth_X", "MatImageSpeed_X", "MatImageXrep_X", "MatImageYrep_X"], #Integers
			    ["MatHaloAdd", "MatIsRayMirror", "MatIsRayTransp", "MatIsShadeless", "MatAlpha", "MatAmb", "MatDiffuseDark", "MatDiffuseSize", "MatDiffuseSmooth", "MatEmit", "MatRayFilt", "MatFlareBoost", "MatFlareSeed", "MatFlareSize", "MatMirrorFresnel", "MatMirrorFac", "MatRayFresnel", "MatRayFac", "MatHaloSeed",
			     "MatHaloSize", "MatHard", "MatRayIOR", "MatFlares", "MatLines", "MatRings", "MatStar", "MatRayMir", "MatMirrorDepth", "MatRef", "MatRefr", "Matrms", "MatRough", "MatShadA", "MatSpec", "MatSpecSize", "MatSpecSmooth", "MatSpecTra", "MatSSSBack", "MatSSSColBlend",
			     "MatSSSError", "MatSSSIOR", "MatSSSRadiusB", "MatSSSRadiusR", "MatSSSRadiusG", "MatSSSTex", "MatHaloSubSize", "MatRayDepth", "MatTranslu", "MatZoffs", "MatMapCol_X", "MatMapDisp_X", "MatMapDVar_X", "MatMapNor_X", "MatMapOfsX_X", "MatMapOfsY_X", "MatMapOfsZ_X",
			     "MatMapOfSzXY_X", "MatMapSizeX_X", "MatMapSizeY_X", "MatMapSizeZ_X", "MatMapVar_X", "MatTexFrames_X", "MatTexOffs_X", "MatTexStartFr_X", "MatTexBright_X", "MatTexContr_X", "MatTexMinX_X", "MatTexMaxX_X", "MatTexMinY_X", "MatTexMaxY_X", "MatTexFieIma_X", "MatTexFilter_X",
			     "MatTexXrepeat_X", "MatTexYrepeat_X", "MatTexDistAmnt_X", "MatTexExp_X", "MatTexiScale_X", "MatTexH_X", "MatTexLacu_X", "MatTexNDepth_X", "MatTexNSize_X", "MatTexOcts_X", "MatTexTurb_X", "MatTexW1_X", "MatTexW2_X", "MatTexW3_X", "MatTexW4_X", "MatImageSizeX_X",
			     "MatImageSizeY_X", "MatImageStart_X", "MatImageEnd_X", "MatImageDepth_X", "MatImageSpeed_X", "MatImageXrep_X", "MatImageYrep_X"], #floats
			    ["MatMirrorColor", "MatCol", "MatSpecCol", "MatSSSCol", "MatMapColor_X", "MatTexColor_X"], #Colors
			    [], #Points
			    [], #Vectors
			    [], #Normals
			    [], #Matrices
			    [], #Hpoints
			    ["MatImageName_X"]], #Strings
			    #Camera tokens (imager shaders/code)
			   [["CameraAlpha", "CameraAngle", "CameraEnd", "CameraStart", "CameraDofDist", "CameraSize", "CameraLens", "CameraScale", "CameraX", "CameraY"], #Integers
			    ["CameraAlpha", "CameraAngle", "CameraEnd", "CameraStart", "CameraDofDist", "CameraSize", "CameraLens", "CameraScale", "CameraX", "CameraY"], #Floats
			    [], #Colors
			    ["TO", "FROM"], #Points
			    ["TO"], #Vectors
			    ["TO"], #Normals
			    ["FROM"], #Matrices
			    [], #Hpoints
			    []], #Strings
			    #World/Scene Global tokens (for all shaders/code)
			   [["####", "LightID", "SceneAspX", "SceneAspY", "SceneEnd", "SceneFps", "SceneBf", "SceneFilterSize", "ScenePlanes", "SceneOSALevel", "SceneStart", "SceneSizeX", "SceneSizeY", "SceneXparts", "SceneYparts", "WorldIsMist", "WorldMistType", "WorldMist", "WorldSta", "WorldDi",
			     "WorldIsOcc", "WorldHi", "WorldSize", "WorldMinDist", "WorldStarDist", "WorldColnoise"], #Integers
			    ["####", "SceneAspX", "SceneAspY", "SceneEnd", "SceneFps", "SceneBf", "SceneFilterSize", "ScenePlanes", "SceneOSALevel", "SceneStart", "SceneSizeX", "SceneSizeY", "SceneXparts", "SceneYparts", "WorldIsMist", "WorldMistType", "WorldMist", "WorldSta", "WorldDi", "WorldHi",
			     "WorldIsOcc", "WorldSize", "WorldMinDist", "WorldStarDist", "WorldColnoise"], #Floats
			    ["SceneEdgeColor", "WorldAmbCol", "WorldHorCol", "WorldZenCol"], #Colors
			    [], #Points
			    [], #Vectors
			    [], #Normals
			    [], #Matrices
			    [], #Hpoints
			    ["ObjectName", "ProjectDir", ]],#Strings
			    #None Group
			   [[],
			    [],
			    [],
			    [],
			    [],
			    [],
			    [],
			    [],
			    []]] #None

#This array is used to try and identity standard integer and float shader parameters and return standard upper and lower bounds adjustments for easy translation of blender controls to shader parameters
#The array uses the following fields: ["blender control token", (+/-float) blender control adder as string, (+/-float) blender control multiplier as string]
StandardRanges		= [["LampEnergy", "0.0", "30.0"],
			   ["LampSpotSi", "0.0", "0.5"],
			   ["LampSpotBl", "0.0", "0.2"],
			   ["MatHard", "0.0", "0.25"]]

#This array is used to try and identity standard shader parameters and replace them with pre-set token parameters
StandardTokens		= [["float intensity", "<LampEnergy_F_M30.0_A0.0>"],
			   ["point to", "<TO_P>"],
			   ["point from", "<FROM_P>"],
			   ["color lightcolor", "<LampLightColor_C>"],
			   ["float coneangle", "<LampSpotSi_F_M0.5_A0.0>"],
			   ["float conedeltaangle", "<LampSpotBl_F_M0.2_A0.0>"],
			   ["color specularcolor", "<MatSpecCol_C>"],
			   ["float roughness", "<MatHard_M-0.001956947162426614481_A1.0_F>"],
			   ["float Ks", "<MatSpec_M1.0_A0.0_F>"],
			   ["float Kd", "<MatRef_M1.0_A0.0_F>"],
			   ["float Ka", "<MatAmb_M1.0_A0.0_F>"],
			   ["float Km", "<MatMapDisp_X1_M1.0_A0.0_F>"],
			   ["float __nondiffuse", "<LampNoDiffuse_F_M1.0_A0.0>"],
			   ["float __nonspecular", "<LampNoSpec_F_M1.0_A0.0>"]]

#These are the default shaders to approximate Blender like renders
surfaceShader		= ["/* MOSAIC default surface shader for Blender integration */\n",
			   "\n",
			   "void stAdjust(output float sAdj,tAdj;float s,t,texOfSz[4]) //Adjust texture st with xy offset and size\n",
			   "{\n",
			   "\tsAdj = (s*texOfSz[2]-(texOfSz[2]-1)/2)+texOfSz[0];\n",
			   "\ttAdj = (t*texOfSz[3]-(texOfSz[3]-1)/2)-texOfSz[1];\n",
			   "}\n",
			   "\n",
			   "surface\n",
			   "MOSAICsurface(\n",
			   "\tfloat Amb=1; //Standard Blender material controls\n",
			   "\tfloat Ref=0.8;\n",
			   "\tfloat Spec=0.5;\n",
			   "\tfloat RayMir=1;\n",
			   "\tfloat Hard=0.1;\n",
			   "\tfloat Alpha=1;\n",
			   "\tfloat Tralu=0;\n",
			   "\tfloat Emit=0;\n",
			   "\tfloat ColMix=1;\n",
			   "\tfloat CmirMix=1;\n",
			   "\tfloat CspMix=1;\n",
			   "\tfloat IOR=1.5;\n",
			   "\tfloat MirFresnel=1;\n",
			   "\tfloat TranspFresnel=1;\n",
			   "\tfloat OccMaxdist=1e38; //User non Blender controls\n",
			   "\tfloat OccSamples=8;\n",
			   "\tfloat OccEnergy=1;\n",
			   "\tfloat OccMapBlur=0.1;\n",
			   "\tfloat OccBias=0.1;\n",
			   "\tfloat EnvSamples=8;\n",
			   "\tfloat EnvBlur=0;\n",
			   "\tfloat isRayMirror=0; //Material state toggles\n",
			   "\tfloat isRayTransp=0;\n",
			   "\tfloat isShadeless=0;\n",
			   "\tfloat isOcclusion=0;\n",
			   "\tcolor SpecCol=1; //Standard Blender material colors\n",
			   "\tcolor MirCol=1;\n",
			   "\tcolor OccCol=1;\n",
			   "\tcolor AmbCol=1;\n",
			   "\tstring ColMap=\"\"; //Standard Blender texture channels\n",
			   "\tstring AlphaMap=\"\";\n",
			   "\tstring CspMap=\"\";\n",
			   "\tstring RayMirMap=\"\";\n",
			   "\tstring CmirMap=\"\";\n",
			   "\tstring RefMap=\"\";\n",
			   "\tstring SpecMap=\"\";\n",
			   "\tstring HardMap=\"\";\n",
			   "\tstring AmbMap=\"\";\n",
			   "\tstring EmitMap=\"\";\n",
			   "\tstring OccMap=\"\"; //User non Blender materials\n",
			   "\tstring HDRIEnvMap=\"\";\n",
			   "\tstring EnvMap=\"\";\n",
			   "\tvarying float ColOfSz[4]={0,0,1,1}; //Texture mapping arrays as offset x/y scale x/y\n",
			   "\tvarying float AlphaOfSz[4]={0,0,1,1};\n",
			   "\tvarying float CspOfSz[4]={0,0,1,1};\n",
			   "\tvarying float RayMirOfSz[4]={0,0,1,1};\n",
			   "\tvarying float CmirOfSz[4]={0,0,1,1};\n",
			   "\tvarying float RefOfSz[4]={0,0,1,1};\n",
			   "\tvarying float SpecOfSz[4]={0,0,1,1};\n",
			   "\tvarying float HardOfSz[4]={0,0,1,1};\n",
			   "\tvarying float AmbOfSz[4]={0,0,1,1};\n",
			   "\tvarying float EmitOfSz[4]={0,0,1,1};)\n",
			   "{\n",
			   "\tvector In = normalize(I);\n",
			   "\tnormal Nf = normalize(faceforward(N,In));\n",
			   "\tfloat sAdj,tAdj;\n",
			   "\tif (ColMap != \"\") //Are we using a color texture map?\n",
			   "\t{\n",
			   "\t\tstAdjust(sAdj,tAdj,s,t,ColOfSz);\n",
			   "\t\tCi = color mix(Cs,color texture(ColMap,sAdj,tAdj),ColMix);\n",
			   "\t}\n",
			   "\telse Ci = Cs;\n",
			   "\tif (isShadeless == 0) //Only process the rest if we are not shadeless\n",
			   "\t{\n",
			   "\t\tcolor Uad = color \"rgb\" (0,0,0);\n",
			   "\t\tif (EmitMap != \"\" || Emit > 0) //Are we using emit controls or map?\n",
			   "\t\t{\n",
			   "\t\t\tif (EmitMap != \"\") //Are we using a emit texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,EmitOfSz);\n",
			   "\t\t\t\tUad += Emit*Ci+float texture(EmitMap,sAdj,tAdj);\n",
			   "\t\t\t}\n",
			   "\t\t\telse Uad += Emit*Ci;\n",
			   "\t\t}\n",
			   "\t\tif (AmbMap != \"\" || Amb > 0) //Are we using ambient controls or map?\n",
			   "\t\t{\n",
			   "\t\t\tfloat hits = 0;\n",
			   "\t\t\tfloat Uam = 1;\n",
			   "\t\t\tcolor Ua = ambient();\n",
			   "\t\t\tif (isOcclusion > 0) //Is ambience supposed to be occlusion or HDRI?\n",
			   "\t\t\t{\n",
			   "#if defined(DELIGHT) //Is this 3Delight style HDRI?\n",
			   "\t\t\t\tif (HDRIEnvMap != \"\") Ua += (1-indirectdiffuse(P,Nf,OccSamples,\"bias\",OccBias,\"maxdist\",OccMaxdist,\"environmentmap\",HDRIEnvMap))*OccEnergy;\n",
			   "#endif //Is this other raytrace renderers style HDRI?\n",
			   "#if (defined(PRMAN)||defined(AIR)||defined(PIXIE))\n",
			   "\t\t\t\tif (HDRIEnvMap != \"\") Ua += indirectdiffuse(P,Nf,OccSamples,\"bias\",OccBias,\"maxdist\",OccMaxdist,\"environmentmap\",HDRIEnvMap)*OccEnergy;\n",
			   "#endif\n",
			   "#if (defined(PRMAN)||defined(DELIGHT)||defined(PIXIE)) //Is this other raytrace renderers style occlusion?\n",
			   "\t\t\t\telse Ua += (1-occlusion(P,Nf,OccSamples,\"bias\",OccBias,\"maxdist\",OccMaxdist))*OccCol*OccEnergy;\n",
			   "#endif\n",
			   "#if defined(AIR) //Is this Air style occlusion?\n",
			   "\t\t\t\telse\n",
			   "\t\t\t\t{\n",
			   "\t\t\t\t\tnormal Nunoccl = 0;\n",
			   "\t\t\t\t\tUa += (1-occlusion(P,Nf,radians(90),Nunoccl,\"samples\",OccSamples,\"bias\",OccBias,\"blur\",OccMapBlur))*OccCol*OccEnergy;\n",
			   "\t\t\t\t}\n",
			   "#endif\n",
			   "#if defined(AQSIS) //Is this Aqsis sytle depth map occlusion?\n",
			   "\t\t\t\tif (OccMap != \"\") Ua += (1-occlusion(OccMap,P,Nf,0,\"samples\",OccSamples,\"bias\",OccBias,\"blur\",OccMapBlur))*OccCol*OccEnergy;\n",
			   "#endif\n",
			   "\t\t\t}\n",
			   "\t\t\tif (AmbMap != \"\") //Are we using a ambient texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,AmbOfSz);\n",
			   "\t\t\t\tUam = float texture(AmbMap,sAdj,tAdj);\n",
			   "\t\t\t}\n",
			   "\t\t\tUad += (Ua+AmbCol)*Uam*Amb;\n",
			   "\t\t}\n",
			   "\t\tif (RefMap != \"\" || Ref > 0) //Are we using ref (diffuse) controls or map?\n",
			   "\t\t{\n",
			   "\t\t\tcolor Udif = diffuse(Nf);\n",
			   "\t\t\tif (Tralu > 0) Udif += diffuse(-Nf)*Tralu;\n",
			   "\t\t\tif (RefMap != \"\") //Are we using a ref texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,RefOfSz);\n",
			   "\t\t\t\tUad += mix(float texture(RefMap,sAdj,tAdj)*Udif,Udif,Ref);\n",
			   "\t\t\t}\n",
			   "\t\t\telse Uad += Ref*Udif;\n",
			   "\t\t}\n",
			   "\t\tCi *= Uad;\n",
			   "\t\t//Are we using raytrace or environment controls for reflection/refraction?\n",
			   "\t\tif (EnvMap != \"\" || isRayMirror > 0 || isRayTransp > 0)\n",
			   "\t\t{\n",
			   "\t\t\tcolor Umc = MirCol;\n",
			   "\t\t\tfloat Um = RayMir;\n",
			   "\t\t\tif (RayMirMap != \"\") //Are we using a mirror texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,RayMirOfSz);\n",
			   "\t\t\t\tUm = mix(RayMir,float texture(RayMirMap,sAdj,tAdj),1-RayMir);\n",
			   "\t\t\t}\n",
			   "\t\t\tif (CmirMap != \"\") //Are we using a mirror color texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,CmirOfSz);\n",
			   "\t\t\t\tUmc = mix(MirCol,color texture(CmirMap,sAdj,tAdj),CmirMix);\n",
			   "\t\t\t}\n",
			   "\t\t\tif (isRayMirror == 0 && EnvMap != \"\") //Are we using environment reflection map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tvector R = reflect(normalize(I),Nf);\n",
			   "\t\t\t\tif (EnvMap != \"raytrace\") R = ntransform(\"world\",R)*(1,1,-1);\n",
			   "\t\t\t\tCi = mix(Ci,color environment(EnvMap,R,\"samples\",EnvSamples,\"blur\",EnvBlur)*Umc,Um);\n",
			   "\t\t\t}\n",
			   "\t\t\telse\n",
			   "\t\t\t{\n",
			   "\t\t\t\tvector R,T;\n",
			   "\t\t\t\tfloat Kmr,Kmt;\n",
			   "\t\t\t\tfresnel(In,Nf,(In.N < 0 ? 1/IOR:IOR),Kmr,Kmt,R,T);\n",
			   "\t\t\t\tif (isRayTransp > 0) //Are we using raytrace refraction?\n",
			   "\t\t\t\t{\n",
			   "\t\t\t\t\tKmt = clamp(Kmr/TranspFresnel*12,0,1);\n",
			   "\t\t\t\t\tCi = Ci*Kmt+trace(P,T)*(1-Kmt);\n",
			   "\t\t\t\t}\n",
			   "\t\t\t\tif (isRayMirror > 0) //Are we using raytrace reflection?\n",
			   "\t\t\t\t{\n",
			   "\t\t\t\t\tif (MirFresnel > 0) Kmr = clamp(Kmr/(MirFresnel/12),0,1);\n",
			   "\t\t\t\t\telse Kmr = 1;\n",
			   "\t\t\t\t\tCi = Ci*(1-Um*Kmr)+trace(P,R)*Umc*Um*Kmr;\n",
			   "\t\t\t\t}\n",
			   "\t\t\t}\n",
			   "\t\t}\n",
			   "\t\tif (SpecMap != \"\" || Spec > 0) //Are we using specular controls or maps?\n",
			   "\t\t{\n",
			   "\t\t\tcolor Usc = SpecCol;\n",
			   "\t\t\tfloat Ur = Hard;\n",
			   "\t\t\tif (HardMap != \"\") //Are we using a hard texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,HardOfSz);\n",
			   "\t\t\t\tUr += Hard*float texture(HardMap,sAdj,tAdj);\n",
			   "\t\t\t}\n",
			   "\t\t\tcolor Us = specular(Nf,-In,PI/Ur);\n",
			   "\t\t\tif (CspMap != \"\") //Are we using a specular color texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,CspOfSz);\n",
			   "\t\t\t\tUsc = mix(SpecCol,color texture(CspMap,sAdj,tAdj),CspMix);\n",
			   "\t\t\t}\n",
			   "\t\t\tif (SpecMap != \"\") //Are we using a specular map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,SpecOfSz);\n",
			   "\t\t\t\tCi += Usc*(Spec*float texture(SpecMap,sAdj,tAdj)*Us);\n",
			   "\t\t\t}\n",
			   "\t\t\telse Ci += Usc*Spec*Us;\n",
			   "\t\t}\n",
			   "\t}\n",
			   "\tif (AlphaMap != \"\") //Are we using a alpha texture map?\n",
			   "\t{\n",
			   "\t\tstAdjust(sAdj,tAdj,s,t,AlphaOfSz);\n",
			   "\t\tOi = mix(float texture(AlphaMap,sAdj,tAdj),Alpha,Alpha);\n",
			   "\t}\n",
			   "\telse Oi = Os;\n",
			   "\tCi *= Oi;\n",
			   "}\n"]

displaceShader		= ["/* MOSAIC default displacement shader for Blender integration */\n",
			   "\n",
			   "void stAdjust(output float sAdj,tAdj;float s,t,texOfSz[4]) //Adjust texture st with xy offset and size\n",
			   "{\n",
			   "\tsAdj = (s*texOfSz[2]-(texOfSz[2]-1)/2)+texOfSz[0];\n",
			   "\ttAdj = (t*texOfSz[3]-(texOfSz[3]-1)/2)-texOfSz[1];\n",
			   "}\n",
			   "\n",
			   "displacement\n",
			   "MOSAICdisplace(\n",
			   "\tfloat Disp=1; //Standard Blender material controls\n",
			   "\tfloat Nor=1;\n",
			   "\tstring DispMap=\"\"; //Standard Blender texture channels\n",
			   "\tstring NorMap=\"\";\n",
			   "\tvarying float DispOfSz[4]={0,0,1,1}; //Texture mapping arrays as offset x/y scale x/y\n",
			   "\tvarying float NorOfSz[4]={0,0,1,1};)\n",
			   "{\n",
			   "\tfloat sAdj,tAdj;\n",
			   "\tif (DispMap != \"\") //Are we using a displacement texture map?\n",
			   "\t{\n",
			   "\t\tstAdjust(sAdj,tAdj,s,t,DispOfSz);\n",
			   "\t\tfloat amp = Disp*float texture(DispMap,sAdj,tAdj);\n",
			   "\t\tP += amp*normalize(N);\n",
			   "\t}\n",
			   "\tnormal Un = calculatenormal(P);\n",
			   "\tif (NorMap != \"\") //Are we using a normal texture map?\n",
			   "\t{\n",
			   "\t\tnormal Nref = normalize(Un);\n",
			   "\t\tvector dPds = normalize(Deriv(P,s));\n",
			   "\t\tvector dPdt = normalize(Deriv(P,t));\n",
			   "\t\tstAdjust(sAdj,tAdj,s,t,NorOfSz);\n",
			   "\t\tcolor Ncolor = color texture(NorMap,sAdj,tAdj);\n",
			   "\t\tvector Nvector = (vector(Ncolor)*2)-vector(1.0,1.0,1.0);\n",
			   "\t\tvector Ntransformed = vector(comp(Nvector,0)*comp(dPds,0)+comp(Nvector,1)*comp(dPdt,0)+comp(Nvector,2)*comp(Nref,0),\n",
			   "\t\t\t\t\t\tcomp(Nvector,0)*comp(dPds,1)+comp(Nvector,1)*comp(dPdt,1)+comp(Nvector,2)*comp(Nref,1),\n",
			   "\t\t\t\t\t\tcomp(Nvector,0)*comp(dPds,2)+comp(Nvector,1)*comp(dPdt,2)+comp(Nvector,2)*comp(Nref,2));\n",
			   "\t\tN = mix(Un,normal normalize(Ntransformed),Nor/2);\n",
			   "\t}\n",
			   "\telse N = Un;\n",
			   "}\n"]

lightShader		= ["/* MOSAIC default light shader for Blender integration */\n",
			   "\n",
			   "void stAdjust(output float sAdj,tAdj;float s,t,texOfSz[4]) //Adjust texture st with xy offset and size\n",
			   "{\n",
			   "\tsAdj = (s*texOfSz[2]-(texOfSz[2]-1)/2)+texOfSz[0];\n",
			   "\ttAdj = (t*texOfSz[3]-(texOfSz[3]-1)/2)-texOfSz[1];\n",
			   "}\n",
			   "\n",
			   "float Attenuation(float Ldepth,LinAtten,SqrAtten,QuadAtten,Distance,SphereAtten;) //Returns different attenuations of light depth\n",
			   "{\n",
			   "\tfloat attenuation = 1;\n",
			   "\tattenuation = Distance/(LinAtten*Ldepth+SqrAtten*Ldepth*2+QuadAtten*Ldepth*Ldepth+Distance);\n",
			   "\tif (SphereAtten > 0) attenuation *= 1-Ldepth/Distance;\n",
			   "\treturn clamp(attenuation,0,1);\n",
			   "}\n",
			   "\n",
			   "light MOSAIClight(\n",
			   "\tfloat LightType=0; //Standard Blender lamp controls\n",
			   "\tfloat Energy=1;\n",
			   "\tfloat Dist=1;\n",
			   "\toutput float SpotSi=radians(30);\n",
			   "\toutput float SpotBl=radians(5);\n",
			   "\toutput float Quad1=1;\n",
			   "\toutput float Quad2=0;\n",
			   "\toutput float Quad3=0;\n",
			   "\tpoint from=point \"shader\" (0,0,0);\n",
			   "\tpoint to=point \"shader\" (0,0,1);\n",
			   "\tpoint up=point \"eye\" (0,1,0);\n",
			   "\tcolor LightColor= color \"rgb\" (1,1,1);\n",
			   "\tfloat isRaytrace=0; //Lamp state toggles\n",
			   "\tfloat isSphere=0;\n",
			   "\tfloat isQuad=0;\n",
			   "\tvarying float ProjOfSz[4]={0,0,1,1}; //Texture mapping array as offset x/y scale x/y\n",
			   "\toutput float __nondiffuse=0; //Standard built in message passing parameters\n",
			   "\toutput float __nonspecular=0;\n",
			   "\toutput float __foglight=1;\n",
			   "\toutput float Samples=8; //User non Blender controls\n",
			   "\toutput float Blur=0.01;\n",
			   "\toutput float Bias=0.1;\n",
			   "\tstring projectionmap=\"\"; //Projector texture\n",
			   "\toutput string shadowname=\"\"; //User shadow map channels\n",
			   "\tstring shadowname_px=\"\";\n",
			   "\tstring shadowname_nx=\"\";\n",
			   "\tstring shadowname_py=\"\";\n",
			   "\tstring shadowname_ny=\"\";\n",
			   "\tstring shadowname_pz=\"\";\n",
			   "\tstring shadowname_nz=\"\";)\n",
			   "{\n",
			   "\tuniform vector Z = normalize(to-from);\n",
			   "\tcolor vis = 1;\n",
			   "\tfloat sAdj,tAdj;\n",
			   "\tif (isQuad == 0) //Setup attenuations for Quad type\n",
			   "\t{\n",
			   "\t\tQuad1 = 1;\n",
			   "\t\tQuad2 = 0;\n",
			   "\t}\n",
			   "\tif (LightType == 4) //If an area light manually set attenuation and spot size and blend\n",
			   "\t{\n",
			   "\t\tQuad1 = 1;\n",
			   "\t\tQuad2 = 1;\n",
			   "\t\tQuad3 = 1;\n",
			   "\t\tSpotSi = radians(90);\n",
			   "\t\tSpotBl = radians(50);\n",
			   "\t}\n",
			   "\tif (isRaytrace > 0) shadowname = \"raytrace\"; //If raytracing then setup use \"raytrace\" map name method\n",
			   "\tif (LightType == 1) //Are we a distant light?\n",
			   "\t{\n",
			   "\t\tsolar (to-from,0.0)\n",
			   "\t\t{\n",
			   "\t\t\tif (shadowname != \"\") vis = (1-shadow(shadowname,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias));\n",
			   "\t\t\tCl = vis*Energy*LightColor;\n",
			   "\t\t}\n",
			   "\t}\n",
			   "\telse if (LightType == 2 || LightType == 4) //Are we a spot light or single light in a array of area lights?\n",
			   "\t{\n",
			   "\t\tuniform vector Y = normalize(Z^vector up);\n",
			   "\t\tuniform vector X = normalize(Y^Z);\n",
			   "\t\tuniform float spread = 1/tan(radians(SpotSi)*57);\n",
			   "\t\tilluminate (from,Z,SpotSi)\n",
			   "\t\t{\n",
			   "\t\t\tfloat sloc = spread*L.X/L.Z*0.5+0.5;\n",
			   "\t\t\tfloat tloc = spread*L.Y/L.Z*0.5+0.5;\n",
			   "\t\t\tvis *= smoothstep(cos(SpotSi),cos(SpotSi-SpotBl),(L.Z)/length(L));\n",
			   "\t\t\tif (projectionmap != \"\") //Are we using a projection texture map?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tstAdjust(sAdj,tAdj,s,t,ProjOfSz);\n",
			   "\t\t\t\tvis *= color texture(projectionmap,sAdj,tAdj);\n",
			   "\t\t\t}\n",
			   "\t\t\tif (shadowname != \"\") vis *= 1-shadow(shadowname,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\tCl = vis*Energy*LightColor*Attenuation(length(L),Quad1,Quad2,Quad3,Dist,isSphere);\n",
			   "\t\t}\n",
			   "\t}\n",
			   "\telse //Are we a point light?\n",
			   "\t{\n",
			   "\t\tilluminate (from)\n",
			   "\t\t{\n",
			   "\t\t\tpoint Lworld = transform(\"world\",L+point \"world\" (0,0,0))*point (1,1,-1);\n",
			   "\t\t\tfloat ax = abs(xcomp(Lworld));\n",
			   "\t\t\tfloat ay = abs(ycomp(Lworld));\n",
			   "\t\t\tfloat az = abs(zcomp(Lworld));\n",
			   "\t\t\tif (shadowname != \"\") vis = 1-shadow(shadowname,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\telse if ((shadowname_px != \"\") && (shadowname_nx != \"\") && (ax > ay) && (ax > az)) //Are we using X+- shadow maps?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tif (xcomp(Lworld) > 0.0) vis = 1-shadow(shadowname_px,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\t\telse vis = 1-shadow(shadowname_nx,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\t}\n",
			   "\t\t\telse if ((shadowname_py != \"\") && (shadowname_ny != \"\") && (ay > ax) && (ay > az)) //Are we using Y+- shadow maps?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tif (ycomp(Lworld) > 0.0) vis = 1-shadow(shadowname_py,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\t\telse vis = 1-shadow(shadowname_ny,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\t}\n",
			   "\t\t\telse if ((shadowname_pz != \"\") && (shadowname_nz != \"\") && (az > ay) && (az > ax)) //Are we using Z+- shadow maps?\n",
			   "\t\t\t{\n",
			   "\t\t\t\tif (zcomp(Lworld) > 0.0) vis = 1-shadow(shadowname_pz,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\t\telse vis = 1-shadow(shadowname_nz,Ps,\"samples\",Samples,\"blur\",Blur,\"bias\",Bias);\n",
			   "\t\t\t}\n",
			   "\t\t\tCl = vis*Energy*LightColor*Attenuation(length(L),Quad1,Quad2,Quad3,Dist,isSphere);\n",
			   "\t\t}\n",
			   "\t}\n",
			   "}\n"]

volumeShader		= ["/* MOSAIC default atmosphere shader for Blender integration */\n",
			   "volume\n",
			   "MOSAICfog(\n",
			   "\tfloat Sta=0; //Standard Blender world controls\n",
			   "\tfloat Di=0;\n",
			   "\tfloat Hi=0;\n",
			   "\tfloat Misi=0;\n",
			   "\tfloat isMist=0;\n",
			   "\tfloat MistType=0;\n",
			   "\tcolor MistCol=0;)\n",
			   "{\n",
			   "\tif (isMist > 0 && Sta < Di) //Are we using mist?\n",
			   "\t{\n",
			   "\t\tfloat LI = length(I)-Sta;\n",
			   "\t\tfloat DL = Di-Sta;\n",
			   "\t\tif (MistType == 0) DL = DL/clamp(LI/DL,0,1);\n",
			   "\t\telse if (MistType == 1) DL = DL;\n",
			   "\t\telse if (MistType == 2) DL = (DL+LI)/2;\n",
			   "\t\tfloat d = 1-clamp(LI/DL,0,1);\n",
			   "\t\tif (Hi > 0) d = mix(d,1,clamp(zcomp(transform(\"world\",point I))/Hi,0,1));\n",
			   "\t\td =  mix(d,0,Misi);\n",
			   "\t\tCi = mix(MistCol,Ci,d);\n",
			   "\t\tOi = mix(color(1,1,1),Oi,d);\n",
			   "\t}\n",
			   "}\n"]

imageShader		= ["/* MOSAIC default image shader for Blender integration */\n",
			   "imager\n",
			   "MOSAICbackground(\n",
			   "\tcolor bgcolor = color(1, 1, 1))\n",
			   "{\n",
			   "\tCi += (1 - alpha) * bgcolor;\n",
			   "\tOi = 1;\n",
			   "\talpha = 1;\n",
			   "}\n"]

#These are the default shader fragments to approximate blender like renders
surfaceFragment		= ["#This shader automatically uses these material controls:|ColRGB, SpeRGB, MirRGB colors, Alpha slider, Shadeless toggle|Ref, Spec, Hard, Tralu, Amb, Emit sliders, GR: text|RayMirror, RayTransp toggles, RayMir, Both Fresnels, IOR|ofsX, ofsY, sizeX, sizeY|Uses first valid texture channel assigned to any property, Col slider\n",
			   "Surface \"MOSAICsurface\"\n",
			   "\t\"uniform float EnvBlur\" [ 0 ] #[ 0 ]\n",
			   "\t\"uniform float EnvSamples\" [ 8 ] #[ 8 ]\n",
			   "\t\"uniform float OccBias\" [ 0.1 ] #[ 0.1 ]\n",
			   "\t\"uniform float OccMaxdist\" [ 1e38 ] #[ 1e38 ]\n",
			   "\t\"uniform float OccSamples\" [ 8 ] #[ 8 ]\n",
			   "\t\"uniform float OccEnergy\" [ 1 ] #[ 1 ]\n",
			   "\t\"uniform float OccMapBlur\" [ 0.1 ] #[ 0.1 ]\n",
			   "\t\"uniform float isOcclusion\" <WorldIsOcc_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float isShadeless\" <MatIsShadeless_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float isRayTransp\" <MatIsRayTransp_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float isRayMirror\" <MatIsRayMirror_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float TranspFresnel\" <MatRayFresnel_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float MirFresnel\" <MatMirrorFresnel_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float IOR\" <MatRayIOR_M1.0_A0.0_F> #[ 1.5 ]\n",
			   "\t\"uniform float ColMix\" <MatMapCol_X11_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float CmirMix\" <MatMapCol_X14_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float CspMix\" <MatMapCol_X13_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float Emit\" <MatEmit_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Tralu\" <MatTranslu_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Alpha\" <MatAlpha_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float Hard\" <MatHard_M0.25_A0.0_F> #[ 0.1 ]\n",
			   "\t\"uniform float RayMir\" <MatRayMir_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float Spec\" <MatSpec_M1.0_A0.0_F> #[ 0.5 ]\n",
			   "\t\"uniform float Ref\" <MatRef_M1.0_A0.0_F> #[ 0.8 ]\n",
			   "\t\"uniform float Amb\" <MatAmb_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform color AmbCol\" <WorldAmbCol_C> #[ 1 1 1 ]\n",
			   "\t\"uniform color OccCol\" <WorldHorCol_C> #[ 1 1 1 ]\n",
			   "\t\"uniform color MirCol\" <MatMirrorColor_C> #[ 1 1 1 ]\n",
			   "\t\"uniform color SpecCol\" <MatSpecCol_C> #[ 1 1 1 ]\n",
			   "\t\"uniform string EmitMap\" <MatImageName_X21_S> #[ \"\" ]\n",
			   "\t\"uniform string AmbMap\" <MatImageName_X17_S> #[ \"\" ]\n",
			   "\t\"uniform string HardMap\" <MatImageName_X18_S> #[ \"\" ]\n",
			   "\t\"uniform string SpecMap\" <MatImageName_X16_S> #[ \"\" ]\n",
			   "\t\"uniform string RefMap\" <MatImageName_X15_S> #[ \"\" ]\n",
			   "\t\"uniform string CmirMap\" <MatImageName_X14_S> #[ \"\" ]\n",
			   "\t\"uniform string RayMirMap\" <MatImageName_X19_S> #[ \"\" ]\n",
			   "\t\"uniform string CspMap\" <MatImageName_X13_S> #[ \"\" ]\n",
			   "\t\"uniform string AlphaMap\" <MatImageName_X20_S> #[ \"\" ]\n",
			   "\t\"uniform string ColMap\" <MatImageName_X11_S> #[ \"\" ]\n",
			   "\t\"uniform string EnvMap\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string HDRIEnvMap\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string OccMap\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"varying float [4] EmitOfSz\" <MatMapOfSzXY_X21_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] AmbOfSz\" <MatMapOfSzXY_X17_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] HardOfSz\" <MatMapOfSzXY_X18_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] SpecOfSz\" <MatMapOfSzXY_X16_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] RefOfSz\" <MatMapOfSzXY_X15_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] CmirOfSz\" <MatMapOfSzXY_X14_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] RayMirOfSz\" <MatMapOfSzXY_X19_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] CspOfSz\" <MatMapOfSzXY_X13_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] AlphaOfSz\" <MatMapOfSzXY_X20_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] ColOfSz\" <MatMapOfSzXY_X11_M1.0_A0.0_F> #[ 0 0 1 1 ]"]

displaceFragment	= ["#This shader automatically uses these material controls:|ofsX, ofsY, sizeX, sizeY|Uses first valid texture channel assigned to any propery, Nor and Disp sliders\n",
			   "Displacement \"MOSAICdisplace\"\n",
			   "\t\"uniform float Nor\" <MatMapNor_X12_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float Disp\" <MatMapDisp_X23_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform string NorMap\" <MatImageName_X12_S> #[ \"\" ]\n",
			   "\t\"uniform string DispMap\" <MatImageName_X23_S> #[ \"\" ]\n",
			   "\t\"varying float [4] NorOfSz\" <MatMapOfSzXY_X12_M1.0_A0.0_F> #[ 0 0 1 1 ]\n",
			   "\t\"varying float [4] DispOfSz\" <MatMapOfSzXY_X23_M1.0_A0.0_F> #[ 0 0 1 1 ]"]

lightFragment		= ["#This shader automatically uses these lamp controls:|Lamp,Area,Spot,Sun,Hemi,Quad,Sphere,NoDiffuse,NoSpecular toggles|Dist,Energy,RGB,SizeXY,Quad1,Quad2 controls|RayShadow toggle, SpotSi,SpotBl controls\n",
			   "LightSource \"MOSAIClight\" <LightID_I>\n",
			   "\t\"uniform float Bias\" [ 0.1 ] #[ 0.1 ]\n",
			   "\t\"uniform float Blur\" [ 0.01 ] #[ 0.01 ]\n",
			   "\t\"uniform float Samples\" [ 8 ] #[ 8 ]\n",
			   "\t\"varying float [4] ProjOfSz\" [ 0 0 1 1 ] #[ 0 0 1 1 ]\n",
			   "\t\"uniform float __foglight\" [ 1 ] #[ 1 ]\n",
			   "\t\"uniform float __nonspecular\" <LampNoSpec_F_M1.0_A0.0> #[ 0 ]\n",
			   "\t\"uniform float __nondiffuse\" <LampNoDiffuse_F_M1.0_A0.0> #[ 0 ]\n",
			   "\t\"uniform float isQuad\" <LampIsQuad_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float isSphere\" <LampIsSphere_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float isRaytrace\" <LampIsRaytrace_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Quad3\" [ 0 ] #[ 0 ]\n",
			   "\t\"uniform float Quad2\" <LampQuad2_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Quad1\" <LampQuad1_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float SpotBl\" <LampSpotBl_M0.2_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float SpotSi\" <LampSpotSi_M0.5_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Dist\" <LampDist_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float Energy\" <LampEnergy_M1.0_A0.0_F> #[ 1 ]\n",
			   "\t\"uniform float LightType\" <LampType_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform point up\" [ 0 1 0 ] #[ 0 1 0 ]\n",
			   "\t\"uniform point to\" <TO_P> #[ 0 0 1 ]\n",
			   "\t\"uniform point from\" <FROM_P> #[ 0 0 0 ]\n",
			   "\t\"uniform color LightColor\" <LampLightColor_C> #[ 1 1 1 ]\n",
			   "\t\"uniform string projectionmap\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string shadowname_nz\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string shadowname_pz\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string shadowname_ny\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string shadowname_py\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string shadowname_nx\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string shadowname_px\" [ \"\" ] #[ \"\" ]\n",
			   "\t\"uniform string shadowname\" [ \"\" ] #[ \"\" ]"]
			   
volumeFragment		= ["#This shader automatically uses these world controls:|HoRGB is used for mist color|Mist Toggle, Qua/Lin/Sqr Progression, Sta, Di, Hi, Misi\n",
			   "Atmosphere \"MOSAICfog\"\n",
			   "\t\"uniform float isMist\" <WorldIsMist_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Misi\" <WorldMist_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Hi\" <WorldHi_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Di\" <WorldDi_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float Sta\" <WorldSta_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform float MistType\" <WorldMistType_M1.0_A0.0_F> #[ 0 ]\n",
			   "\t\"uniform color MistCol\" <WorldHorCol_C> #[ 0 0 0 ]"]

imageFragment		= ["#This shader automatically uses these world controls:|HoRGB is used for the background color\n",
			   "Imager \"MOSAICbackground\"\n",
			   "\t\"uniform color bgcolor\" <WorldHorCol_C> #[ 1 1 1 ]"]

####################################################################### SETUP GUI GLOBAL VARIABLES
#Global GUI Vars
killExport		= False						#Used to kill render process on esc
instanceCount		= 0						#Used to keep track of object instances being used
lightList		= []						#Used to keep track of lights in current working scene
lightDupliIndex		= 0						#Used to track current dupli light instance
lightAreaIndex		= 0						#used to track current arealight array index
ScrollPos		= 0						#Mouse scroll offset for menu graphics
ScrollState		= 0						#Last know SubWindows total overlap to available window area
LastObject		= ""						#Used to trigger redraw when active selection has changed and mouse moves over area
LastScene		= ""
LastMaterial		= ""
MousePos		= [0, 0]					#Track mouse position

#Events Constants
EVENT_WIDTH		= 500						#Sets the increments in event numbers between sub-windows, this basically means the number of buttons possible in each sub-window
EVENT_NONE		= 1
EVENT_ACTIONS_SET	= EVENT_WIDTH*1
EVENT_SETTINGS_SET	= EVENT_WIDTH*2
EVENT_UTILITY_SET	= EVENT_WIDTH*3
EVENT_PROJECT_SET	= EVENT_WIDTH*4
EVENT_SCENE_SET		= EVENT_WIDTH*5
EVENT_CAMERA_SET	= EVENT_WIDTH*6
EVENT_GROUP_SET		= EVENT_WIDTH*7
EVENT_GEOM_SET		= EVENT_WIDTH*8
EVENT_LIGHT_SET		= EVENT_WIDTH*9
EVENT_MAT_SET		= EVENT_WIDTH*10

#ButtonData index constants
#Sub-windows
ACTIONS			= 0
SETTINGS		= 1
UTILITIES		= 2
PROJECT			= 3
SCENES			= 4
CAMERAS			= 5
GROUPS			= 6
GEOMETRY		= 7
LIGHTS			= 8
MATERIALS		= 9
#Buttons
ACT_RENDER		= 0
ACT_ANIMATION		= 1
ACT_PREVIEW		= 2
ACT_DIVIDER1		= 3
ACT_RENDER_RIB		= 4
ACT_CREATE_RIB		= 5
ACT_CREATE_SEL		= 6
ACT_COMPILE_SL		= 7
ACT_EXPORT_MAPS		= 8
ACT_COMPRESS_RIB	= 9
ACT_CLEAN_DIR		= 10
ACT_DIVIDER2		= 11
ACT_HELP		= 12
ACT_QUIT		= 13
SET_PRESETS		= 0
SET_RENDER_BIN		= 1
SET_SHADER_BIN		= 2
SET_TEXMAKE_BIN		= 3
SET_ENVMAKE_BIN		= 4
SET_INFO_BIN		= 5
SET_SHADER_EXT		= 6
SET_RIB_EXT		= 7
SET_TEX_EXT		= 8
SET_TEXT_FILTER		= 9
SET_EXPORTER_SW		= 10
SET_EMEBED_PRESET	= 11
SET_DIVIDER2		= 12
SET_OUTPUT_DIR		= 13
SET_CREATE_SHDIR	= 14
UTIL_PURGE_PASSES	= 0
UTIL_COPY_PROP		= 1
UTIL_CLEAR_PROP		= 2
UTIL_RELOAD_TEXT	= 3
UTIL_SAVE_TEXT		= 4
UTIL_DIVIDER1		= 5
UTIL_SHADOWMAP		= 6
UTIL_REFLMAP		= 7
UTIL_CUBEMAP		= 8
UTIL_HDRIMAP		= 9
UTIL_OCCLMAP		= 10
UTIL_SSSMAP		= 11
UTIL_DIVIDER2		= 12
UTIL_GENERATE_FRAG	= 13
UTIL_SELECT_FRAG	= 14
UTIL_RELOAD_FRAG	= 15
UTIL_COPY_FRAG		= 16
UTIL_DELETE_FRAG	= 17
UTIL_PREVIEW_FRAG	= 18
UTIL_DIVIDER3		= 19
PROJECT_FOLDER		= 0
PROJECT_DIVIDER		= 1
PROJECT_ARCHIVES	= 2
PROJECT_SHADERS		= 3
PROJECT_TEXTURES	= 4
PROJECT_DISPLAYS	= 5
PROJECT_PROCEDURALS	= 6
PROJECT_RESOURCES	= 7
PROJECT_DIVIDER2	= 8
PROJECT_TEXTURE_EXPORT	= 9
PROJECT_CREATE_PASS	= 10
PROJECT_PASSES		= 11
PROJECT_DIVIDER3	= 12
SCENE_SELECT		= 0
SCENE_SELECT_SET	= 1
SCENE_CREATE_SET	= 2
SCENE_DELETE_SET	= 3
SCENE_DIVIDER1		= 4
SCENE_FRAME_ARCH	= 5
SCENE_HEADER_CODE	= 6
SCENE_BEGINFRAME_CODE	= 7
SCENE_BEGINWORLD_CODE	= 8
SCENE_ENDWORLD_CODE	= 9
SCENE_ENDFRAME_CODE	= 10
SCENE_DIVIDER2		= 11
SCENE_ATMO		= 12
SCENE_ATMO_NOTES	= 13
SCENE_DIVIDER3		= 14
SCENE_SHADE_RATE	= 15
SCENE_EYES		= 16
SCENE_GRID		= 17
SCENE_BUCKET		= 18
SCENE_XSAMPLES		= 19
SCENE_YSAMPLES		= 20
SCENE_FILTER		= 21
SCENE_XWIDTH		= 22
SCENE_YWIDTH		= 23
SCENE_DIVIDER4		= 24
SCENE_HIDER		= 25
SCENE_HIDER_EMIT	= 26
SCENE_HIDER_JITTER	= 27
SCENE_MAXERROR		= 28
SCENE_MAXDEPTH		= 29
SCENE_SHADOW_BIAS	= 30
SCENE_TRACE_BIAS	= 31
SCENE_GLOBALMAP		= 32
SCENE_CAUSTICMAP	= 33
SCENE_DIVIDER5		= 34
SCENE_CUSTOM_RENDER	= 35
SCENE_DIVIDER6		= 36
SCENE_SHADOW_MAP	= 37
SCENE_LATLONG_MAP	= 38
SCENE_CUBE_MAP		= 39
SCENE_PERSPECTIVE	= 40
SCENE_LENS		= 41
SCENE_NEARCLIP		= 42
SCENE_FARCLIP		= 43
SCENE_DUPLI_INDEX	= 44
SCENE_AREA_INDEX	= 45
SCENE_ENV_DOF		= 46
SCENE_ENV_FOCAL		= 47
SCENE_ENV_FSTOP		= 48
SCENE_ENV_DIST		= 49
SCENE_DIVIDER7		= 50
SCENE_QUANTIZE		= 51
SCENE_ADD_DISPLAY	= 52
CAM_SELECT		= 0
CAM_SELECT_SET		= 1
CAM_CREATE_SET		= 2
CAM_DELETE_SET		= 3
CAM_DIVIDER1		= 4
CAM_ARCH		= 5
CAM_BEGIN_CODE		= 6
CAM_END_CODE		= 7
CAM_DIVIDER2		= 8
CAM_IMAGE		= 9
CAM_IMAGE_NOTES		= 10
CAM_DIVIDER3		= 11
CAM_MBLUR		= 12
CAM_FRAMES		= 13
CAM_DOF			= 14
CAM_FSTOP		= 15
CAM_FOCAL		= 16
CAM_SHUT_MIN		= 17
CAM_SHUT_MAX		= 18
GRP_SELECT		= 0
GRP_DIVIDER1		= 1
GRP_ARCH		= 2
GRP_BEGIN_CODE		= 3
GRP_END_CODE		= 4
GRP_DIVIDER2		= 5
GRP_ATMO		= 6
GRP_ATMO_NOTES		= 7
GEO_SELECT		= 0
GEO_SELECT_SET		= 1
GEO_CREATE_SET		= 2
GEO_DELETE_SET		= 3
GEO_DIVIDER1		= 4
GEO_OBJ_ARCH		= 5
GEO_DATA_ARCH		= 6
GEO_BEGINOBJ_CODE	= 7
GEO_GEO_CODE		= 8
GEO_ENDOBJ_CODE		= 9
GEO_DIVIDER2		= 10
GEO_ATMO		= 11
GEO_ATMO_NOTES		= 12
GEO_DIVIDER3		= 13
GEO_SHADE_RATE		= 14
GEO_ORIENTATION		= 15
GEO_SHADE_INTER		= 16
GEO_PARA_CLASS		= 17
GEO_DISP_BOUND		= 18
GEO_COOR_SYS		= 19
GEO_DIVIDER4		= 20
GEO_CULL_HIDDEN		= 21
GEO_CULL_BACKFACE	= 22
GEO_DICE_BINARY		= 23
GEO_DICE_RASTER		= 24
GEO_TRACE_DISPLACE	= 25
GEO_TRACE_MOTION	= 26
GEO_DIVIDER5		= 27
GEO_ANIM_OBJECT		= 28
GEO_OBJ_MBLUR		= 29
GEO_OBJ_FRAMES		= 30
GEO_GEO_MBLUR		= 31
GEO_GEO_FRAMES		= 32
LIGHT_SELECT		= 0
LIGHT_SELECT_SET	= 1
LIGHT_CREATE_SET	= 2
LIGHT_DELETE_SET	= 3
LIGHT_DIVIDER1		= 4
LIGHT_ARCH		= 5
LIGHT_BEGIN_CODE	= 6
LIGHT_END_CODE		= 7
LIGHT_DIVIDER2		= 8
LIGHT_SHADER		= 9
LIGHT_SHADER_NOTES	= 10
LIGHT_DIVIDER3		= 11
LIGHT_MBLUR		= 12
LIGHT_FRAMES		= 13
MAT_SELECT		= 0
MAT_SELECT_SET		= 1
MAT_CREATE_SET		= 2
MAT_DELETE_SET		= 3
MAT_DIVIDER1		= 4
MAT_ARCH		= 5
MAT_BEGIN_CODE		= 6
MAT_END_CODE		= 7
MAT_DIVIDER2		= 8
MAT_SURF		= 9
MAT_SURF_NOTES		= 10
MAT_DISP		= 11
MAT_DISP_NOTES		= 12
MAT_INT_VOL		= 13
MAT_INT_VOL_NOTES	= 14
MAT_EXT_VOL		= 15
MAT_EXT_VOL_NOTES	= 16
MAT_AREA		= 17
MAT_AREA_NOTES		= 18
MAT_DIVIDER3		= 19
MAT_VIS_TRANS		= 20
MAT_VIS_SPECULAR	= 21
MAT_VIS_DIFFUSE		= 22
MAT_VIS_PHOTON		= 23
MAT_VIS_CAMERA		= 24
MAT_DIVIDER4		= 25
MAT_SHADINGMODEL	= 26
MAT_SHADE_TRANS		= 27
MAT_SHADE_SPECULAR	= 28
MAT_SHADE_DIFFUSE	= 29
MAT_SHADE_CAMERA	= 30
MAT_DIVIDER5		= 31
MAT_INVERTUV_U		= 32
MAT_INVERTUV_V		= 33
MAT_MBLUR		= 34
MAT_FRAMES		= 35
#Window data indexes
WIN_EVENT		= 0
WIN_COLLAPSE		= 1
WIN_TITLE		= 2
WIN_COLOR		= 3
WIN_BUTS		= 4
#Button data indexes
BUTTON			= 0
BUT_MENU		= 1
BUT_SHOW		= 2
BUT_TYPE		= 3
BUT_WIDTH_DIV		= 4
BUT_TRIGGER		= 5
BUT_TITLE		= 6
BUT_TIP			= 7
BUT_PROP		= 8
BUT_DEFAULT		= 9
BUT_MIN			= 10
BUT_MAX			= 11

#Button Data - This is a 4 element array containing data for [sub-window arrays...][sub_data..., Buttons_arrays...][Buttons data fields...]
#Sub-window data is:	[event #, Collapse?, Title, color adjust, [buttons]]
#Button data is:	[Button Object, Last Selection, Show?, Button type(0-button, 1-list, 2-Int, 3-Tog, 4-Str, 5-Line), Button Width Ratio, Special Trigger (use varies depending on button type), Title, Tool Tip, Prop (titles for menu and properties), default value, min value, max value]
#NOTE: If Title = "CodeF", "SourceF", "SurfaceF", "DisplacementF", "VolumeF", "ImageF", "LightF", "SceneF", "CameraF", "GroupF", "GeometryF", "LampF", "MaterialF", "SceneSetF", "CameraSetF", "GeoSetF", "LampSetF", "MaterialSetF", "ShadersF" then a menu will be generated with those items
ButtonData		= [[EVENT_ACTIONS_SET, False, "MOSAIC Actions", [1.0,1.0,1.0,1.0],
			   [[Blender.Draw.Create(1), "", True, 0, 100.0, 1, "(R)ender Current Frame", "Press \"r\" to render current frame in current scene", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Render (A)nimation/Passes", "Press \"a\" to render current scenes animation from Sta to End or use Render Passes if set", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "(P)review Selected Object/s", "Press \"p\" to preview current selection/s using the last 3D view", "", 1, 0, 1],
			    [0, "", True, 5, 100.0, 1, "Export Options", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 3, 0.33, 1, "Render RIB", "Whether or not to Call renderer after RIB code generation", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 3, 0.33, 1, "Create RIB", "Whether or not to create Rib files from current scene", "", 1, 0, 1],
			    [Blender.Draw.Create(0), "", True, 3, 100.0, 1, "Only Select", "Only update selected geometry (non archive code will have to regenerate)", "", 0, 0, 1],
			    [Blender.Draw.Create(1), "", True, 3, 0.33, 1, "Compile SL", "Whether or not to compile projects shaders", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 3, 0.33, 1, "Export Maps", "Whether or not to export and optimize texture maps", "", 1, 0, 1],
			    [Blender.Draw.Create(0), "", True, 3, 100.0, 1, "gzip RIBs", "Use gzip compression on all RIBs (clears project folder when clicked!)", "", 0, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Purge Project Export Directory", "Removes project folder and all contents exported or generated for project render", "", 1, 0, 1],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "(H)elp", "Press \"h\" to view Mosaic's help doc", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "(Q)uit", "Press \"q\" to quit Mosaic", "", 1, 0, 1]]],
			   [EVENT_SETTINGS_SET, True, "MOSAIC Settings", [1.0,1.0,1.0,1.0],
			   [[Blender.Draw.Create(1), "", True, 1, 100.0, 130, RendererList, "Select a renderer preset to automatically fill in binary settings", "Renderer Presets", RenderPreset, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Renderer Binary", "Renderer: "+RenderBin, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Shader Compiler", "Compiler: "+CompilerBin, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Texture Optimizer", "Texture Optimizer: "+TexmakeBin, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "LatEnv Optimizer", "LatEnv Optimizer: "+EnvmakeBin, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Shader Info", "Shader Info: "+InfoBin, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Shader Extension", "Shader Extension: "+ShaderExt, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "RIB file Extension", "RIB Extension: "+RibExt, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Texture Extension", "Texture Export Extension: "+TextureExt, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Fragment Filters", "Text fragment name filters allow you to group text files into catagories for MOSAIC's menus", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Exporter Switches", "This dialog provides a series of switches to control whats exported and whats not", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 3, 100.0, 1, "Embed Above Settings In Project", "Embeds the above presets and filters in a Blender text called \"MOSAIC Presets\" instead of the registry", "", PresetEmbed, 0, 1],
			    [0, "", True, 5, 100.0, 1, "Library and Export Paths", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Export Directory", "Export Directory: "+RenderDir, "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Add Shader Library", "Add a path to a shader library (can contain both compiled shaders and shader source files)", "", 1, 0, 1]]],
			   [EVENT_UTILITY_SET, True, "MOSAIC Utilities", [1.0,1.0,1.0,1.0],
			   [[Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Purge Unreferenced Scene/Passes", "Purges all scenes not being used in the \"Project Setup\" tabs render passes list or current scene", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Copy Properties", "Copies Active objects RenderMan settings too all other objects in selection of same type", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Clear Properties", "Clears selected objects of all RenderMan settings or clears everything in all scene if no selection", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Reload Texts", "Updates all text files in Blender from original external sources (if still valid)", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Save Texts", "Saves all text files in Blender to original external sources (if still valid)", "", 1, 0, 1],
			    [0, "", True, 5, 100.0, 1, "Render Pass Utilities", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Create Shadow Map Pass", "Creates a shadow map pass for the selected light of other selected objects or whole scene if light is the only selection", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Create LatLong Map Pass", "Creates a LatLong environment map pass for the active object of other selected objects or whole scene if only active object selection", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Create Cube Map Pass", "Creates a cube environment map pass for the active object of other selected objects or whole scene if only active object selection", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Create HDRI Map Pass", "Creates a HDRI cube map pass from the active objects perspective of other selected objects or whole scene if only active object selection (useful for HDRI occlusion ect)", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Create Occlusion Pass", "Creates a occlusion map pass of selected objects or whole scene if there are no selections (Aqsis specific feature!)", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Create SSS Map Pass", "Creates a Sub Surface Scattering map pass for the selected light of other selected objects or whole scene if light is the only selection", "", 1, 0, 1],
			    [0, "", True, 5, 100.0, 1, "Shader Utilities", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Generate Shader Fragment", "Generates a shader fragment from loaded shader sources or pre-compiled shaders from your shader library paths", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 1, 0.75, 110, "ShadersF", "Edit the selected shader fragments parameters", "Shader Parameters", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 16.0, 1, "R", "Reload selected shader fragment (necessary if you alter the fragment externally)", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 16.0, 1, "C", "Copy selected shader fragment", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 16.0, 1, "X", "Delete selected shader fragment", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "P", "Preview this shader (use the generated \"PREVIEW\" material to tweak token connections)", "", 1, 0, 1],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1]]],
			   [EVENT_PROJECT_SET, True, "Project Setup", [1.0,0.75,0.25,1.0],
			   [[Blender.Draw.Create("Mosaic"), "", True, 4, 100.0, 130, "Project Folder", "Project export folder to create in \"MOSAIC Settings\" Export Directory", "Project Folder", "Mosaic", 0, 255],
			    [0, "", True, 5, 100.0, 1, "Search Paths", "", "", 1, 0, 1],
			    [Blender.Draw.Create(""), "", True, 4, 100.0, 130, "Archive Searchpath", "Search paths for archive RIBs (blank to use default, NONE to turn off)", "Archive Searchpath", "@:.:Archives:Archives/Scenes:Archives/Groups:Archives/Materials:Archives/Lights:Archives/Cameras:Archives/Geometry:Archives/Objects", 0, 255],
			    [Blender.Draw.Create(""), "", True, 4, 100.0, 130, "Shader Searchpath", "Search paths for shaders (blank to use default, NONE to turn off)", "Shader Searchpath", "@:.:Shaders", 0, 255],
			    [Blender.Draw.Create(""), "", True, 4, 100.0, 130, "Texture Searchpath", "Search paths for textures maps (blank to use default, NONE to turn off)", "Texture Searchpath", "@:.:Maps", 0, 255],
			    [Blender.Draw.Create(""), "", True, 4, 100.0, 130, "Display Searchpath", "Search paths for displays (blank to use default, NONE to turn off)", "Display Searchpath", "NONE", 0, 255],
			    [Blender.Draw.Create(""), "", True, 4, 100.0, 130, "Procedural Searchpath", "Search paths for procedurals (blank to use default, NONE to turn off)", "Procedural Searchpath", "NONE", 0, 255],
			    [Blender.Draw.Create(""), "", True, 4, 100.0, 130, "Resource Searchpath", "Search paths for resources (blank to use default, NONE to turn off)", "Resource Searchpath", "NONE", 0, 255],
			    [0, "", True, 5, 100.0, 1, "Export Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 0.5, 1, "Texture Export Options", "Setup how each texture is exported and optimized", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", True, 0, 100.0, 1, "Create Render Pass", "Creates a new render pass to specify connected scene and its RIBset, sta-end frames and order", "", 1, 0, 1],
			    [Blender.Draw.Create(""), "", True, 4, 100.0, 90, "Render Passes", "Manually type select scenes through frame ranges using \"scene@ribset:sta-end\" for examples PhotonPass@Photon:1-1,CausticPass@Caustic:1-1,BeautyPass@DEFAULT:1-20,ect...", "Render Passes", "", 0, 399],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1]]],
			   [EVENT_SCENE_SET, True, "Scenes Setup", [1.0,0.75,0.75,1.0],
			   [[Blender.Draw.Create(1), "", True, 1, 100.0, 130, "SceneF", "Select the scene to setup", "Select Scene", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "SceneSetF", "Select which user created RIB setup you want to use for this scene and renderpass", "Select RIBset", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 0.5, 1, "Create New RIBset", "Create a new user defined RIB setup for this object", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Delete This RIBset", "Delete the current user defined RIB setup for this object", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Code Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, ["Frame Archive:%t|Read Archive|Inline Code", "Read Archive", "Inline Code"], "Set the archive method for rib in frame blocks", "Frame Archive", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code at the beginning of main RIB", "Header Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into beginning of frame block", "Frame Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into beginning of world block", "World Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into end of world block", "World End Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into end of frame block", "Frame End Code", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Shader Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(2), ["","","vs_MOSAICfog"], False, 1, 0.8, 130, "VolumeF", "Set atmosphere shader for entire scene", "Atmosphere Shader", 2, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Options and Attributes", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1.0), "", False, 2, 0.5, 1, "Shading Rate: ", "Sets RiShadingRate for current scene (0 is off)", "Shading Rate", 1.0, 0.0, 20.0],
			    [Blender.Draw.Create(6), "", False, 2, 100.0, 1, "eyesplits: ", "Eye-plane eyesplits failure detection threshold (0 is off)", "eyesplits", 6, 0, 1024],
			    [Blender.Draw.Create(0), "", False, 2, 0.5, 1, "gridsize: ", "Maximum number of micropolygons shaded at once (0 is off)", "gridsize", 0, 0, 1024],
			    [Blender.Draw.Create(0), "", False, 2, 100.0, 1, "bucketsize: ", "Dimensions of pixel blocks the screen gets divided into (0 is off)", "bucketsize", 0, 0, 1024],
			    [Blender.Draw.Create(4), "", False, 2, 0.5, 1, "Xsamples: ", "RiPixelSamples xwidth parameter (0 is off)", "Xsamples", 4, 0, 200],
			    [Blender.Draw.Create(4), "", False, 2, 100.0, 1, "Ysamples: ", "RiPixelSamples ywidth parameter (0 is off)", "Ysamples", 4, 0, 200],
			    [Blender.Draw.Create(""), "", False, 4, 0.33, 0, "Filter: ", "If blank RiPixelFilter is not used (box, triangle, catmull-rom, sinc, gaussian)", "Filter", "", 0, 255],
			    [Blender.Draw.Create(2), "", False, 2, 0.33, 1, "Xwidth: ", "RiPixelFilter xwidth parameter", "FilterX", 2, 1, 200],
			    [Blender.Draw.Create(2), "", False, 2, 100.0, 1, "Ywidth: ", "RiPixelFilter ywidth parameter", "FilterY", 2, 1, 200],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.33, 0, ["Select Hider:%t|Hider: DEFAULT|Hider: hidden|Hider: raytrace|Hider: photon|Hider: zbuffer", "", "hidden", "raytrace", "photon", "zbuffer"], "Select which hider to use", "Select Hider", 1, 0, 1],
			    [Blender.Draw.Create(0), "", False, 2, 0.33, 1, "Emit: ", "Number of photons to emit per light using photon hider (0 is off) ", "Emit", 0, 0, 1000000000],
			    [Blender.Draw.Create(0), "", False, 2, 100.0, 1, "Jitter: ", "Amount of jitter per sample for the hidden hider (0 is off) ", "Jitter", 0, 0, 20],
			    [Blender.Draw.Create(0.0), "", False, 2, 0.5, 1, "Irr maxerror: ", "This is a quality control for the irradiance cache (0 is off) ", "Irr maxerror", 0.0, 0.0, 1.0],
			    [Blender.Draw.Create(0), "", False, 2, 100.0, 1, "Trace maxdepth: ", "The maximum raytracing recursion depth (0 is off) ", "Trace maxdepth", 0, 0, 1000],
			    [Blender.Draw.Create(0.0), "", False, 2, 0.5, 1, "Shadow bias: ", "Amount of bias for shadow maps (0.0 is off)", "Shadow bias", 0.0, 0.0, 10.0],
			    [Blender.Draw.Create(0.0), "", False, 2, 100.0, 1, "Trace bias: ", "Amount of bias for raytracing (0.0 is off)", "Trace bias", 0.0, 0.0, 10.0],
			    [Blender.Draw.Create(""), "", False, 4, 100.0, 0, "Photon globalmap: ", "Specifies global photonmap to create for photon hider", "Photon globalmap", "", 0, 255],
			    [Blender.Draw.Create(""), "", False, 4, 100.0, 0, "Photon causticmap: ", "Specifies global causticmap to create for photon hider", "Photon causticmap", "", 0, 255],
			    [0, "", False, 5, 100.0, 1, "Per Pass Control", "", "", 1, 0, 1],
			    [Blender.Draw.Create(""), "", False, 4, 100.0, 130, "Custom Render Call: ", "Use custom render command for this scene/pass (uses \"MOSAIC Settings\" Renderer if blank)", "Custom Render Call", "", 0, 255],
			    [0, "", False, 5, 100.0, 1, "Env Mapping Control", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 0.33, 1, "ShadowMap", "Create a shadow map for this scene by entering a depth file", "", "", 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 0.33, 1, "LatLongMap", "Create a LatLong Environment map for this scene by entering an image", "", "", 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "CubeMap", "Create a cube environment map for this scene by entering 6 images", "", "", 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["Projections:%t|Camera: Perspective|Camera: Orthographic|World: px|World: py|World: pz|World: nx|World: ny|World: nz", "persp", "ortho", "px", "py", "pz", "nx", "ny", "nz"], "Use to set active camera (lamp, object, dupli or preview render) perspectives, useful for shadow and cube map passes", "Perspective", 1, 0, 1],
			    [Blender.Draw.Create(90.0), "", False, 2, 100.0, 1, "Degrees/Scale: ", "Use to set active camera (lamp, object, dupli or preview render) perspectives degrees or orthographic scale", "Degrees", 90.0, 0.0, 360.0],
			    [Blender.Draw.Create(0.1), "", False, 2, 0.5, 1, "Near Clip: ", "Use to set active camera (lamp, object, dupli or preview render) near clipping", "nearclip", 0.1, 0.1, 5000.0],
			    [Blender.Draw.Create(10000.0), "", False, 2, 100.0, 1, "Far Clip: ", "Use to set active camera (lamp, object, dupli or preview render) far clipping", "farclip", 1000.0, 0.1, 5000.0],
			    [Blender.Draw.Create(0), "", False, 2, 0.5, 1, "Dupli Index: ", "Use to set active camera (lamp or object) index when used in a dupli system", "dupliindex", 0, 0, 100000],
			    [Blender.Draw.Create(0), "", False, 2, 100.0, 1, "Area Index: ", "Use to set active camera (area lamp) index when used in a area light array", "areaindex", 0, 0, 255],
			    [Blender.Draw.Create(0), "", False, 3, 0.20, 1, "EnvDOF", "Enable environment map DOF for active camera (lamp, object, dupli or preview render)", "EnvDOF", 0, 0, 1],
			    [Blender.Draw.Create(45.0), "", False, 2, 0.30, 1, "focalL: ", "Environment map DOF focal length (lamp, object, dupli or preview render)", "DOFFocal", 45.0, 0.0, 5000.0],
			    [Blender.Draw.Create(22.0), "", False, 2, 0.25, 1, "fstop: ", "Environment map DOF fstop for active camera (lamp, object, dupli or preview render)", "Envfstop", 22.0, 0.0, 600.0],
			    [Blender.Draw.Create(0.0), "", False, 2, 100.0, 1, "dist: ", "Environment map DOF distance (lamp, object, dupli or preview render)", "DOFDist", 0.0, 0.0, 5000.0],
			    [0, "", False, 5, 100.0, 1, "Display Setup", "", "", 1, 0, 1],
			    [Blender.Draw.Create(""), "", False, 4, 0.5, 0, "Quantize: ", "RiQuantize values such as \"rgba\" 0 0 0 0 for high dynamic range ect (blank is off)", "Quantize", "", 0, 255],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Add Display Driver", "Add a custom display driver to the display list (standard display and framebuffer always available)", "", "Display \"+<####>.tif\" \"file\" \"rgba\"<DIVIDER>Display \"+<####>.tif\" \"framebuffer\" \"rgb\"", 0, 1]]],
			   [EVENT_CAMERA_SET, True, "Cameras Setup", [1.0,0.75,1.0,1.0],
			   [[Blender.Draw.Create(1), "", True, 1, 100.0, 130, "CameraF", "Select the camera to setup", "Select Camera", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 1.0, 130, "CameraSetF", "Select which user created RIB setup you want to use for this scene and renderpass", "Select RIBset", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 0.5, 1, "Create New RIBset", "Create a new user defined RIB setup for this object", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Delete This RIBset", "Delete the current user defined RIB setup for this object", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Code Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, ["Camera Archive:%t|Read Archive|Inline Code", "Read Archive", "Inline Code"], "Set the archive method for camera", "Camera Archive", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into beginning of camera block", "Camera Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into end of camera block", "Camera End Code", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Shader Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(2), ["","","is_MOSAICbackground"], False, 1, 0.8, 130, "ImageF", "Set image shader to current camera view", "Image Shader", 2, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Options and Attributes", "", "", 1, 0, 1],
			    [Blender.Draw.Create(0), "", False, 3, 0.5, 1, "Camera MBlur", "Enables motion blur (transform)", "CameraMBlur", 0, 0, 1],
			    [Blender.Draw.Create(5), "", False, 2, 100.0, 1, "frames: ", "Number of frames to blur across", "CameraFrames", 5, 2, 1000],
			    [Blender.Draw.Create(0), "", False, 3, 0.33, 1, "Use DOF", "Enable DOF (focaldistance is set by cameras DoFDist)", "Use DOF", 0, 0, 1],
			    [Blender.Draw.Create(22.0), "", False, 2, 0.33, 1, "fstop: ", "RiDepthOfField fstop setting", "fstop", 22.0, 0.0, 600.0],
			    [Blender.Draw.Create(45.0), "", False, 2, 100.0, 1, "focalL: ", "RiDepthOfField focal length setting", "focalL", 45.0, 0.0, 5000.0],
			    [Blender.Draw.Create(0.0), "", False, 2, 0.5, 1, "Shutter min: ", "Sets RiShutter min parameter (min and max as 0 is off)", "shuttermin", 0.0, 0.0, 100.0],
			    [Blender.Draw.Create(1.0), "", False, 2, 100.0, 1, "Shutter max: ", "Sets RiShutter max paramter (min and max as 0 is off)", "shuttermax", 1.0, 0.0, 100.0]]],
			   [EVENT_GROUP_SET, True, "Groups Setup", [0.75,0.75,1.0,1.0],
			   [[Blender.Draw.Create(1), "", True, 1, 100.0, 130, "GroupF", "Select the group to setup", "Select Group", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Code Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(2), "", False, 1, 100.0, 130, ["Group Block:%t|Attribute Block|Ignore Group", "Attribute Block", "Ignore Group"], "Wraps geometry in selected group into a attribute block for custom attributes", "Group Block", 2, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into beginning of group block", "Group Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into end of group block", "Group End Code", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Shader Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.8, 130, "VolumeF", "Set atmosphere shader for objects in this group", "Atmosphere Shader", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1]]],
			   [EVENT_GEOM_SET, True, "Geometry Setup", [0.75,1.0,1.0,1.0],
			   [[Blender.Draw.Create(1), "", True, 1, 100.0, 130, "GeometryF", "Select the geometry to setup", "Select Geometry", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "GeoSetF", "Select which user created RIB setup you want to use for this scene and renderpass", "Select RIBset", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 0.5, 1, "Create New RIBset", "Create a new user defined RIB setup for this object", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Delete This RIBset", "Delete the current user defined RIB setup for this object", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Code Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(2), "", False, 1, 100.0, 130, ["Object Archive:%t|Delayed Archive|Read Archive|Inline Code", "Delayed Archive", "Read Archive", "Inline Code"], "Set the archive method for this object", "Object Archive", 2, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, ["Datablock Archive:%t|Read Archive|Instance Object|Inline Code", "Read Archive", "Instance Object", "Inline Code"], "Set the archive method for this objects geometry Datablock", "Datablock Archive", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into beginning of object block", "Object Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert hand written geometry using meshes materials and settings", "Geometry Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into end of object block", "Object End Code", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Shader Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.8, 130, "VolumeF", "Set atmosphere shader for this object", "Atmosphere Shader", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Options and Attributes", "", "", 1, 0, 1],
			    [Blender.Draw.Create(0.0), "", False, 2, 0.5, 1, "Shading Rate: ", "Sets RiShadingRate for this object (0.0 will use the scenes rate)", "Shading Rate", 0.0, 0.0, 20.0],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["Geometry Orientation:%t|orient: DEFAULT|orient: lh|orient: rh", "", "Orientation \"lh\"\n", "Orientation \"rh\"\n"], "Use \"lh\" or \"rh\" RiOrientation (DEFAULT exports nothing)", "Orientation", 1, 0, 1],
			    [Blender.Draw.Create(3), "", False, 1, 0.5, 0, ["Shading Interpolation:%t|shading: DEFAULT|shading: constant|shading: smooth", "", "ShadingInterpolation \"constant\"\n", "ShadingInterpolation \"smooth\"\n"], "Use \"constant\" or \"smooth\" RiShadingInterpolation (DEFAULT exports nothing)", "ShadingInt", 3, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["para class:%t|para class: facevarying|para class: facevertex|para class: vertex", "facevarying", "facevertex", "vertex"], "Use \"facevarying\" or \"facevertex\" parameter class types in exported geometry data", "paraclass", 1, 0, 1],
			    [Blender.Draw.Create(0.35), "", False, 2, 0.5, 1, "DisplaceBound: ", "Increase to compensate for displacements clipping on bounding box (0.0 is off)", "Bound", 0.35, 0.0, 10.0],
			    [Blender.Draw.Create("shader"), "", False, 4, 100.0, 0, "CoorSystem: ", "Set displacementbound coordinate system (object, world, camera, screen, raster, shader)", "Coor", "shader", 0, 255],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["cull hidden:%t|cull hidden: DEFAULT|cull hidden: int 0 (OFF)|cull hidden: int 1 (ON)", "", "0", "1"], "Set whether or not to cull hidden primitives", "cull hidden", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["cull backface:%t|cull backface: DEFAULT|cull backface: int 0 (OFF)|cull backface: int 1 (ON)", "", "0", "1"], "Set whether or not to cull backfaces", "cull backface", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["dice binary:%t|dice binary: DEFAULT|dice binary: int 0 (OFF)|dice binary: int 1 (ON)", "", "0", "1"], "Set whether or not to use binary dicing", "dice binary", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["dice raster:%t|dice raster: DEFAULT|dice raster: int 0 (OFF)|dice raster: int 1 (ON)", "", "0", "1"], "Set whether or not to use raster oriented dicing", "dice raster", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["trace displacements:%t|trace displace: DEFAULT|trace displace: int 0 (OFF)|trace displace: int 1 (ON)", "", "0", "1"], "Set whether or not to use displacements in raytracing", "trace displacements", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["trace motion:%t|trace motion: DEFAULT|trace motion: int 0 (OFF)|trace motion: int 1 (ON)", "", "0", "1"], "Set whether or not to use raytracing in motion blur", "trace motion", 1, 0, 1],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 3, 100.0, 1, "Use Object in Animations", "Used to manually control if this object is calculated beyond starting frame (speed hack)", "Animate Object", 1, 0, 1],
			    [Blender.Draw.Create(0), "", False, 3, 0.5, 1, "Transform MBlur", "Enables motion blur on object motion (translate, rotate, scale)", "ObjectMBlur", 0, 0, 1],
			    [Blender.Draw.Create(5), "", False, 2, 100.0, 1, "frames: ", "Number of frames to blur across", "ObjectFrames", 5, 2, 1000],
			    [Blender.Draw.Create(0), "", False, 3, 0.5, 1, "Mesh MBlur", "Enables motion blur on mesh data (any mesh animation)", "MeshMBlur", 0, 0, 1],
			    [Blender.Draw.Create(5), "", False, 2, 100.0, 1, "frames: ", "Number of frames to blur across", "MeshFrames", 5, 2, 1000]]],
			   [EVENT_LIGHT_SET, True, "Lights Setup", [0.75,1.0,0.75,1.0],
			   [[Blender.Draw.Create(1), "", True, 1, 100.0, 130, "LampF", "Select the light to setup", "Select Light", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "LampSetF", "Select which user created RIB setup you want to use for this scene and renderpass", "Select RIBset", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 0.5, 1, "Create New RIBset", "Create a new user defined RIB setup for this object", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Delete This RIBset", "Delete the current user defined RIB setup for this object", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Code Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, ["Light Archive:%t|Read Archive|Inline Code", "Read Archive", "Inline Code"], "Set the archive method for this light", "Light Archive", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into beginning of light block", "Light Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into end of light block", "Light End Code", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Shader Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(2), ["","","ls_MOSAIClight"], False, 1, 0.8, 130, "LightF", "Set shader for this light", "Light Shader", 2, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Options and Attributes", "", "", 1, 0, 1],
			    [Blender.Draw.Create(0), "", False, 3, 0.5, 1, "Light MBlur", "Enables motion blur (transform, shader)", "LightMBlur", 0, 0, 1],
			    [Blender.Draw.Create(5), "", False, 2, 100.0, 1, "frames: ", "Number of frames to blur across", "LightFrames", 5, 2, 1000]]],
			   [EVENT_MAT_SET, True, "Materials Setup", [1.0,1.0,0.75,1.0],
			   [[Blender.Draw.Create(1), "", True, 1, 100.0, 130, "MaterialF", "Select the material block to setup", "Select Material", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "MaterialSetF", "Select which user created RIB setup you want to use for this scene and renderpass", "Select RIBset", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 0.5, 1, "Create New RIBset", "Create a new user defined RIB setup for this object", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Delete This RIBset", "Delete the current user defined RIB setup for this object", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Code Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, ["Material Archive:%t|Read Archive|Inline Code", "Read Archive", "Inline Code"], "Set the archive method for this material block", "Material Archive", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into beginning of material block", "Material Begin Code", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 130, "CodeF", "Insert custom code fragment into end of material block", "Material End Code", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Shader Management", "", "", 1, 0, 1],
			    [Blender.Draw.Create(2), ["","","ss_MOSAICsurface"], False, 1, 0.8, 130, "SurfaceF", "Set surface shader for this material block", "Surface Shader", 2, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [Blender.Draw.Create(2), ["","","ds_MOSAICdisplace"], False, 1, 0.8, 130, "DisplacementF", "Set displacement shader for this material block", "Displacement Shader", 2, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.8, 130, "VolumeF", "Set interior volume shader for this material block", "Int Volume Shader", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.8, 130, "VolumeF", "Set exterior volume shader for this material block", "Ext Volume Shader", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.8, 130, "LightF", "Set arealight shader for this material block", "Area Light Shader", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 0, 100.0, 1, "Notes", "Click to read any notes for the currently selected shader", "", 1, 0, 1],
			    [0, "", False, 5, 100.0, 1, "Options and Attributes", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["visibility transmission:%t|transmission: DEFAULT|transmission: int 0 (OFF)|transmission: int 1 (ON)|transmission: string \"transparent\"|transmission: string \"opaque\"|transmission: string \"Os\"|transmission: string \"shader\"",
			     "", "Attribute \"visibility\" \"int transmission\" [ 0 ]\n", "Attribute \"visibility\" \"int transmission\" [ 1 ]\n", "Attribute \"visibility\" \"string transmission\" [ \"transparent\" ]\n", "Attribute \"visibility\" \"string transmission\" [ \"opaque\" ]\n", "Attribute \"visibility\" \"string transmission\" [ \"Os\" ]\n", "Attribute \"visibility\" \"string transmission\" [ \"shader\" ]\n"],
			     "Is this visibile to transmission rays (both new integer and string forms are available)", "visibility transmission", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["visibility specular:%t|specular: DEFAULT|specular: int 0 (OFF)|specular: int 1 (ON)|trace: int 0 (OFF)|trace: int 1 (ON)",
			     "", "Attribute \"visibility\" \"int specular\" [ 0 ]\n", "Attribute \"visibility\" \"int specular\" [ 1 ]\n", "Attribute \"visibility\" \"int trace\" [ 0 ]\n", "Attribute \"visibility\" \"int trace\" [ 1 ]\n"],
			     "Is this visibile to rays created by trace() (both new integer and string forms are available)", "visibility specular", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["visibility diffuse:%t|diffuse: DEFAULT|diffuse: int 0 (OFF)|diffuse: int 1 (ON)",
			     "", "Attribute \"visibility\" \"int diffuse\" [ 0 ]\n", "Attribute \"visibility\" \"int diffuse\" [ 1 ]\n"],
			     "Is this visibile to rays created by indirectdiffuse() and occlusion()", "visibility diffuse", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["visibility photon:%t|photon: DEFAULT|photon: int 0 (OFF)|photon: int 1 (ON)",
			     "", "Attribute \"visibility\" \"int photon\" [ 0 ]\n", "Attribute \"visibility\" \"int photon\" [ 1 ]\n"],
			     "Is this visibile to photons", "visibility photon", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["visibility camera:%t|camera: DEFAULT|camera: int 0 (OFF)|camera: int 1 (ON)",
			     "", "Attribute \"visibility\" \"int camera\" [ 0 ]\n", "Attribute \"visibility\" \"int camera\" [ 1 ]\n"],
			     "Is this visibile to camera rays", "visibility camera", 1, 0, 1],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["photon shadingmodel:%t|shadingmodel: DEFAULT|shadingmodel: string \"matte\"|shadingmodel: string \"glass\"|shadingmodel: string \"water\"|shadingmodel: string \"chrome\"|shadingmodel: string \"dielectic\"|shadingmodel: string \"transparent\"",
			     "", "Attribute \"photon\" \"string shadingmodel\" \"matte\"\n", "Attribute \"photon\" \"string shadingmodel\" \"glass\"\n", "Attribute \"photon\" \"string shadingmodel\" \"water\"\n", "Attribute \"photon\" \"string shadingmodel\" \"chrome\"\n", "Attribute \"photon\" \"string shadingmodel\" \"dielectic\"\n", "Attribute \"photon\" \"string shadingmodel\" \"transparent\"\n"],
			     "Select the shading model to use when scattering photons", "photon shadingmodel", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["shade transmissionhitmode:%t|transmissionhitmode: DEFAULT|transmissionhitmode: string \"shader\"|transmissionhitmode: string \"primitive\"",
			     "", "Attribute \"shade\" \"string transmissionhitmode\" \"shader\"\n", "Attribute \"shade\" \"string transmissionhitmode\" \"primitive\"\n"],
			     "How is opacity for transmisison rays determined", "shade transmissionhitmode", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["shade specularhitmode:%t|specularhitmode: DEFAULT|specularhitmode: string \"shader\"|specularhitmode: string \"primitive\"",
			     "", "Attribute \"shade\" \"string specularhitmode\" \"shader\"\n", "Attribute \"shade\" \"string specularhitmode\" \"primitive\"\n"],
			     "How is oopacity and color for specular rays determined", "shade specularhitmode", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 0.5, 0, ["shade diffusehitmode:%t|diffusehitmode: DEFAULT|diffusehitmode: string \"shader\"|diffusehitmode: string \"primitive\"",
			     "", "Attribute \"shade\" \"string diffusehitmode\" \"shader\"\n", "Attribute \"shade\" \"string diffusehitmode\" \"primitive\"\n"],
			     "How is oopacity and color for diffuse rays determined", "shade diffusehitmode", 1, 0, 1],
			    [Blender.Draw.Create(1), "", False, 1, 100.0, 0, ["shade camearhitmode:%t|camearhitmode: DEFAULT|camearhitmode: string \"shader\"|camearhitmode: string \"primitive\"",
			     "", "Attribute \"shade\" \"string camerahitmode\" \"shader\"\n", "Attribute \"shade\" \"string camerahitmode\" \"primitive\"\n"],
			     "Allows you to control the culling of objects behind", "shade camearhitmode", 1, 0, 1],
			    [0, "", True, 5, 100.0, 0, "", "", "", 1, 0, 1],
			    [Blender.Draw.Create(0), "", False, 3, 0.5, 1, "Flip \"U\" Tex Coor", "This controls the direction of the \"U\" texture UV coordinates during export", "InvertTexU", 0, 0, 1],
			    [Blender.Draw.Create(1), "", False, 3, 100.0, 1, "Flip \"V\" Tex Coor", "This controls the direction of the \"V\" texture UV coordinates during export", "InvertTexV", 1, 0, 1],
			    [Blender.Draw.Create(0), "", False, 3, 0.5, 1, "Shader MBlur", "Enables motion blur (all animated shader parameters)", "ShaderMBlur", 0, 0, 1],
			    [Blender.Draw.Create(5), "", False, 2, 100.0, 1, "frames: ", "Number of frames to blur across", "ShaderFrames", 5, 2, 1000]]]]

#Dialog index constants
DIALOG_FILE_FILTER	= 0
DIALOG_EXPORTER_SW	= 1
DIALOG_FRAG_NAME	= 2
DIALOG_RENDER_BIN	= 3
DIALOG_COMPILER_BIN	= 4
DIALOG_TEX_OPT		= 5
DIALOG_ENV_OPT		= 6
DIALOG_INFO_BIN		= 7
DIALOG_SHADER_NAME	= 8
DIALOG_RANGE_ADJ	= 9
DIALOG_COMMENTS		= 10
DIALOG_CREATE_RIBSET	= 11
DIALOG_SL_EXT		= 12
DIALOG_RIB_EXT		= 13
DIALOG_TEX_EXT		= 14
DIALOG_COPY_FRAG	= 15
DIALOG_PREVIEW		= 16
DIALOG_SHADOW		= 17
DIALOG_LATLONG		= 18
DIALOG_CUBE		= 19

#Array of dialogs
DialogData		= [#File Filter Dialog
			   [("Code Fragment: ", Create(Filters[0]), 0, 10, "Text name filter for code fragments (blank will show all files)"),
			    ("Shader Source: ", Create(Filters[1]), 0, 10, "Text name filter for shader source GENERALLY LEAVE AS IS!!!!"),
			    ("Surface Shader: ", Create(Filters[2]), 0, 10, "Text name filter for surface shaders (blank will show all files)"),
			    ("Displace Shade: ", Create(Filters[3]), 0, 10, "Text name filter for displacement shaders (blank will show all files)"),
			    ("Volume Shader: ", Create(Filters[4]), 0, 10, "Text name filter for volume shaders (blank will show all files)"),
			    ("Imager Shader: ", Create(Filters[5]), 0, 10, "Text name filter for showing image shaders (blank will show all files)"),
			    ("Light Shader: ", Create(Filters[6]), 0, 10, "Text name filter for all light shaders (blank will show all files)"),
			    ("Shader Include: ", Create(Filters[7]), 0, 10, "Text name filter for shader include GENERALLY LEAVE AS IS!!!!")],
			   #Exporter Switches Dialog
			   [("RiFrameBegin/End", Create(RibFrames), "If unchecked NO RiFrameBegin/End blocks will be used in RIB export (no animation will be possible)"),
			    ("RiWorldBegin/End", Create(RibWorlds), "If unchecked NO RiWorkdBegin/End blocks will be used in RIB export"),
			    ("RiScreenWindow", Create(RibScreen), "If unchecked NO RiScreenWindow will be used in RIB export"),
			    ("RiProjection", Create(RibProjection), "If unchecked NO RiProjection will be used in RIB export(camera lens/scale wont work)"),
			    ("RiClipping", Create(RibClipping), "If unchecked NO RiClipping will be used in  RIB export (scene, camera and lamp clipping wont work)"),
			    ("RiColor", Create(RibColor), "If unchecked NO RiColor will be used in RIB export (geometry color will only work through shaders)"),
			    ("RiOpacity", Create(RibOpacity), "If unchecked NO RiOpacity will be used in RIB export (geometry alpha will only work through shaders)"),
			    ("RiSides", Create(RibSides), "If unchecked NO RiSides will be used in RIB export (geometry double/single sided wont work)"),
			    ("RiBound", Create(RibBound), "If unchecked NO RiBound will be used in RIB export"),
			    ("Vertex Colors", Create(RibVertexCols), "If unchecked NO per vertex colors will be used in RIB export"),
			    ("Vertex UV's", Create(RibVertexUVs), "If unchecked NO per vertex UV's will be used in RIB export"),
			    ("Surface Normals", Create(RibNormals), "If unchecked NO per face normals will be used in RIB export"),
			    ("RIB Comments", Create(RibComments), "If unchecked all comments in all RIB export will be stripped")],
			   #Shader Fragment Name Dialog
			   [("", Create(""), 0, 21, "The text name to save shader fragment as")],
			   #Renderman Binary Dialog
			   [("", Create(RenderBin), 0, 100, "Use <RIB> in options to place input rib, appended if unused")],
			   #Shader Compiler Binary Dialog
			   [("", Create(CompilerBin), 0, 100, "Use <SHADER> in options to place input shader, appended if unused (requires BMRT style ouput)")],
			   #Texture Optimizer Dialog
			   [("", Create(TexmakeBin), 0, 100, "Use <TEXIN> and <TEXOUT> to place textures in user options, both auto appended if unused")],
			   #Environment Optimizer Dialog
			   [("", Create(EnvmakeBin), 0, 100, "Use <TEXIN> and <TEXOUT> to place textures in user options, both auto appended if unused")],
			   #Shader Info Dialog
			   [("", Create(InfoBin), 0, 100, "Define the shader info binary (used by Shader Fragment utilities)")],
			   #Shader Name Dialog
			   [("", Create(""), 0, 100, "Type the name of a shader already compiled and available for this renderer")],
			   #Range Multiplier and Adder Dialog
			   [("Multiply Range", Create("1.0"), 0, 100, "This allows you to multiply the control value allowing you to change its range"),
			    ("Adder to Range", Create("0.0"), 0, 100, "After multiplication this allows you to shift the new control value range")],
			   #Shader comment Dialog
			   [("", Create("No usage comments"), 0, 399, "Type the comment you want to show for this shader (use | for multiple lines)")],
			   #Create new RIBset dialog
			   [("", Create(""), 0, 100, "Type the name of the new RIB setup to create for this object")],
			   #Shader extension dialog
			   [("", Create(ShaderExt), 0, 100, "Type the file extension used for your renderers compiled shaders")],
			   #RIB extension dialog
			   [("", Create(RibExt), 0, 100, "Type the file extension used for your renderers RIB files")],
			   #Texture export extension dialog
			   [("", Create(TextureExt), 0, 100, "Type the file extension used to export and optimize textures")],
			   #Copy fragment dialog
			   [("", Create(""), 0, 21, "Type the name of the copied fragment (leave to cancel copy)")],
			   #Preview setup dialog
			   [("Resolution: ", Create(320), 80, 1024, "Height and Width resolution squared of preview"),
			    ("Preview Model: ", Create(1), 1, 6, "Preview model: 1=Sphere, 2=Cube, 3=Cone, 4=Cylinder, 5=Suzanne, 6=Strands"),
			    ("Light Setup: ", Create(1), 1, 3, "Preview lighting setup: 1=White, 2=Color, 3=Flat"),
			    ("Light Energy: ", Create(30), 0, 1000, "Preview lighting intensity")],
			   #Shadow map dialog
			   [("picturename : ", Create(""), 0, 255, "Input depth file usually from a zfile display render"),
			    ("texturename : ", Create(""), 0, 255, "Output shadow map texture for use in shadow light shaders (blank to disable)")],
			   #LatLong environment map dialog
			   [("picturename : ", Create(""), 0, 255, "Input image usually a render from the mirrors point of view"),
			    ("texturename : ", Create(""), 0, 255, "Output environment map for use in environment shaders (blank to disable)"),
			    ("filterfunc : ", Create(""), 0, 255, "Filter to use on image (\"box\", \"triangle\", \"catmull-rom\", \"b-spline\", \"gaussian\", \"sinc\")"),
			    ("swidth : ", Create(""), 0, 255, "Filter width strength"),
			    ("twidth : ", Create(""), 0, 255, "Filter height strength")],
			   #Cube environment map dialog
			   [("px : ", Create(""), 0, 255, "Input image usually a render from +X +Y -Z direction"),
			    ("nx : ", Create(""), 0, 255, "Input image usually a render from -X +Y +Z direction"),
			    ("py : ", Create(""), 0, 255, "Input image usually a render from +Y -Z +X direction"),
			    ("ny : ", Create(""), 0, 255, "Input image usually a render from -Y +Z +X direction"),
			    ("pz : ", Create(""), 0, 255, "Input image usually a render from +Z +Y +X direction"),
			    ("nz : ", Create(""), 0, 255, "Input image usually a render from -Z +Y -X direction"),
			    ("texturename : ", Create(""), 0, 255, "Output environment map for use in environment shaders (blank to disable)"),
			    ("fov : ", Create(""), 0, 255, "Fov used to seam the maps together, use larger then 90.0 value to intersect maps"),
			    ("filterfunc : ", Create(""), 0, 255, "Filter to use on image (\"box\", \"triangle\", \"catmull-rom\", \"b-spline\", \"gaussian\", \"sinc\")"),
			    ("swidth : ", Create(""), 0, 255, "Filter width strength"),
			    ("twidth : ", Create(""), 0, 255, "Filter height strength")]]

ApplyPresetGlobals()									#Apply global presets before building GUI
BuildPassesButtons(Blender.Scene.Get()[0])					#Go ahead and populate scenepasses in Projects tab in ButtonData list before we draw anything
BuildPathsButtons()								#Go ahead and populate the user shader paths ButtonData list


####################################################################### START USER GLOBAL FUNCTIONS
#### Default shudown routine
def Shutdown():
	print "MOSAIC shutting down..."
	Exit()
	
	
#### Returns a string for the type of object passed
def TypeString(Object):
	if (type(Object) == Blender.Types.SceneType):		return "Scene"
	elif (type(Object) == Blender.Types.MaterialType):	return "Material"
	elif (type(Object) == Blender.Types.MeshType):		return "Mesh"
	elif (type(Object) == Blender.Types.LampType):		return "Lamp"
	elif (type(Object) == Blender.Types.CameraType):	return "Camera"
	elif (type(Object) == Blender.Types.CurveType):		return "Curve"
	elif (type(Object) == Blender.Types.ObjectType):	return Object.getType()
	else:							return "None"


#### Generate a project folder name from "Project Setup"->"Project Folder" entry or use default if not set
def GetProjectFolder():
	global RenderDir, ProjectDir, ButtonData
	ProjectDir = RenderDir+GetProperty(Blender.Scene.Get()[0], "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUT_DEFAULT])+sys.sep
	return ProjectDir


#### Create passed "OutputDir" and all standard project folders
def SetupDirectories(OutputDir):
	if (OutputDir):
		try:
			if (sys.exists(OutputDir) != 2):				os.mkdir(OutputDir)
			if (sys.exists(OutputDir+"Cache") != 2):			os.mkdir(OutputDir+"Cache")
			if (sys.exists(OutputDir+"Shaders") != 2):			os.mkdir(OutputDir+"Shaders")
			if (sys.exists(OutputDir+"Maps") != 2):				os.mkdir(OutputDir+"Maps")
			if (sys.exists(OutputDir+"Archives") != 2):			os.mkdir(OutputDir+"Archives")
			if (sys.exists(OutputDir+"Archives"+sys.sep+"Scenes") != 2):	os.mkdir(OutputDir+"Archives"+sys.sep+"Scenes")
			if (sys.exists(OutputDir+"Archives"+sys.sep+"Materials") != 2):	os.mkdir(OutputDir+"Archives"+sys.sep+"Materials")
			if (sys.exists(OutputDir+"Archives"+sys.sep+"Lights") != 2):	os.mkdir(OutputDir+"Archives"+sys.sep+"Lights")
			if (sys.exists(OutputDir+"Archives"+sys.sep+"Cameras") != 2):	os.mkdir(OutputDir+"Archives"+sys.sep+"Cameras")
			if (sys.exists(OutputDir+"Archives"+sys.sep+"Geometry") != 2):	os.mkdir(OutputDir+"Archives"+sys.sep+"Geometry")
			if (sys.exists(OutputDir+"Archives"+sys.sep+"Objects") != 2 ):	os.mkdir(OutputDir+"Archives"+sys.sep+"Objects")
		except:
			ErrorPopup("Could not write output directories, check paths and permissions!")
			return 1
		return 0


#### Removes passed Directory and everything in them!
def DelTree(Directory, RemoveRoot = False):
	if (Directory and sys.exists(Directory) == 2):
		for root, dirs, files in os.walk(Directory, topdown=False):
			for name in files:
				os.remove(os.path.join(root, name))
			for name in dirs:
				os.rmdir(os.path.join(root, name))
		if (RemoveRoot): os.rmdir(Directory)


#### List files in directory that match filter
def ListTree(Directory, FilterList = [""], JustRoot = False, endsWith = False):
	fileList = []
	FilterCount = len(FilterList)
	
	if (type(Directory) == list):	dirList = Directory
	else:				dirList = [Directory]
	for dirItem in dirList:
		if (dirItem and sys.exists(dirItem)):
			for root, dirs, files in os.walk(dirItem, topdown=True):
				for name in files:
					foundCount	= 0
					for Filter in FilterList:
						if(not Filter or (endsWith and name.endswith(Filter)) or (not endsWith and name.count(Filter))): foundCount = foundCount+1
					if (foundCount == FilterCount): fileList.append(name)
				if (JustRoot): break #If just viewing root folder then quit looking
	return fileList


#### Converts passed textList string list into a Blender Text object of name textName
def ListToText(textName, textList):
	newText = Blender.Text.New(textName)
	for line in textList: newText.write(line)


#### Exports blender text as a text file in current directory
def ExportText(blenderText):
	try:
		textfile = open(blenderText.name, 'wb')
		for line in blenderText.asLines():
			textfile.write(line+"\n")
		textfile.close()
	except:
		ErrorPopup("Could not export text file, check paths and permissions!")
		return 1
	return 0


#### Makes default Blender text shaders and fragments if they don't already exist
def MakeDefaultShaders():
	global surfaceShader, displaceShader, lightShader, volumeShader, imageShader, surfaceFragment, displaceFragment, lightFragment, volumeFragement, imageFragment
	nameList	= [text.name for text in Blender.Text.Get()]
	if (not nameList.count("MOSAICsurface.sl")):	ListToText("MOSAICsurface.sl", surfaceShader)
	if (not nameList.count("MOSAICdisplace.sl")):	ListToText("MOSAICdisplace.sl", displaceShader)
	if (not nameList.count("MOSAIClight.sl")):	ListToText("MOSAIClight.sl", lightShader)
	if (not nameList.count("MOSAICfog.sl")):	ListToText("MOSAICfog.sl", volumeShader)
	if (not nameList.count("MOSAICbackground.sl")):	ListToText("MOSAICbackground.sl", imageShader)
	if (not nameList.count("ss_MOSAICsurface")):	ListToText("ss_MOSAICsurface", surfaceFragment)
	if (not nameList.count("ds_MOSAICdisplace")):	ListToText("ds_MOSAICdisplace", displaceFragment)
	if (not nameList.count("ls_MOSAIClight")):	ListToText("ls_MOSAIClight", lightFragment)
	if (not nameList.count("vs_MOSAICfog")):	ListToText("vs_MOSAICfog", volumeFragment)
	if (not nameList.count("is_MOSAICbackground")):	ListToText("is_MOSAICbackground", imageFragment)


#### Creates a new sequence filename with given frame number from an old sequence filename (using same basic rules that blender uses to figure out sequence order)
def CreateSeqName(FileName, Frame, NumFrames = 0, StartFrame = 1, Offset = 0, Fields = 2, isCyclic = False):
	if (NumFrames):
		Frame		= int((Frame-(StartFrame-1)-1)/(Fields/2.0)+1+Offset)
		if (isCyclic):
			Frame	= ((Frame-1)-(int((Frame-1)/NumFrames)*NumFrames))+1
		else:
			if (Frame < 1):			Frame = 1
			elif (Frame > NumFrames):	Frame = NumFrames
	
	if (FileName and Frame and Frame > 0):
		frameStr	= str(Frame)
		frameIndex	= len(frameStr)-1
		seqList		= []
		seqSet		= False
		seqLast		= False
		for char in reversed([char for char in FileName]):
			if (char.isdigit() and not seqSet):
				if (frameIndex >= 0):
					seqList.append(frameStr[frameIndex])
					frameIndex = frameIndex-1
				else:
					seqList.append('0')
				seqLast = True
			else:
				if (seqLast and not char.isdigit()):
					seqSet	= True
					seqLast	= False
					if (frameIndex >= 0):
						seqList.append(frameStr[0:frameIndex+1])
						frameIndex = -1
				seqList.append(char)
		return "".join(reversed(seqList))
	else:	return FileName


#### Creates and compiles shader in current directory from passed blender text object containing shader source
def CompileShader(shaderText):
	global CompilerBin
	if (not CompilerBin):
		ErrorPopup("Must set shader compiler binary under MOSAIC setting tab!")
		return 0
	print "\tWriting Shader "+shaderText.name+"..."
	if (ExportText(shaderText)): return 1
	print "\tCompiling Shader "+shaderText.name+"..."
	compileCall = CompilerBin
	if (compileCall.count("<SHADER>")): compileCall = compileCall.replace("<SHADER>", shaderText.name)
	else: compileCall = compileCall+" \""+shaderText.name+"\""
	os.system(compileCall)
	return 0


#### Creates a string with the number of tabs requested
def CreateTabs(tabLevel = 1):
	tabString = ""
	while tabLevel > 0:
		tabString	= tabString+"\t"
		tabLevel	= tabLevel-1
	return tabString


#### Adds tabs to beginning of each line of passed list
def AddTabs(List, TabLevel):
	if (List and TabLevel):
		for index, item in enumerate(List):
			List[index] = CreateTabs(TabLevel)+item
	return List


#### Parse tokens in source strings based on passed Object type
#### Object can be a single object or object list, if it is a list it will cycle through each object type parsing tokens for each type in the line
def ParseTokens(Scene, tokenObjects, Source, fragmentName = ""):
	global lightList, lightDupliIndex, lightAreaIndex, ProjectDir, RibComments
	if (Source and Source.count('<')):				#Only process if theres source code and it has tokens!
		if (type(tokenObjects) != list):	Objects = [tokenObjects] #If this is not a list then put object in list
		else:					Objects = tokenObjects
		for original in [block[0] for block in [end.split('>') for end in [start for start in Source.split('<')]] if len(block) > 1]: #Cycle through any tokens in this source line
			
			token		= ''
			tokenType	= ''
			texIndex	= -2
			rangeAdder	= 0.0
			rangeMulti	= 1.0
			controlValue	= 'NONE'
			controlString	= "\"Token Error\""
			world		= Scene.world			#Get this scenes world data for tokens
			
			for index, parameter in enumerate(original.split('_')): #Extract token parameters to be processed
				try:
					if (index == 0):					token		= parameter
					elif (parameter[0] == 'X'):				texIndex	= int(parameter.lstrip('X'))-1
					elif (parameter[0] == 'A'):				rangeAdder	= float(parameter.lstrip('A'))
					elif (parameter[0] == 'M' and len(parameter) > 1):	rangeMulti	= float(parameter.lstrip('M'))
					else:							tokenType	= parameter
				except:
					ErrorPopup("Invalid token parameter \""+parameter+"\" in <"+original+"> using defaults instead!")
					continue			#If theres an error skip token parameter and go to next one
			
			for Object in Objects:
				#Global parameters
				if (token.count('#') == len(token)):				controlValue = str(Scene.render.cFrame)
				elif (token == "ProjectDir"):					controlValue = ProjectDir
				elif (token == "ObjectName"):
					if (Object):						controlValue = Object.name #Pass objects name through token
					elif (Scene):						controlValue = Scene.name #If no object pass scenes name through token
				elif (token == "SceneAspX"):					controlValue = Scene.render.aspectX
				elif (token == "SceneAspY"):					controlValue = Scene.render.aspectY
				elif (token == "SceneEdgeColor"):				controlValue = list(Scene.render.edgeColor)
				elif (token == "SceneEnd"):					controlValue = Scene.render.eFrame
				elif (token == "SceneFps"):					controlValue = Scene.render.fps
				elif (token == "SceneBf"):					controlValue = Scene.render.mblurFactor
				elif (token == "SceneFilterSize"):				controlValue = Scene.render.gaussFilter
				elif (token == "ScenePlanes"):					controlValue = Scene.render.imagePlanes
				elif (token == "SceneOSALevel"):				controlValue = Scene.render.OSALevel
				elif (token == "SceneStart"):					controlValue = Scene.render.sFrame
				elif (token == "SceneSizeX"):					controlValue = Scene.render.sizeX
				elif (token == "SceneSizeY"):					controlValue = Scene.render.sizeY
				elif (token == "SceneXparts"):					controlValue = Scene.render.xParts
				elif (token == "SceneYparts"):					controlValue = Scene.render.yParts
				elif (world):				#Is there world data to check?
					if (token == "WorldAmbCol"):				controlValue = list(world.getAmb())
					elif (token == "WorldHorCol"):				controlValue = list(world.getHor())
					elif (token == "WorldZenCol"):				controlValue = list(world.getZen())
					elif (token == "WorldIsMist"):				controlValue = world.getMode()&1
					elif (token == "WorldIsOcc"):				controlValue = world.getMode()&16
					elif (token == "WorldMistType"):			controlValue = world.getMistype()
					elif (token == "WorldMist"):				controlValue = world.getMist()[0]
					elif (token == "WorldSta"):				controlValue = world.getMist()[1]
					elif (token == "WorldDi"):				controlValue = world.getMist()[2]
					elif (token == "WorldHi"):				controlValue = world.getMist()[3]
					elif (token == "WorldSize"):				controlValue = world.getStar()[3]
					elif (token == "WorldMinDist"):				controlValue = world.getStar()[4]
					elif (token == "WorldStarDist"):			controlValue = world.getStar()[5]
					elif (token == "WorldColnoise"):			controlValue = world.getStar()[6]
				if (controlValue != 'NONE'):	break	#If already found then break!
				
				#Object and type based parameters
				if (type(Object) == Blender.Types.ObjectType):	#Used for all object based parameters
					if (token == "TO" or token == "FROM"):	#To and from can be used for any object
						m = Object.mat			#Global matrix
						if (token == "TO" and tokenType == 'P'):
							controlValue	= [-m[2][0]+m[3][0], -m[2][1]+m[3][1], -m[2][2]+m[3][2]] #To point
						if (token == "TO" and (tokenType == 'V' or tokenType == 'N')):
							controlValue	= list(Vector([-m[2][0]+m[3][0], -m[2][1]+m[3][1], -m[2][2]+m[3][2]]).normalize()) #To vector/normal
						if (token == "FROM" and tokenType == 'P'):
							controlValue	= [m[3][0]/m[3][3], m[3][1]/m[3][3], m[3][2]/m[3][3]] #From point
						if (token == "FROM" and tokenType == 'M'):
							controlValue	= list(m) #From matrix
					elif (token == "LightID"):
						if (lightList.count([Object, lightDupliIndex, lightAreaIndex, True])): controlValue = lightList.index([Object, lightDupliIndex, lightAreaIndex, True])+1 #Illuminate ID for lights and arealight objects
						else:						controlValue = 'SKIP'
					
					elif (Object.getType() == "Lamp"): #Used for light parameters
						if (token == "LampLightColor"):			controlValue = list(Object.getData().col)
						elif (token == "LampEnergy"):			controlValue = Object.getData().energy
						elif (token == "LampDist"):			controlValue = Object.getData().dist
						elif (token == "LampSpotSi"):			controlValue = Object.getData().spotSize*0.0174532925199
						elif (token == "LampSpotBl"):			controlValue = Object.getData().spotBlend
						elif (token == "LampShadBufSize"):		controlValue = Object.getData().bufferSize
						elif (token == "LampSamples"):			controlValue = Object.getData().samples
						elif (token == "LampHaloInt"):			controlValue = Object.getData().haloInt
						elif (token == "LampBias"):			controlValue = Object.getData().bias
						elif (token == "LampSoft"):			controlValue = Object.getData().softness
						elif (token == "LampClipSta"):			controlValue = Object.getData().clipStart
						elif (token == "LampClipEnd"):			controlValue = Object.getData().clipEnd
						elif (token == "LampSizeX"):			controlValue = Object.getData().areaSizeX
						elif (token == "LampSizeY"):			controlValue = Object.getData().areaSizeY
						elif (token == "LampSamplesX"):			controlValue = Object.getData().raySamplesX
						elif (token == "LampSamplesY"):			controlValue = Object.getData().raySamplesY
						elif (token == "LampHaloStep"):			controlValue = Object.getData().haloStep
						elif (token == "LampQuad1"):			controlValue = Object.getData().quad1
						elif (token == "LampQuad2"):			controlValue = Object.getData().quad2
						elif (token == "LampNoDiffuse"):		controlValue = (Object.getData().mode&Blender.Lamp.Modes["NoDiffuse"])/Blender.Lamp.Modes["NoDiffuse"]
						elif (token == "LampNoSpec"):			controlValue = (Object.getData().mode&Blender.Lamp.Modes["NoSpecular"])/Blender.Lamp.Modes["NoSpecular"]
						elif (token == "LampType"):			controlValue = Object.getData().type
						elif (token == "LampIsQuad"):			controlValue = (Object.getData().mode&Blender.Lamp.Modes["Quad"])/Blender.Lamp.Modes["Quad"]
						elif (token == "LampIsRaytrace"):		controlValue = (Object.getData().mode&Blender.Lamp.Modes["RayShadow"])/Blender.Lamp.Modes["RayShadow"]
						elif (token == "LampIsSphere"):			controlValue = (Object.getData().mode&Blender.Lamp.Modes["Sphere"])/Blender.Lamp.Modes["Sphere"]
					elif (Object.getType() == "Camera"): #Used for camera parameters
						if (token == "CameraAlpha"):			controlValue = Object.getData().alpha
						elif (token == "CameraAngle"):			controlValue = Object.getData().angle
						elif (token == "CameraEnd"):			controlValue = Object.getData().clipEnd
						elif (token == "CameraStart"):			controlValue = Object.getData().clipStart
						elif (token == "CameraDofDist"):		controlValue = Object.getData().dofDist
						elif (token == "CameraSize"):			controlValue = Object.getData().drawSize
						elif (token == "CameraLens"):			controlValue = Object.getData().lens
						elif (token == "CameraScale"):			controlValue = Object.getData().scale
						elif (token == "CameraX"):			controlValue = Object.getData().shiftX
						elif (token == "CameraY"):			controlValue = Object.getData().shiftY
				elif (type(Object) == Blender.Types.MaterialType): #Used for material parameters
					if (token == "MatHaloAdd"):				controlValue = Object.add
					elif (token == "MatIsShadeless"):			controlValue = (Object.mode&Blender.Material.Modes.SHADELESS)/Blender.Material.Modes.SHADELESS
					elif (token == "MatIsRayTransp"):			controlValue = (Object.mode&Blender.Material.Modes.RAYTRANSP)/Blender.Material.Modes.RAYTRANSP
					elif (token == "MatIsRayMirror"):			controlValue = (Object.mode&Blender.Material.Modes.RAYMIRROR)/Blender.Material.Modes.RAYMIRROR
					elif (token == "MatAmb"):				controlValue = Object.amb
					elif (token == "MatAlpha"):				controlValue = Object.alpha
					elif (token == "MatDiffuseDark"):			controlValue = Object.diffuseDarkness
					elif (token == "MatDiffuseSize"):			controlValue = Object.diffuseSize
					elif (token == "MatDiffuseSmooth"):			controlValue = Object.diffuseSmooth
					elif (token == "MatEmit"):				controlValue = Object.emit
					elif (token == "MatRayFilt"):				controlValue = Object.filter
					elif (token == "MatFlareBoost"):			controlValue = Object.flareBoost
					elif (token == "MatFlareSeed"):				controlValue = Object.flareSeed
					elif (token == "MatFlareSize"):				controlValue = Object.flareSize
					elif (token == "MatMirrorFresnel"):			controlValue = Object.fresnelDepth
					elif (token == "MatMirrorFac"):				controlValue = Object.fresnelDepthFac
					elif (token == "MatRayFresnel"):			controlValue = Object.fresnelTrans
					elif (token == "MatRayFac"):				controlValue = Object.fresnelTransFac
					elif (token == "MatHaloSeed"):				controlValue = Object.haloSeed
					elif (token == "MatHaloSize"):				controlValue = Object.haloSize
					elif (token == "MatHard"):				controlValue = Object.hard
					elif (token == "MatRayIOR"):				controlValue = Object.IOR
					elif (token == "MatMirrorColor"):			controlValue = list(Object.mirCol)
					elif (token == "MatFlares"):				controlValue = Object.nFlares
					elif (token == "MatLines"):				controlValue = Object.nLines
					elif (token == "MatRings"):				controlValue = Object.nRings
					elif (token == "MatStar"):				controlValue = Object.nStars
					elif (token == "MatRayMir"):				controlValue = Object.rayMirr
					elif (token == "MatMirrorDepth"):			controlValue = Object.rayMirrDepth
					elif (token == "MatRef"):				controlValue = Object.ref
					elif (token == "MatRefr"):				controlValue = Object.refracIndex
					elif (token == "MatCol"):				controlValue = list(Object.rgbCol)
					elif (token == "Matrms"):				controlValue = Object.rms
					elif (token == "MatRough"):				controlValue = Object.roughness
					elif (token == "MatShadA"):				controlValue = Object.shadAlpha
					elif (token == "MatSpec"):				controlValue = Object.spec
					elif (token == "MatSpecCol"):				controlValue = list(Object.specCol)
					elif (token == "MatSpecSize"):				controlValue = Object.specSize
					elif (token == "MatSpecSmooth"):			controlValue = Object.specSmooth
					elif (token == "MatSpecTra"):				controlValue = Object.specTransp
					elif (token == "MatSSSBack"):				controlValue = Object.sssBack
					elif (token == "MatSSSCol"):				controlValue = list(Object.sssCol)
					elif (token == "MatSSSColBlend"):			controlValue = Object.sssColorBlend
					elif (token == "MatSSSError"):				controlValue = Object.sssError
					elif (token == "MatSSSIOR"):				controlValue = Object.sssIOR
					elif (token == "MatSSSRadiusB"):			controlValue = Object.sssRadiusBlue
					elif (token == "MatSSSRadiusR"):			controlValue = Object.sssRadiusRed
					elif (token == "MatSSSRadiusG"):			controlValue = Object.sssRadiusGreen
					elif (token == "MatSSSTex"):				controlValue = Object.sssTextureScatter
					elif (token == "MatHaloSubSize"):			controlValue = Object.subSize
					elif (token == "MatRayDepth"):				controlValue = Object.transDepth
					elif (token == "MatTranslu"):				controlValue = Object.translucency
					elif (token == "MatZoffs"):				controlValue = Object.zOffset
					elif (texIndex > -2 and texIndex < 23):	#Are we using a texture token
						maps = Object.getTextures()	#Lets get available textures
						if (texIndex == -1 or texIndex > 9): #If we are not manually selecting a slot then find first valid
							for index in range(10):
								if (maps[index] and maps[index].tex.getType() == "Image"): #If this index is a valid texture then see where were using it
									if (texIndex == -1 or				#If were using first valid
									    (texIndex == 10 and maps[index].mtCol) or	#If were using ColMap
									    (texIndex == 11 and maps[index].mtNor) or	#If were using NorMap
									    (texIndex == 12 and maps[index].mtCsp) or	#If were using CspMap
									    (texIndex == 13 and maps[index].mtCmir) or	#If were using CmirMap
									    (texIndex == 14 and maps[index].mtRef) or	#If were using RefMap
									    (texIndex == 15 and maps[index].mtSpec) or	#If were using SpecMap
									    (texIndex == 16 and maps[index].mtAmb) or	#If were using AmbMap
									    (texIndex == 17 and maps[index].mtHard) or	#If were using HardMap
									    (texIndex == 18 and maps[index].mtRayMir) or #If were using RayMirMap
									    (texIndex == 19 and maps[index].mtAlpha) or	#If were using AlphaMap
									    (texIndex == 20 and maps[index].mtEmit) or	#If were using EmitMap
									    (texIndex == 21 and maps[index].mtTranslu) or #If were using TransluMap
									    (texIndex == 22 and maps[index].mtDisp)): texIndex = index
								if (texIndex > -1 and texIndex < 10): break #If a valid texture is found then break
						if (texIndex > -1 and texIndex < 10 and maps[texIndex]): #Is there a mapping available at given index
							if (token == "MatMapColor"):		controlValue = list(maps[texIndex].col)
							elif (token == "MatMapCol"):		controlValue = maps[texIndex].colfac
							elif (token == "MatMapDisp"):		controlValue = maps[texIndex].dispfac
							elif (token == "MatMapDVar"):		controlValue = maps[texIndex].dvar
							elif (token == "MatMapNor"):		controlValue = maps[texIndex].norfac
							elif (token == "MatMapOfSzXY"):		controlValue = [maps[texIndex].ofs[0], maps[texIndex].ofs[1], maps[texIndex].size[0], maps[texIndex].size[1]]
							elif (token == "MatMapOfsX"):		controlValue = maps[texIndex].ofs[0]
							elif (token == "MatMapOfsY"):		controlValue = maps[texIndex].ofs[1]
							elif (token == "MatMapOfsZ"):		controlValue = maps[texIndex].ofs[2]
							elif (token == "MatMapSizeX"):		controlValue = maps[texIndex].size[0]
							elif (token == "MatMapSizeY"):		controlValue = maps[texIndex].size[1]
							elif (token == "MatMapSizeZ"):		controlValue = maps[texIndex].size[2]
							elif (token == "MatMapVar"):		controlValue = maps[texIndex].varfac
							elif (token == "MatMapWarp"):		controlValue = maps[texIndex].warpfac
							if (controlValue != 'NONE'):		break	#If already found then break!
							tex = maps[texIndex].tex
							if (tex):		#Is there a texture available for this mapping
								if (token == "MatTexFrames"):	controlValue = tex.animFrames
								elif (token == "MatTexOffs"):	controlValue = tex.animOffset
								elif (token == "MatTexStartFr"):controlValue = tex.animStart
								elif (token == "MatTexBright"):	controlValue = tex.brightness
								elif (token == "MatTexContr"):	controlValue = tex.contrast
								elif (token == "MatTexMinX"):	controlValue = tex.crop[0]
								elif (token == "MatTexMaxX"):	controlValue = tex.crop[2]
								elif (token == "MatTexMinY"):	controlValue = tex.crop[1]
								elif (token == "MatTexMaxY"):	controlValue = tex.crop[3]
								elif (token == "MatTexFieIma"):	controlValue = tex.fieldsPerImage
								elif (token == "MatTexFilter"):	controlValue = tex.filterSize
								elif (token == "MatTexXrepeat"):controlValue = tex.repeat[0]
								elif (token == "MatTexYrepeat"):controlValue = tex.repeat[1]
								elif (token == "MatTexColor"):	controlValue = list(tex.rgbCol)
								elif (token == "MatTexDistAmnt"):controlValue = tex.distAmnt
								elif (token == "MatTexExp"):	controlValue = tex.exp
								elif (token == "MatTexiScale"):	controlValue = tex.iScale
								elif (token == "MatTexH"):	controlValue = tex.hFracDim
								elif (token == "MatTexLacu"):	controlValue = tex.lacunarity
								elif (token == "MatTexNDepth"):	controlValue = tex.noiseDepth
								elif (token == "MatTexNSize"):	controlValue = tex.noiseSize
								elif (token == "MatTexOcts"):	controlValue = tex.octs
								elif (token == "MatTexTurb"):	controlValue = tex.turbulence
								elif (token == "MatTexW1"):	controlValue = tex.weight1
								elif (token == "MatTexW2"):	controlValue = tex.weight2
								elif (token == "MatTexW3"):	controlValue = tex.weight3
								elif (token == "MatTexW4"):	controlValue = tex.weight4
								if (controlValue != 'NONE'):	break	#If already found then break!
								image = tex.image
								if (image):
									if (token == "MatImageName"):
										if (image.source == Blender.Image.Sources.SEQUENCE):
											controlValue = CreateSeqName(sys.splitext(sys.basename(image.getFilename()))[0]+TextureExt, Scene.render.cFrame, tex.animFrames, tex.animStart, tex.animOffset, tex.fieldsPerImage, tex.cyclic)
										else:	controlValue = sys.splitext(sys.basename(image.getFilename()))[0]+TextureExt
									elif (token == "MatImageSizeX"):controlValue = image.size[0]
									elif (token == "MatImageSizeY"):controlValue = image.size[1]
									elif (token == "MatImageDepth"):controlValue = image.depth
									elif (token == "MatImageStart"):controlValue = image.start
									elif (token == "MatImageEnd"):	controlValue = image.end
									elif (token == "MatImageSpeed"):controlValue = image.speed
									elif (token == "MatImageXrep"):	controlValue = image.xrep
									elif (token == "MatImageYrep"):	controlValue = image.yrep
								else:	controlValue = 'NOTEX'
							else:		controlValue = 'NOTEX'
						else:			controlValue = 'NOTEX'
				if (controlValue == 'NOTEX'):		#If theres no images then exit gracefully instead of erroring
					if (tokenType == 'S'):				controlValue = ""
					elif (tokenType == 'I' or tokenType == 'F'):
						if (token == "MatMapOfSzXY"):	controlValue = [0,0,1,1]
						else:				controlValue = 0
					else:						controlValue = []
				if (controlValue != 'NONE'):	break	#If already found then break!
			
			if(controlValue != 'NONE' and controlValue != 'SKIP'): #If we have a valid value then process
				if (type(controlValue) == str):		#Lets process string types
					if (token.count('#') == len(token)): #Lets process frame number string
						controlString = token.replace('#', '0')[len(controlValue):len(token)]+controlValue
					if (tokenType == 'S'):
						controlString = "[ \""+controlValue+"\" ]"
				elif (type(controlValue) == list):	#Lets process list types
					controlString = "[ "
					if (tokenType == 'M'):
						for element1 in controlValue:
							for element2 in element1: controlString += str(element2)+" "
					elif (tokenType == 'I' or  tokenType == 'F'):
						for element in controlValue: controlString += str((float(element)*rangeMulti)+rangeAdder)+" "
					elif (tokenType == 'P' or tokenType == 'N' or tokenType == 'V' or tokenType == 'C' or  tokenType == 'H'):
						for element in controlValue: controlString += str(element)+" "
					elif (tokenType == 'S'):
						for element in controlValue: controlString += "\""+element+"\" "
					else:
						for element in controlValue: controlString += "\"\" "
					controlString += "]"
				else:					#Lets processes whatever where left with
					controlValue = (float(controlValue)*rangeMulti)+rangeAdder #Lets adjust values range based on user token parameters
					if (tokenType == 'I'):
						if (token == "LightID"):	controlString = str(int(controlValue)) #For integer as command
						else:				controlString = "[ "+str(int(controlValue))+" ]" #For integer as parameter
					elif (tokenType == 'F'): controlString	= "[ "+str(float(controlValue))+" ]" #For float
			if(controlValue != 'SKIP'):			#If we are not skipping then write token (used to give multiple objects a chance to be valid!)
				if(controlString == "\"Token Error\""):  ErrorPopup("Incorrect syntax for token <"+original+"> in fragment "+fragmentName) #Show token error if there was one
				Source = Source.replace('<'+original+'>', controlString) #Now at last, lets insert the control value over the token
	if (Source and not RibComments and Source.count('#')):		Source = Source[0:Source.find('#')].rstrip() #Strip comments at end of line if using no comments
	return Source


#### Interprete any tokens for custom code fragment
def ParseFragment(Scene, Object, FragmentName, TabLevel = 0):
	global RibComments
	fragment = []
	if (FragmentName):						#Dont process if theres no name
		text = [Text for Text in Blender.Text.Get() if Text and Text.name == FragmentName] #Try and get FragmentName text
		if (text):						#If no text by that name then do nothing
			for line in text[0].asLines():			#Process text line by line
				if (line and (RibComments or line.rstrip()[0] != '#')): #Do not process token line comments if not doing comments in export
					fragment.append(CreateTabs(TabLevel)+ParseTokens(Scene, Object, line, FragmentName)+"\n") #Processes any tokens in text
	return fragment


#### Passes parameters to function pointer to generate RIB code that is either passed straight through or wrapped in motion block through blurLength frames according to useBlur state
def MotionBlock(Scene, functionPointer, functionParam1 = "", functionParam2 = "", functionParam3 = "", useBlur = False, blurLength = 1, tabLevel = 0):
	motionCode					= []
	if (functionPointer):						#If we cant generate code then return blank
		beginCode				= "MotionBegin [ "
		startFrame				= Scene.render.currentFrame() #Get current frame so we can reset later
		blurSegments				= 0		#Keep track of how many valid blur code segments are created
		if (useBlur):				blurFrame = blurLength
		else:					blurFrame = 1
		while blurFrame > 0:					#Cycle through the number of frames specified adjusting the render frame accordingly
			if (startFrame-blurFrame+1 > 0):Scene.render.currentFrame(startFrame-blurFrame+1) #Set frame back to blur length
			else:				Scene.render.currentFrame(1) #If blurLength is before first frame just make first frame
			functionReturn			= functionPointer(functionParam1, functionParam2, functionParam3) #Create code
			if (functionReturn == 'NORIB'):	return functionReturn #If an error was returned then pass it straight through
			elif (functionReturn):
				blurSegments = blurSegments+1
				motionCode.extend(functionReturn)
			if (useBlur): print CreateTabs(tabLevel)+"- Motion blur pass "+str((blurLength-blurFrame)+1)+" of "+str(blurLength)
			blurFrame = blurFrame-1				#Update frame
		if (blurSegments > 1 and useBlur):			#If we are blurring and we have any code then assemble a motion block
			for blurIndex in range(blurSegments): 		beginCode = beginCode+str(float(blurIndex)/float(blurSegments-1))+" "
			motionCode = AddTabs(motionCode, 1)		#Tab motion block body
			motionCode.insert(0, beginCode+"]\n")		#Add motion block begin
			motionCode.append("MotionEnd\n")		#Add motion block end
		Scene.render.currentFrame(startFrame)			#Reset frame to were we started
	return motionCode


#### Generate RIB code for material opacity
def RibifyOpacity(Material, Dummy1 = False, Dummy2 = False):
	opacity = []
	if (Material): opacity = ["Opacity [ "+str(Material.alpha)+" "+str(Material.alpha)+" "+str(Material.alpha)+" ]\n"]
	return opacity


#### Generate RIB code for material color
def RibifyColor(Material, Dummy1 = False, Dummy2 = False):
	color = []
	if (Material): color = ["Color [ "+str(Material.rgbCol[0])+" "+str(Material.rgbCol[1])+" "+str(Material.rgbCol[2])+" ]\n"]
	return color


#### Generate RIB code for light groups for passed material as a collection of RiIlluminate on and offs for all lights in LightList
def RibifyLightgroup(Material, TabLevel = 0):
	global lightList, RibComments
	lightgroupCode = []
	if (Material and Material.lightGroup):
		if (RibComments): lightgroupCode.append("##Light Group Illuminates\n")
		for index, light in enumerate(lightList):
			if (light[3]):					#Only process light if it is used in this scene
				if ([True for GrLight in Material.lightGroup.objects if GrLight == light[0]]): lightgroupCode.append(CreateTabs(TabLevel)+"Illuminate "+str(index+1)+" 1\n")
				else: lightgroupCode.append(CreateTabs(TabLevel)+"Illuminate "+str(index+1)+" 0\n")
	return lightgroupCode


#### Returns token interpreted RIB code for shader code in TextName
def RibifyShader(Scene, Material, TextName):
	global RibComments
	Shader = []
	if (TextName):
		oldRibComments	= RibComments
		RibComments	= False					#Automatically strip comments from shaders since some compilers don't like them!
		Shader = ParseFragment(Scene, Material, TextName)
		RibComments	= oldRibComments
	return Shader


#### Generate RIB code for poly, mesh, clouds and sds, separating elements by passed material index: matIndices = [materialIndex, Udirection, Vdirection]
def RibifyMesh(Object, matIndices, material = ""):
	global killExport, ButtonData, RibNormals, RibVertexUVs, RibVertexCols, VertexNormals
	geoCode		= []
	sdsObject	= False						#Track if object is using sds mod
	for modifier in Object.modifiers:				#Cycle through object modifiers to determine if this is an sds object
		if (modifier.type == Modifier.Types.SUBSURF):
			sdsObject = True
	mesh = Blender.Mesh.New()					#Create new object for render
	mesh.getFromObject(Object, 0, 1)				#Extract display ready mesh for render
	npolyCode	= []
	nvertCode	= []
	vertsCode 	= []
	normalCode	= []
	uvCode		= []
	colorCode	= []
	sdsTagCode	= []
	sdsTagNint	= []
	sdsTagNfloat1	= []
	sdsTagNfloat2	= []
	allSmooth	= True
	allFlat		= True
	delFaces	= False
	
	if (mesh.faces):						#Only process mesh if it has faces
		if (material):
			halo = material.mode&Material.Modes.HALO
		else:	halo	= False
		
		if (matIndices[0] == -1):
			allSmooth = True
			allFlat = False
		elif (matIndices[0] == -2):
			allSmooth = False
			allFlat = True
		else:
			mesh.sel	= False				#Make sure nothing is selected on mesh
			for face in mesh.faces:				#Isolate faces that are using same material as passed
				if (face.mat == matIndices[0]):
					face.sel		= True
					if (face.smooth):	allFlat	= False
					else:			allSmooth = False
				else: delFaces			= True
			if (delFaces):
				mesh.faces.delete(1, [face for face in mesh.faces if not face.sel]) #Remove any faces and edges that are not using passed material
				mesh.verts.delete([vert for vert in mesh.verts if not vert.sel]) #Remove any vertices that are not using passed material
		
		for vert in mesh.verts:					#Cycle through vertices and generate code
			vertsCode.extend([str(vert.co[0])+" ", str(vert.co[1])+" ", str(vert.co[2])+" "])
			if (VertexNormals): normalCode.extend([str(vert.no[0])+" ", str(vert.no[1])+" ", str(vert.no[2])+" "])
		
		if (vertsCode):						#Only process faces if there are verts
			if (not halo):					#Only process faces if this is not a halo
				for face in mesh.faces:			#Cycle through meshes faces
					while QTest():			#Cycle through events looking for an esc
						if (ESCKEY in QRead()): #If user escaped
							killExport = True
							return []
					faceSides = len(face)
					if ((faceSides == 3 or faceSides == 4) and len(face.verts) < 5):
						npolyCode.append(str(faceSides)+" ")
						nvertCode.extend([str(face.v[0].index)+" ", str(face.v[1].index)+" ", str(face.v[2].index)+" "])
						if (faceSides == 4): nvertCode.append(str(face.v[3].index)+" ")
						if (not VertexNormals):	#If this is supposed to be vetex type then no color or uv
							if (mesh.faceUV): #Process face UV if there are any
								for uvIndex in range(faceSides): #Cycle through uv coordinates
									if (matIndices[1]):	uvCode.append(str(1.0-face.uv[uvIndex][0])+" ")	#If flipping U then...
									else:			uvCode.append(str(face.uv[uvIndex][0])+" ")	#Otherwise...
									if (matIndices[2]):	uvCode.append(str(1.0-face.uv[uvIndex][1])+" ")	#If flipping V then...
									else:			uvCode.append(str(face.uv[uvIndex][1])+" ")	#Otherwise...
							if (mesh.vertexColors):	#Process faces vertex colors if there are any
								colorCode.extend([str(face.col[0][0]/256.0)+" ", str(face.col[0][1]/256.0)+" ", str(face.col[0][2]/256.0)+" ", str(face.col[1][0]/256.0)+" ", str(face.col[1][1]/256.0)+" ", str(face.col[1][2]/256.0)+" ", str(face.col[2][0]/256.0)+" ", str(face.col[2][1]/256.0)+" ", str(face.col[2][2]/256.0)+" "])
								if (faceSides == 4): colorCode.extend([str(face.col[3][0]/256.0)+" ", str(face.col[3][1]/256.0)+" ", str(face.col[3][2]/256.0)+" "])
							if ((sdsObject and not allSmooth) or (not sdsObject and not allFlat)): #Process face normals if renderman primitive defaults wont work
								if (face.smooth):
									normalCode.extend([str(face.v[0].no[0])+" ", str(face.v[0].no[1])+" ", str(face.v[0].no[2])+" ", str(face.v[1].no[0])+" ", str(face.v[1].no[1])+" ", str(face.v[1].no[2])+" ", str(face.v[2].no[0])+" ", str(face.v[2].no[1])+" ", str(face.v[2].no[2])+" "])
									if (faceSides == 4): normalCode.extend([str(face.v[3].no[0])+" ", str(face.v[3].no[1])+" ", str(face.v[3].no[2])+" "])
								else:
									normalCode.extend([str(face.no[0])+" ", str(face.no[1])+" ", str(face.no[2])+" ", str(face.no[0])+" ", str(face.no[1])+" ", str(face.no[2])+" ", str(face.no[0])+" ", str(face.no[1])+" ", str(face.no[2])+" "])
									if (faceSides == 4): normalCode.extend([str(face.no[0])+" ", str(face.no[1])+" ", str(face.no[2])+" "])
			
				if (sdsObject):				#If this is a sds process edge creases
					for edge in mesh.edges:
						if (edge.crease > 0):	#Only process edges that have crease data
							sdsTagCode.append(" \"crease\"")
							sdsTagNint.append(" 2 1")
							sdsTagNfloat1.extend([" "+str(edge.v1.index), " "+str(edge.v2.index)])
							crease = (edge.crease/255.0)*5.5 #Calculate crease up to 5.5 (looks the same as blenders up to that point)
							if (crease > 5.0): crease = crease+((crease-5.0)*6) #After 5.0 increase sharpening rate to match blenders rate
							sdsTagNfloat2.append(" "+str(crease)) #Not quite using fully square edge (10.0) but seems to match blenders creasing
					geoCode.append("SubdivisionMesh \"catmull-clark\"\n")
				else:	geoCode.append("PointsPolygons\n")
			else:						#If this is a halo then make a point cloud
				geoCode.append("Points\n")
				sdsObject = False
			
			if (npolyCode):		geoCode.append("\t[ "+"".join(npolyCode)+"]\n")
			if (nvertCode):		geoCode.append("\t[ "+"".join(nvertCode)+"]\n")
			if (sdsObject):		geoCode.append("\t[ \"interpolateboundary\""+"".join(sdsTagCode)+" ] [ 0 0"+"".join(sdsTagNint)+" ] ["+"".join(sdsTagNfloat1)+" ] ["+"".join(sdsTagNfloat2)+" ]\n")
			if (vertsCode):		geoCode.append("\t\"P\" [ "+"".join(vertsCode)+"]\n")
			if (normalCode and RibNormals):		geoCode.append("\t\"N\" [ "+"".join(normalCode)+"]\n")
			if (colorCode and RibVertexCols):	geoCode.append("\t\"Cs\" [ "+"".join(colorCode)+"]\n")
			if (uvCode and RibVertexUVs):		geoCode.append("\t\"st\" [ "+"".join(uvCode)+"]\n")
			if (halo):		geoCode.append("\t\"constantwidth\" [ "+str(material.haloSize)+" ]\n")
	
	mesh.verts = None						#Lets clean up	
	del(mesh)
	if (not geoCode): geoCode = 'NORIB'
	return geoCode


#### Generate RIB code for curves and point clouds from particles
def RibifyParticles(Object, materialIndex, material = ""):
	global killExport
	partCode	= []
	vectsCode	= []
	nvectCode	= []
	widthCode	= []
	if (material):							#If theres a material get strand start and end thickness
		width	= material.haloSize
		tip	= width*(material.add)
	else:								#If theres no material then create strand thickness defaults
		width	= 0.02
		tip	= 0.0
	localMatrix	= Object.getMatrix("worldspace").copy().invert() #Get a copy of this objects world matrix and make it local
	particleData	= [effect for effect in Object.effects if effect.dispMat-1 == materialIndex] #Get all particles with current material
	
	if (particleData and width):					#Are there any particles to process and are they visible
		for effect in particleData:
			particleVects	= effect.getParticlesLoc()
			if (particleVects):
				maxVect		= len(max(particleVects)) #Whats the max static length
				numParticles	= len(particleVects)
				percent		= 0
				if (maxVect < 2):	print "\t\t\tProcessing "+str(numParticles)+" particle points:"
				elif (maxVect == 2): 	print "\t\t\tProcessing "+str(numParticles)+" particle vectors:"
				else:			print "\t\t\tProcessing "+str(numParticles)+" particle strands:"
				print "\t\t\t\t- 0%"
			for partCount, vects in enumerate(particleVects):
				percent		= ((partCount+1.0)/numParticles)*100
				if (not percent%10): print "\t\t\t\t- "+str(int(percent))+"%" #Show percent in 10 increments
				while QTest():				#Cycle through events looking for an esc
					if (ESCKEY in QRead()):	#If user escaped
						killExport = True
						return []
				if (len(vects) > 1):
					if (type(vects) == Blender.Types.vectorType): #If particles are points only
						vects			= vects*localMatrix #Transform vectors into objects local space
						vectsCode.extend([str(vects[0])+" ", str(vects[1])+" ", str(vects[2])+" "])
					elif (maxVect == 2):		#If max static length is 2 points then use this optimization
						vect1			= vects[0]*localMatrix
						vect2			= vects[1]*localMatrix
						nvectCode.append("2 ")
						vectsCode.extend([str(vect1[0])+" ", str(vect1[1])+" ", str(vect1[2])+" ", str(vect2[0])+" ", str(vect2[1])+" ", str(vect2[2])+" "])
						if (width != tip):	widthCode.extend([str(width)+" ", str(tip)+" "])
					else:				#Otherwise particles are static curves
						lastPoint	= len(vects)-1
						for index, point in enumerate(vects): #Cycle through all the points in this strand
							remainder	= index%3 #The remainder of points not within beziers point requirements
							if (remainder and index == lastPoint): addCount = (3-remainder)+1 #How many times to subivide last segment for proper bezier
							else: addCount	= 1
							vectsCount	= lastPoint+addCount
							if (width != tip and (not remainder or index == lastPoint)): #Calculate varying widths on bezier segments breaks only when not using constant width
								widthCode.append(str(width-(((width-tip)/lastPoint)*index))+" ")
							point		= point*localMatrix #Transform vectors into objects local space
							for count in range(addCount): vectsCode.extend([str(point[0])+" ", str(point[1])+" ", str(point[2])+" "]) #Add point or add multiple points to complete a bezier curve
						nvectCode.append(str(vectsCount)+" ")
		if (vectsCode):						#Only draw code if there were particles
			if (not nvectCode):	partCode.append("Points\n")
			elif (maxVect == 2):	partCode.append("Curves \"linear\"\n")
			else:			partCode.append("Curves \"cubic\"\n")
			if (nvectCode): 	partCode.append("\t[ "+"".join(nvectCode)+"] \"nonperiodic\"\n")
			partCode.append("\t\"P\" [ "+"".join(vectsCode)+"]\n")
			if (widthCode):		partCode.append("\t\"width\" [ "+"".join(widthCode)+"]\n")
			else:			partCode.append("\t\"constantwidth\" [ "+str(width)+" ]\n")
	if (not partCode): partCode = 'NORIB'
	return partCode


#### Generate RIB code for curves
def RibifyCurve(Object, materialIndex, material = ""):
	global killExport, RibNormals
	curveCode		= []
	vectsCode		= []
	nvectCode		= []
	normalCode		= []
	widthCode		= []
	ribbonWidth		= 0.0
	curveData		= Object.getData(False, True)
	if (material):							#If theres a material get curve start and end thickness
		width		= material.haloSize
		tip		= width*(material.add)
	else:								#If theres no material then set to not create curve
		width		= 0.0
		tip		= 0.0
	
	if (curveData):							#Are there any curves to process
		ribbonWidth	= curveData.getExt1()*2			#Get curve width (if zero then material strand width is used)
		if (ribbonWidth): width = ribbonWidth			#If curve has width set the ribbon width to curve width
		if ([True for curve in curveData if curve.isCyclic()]):	cyclic	= "periodic" #If any curves are cyclic then all curves in this object are cyclic
		else:	cyclic	= "nonperiodic"
		
		if (width):						#Are the curves visible
			for Curve in curveData:
				while QTest():				#Cycle through events looking for an esc
					if (ESCKEY in QRead()):	#If user escaped
						killExport = True
						return []
				if (Curve.getType() == 1 and Curve.getMatIndex() == materialIndex): #Only process bezier curves and curves with passed material index
					for nodeIndex, node in enumerate(Curve): #Cycle through all bezier nodes
						for vectIndex, vect in enumerate(node.vec): #Cycle through all control points in bezier curve
							if (nodeIndex+vectIndex != 0): #Dont use first control point
								if (cyclic == "periodic" or nodeIndex+vectIndex != len(Curve)+1): vectsCode.extend([str(vect[0])+" ", str(vect[1])+" ", str(vect[2])+" "]) #Add points into code list (only use last control point if curves are cyclic)
						if (ribbonWidth):	#Apply custom widths and normals if using a ribbon
							if (node.radius):	widthCode.append(str(width*node.radius)+" ")  #If theres ribbon width then apply width for this point and adjust it by radius
							else:			widthCode.append(str(width)+" ")
							normal	= Mathutils.TriangleNormal(Mathutils.Vector(node.vec[0]), Mathutils.Vector(node.vec[1]), Mathutils.Vector(node.vec[1])+Mathutils.Vector([0.0, 0.0, 1.0])) #Find normal by adding a point with higher z and finding normal
							normal	= normal*RotationMatrix(180.0-node.tilt*51.42857, 3, "r", Mathutils.Vector(node.vec[0])-Mathutils.Vector(node.vec[1])) #Rotate normal by amount in nodes tilt value
							if (str(normal[0]).lower().find('nan')>=0): normal[0] = 0.0
							if (str(normal[1]).lower().find('nan')>=0): normal[1] = 0.0
							if (str(normal[2]).lower().find('nan')>=0): normal[2] = 0.0
							normalCode.extend([str(normal[0])+" ", str(normal[1])+" ", str(normal[2])+" "])
						elif (width != tip):	#Otherwise apply material base and tip widths if they are set
							widthCode.append(str(width-(((width-tip)/(len(Curve)-1))*nodeIndex))+" ")
					if (cyclic == "periodic"):	#If curves are cyclic
						nvectCode.append(str(len(Curve)*3)+" ")
						vectsCode.extend([str(Curve[0].vec[0][0])+" ", str(Curve[0].vec[0][1])+" ", str(Curve[0].vec[0][2])+" "]) #Add first control point to end of point list for cyclic curve
					else:				#If not...
						nvectCode.append(str((len(Curve)*3)-2)+" ")
				elif (Curve.getMatIndex() == materialIndex):
					print "Only bezier curves supported in RenderMan, skipping this curve!"
			if (vectsCode):					#Only draw code if there were control points
				curveCode.append("Curves \"cubic\"\n")
				curveCode.append("\t[ "+"".join(nvectCode)+"] \""+cyclic+"\"\n")
				curveCode.append("\t\"P\" [ "+"".join(vectsCode)+"]\n")
				if (widthCode):		curveCode.append("\t\"width\" [ "+"".join(widthCode)+"]\n")
				else:			curveCode.append("\t\"constantwidth\" [ "+str(width)+" ]\n")
				if (normalCode and RibNormals):	curveCode.append("\t\"N\" [ "+"".join(normalCode)+"]\n")
	if (not curveCode): curveCode = 'NORIB'
	return curveCode


#### Generate RIB code for NURBS surfaces
def RibifySurface(Object, materialIndex, surfData):
	global killExport
	surfCode		= []
	vectsCode		= []
	if (surfData and materialIndex == 0):				#Does this surface have data (can only use the first material since theres no way to tell what surface uses what material at the moment)
		try:							#Try to access NurvSurf data if cant then assume this is not a surface and return nothing
			if (surfData.cyclicU or surfData.cyclicV): print "Only non cyclic patches available under RiNuPatch, ignoring cyclic tag!"
			nu		= surfData.pointsU
			nv		= surfData.pointsV
			uorder		= surfData.orderU
			vorder		= surfData.orderV
			uknotCount	= nu+uorder
			vknotCount	= nv+vorder
		except:
			print "Only 1x1 or greater NURBS surfaces allowed, skipping this patch!"
			return []
		if (surfData.flagU):	uknots = ["0.0 " for knot in range(0, uorder)]+[str(float(knot)/(uknotCount-(uorder*2)+1))+" " for knot in range(1, uknotCount-(uorder*2)+1)]+["1.0 " for knot in range(uknotCount-uorder, uknotCount)]
		else:				uknots	= [str(float(knot)/uknotCount)+" " for knot in range(0, uknotCount)]
		if (surfData.flagV):	vknots = ["0.0 " for knot in range(0, vorder)]+[str(float(knot)/(vknotCount-(vorder*2)+1))+" " for knot in range(1, vknotCount-(vorder*2)+1)]+["1.0 " for knot in range(vknotCount-vorder, vknotCount)]
		else:				vknots	= [str(float(knot)/vknotCount)+" " for knot in range(0, vknotCount)]
		while QTest():						#Cycle through events looking for an esc
			if (ESCKEY in QRead()):			#If user escaped
				killExport = True
				return []
		for vect in surfData:
			vectsCode.extend([str(vect[0]*vect[3])+" ", str(vect[1]*vect[3])+" ", str(vect[2]*vect[3])+" ", str(vect[3])+" "])
		if (vectsCode):						#Only draw code if there were control points
			surfCode.append("NuPatch\n")
			surfCode.append("\t"+str(nu)+" "+str(uorder)+" [ "+"".join(uknots)+"] 0.0 1.0\n")
			surfCode.append("\t"+str(nv)+" "+str(vorder)+" [ "+"".join(vknots)+"] 0.0 1.0\n")
			surfCode.append("\t\"Pw\" [ "+"".join(vectsCode)+"]\n")
	if (not surfCode): surfCode = 'NORIB'
	return surfCode


#### Generate RIB code for material blocks
def RibifyMaterial(Scene, Object, Material):
	global ButtonData, lightDupliIndex, lightAreaIndex
	materialCode		= []
	if (Material):
		surfCode	= []
		isGroup		= Material.lightGroup
		RIBset		= GetProperty(Scene, "MOSAICRIBset", Material.name+TypeString(Material), "", "", "DEFAULT") #Get which RIBset to use for this object in current scene (if none then use default)
		Mblur		= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_MBLUR][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_MBLUR][BUT_DEFAULT])
		Mframes		= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_FRAMES][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_FRAMES][BUT_DEFAULT])
		isBeginCode	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_BEGIN_CODE][BUT_PROP])
		isEndCode	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_END_CODE][BUT_PROP])
		isSurf		= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_SURF][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_SURF][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_SURF][BUT_DEFAULT]])
		isDisp		= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_DISP][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_DISP][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_DISP][BUT_DEFAULT]])
		isINvol		= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_INT_VOL][BUT_PROP])
		isEXvol		= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_EXT_VOL][BUT_PROP])
		isArea		= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_AREA][BUT_PROP])
		isVisTrans	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_TRANS][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_TRANS][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_TRANS][BUT_DEFAULT]])
		isVisCamera	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_CAMERA][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_CAMERA][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_CAMERA][BUT_DEFAULT]])
		isVisSpec	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_SPECULAR][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_SPECULAR][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_SPECULAR][BUT_DEFAULT]])
		isVisDiffuse	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_DIFFUSE][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_DIFFUSE][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_DIFFUSE][BUT_DEFAULT]])
		isVisPhoton	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_PHOTON][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_PHOTON][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_PHOTON][BUT_DEFAULT]])
		isShadeTrans	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_TRANS][BUT_PROP])
		isShadeCamera	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_CAMERA][BUT_PROP])
		isShadeSpecular	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_SPECULAR][BUT_PROP])
		isShadeDiffuse	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_DIFFUSE][BUT_PROP])
		isShadeModel	= GetProperty(Material, "MOSAICData", RIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_SHADINGMODEL][BUT_PROP])
		if (isVisTrans): materialCode.append(isVisTrans)
		if (isVisSpec): materialCode.append(isVisSpec)
		if (isVisCamera): materialCode.append(isVisCamera)
		if (isVisDiffuse): materialCode.append(isVisDiffuse)
		if (isVisPhoton): materialCode.append(isVisPhoton)
		if (isShadeTrans): materialCode.append(isShadeTrans)
		if (isShadeCamera): materialCode.append(isShadeCamera)
		if (isShadeSpecular): materialCode.append(isShadeSpecular)
		if (isShadeDiffuse): materialCode.append(isShadeDiffuse)
		if (isShadeModel): materialCode.append(isShadeModel)
		if (isBeginCode and isBeginCode != 'NONE'):
			materialCode.extend(ParseFragment(Scene, Material, isBeginCode)) #Parse custom code
		if (isGroup): materialCode.extend(RibifyLightgroup(Material)) #Create RiIlluminate based on any assigned lightgroups
		if (isSurf and isSurf != 'NONE'):
			print "\t\t\t- Surface Shader ("+isSurf+")"
			materialCode.extend(MotionBlock(Scene, RibifyShader, Scene, Material, isSurf, Mblur, Mframes, 3)) #Surface shader
		else: materialCode.append("#No surface shader\n")
		if (isDisp and isDisp != 'NONE'):
			print "\t\t\t- Displacement Shader ("+isDisp+")"
			materialCode.extend(MotionBlock(Scene, RibifyShader, Scene, Material, isDisp, Mblur, Mframes, 3)) #Displacement shader
		else: materialCode.append("#No displacement shader\n")
		if (isINvol and isINvol != 'NONE'):
			print "\t\t\t- Interior Volume Shader ("+isINvol+")"
			materialCode.extend(MotionBlock(Scene, RibifyShader, Scene, Material, isINvol, Mblur, Mframes, 3)) #Interior volume shader
		if (isEXvol and isEXvol != 'NONE'):
			print "\t\t\t- Exterior Volume Shader ("+isEXvol+")"
			materialCode.extend(MotionBlock(Scene, RibifyShader, Scene, Material, isEXvol, Mblur, Mframes, 3)) #Exterior volume shader
		if (isArea and isArea != 'NONE'):
			lightDupliIndex	= 0
			lightAreaIndex	= 0
			print "\t\t\t- Area Light Shader ("+isArea+")"
			materialCode.extend(MotionBlock(Scene, RibifyShader, Scene, [Object, Material], isArea, Mblur, Mframes, 3)) #Arealight shader (uses object instead of material for token parse so proper ID will pass for <LightID_I>)
		if (isEndCode and isEndCode != 'NONE'):
			materialCode.extend(ParseFragment(Scene, Material, isEndCode)) #Parse custom code
	return materialCode


#### Returns a RiTransform matrix for object or a RiConcatTransform matrix if Object and Matrix are supplied (Object being parent and Matrix being world space child matrix).
#### If no Object or Matrix is provided then make a 3D view matrix from current active Blender window. If View is set convert whatever matrix combination is given into a view matrix
def RibifyTransform(Object, Matrix = [], View = False):
	if (Object and Matrix != [] and Matrix != Mathutils.Matrix()):	#If supplying both Object and Matrix then perform concate
		if (type(Matrix) == int):
			if (Matrix < len(Object.DupObjects)):	Matrix = Object.DupObjects[Matrix][1] #If Matrix is an integer then use it as an index into a dupli matrix
			else:					return []
		m = (Matrix.copy()*Object.getMatrix().copy().invert())*Mathutils.Matrix() #Get concate matrix with Object being parent and Matrix being world space child (handy for dupli matrix blur)
	elif (not Object and Matrix != []):				#If no Object and Matrix straight copy Matrix
		if (type(Matrix) == int): Matrix = Mathutils.Matrix()	#If Matrix is an integer and there was no Object the use a unity matrix
		m = Matrix.copy()
	elif (not Object and not Matrix):				#If theres no Object and no Matrix then use the view matrix if theres no view matrix then create an identity matrix
		m = Blender.Window.GetViewMatrix()
		if (not m): m = Mathutils.Matrix()
	else:								#If just object then get its matrix
		m = Object.getMatrix().copy()
	if (View):							#Adjust up for camera view
		if (Object or Matrix):					#Rebuild transform so that scale can only be 1.0 and invert if object perspective
			if (Object and Object.getType == "Camera"):	#If a camera then invert coordinates and pass through
				m.invert()
			else:						#Otherwise object perspective then lock scale to 1 and invert and pass though
				s = ScaleMatrix(1.0,4)
				l = TranslationMatrix(m.translationPart())
				r = m.toQuat().toMatrix().resize4x4()
				m = (r*s*l).invert()
		m *= Mathutils.Matrix([1,0,0,0],[0,1,0,0],[0,0,-1,0],[0,0,0,1]) #Reverse Z to make left handed coordinates
	if (Matrix and Object):
		header	= "ConcatTransform"
		space	= "                  "
	else:
		header	= "Transform"
		space	= "            "
	return	[header+" [ "+str(m[0][0])+" "+str(m[0][1])+" "+str(m[0][2])+" "+str(m[0][3])+"\n",
		 space+str(m[1][0])+" "+str(m[1][1])+" "+str(m[1][2])+" "+str(m[1][3])+"\n",
		 space+str(m[2][0])+" "+str(m[2][1])+" "+str(m[2][2])+" "+str(m[2][3])+"\n",
		 space+str(m[3][0])+" "+str(m[3][1])+" "+str(m[3][2])+" "+str(m[3][3])+" ]\n"]


#### Generate a bounding box for given object, also calculate bounds to contain minimum and maximum geometry movement within MBlur frames range and also include particles or curves if using a Delayed Read archive.
def RibifyBounds(Scene, Object):
	xMin		= None
	xMax		= None
	yMin		= None
	yMax		= None
	zMin		= None
	zMax		= None
	RIBset		= GetProperty(Scene, "MOSAICRIBset", Object.name+TypeString(Object), "", "", "DEFAULT") #Get which RIBset to use for this object in current scene (if none then use default)
	archiveTYPE	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_PROP])
	startFrame	= Scene.render.currentFrame()			#Get current frame so we can reset later
	localMatrix	= Object.getMatrix().copy().invert()
	if (GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_MBLUR][BUT_PROP])|GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_MBLUR][BUT_PROP])):
		blurFrame = max([GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_FRAMES][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_FRAMES][BUT_DEFAULT]), GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_FRAMES][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_FRAMES][BUT_DEFAULT])])
	else: blurFrame = 1
	while blurFrame > 0:						#Cycle through the number of frames specified adjusting the render frame accordingly
		if (startFrame-blurFrame+1 > 0): Scene.render.currentFrame(startFrame-blurFrame+1) #Set frame back to blur length
		else:		Scene.render.currentFrame(1)		#If blurLength is before first frame just make first frame
		blurFrame	= blurFrame-1				#Update frame
		extents = [vector*localMatrix for vector in Object.boundingBox] #Get each bounds vector and transform into local space
		for effect in Object.effects:
			partLoc = effect.getParticlesLoc()
			if (partLoc):
				if (type(partLoc[0]) == Blender.Types.vectorType):
					extents.extend(partLoc)	#Get each vector in particle and transform into local space
				else:
					for curve in partLoc:
						for vect in curve:
							extents.append(vect*localMatrix) #Get each vector in curve and transform into local space
		if (xMin != None): extents.extend([[xMin, yMin, zMin], [xMax, yMax, zMax]]) #Also check last min and max values found if doing animation or blur		
		xMin		= min(map(lambda x: x[0], extents))
		xMax		= max(map(lambda x: x[0], extents))
		yMin		= min(map(lambda y: y[1], extents))
		yMax		= max(map(lambda y: y[1], extents))
		zMin		= min(map(lambda z: z[2], extents))
		zMax		= max(map(lambda z: z[2], extents))
		
	Scene.render.currentFrame(startFrame)				#Reset frame to were we started
	return [xMin, xMax, yMin, yMax, zMin, zMax] #Create min and max bounds


#### Returns a transparent blue box representing the passed bounding box as a text list
def ShowBounds(boundB = [-1, 1, -1, 1 , -1, 1]):
	Code = ["AttributeBegin\n"]
	Code.append("\tOpacity [ 0.5 0.5 0.5 ]\n")
	Code.append("\tColor [ 0.0 0.0 1.0 ]\n")
	Code.append("\tPointsPolygons [ 4 4 4 4 4 4 ] [ 0 3 2 1 1 2 6 5 5 6 7 4 4 7 3 0 2 3 7 6 0 4 5 1 ] \"P\" [ "+str(boundB[0])+" "+str(boundB[2])+" "+str(boundB[5])+" "+str(boundB[0])+" "+str(boundB[2])+" "+str(boundB[4])+" "+str(boundB[0])+" "+str(boundB[3])+" "+str(boundB[4])+" "+str(boundB[0])+" "+str(boundB[3])+" "+str(boundB[5])+" "+str(boundB[1])+" "+str(boundB[2])+" "+str(boundB[5])+" "+str(boundB[1])+" "+str(boundB[2])+" "+str(boundB[4])+" "+str(boundB[1])+" "+str(boundB[3])+" "+str(boundB[4])+" "+str(boundB[1])+" "+str(boundB[3])+" "+str(boundB[5])+" ]\n")
	Code.append("AttributeEnd\n")
	return Code


#### Returns the [x,y,z] position of individual light in arealight's lightarray at given areaIndex around a [0,0,0] origin
def LightarrayPosition(Lamp, areaIndex = 0):
	areaPos	= [0, 0, 0]
	if (Lamp and Lamp.getType() == "Lamp"):				#Is this a lamp?
		lampData = Lamp.getData()
		if (lampData and lampData.getType() == 4):		#Is this an area light?
			areaSamplesX		= lampData.getRaySamplesX()
			areaSamplesY		= lampData.getRaySamplesY()
			areaSizeX		= lampData.getAreaSizeX()
			areaSizeY		= lampData.getAreaSizeY()
			areaXY			= divmod(areaIndex, areaSamplesX)
			if (areaSamplesX > 1):	x = (areaSizeX/(areaSamplesX-1))*areaXY[1]-areaSizeX/2
			else:			x = 0
			if (areaSamplesY > 1):	y = (areaSizeY/(areaSamplesY-1))*areaXY[0]-areaSizeY/2
			else:			y = 0
			areaPos			= [x, y, 0]
	return areaPos


#### Generate rib code for the passed Object
def RibifyObject(Scene, Object, Frame, TabLevel = 0, isCamera = False, RIBsetBypass = ""):
	global ButtonData, killExport, RibComments, lightDupliIndex, lightAreaIndex, RibScreen, RibClipping, RibProjection, RibColor, RibOpacity, RibBound, RibSides, RibVertexCols, RibNormals, RibVertexUVs, VertexNormals
	if (RIBsetBypass):		scRIBset = RIBsetBypass
	else:				scRIBset = GetProperty(Scene, "MOSAICRIBset", Scene.name+TypeString(Scene), "", "", "DEFAULT") #Get which RIBset to use in current scene (if none then use default)
	if (scRIBset == "DEFAULT"):	scRIBindex = "0"
	else:				scRIBindex = str([k for k, v in Scene.properties["MOSAICData"].iteritems()].index(scRIBset))
	objectCode	= []
	dupliIndex	= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_DUPLI_INDEX][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_DUPLI_INDEX][BUT_DEFAULT])
	areaIndex	= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_AREA_INDEX][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_AREA_INDEX][BUT_DEFAULT])
	if (Object):
		objectType = Object.getType()
		RIBset = GetProperty(Scene, "MOSAICRIBset", Object.name+TypeString(Object), "", "", "DEFAULT") #Get which RIBset to use for this object in current scene (if none then use default)
		if (RIBset == "DEFAULT"):	RIBindex = "0"
		else:				RIBindex = str([k for k, v in Object.properties["MOSAICData"].iteritems()].index(RIBset))
	else:
		objectType = ""
		RIBset = "DEFAULT"
		RIBindex = "0"
	
	#### Camera export code
	if (isCamera):							#Handle object as a camera
		#Figure for custom aspect ratios
		Xres	= Scene.render.sizeX
		Yres	= Scene.render.sizeY
		Xratio	= Xres*(float(Scene.render.aspectX)/200)	#Image width after x aspect adjustment
		Yratio	= Yres*(float(Scene.render.aspectY)/200)	#Image height after y aspect adjustment
		if (Xratio >= Yratio):					#Figure out which side is longer to get ratio from
			aspectRatio	= Xratio/float(Yratio)
			Xaspect		= aspectRatio
			Yaspect		= 1.0
		else:
			aspectRatio	= Yratio/float(Xratio)
			Yaspect		= aspectRatio
			Xaspect		= 1.0
		#Setup universal variables
		shadingRate		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_SHADE_RATE][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_SHADE_RATE][BUT_DEFAULT])
		xSamples		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_XSAMPLES][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_XSAMPLES][BUT_DEFAULT])
		ySamples		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_YSAMPLES][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_YSAMPLES][BUT_DEFAULT])
		perspective		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_PERSPECTIVE][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_PERSPECTIVE][BUT_TITLE][ButtonData[SCENES][WIN_BUTS][SCENE_PERSPECTIVE][BUT_DEFAULT]])
		lens			= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_LENS][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_LENS][BUT_DEFAULT])
		nearClip		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_NEARCLIP][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_NEARCLIP][BUT_DEFAULT])
		farClip			= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_FARCLIP][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_FARCLIP][BUT_DEFAULT])
		useDOF			= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_ENV_DOF][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_ENV_DOF][BUT_DEFAULT])
		distDOF			= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_ENV_DIST][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_ENV_DIST][BUT_DEFAULT])
		fstopDOF		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_ENV_FSTOP][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_ENV_FSTOP][BUT_DEFAULT])
		focalDOF		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_ENV_FOCAL][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_ENV_FOCAL][BUT_DEFAULT])
		isFilter		= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_FILTER][BUT_PROP])
		xFilter			= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_XWIDTH][BUT_PROP])
		yFilter			= GetProperty(Scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_YWIDTH][BUT_PROP])
		shutterMin		= 0
		shutterMax		= 0
		offsetMatrix		= []
		cameraMatrix		= ""
		areaOffset		= []
		duplis			= []
		useBlur			= 0
		blurFrames		= 5
		isView			= True
		#Add universal code
		objectCode.append("Format "+str(Xres)+" "+str(Yres)+" 1\n")
		if (shadingRate):		objectCode.append("ShadingRate "+str(shadingRate)+"\n")
		if (xSamples and ySamples):	objectCode.append("PixelSamples "+str(xSamples)+" "+str(ySamples)+"\n")
		if (isFilter):			objectCode.append("PixelFilter \""+isFilter+"\" "+str(xFilter)+" "+str()+"\n")
		#Add object specific code
		if (objectType):
			if (objectType == "Camera"):
				print "\tExporting Camera Perspective: "+Object.name
				useBlur		= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_MBLUR][BUT_PROP], "", 0)
				blurFrames	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_FRAMES][BUT_PROP], "", 5)
				shutterMin	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_SHUT_MIN][BUT_PROP], "", ButtonData[CAMERAS][WIN_BUTS][CAM_SHUT_MIN][BUT_DEFAULT])
				shutterMax	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_SHUT_MAX][BUT_PROP], "", ButtonData[CAMERAS][WIN_BUTS][CAM_SHUT_MAX][BUT_DEFAULT])
				useDOF		= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_DOF][BUT_PROP])
				fstopDOF	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_FSTOP][BUT_PROP], "", ButtonData[CAMERAS][WIN_BUTS][CAM_FSTOP][BUT_DEFAULT])
				focalDOF	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_FOCAL][BUT_PROP], "", ButtonData[CAMERAS][WIN_BUTS][CAM_FOCAL][BUT_DEFAULT])
				distDOF		= Object.getData().dofDist
				if (perspective == "persp"):		#If scene override is not on then use camera data
					nearClip	= Object.getData().clipStart
					farClip		= Object.getData().clipEnd
					perspective	= Object.getData().type
					if (perspective == "ortho"):	lens = Object.getData().scale
					else:				lens = Object.getData().lens
				isCameraCode	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_BEGIN_CODE][BUT_PROP])
				if (isCameraCode and isCameraCode != 'NONE'): objectCode.extend(ParseFragment(Scene, Object, isCameraCode)) #Parse custom begin code
				if (Scene.render.borderRender):		#Set border cropping region if on
					border	= Scene.render.border
					objectCode.append("CropWindow "+str(border[0])+" "+str(border[2])+" "+str(1.0-border[3])+" "+str(1.0-border[1])+"\n")		
				isImage		= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_IMAGE][BUT_PROP], "", ButtonData[CAMERAS][WIN_BUTS][CAM_IMAGE][BUT_MENU][ButtonData[CAMERAS][WIN_BUTS][CAM_IMAGE][BUT_DEFAULT]])
				if (isImage and isImage != 'NONE'):	objectCode.extend(RibifyShader(Scene, Object, isImage)) #Parse image shader
				isCameraCode	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_END_CODE][BUT_PROP])
				if (isCameraCode and isCameraCode != 'NONE'): objectCode.extend(ParseFragment(Scene, Object, isCameraCode)) #Parse custom end code
			elif (objectType == "Lamp"):
				print "\tExporting Lamp Perspective: "+Object.name
				if (perspective == "persp"):		#If scene override is not on then use lamp data
					lampData	= Object.getData()
					nearClip	= 0.1
					farClip		= lampData.getDist()
					lens		= lampData.getSpotSize()
					if (lampData.getType() == 4):	areaOffset = LightarrayPosition(Object, areaIndex) #If arealight then get offset
			else:	print "\tExporting Object Perspective: "+Object.name

			if (Object.getParent()):			duplis = Object.getParent().DupObjects
			if (duplis and dupliIndex < len(duplis)):	offsetMatrix = duplis[dupliIndex][1]
			elif (areaOffset or (perspective != "persp" and perspective != "ortho")):
				offsetMatrix = Object.mat
				#isView = False
			else:						cameraMatrix = Object
			if (areaOffset):		offsetMatrix = TranslationMatrix(Vector(areaOffset))*offsetMatrix
			if (perspective == "px"):	offsetMatrix = RotationMatrix(-90,4,"y")*TranslationMatrix(offsetMatrix.translationPart())
			elif (perspective == "nx"):	offsetMatrix = RotationMatrix(90,4,"y")*TranslationMatrix(offsetMatrix.translationPart())
			elif (perspective == "py"):	offsetMatrix = RotationMatrix(90,4,"x")*TranslationMatrix(offsetMatrix.translationPart())
			elif (perspective == "ny"):	offsetMatrix = RotationMatrix(-90,4,"x")*TranslationMatrix(offsetMatrix.translationPart())
			elif (perspective == "pz"):	offsetMatrix = RotationMatrix(0,4,"y")*TranslationMatrix(offsetMatrix.translationPart())
			elif (perspective == "nz"):	offsetMatrix = RotationMatrix(180,4,"y")*TranslationMatrix(offsetMatrix.translationPart())
		else:	print "\tExporting Active Window Perspective:"
		
		if (shutterMin or shutterMax):	objectCode.append("Shutter "+str(shutterMin)+" "+str(shutterMax)+"\n")
		if (useDOF):			objectCode.append("DepthOfField "+str(fstopDOF)+" "+str(focalDOF)+" "+str(distDOF)+"\n")
		if (RibClipping):		objectCode.append("Clipping "+str(nearClip)+" "+str(farClip)+"\n")
		if (RibProjection):
			if (perspective == "ortho"):
				objectCode.append("Projection \"orthographic\"\n")
				Xaspect = Xaspect*(lens/(aspectRatio*2.0))	#Readjust Xaspect for ScreenWindow so scaling will work
				Yaspect = Yaspect*(lens/(aspectRatio*2.0))	#Readjust Yaspect for ScreenWindow so scaling will work
			elif (perspective == "persp" and objectType == "Camera"):	objectCode.append("Projection \"perspective\" \"fov\" [ "+str(360.0*atan(16.0/lens/aspectRatio)/pi)+" ]\n")
			else: 								objectCode.append("Projection \"perspective\" \"fov\" [ "+str(lens/aspectRatio)+" ]\n")
		if (RibScreen): objectCode.append("ScreenWindow -"+str(Xaspect)+" "+str(Xaspect)+" -"+str(Yaspect)+" "+str(Yaspect)+"\n") #Set custom x y ratios
		if (Object and RibComments): objectCode.append(ParseTokens(Scene, Object, "##CameraOrientation <FROM_P> <TO_P>\n"))
		objectCode.extend(MotionBlock(Scene, RibifyTransform, cameraMatrix, offsetMatrix, isView, useBlur, blurFrames, 1))
		if (objectType):	objectCode = RibifyInstance(Object, "Archives"+sys.sep+"Cameras"+sys.sep, "CS"+str(Blender.Scene.Get().index(Scene))+"B"+RIBindex+perspective+str(dupliIndex)+str(areaIndex)+Object.name, objectCode, Frame, GetProperty(Object, "MOSAICData", RIBset, ButtonData[CAMERAS][WIN_BUTS][CAM_ARCH][BUT_PROP], "", ButtonData[CAMERAS][WIN_BUTS][CAM_ARCH][BUT_TITLE][ButtonData[CAMERAS][WIN_BUTS][CAM_ARCH][BUT_DEFAULT]]), [], TabLevel)
		else:			objectCode = AddTabs(objectCode, 1)
		return objectCode					#Return early so if this is a object camera its not rendered twice!
	
	#### Lamp export code
	elif (objectType == "Lamp"):
		isLampCode					= GetProperty(Object, "MOSAICData", RIBset, ButtonData[LIGHTS][WIN_BUTS][LIGHT_BEGIN_CODE][BUT_PROP])
		if (isLampCode and isLampCode != 'NONE'):	objectCode.extend(ParseFragment(Scene, Object, isLampCode)) #Parse custom begin code
		isLampShader					= GetProperty(Object, "MOSAICData", RIBset, ButtonData[LIGHTS][WIN_BUTS][LIGHT_SHADER][BUT_PROP], "", ButtonData[LIGHTS][WIN_BUTS][LIGHT_SHADER][BUT_MENU][ButtonData[LIGHTS][WIN_BUTS][LIGHT_SHADER][BUT_DEFAULT]])
		if (isLampShader == 'NONE'):			objectCode.append("#No light shader\n")
		else:
			instanceIndex	= 0				#Keep track of instance index
			parent		= Object.getParent()		#Find parent object
			if (parent):	duplis = parent.DupObjects	#If theres a parent see if it has duplis
			else:		duplis = [(Object, [])]		#Otherwise just use current light
			for instance, matrix in duplis:
				if (instance == Object):		#Only allow a dupli of this child light
					instanceCode = []
					lampData = instance.getData()
					lightType = lampData.getType()
					if (matrix):			instanceCode.extend(RibifyTransform(Object, matrix, False)) #If this is a dupli use its matrix
					if (lightType == 4):		samples = lampData.getRaySamplesX()*lampData.getRaySamplesY()
					else:				samples = 1
					for areaIndex in range(samples):
							areaCode	= []
							lightDupliIndex	= instanceIndex #Setup dupli index before calling shader parser
							lightAreaIndex	= areaIndex	#Setup area index before calling shader parser
							if (samples > 1):
								print "\t\tArea light array: "+str(areaIndex+1)+" of "+str(samples)
								areaPos	= LightarrayPosition(instance, areaIndex)
								v	= Vector(areaPos)*Object.mat.rotationPart()
								areaCode.append("Translate "+str(v[0])+" "+str(v[1])+" "+str(v[2])+"\n")
							if (lightType == 3):	areaCode.append(ParseTokens(Scene, Object, "LightSource \"ambientlight\" <LightID_I> \"float intensity\" <LampEnergy_F_A0_M0.75> \"color lightcolor\" <LampLightColor_C>\n"))
							else:			areaCode.extend(MotionBlock(Scene, RibifyShader, Scene, Object, isLampShader, GetProperty(Object, "MOSAICData", RIBset, ButtonData[LIGHTS][WIN_BUTS][LIGHT_MBLUR][BUT_PROP], "", ButtonData[LIGHTS][WIN_BUTS][LIGHT_MBLUR][BUT_DEFAULT]), GetProperty(Object, "MOSAICData", RIBset, ButtonData[LIGHTS][WIN_BUTS][LIGHT_FRAMES][BUT_PROP], "", ButtonData[LIGHTS][WIN_BUTS][LIGHT_FRAMES][BUT_DEFAULT]), 1)) #Parse light shader
							if (areaCode):
								if (samples > 1):	instanceCode.extend(RibifyInstance(Object, "", Object.name, areaCode, Frame, "Attribute Block"))
								else:			instanceCode.extend(areaCode)
					instanceIndex += 1
					if (instanceCode):
						if (matrix):	objectCode.extend(RibifyInstance(Object, "", Object.name, instanceCode, Frame, "Attribute Block"))
						else:		objectCode.extend(instanceCode)
		isLampCode					= GetProperty(Object, "MOSAICData", RIBset, ButtonData[LIGHTS][WIN_BUTS][LIGHT_END_CODE][BUT_PROP])
		if (isLampCode and isLampCode != 'NONE'):	objectCode.extend(ParseFragment(Scene, Object, isLampCode)) #Parse custom end code
		objectCode = RibifyInstance(Object, "Archives"+sys.sep+"Lights"+sys.sep, "LB"+RIBindex+Object.name, RibifyInstance(Object, "", Object.name, objectCode, Frame, "Attribute Block"), Frame, GetProperty(Object, "MOSAICData", RIBset, ButtonData[LIGHTS][WIN_BUTS][LIGHT_ARCH][BUT_PROP], "", ButtonData[LIGHTS][WIN_BUTS][LIGHT_ARCH][BUT_TITLE][ButtonData[LIGHTS][WIN_BUTS][LIGHT_ARCH][BUT_DEFAULT]]), [], TabLevel)
	
	#### Geometry export code
	elif (objectType == "Mesh" or objectType == "Curve" or objectType == "Surf"):
		#This block is a necessary evil so we know if theres changes to mutiple RIBsets on mutiple materials applied to this object on this scene
		dataBlock			= Object.getData(False, True)
		meshMat				= dataBlock.materials
		objMat				= Object.getMaterials()
		ObjMATsets			= "S"
		for mat in meshMat+objMat:
			if (mat != None):
				matSet		= GetProperty(Scene, "MOSAICRIBset", mat.name+TypeString(mat), "", "", "DEFAULT")
				if (GetProperty(mat, "MOSAICData", "DEFAULT")):	setList = [k for k, v in mat.properties["MOSAICData"].iteritems()]
				else:						setList = ["DEFAULT"]
				if (setList.count(matSet)):			ObjMATsets = ObjMATsets+str(setList.index(matSet))
				else:						ObjMATsets = ObjMATsets+"0"
		#End necessary evil ;)
		
		objectState			= False			#Keep track if any object was actually created
		if (CheckInstance(Object, "OB"+RIBindex+ObjMATsets+Object.name, Frame, not GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_ANIM_OBJECT][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_ANIM_OBJECT][BUT_DEFAULT]), ButtonData[ACTIONS][WIN_BUTS][ACT_CREATE_SEL][BUTTON].val)): #Check if this object needs to be exported
			if (Object.DupObjects):				#If we have dupliobjects then pass them through the loop
				isDupli		= True
				objectList	= Object.DupObjects
				totalDupli	= len(objectList)
			else:						#If we dont then just pass current object through loop
				isDupli		= False
				objectList	= [[Object, []]]
				totalDupli	= 1
			currentDupli		= 0			#Keep count of what dupli number we are for user output
			boundB			= []
			for object, matrix in objectList:		#Cycle through any dupliobjects if none then just process current object
				while QTest():				#Cycle through events looking for an esc
					if (ESCKEY in QRead()):	#If user escaped
						killExport = True
						return []
				objectType	= object.getType()	#Collect new type info for possible dupli object
				if (objectType == "Lamp"):	continue #If this is a lamp dupli then skip
				obRIBset	= GetProperty(Scene, "MOSAICRIBset", object.name+TypeString(object), "", "", "DEFAULT") #Get which RIBset to use for this object in current scene (if none then use default)
				if (obRIBset == "DEFAULT"):	obRIBindex = "0"
				else:				obRIBindex = str([k for k, v in object.properties["MOSAICData"].iteritems()].index(obRIBset))
				currentDupli	= currentDupli+1
				transformCode	= []
				instanceCode	= []
				
				#This block is a necessary evil so we know if theres changes to mutiple RIBsets on mutiple materials applied to this object on this scene
				dataBlock	= object.getData(False, True)
				meshMat		= dataBlock.materials
				objMat		= object.getMaterials()
				objMATsets	= "S"
				for mat in meshMat+objMat:
					if (mat != None):
						matSet		= GetProperty(Scene, "MOSAICRIBset", mat.name+TypeString(mat), "", "", "DEFAULT")
						if (GetProperty(mat, "MOSAICData", "DEFAULT")):	setList = [k for k, v in mat.properties["MOSAICData"].iteritems()]
						else:						setList = ["DEFAULT"]
						if (setList.count(matSet)):			objMATsets = objMATsets+str(setList.index(matSet))
						else:						objMATsets = objMATsets+"0"
				#End necessary evil ;)
				
				geoState	= False			#Keep track if any geometry was created
				if (not isDupli or CheckInstance(object, "DB"+obRIBindex+objMATsets+object.name, Frame, not GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_ANIM_OBJECT][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_ANIM_OBJECT][BUT_DEFAULT]))):
					if (isDupli):
						boundB = RibifyBounds(Scene, object) #Calculate bounds for dupliobject
						print "\t\tProcessing Dupli Object: "+object.name+" ("+str(currentDupli)+" of "+str(totalDupli)+")"
					else:		print "\t\tProcessing Geometry:"
					isObjectCode	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_BEGINOBJ_CODE][BUT_PROP])
					if (isObjectCode and isObjectCode != 'NONE'): instanceCode.extend(ParseFragment(Scene, object, isObjectCode)) #Parse custom object begin code
					shadingRate	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_SHADE_RATE][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_SHADE_RATE][BUT_DEFAULT]) #Set object shading rate
					if (shadingRate): instanceCode.append("ShadingRate "+str(shadingRate)+"\n")
					isShadeInt	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_SHADE_INTER][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_SHADE_INTER][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_SHADE_INTER][BUT_DEFAULT]])
					if (isShadeInt): instanceCode.append(isShadeInt)
					isOrient	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_ORIENTATION][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_ORIENTATION][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_ORIENTATION][BUT_DEFAULT]])
					if (isOrient): instanceCode.append(isOrient)
					isDispBound	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_DISP_BOUND][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_DISP_BOUND][BUT_DEFAULT])
					if (isDispBound): instanceCode.append("Attribute \"displacementbound\" \"float sphere\" [ "+str(isDispBound)+" ] \"string coordinatesystem\" [ \""+GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_COOR_SYS][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_COOR_SYS][BUT_DEFAULT])+"\" ]\n")
					isCullhidden	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_CULL_HIDDEN][BUT_PROP])
					if (isCullhidden): instanceCode.append("Attribute \"cull\" \"int hidden\" [ "+str(isCullhidden)+" ]\n")
					isCullbackface	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_CULL_BACKFACE][BUT_PROP])
					if (isCullbackface): instanceCode.append("Attribute \"cull\" \"int backfacing\" [ "+str(isCullbackface)+" ]\n")
					isDiceBinary	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_DICE_BINARY][BUT_PROP])
					if (isDiceBinary): instanceCode.append("Attribute \"dice\" \"int binary\" [ "+str(isDiceBinary)+" ]\n")
					isDiceRaster	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_DICE_RASTER][BUT_PROP])
					if (isDiceRaster): instanceCode.append("Attribute \"dice\" \"int rasterorient\" [ "+str(isDiceRaster)+" ]\n")
					isTraceDisp	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_TRACE_DISPLACE][BUT_PROP])
					if (isTraceDisp): instanceCode.append("Attribute \"trace\" \"int displacements\" [ "+str(isTraceDisp)+" ]\n")
					isTraceMotion	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_TRACE_MOTION][BUT_PROP])
					if (isTraceMotion): instanceCode.append("Attribute \"trace\" \"int samplemotion\" [ "+str(isTraceMotion)+" ]\n")
					isAtmoShader	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_ATMO][BUT_PROP])
					if (isAtmoShader and isAtmoShader != 'NONE' and isAtmoShader != 'DEFAULT'): instanceCode.extend(RibifyShader(Scene, "", isAtmoShader)) #Parse atmosphere shader
					materials	= []
					for matIndex, material in enumerate(meshMat):
						if (not object.colbits&(1<<matIndex)): #Cycle through color bits and select material occordingly
							if (material != None):			materials.append(material)
							else:					materials.append("")
						elif (objMat and len(objMat)-1 >= matIndex):	materials.append(objMat[matIndex])
						else:						materials.append("")
					if (not meshMat and not objMat):			materials = [""]
					modStack	= []
					modTags		= "X"
					for modifier in object.modifiers: #Cycle through object modifiers that need to be pre-processed
						modTags = modTags+str(modifier.type) #Try to tag modifiers to detect geometry changes on shared datablocks
						if (modifier.type == Modifier.Types.SUBSURF):
							modStack.insert(0, modifier[Modifier.Settings.RENDER])
							modStack.insert(0, modifier[Modifier.Settings.REALTIME])
							modifier[Modifier.Settings.RENDER]	= False
							modifier[Modifier.Settings.REALTIME]	= False
					for matIndex, material in enumerate(materials):
						print "\t\t- Material Pass: "+str(matIndex+1)+" of "+str(len(materials))
						if (material):	matRIBset = GetProperty(Scene, "MOSAICRIBset", material.name+TypeString(material), "", "", "DEFAULT") #Get which RIBset to use for this material in current scene (if none then use default)
						else:		matRIBset = "DEFAULT"
						effects		= object.effects
						attributeCode	= []
						partCode	= []
						geoCode		= []
						matCode		= []
						if (dataBlock):
							if (RibSides):
								if (objectType != "Mesh" or dataBlock.mode&Mesh.Modes.TWOSIDED): attributeCode.append("Sides 2\n")
								else: attributeCode.append("Sides 1\n")
							renderEmitter	= True	#Always render geometry by default
							geoMblur	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_MBLUR][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_MBLUR][BUT_DEFAULT])
							geoFrames	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_FRAMES][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_FRAMES][BUT_DEFAULT])
							geoArchive	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_DATA_ARCH][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_DATA_ARCH][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_DATA_ARCH][BUT_DEFAULT]])
							if (geoArchive == "Inline Code"): 	archiveIndex = "I"
							elif (geoArchive == "Instance Object"):	archiveIndex = "O"
							elif (geoArchive == "Read Archive"):	archiveIndex = "R"
							if (effects):
								partName	= "P"+archiveIndex+"M"+str(matIndex)+object.name
								if (not effects[0].getFlag()&Effect.Flags.EMESH): renderEmitter = False #Should we process emitter geometry
								if (CheckInstance(object, partName, Frame)): #Check if particles needs to be exported
									partCode = MotionBlock(Scene, RibifyParticles, object, matIndex, material, geoMblur, geoFrames, 3)
									if (partCode != 'NORIB'):
										partCode.insert(0, "Basis \"bezier\" 3 \"bezier\" 3\n")
										if (RibNormals): partCode.insert(0, "Declare \"N\" \"varying normal\"\n")
								else: print "\t\t\tInstanced Particles"
								attributeCode.extend(RibifyInstance(object, "Archives"+sys.sep+"Geometry"+sys.sep, partName, partCode, Frame, geoArchive))
							else:	partCode	= 'NORIB'
							if (renderEmitter): #Process geometry
								geoName		= objectType[0:1]+archiveIndex+modTags+"M"+str(matIndex)+dataBlock.name
								if (CheckInstance(dataBlock, geoName, Frame)): #Check if geometry needs to be exported
									if (objectType == "Mesh"):
										print "\t\t\tProcessing Mesh: "+dataBlock.name
										Udirection	= GetProperty(material, "MOSAICData", matRIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_INVERTUV_U][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_INVERTUV_U][BUT_DEFAULT])
										Vdirection	= GetProperty(material, "MOSAICData", matRIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_INVERTUV_V][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_INVERTUV_V][BUT_DEFAULT])
										paraclass	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_PARA_CLASS][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_PARA_CLASS][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_PARA_CLASS][BUT_DEFAULT]])
										if (paraclass == "vertex"):	VertexNormals = 1
										else:				VertexNormals = 0
										geoCode		= MotionBlock(Scene, RibifyMesh, object, [matIndex, Udirection, Vdirection], material, geoMblur, geoFrames, 3)
										if (geoCode != 'NORIB'):
											if (RibNormals):	geoCode.insert(0, "Declare \"N\" \""+paraclass+" normal\"\n")
											if (not VertexNormals): #If using old sytle vertex normals then don't use vertex color or uv
												if (RibVertexUVs):	geoCode.insert(0, "Declare \"st\" \""+paraclass+" float[2]\"\n")
												if (RibVertexCols):	geoCode.insert(0, "Declare \"Cs\" \""+paraclass+" color\"\n")
									elif (objectType == "Curve"):
										print "\t\t\tProcessing Curve: "+dataBlock.name
										geoCode = MotionBlock(Scene, RibifyCurve, object, matIndex, material, geoMblur, geoFrames, 3)
										if (geoCode != 'NORIB'):
											geoCode.insert(0, "Basis \"bezier\" 3 \"bezier\" 3\n")
											if (RibNormals): geoCode.insert(0, "Declare \"N\" \"varying normal\"\n")
									elif (objectType == "Surf"):
										print "\t\t\tProcessing Surface: "+dataBlock.name
										for surfData in object.getData(False, True):
											surf	= MotionBlock(Scene, RibifySurface, object, matIndex, surfData, geoMblur, geoFrames, 3)
											if (surf != 'NORIB'):
												geoCode.extend(surf) #Process surfaces in object (doing this here so motion block works)
											else:
												geoCode = surf #If there was an error pass through
												break
										if (geoCode != 'NORIB'):
											geoCode.insert(0, "Basis \"bezier\" 3 \"bezier\" 3\n")
								else: print "\t\t\tInstance of: "+dataBlock.name
								attributeCode.extend(RibifyInstance(dataBlock, "Archives"+sys.sep+"Geometry"+sys.sep, geoName, geoCode, Frame, geoArchive))
							else: geoCode	= 'NORIB'
							isGeoCode	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_GEO_CODE][BUT_PROP])
							if (isGeoCode and isGeoCode != 'NONE'): attributeCode.extend(ParseFragment(Scene, object, isGeoCode)) #Parse custom geometry code
						if ((isGeoCode and isGeoCode != 'NONE') or partCode != 'NORIB' or geoCode != 'NORIB'): #Make sure there is actually geometry to handle
							geoState	= True
							if (material):
								matShaders	= []
								if (matRIBset == "DEFAULT"):	matRIBindex = "0"
								else:				matRIBindex = str([k for k, v in material.properties["MOSAICData"].iteritems()].index(matRIBset))
								if(material.lightGroup):	matName = "MS"+str(Blender.Scene.Get().index(Scene))+"B"+matRIBindex+material.name #Extend material archive name with scene name if using light groups
								else:				matName = "MB"+matRIBindex+material.name #Otherwise just use material name
								matMblur	= GetProperty(material, "MOSAICData", matRIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_MBLUR][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_MBLUR][BUT_DEFAULT])
								matFrames	= GetProperty(material, "MOSAICData", matRIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_FRAMES][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_FRAMES][BUT_DEFAULT])
								matArchive	= GetProperty(material, "MOSAICData", matRIBset, ButtonData[MATERIALS][WIN_BUTS][MAT_ARCH][BUT_PROP], "", ButtonData[MATERIALS][WIN_BUTS][MAT_ARCH][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_ARCH][BUT_DEFAULT]])
								if (CheckInstance(material, matName, Frame)):
									print "\t\t\tMaterial Shaders: "+matName
									matShaders.extend(RibifyMaterial(Scene, object, material))
								else: print "\t\t\tMaterial Shaders Instance: "+matName
								matCode.extend(RibifyInstance(material, "Archives"+sys.sep+"Materials"+sys.sep, matName, matShaders, Frame, matArchive)) #Create material code
								if (RibColor):
									print "\t\t\t- Material color"
									matCode.extend(MotionBlock(Scene, RibifyColor, material, "", "", matMblur, matFrames, 3)) #Material color
								if (RibOpacity):
									print "\t\t\t- Material opacity"
									matCode.extend(MotionBlock(Scene, RibifyOpacity, material, "", "", matMblur, matFrames, 3)) #Material alpha
							elif (not material):
								matName		= "Default Surface"
								print "\t\t\tMaterial Shaders: "+matName
								if (RibColor): matCode.append("Color [ 0.8 0.8 0.8 ]\n")
								matCode.extend(["Surface \"plastic\" \"float Kd\" [ 0.8 ] \"float Ks\" [ 0.5 ] \"float roughness\" [ 0.25 ]\n"]) #If no materials then make default matte material
							instanceCode.extend(RibifyInstance(dataBlock, "", matName, matCode+attributeCode, Frame, "Attribute Block")) #Wrap geometry and its attributes in a attribute block
						else:	print "\t\t\tNO GEOMETRY FOR THIS MATERIAL!!"
					for modifier in object.modifiers: #Restore any modifier settings from stack
						if (modifier.type == Modifier.Types.SUBSURF):
							modifier[Modifier.Settings.RENDER]	= modStack.pop()
							modifier[Modifier.Settings.REALTIME]	= modStack.pop()
				else:
					print "\t\tProcessing Dupli Instance: "+object.name+" ("+str(currentDupli)+" of "+str(totalDupli)+")"
					geoState		= True	#Automatically make geometry valid if it is an instance
				if (geoState):				#Only process if there is instance code
					objectState		= True	#Show that some code was actually created
					if (instanceCode):		#Only add custom end code if this is not a instance
						isObjectCode	= GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_ENDOBJ_CODE][BUT_PROP])
						if (isObjectCode and isObjectCode != 'NONE'): instanceCode.extend(ParseFragment(Scene, object, isObjectCode)) #Parse custom object end code
					if (isDupli):
						if (currentDupli-1 == dupliIndex and object == Scene.objects.camera): continue #If active camera is this dupli then skip
						if (not boundB): boundB = RibifyBounds(Scene, object) #Calculate bounds for dupliobject
						instanceCode	= RibifyInstance(object, "Archives"+sys.sep+"Objects"+sys.sep, "DB"+obRIBindex+objMATsets+object.name, instanceCode, Frame, GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_DEFAULT]]), boundB)
						transformCode.extend(MotionBlock(Scene, RibifyTransform, Object, currentDupli-1, False, GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_MBLUR][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_MBLUR][BUT_DEFAULT]), GetProperty(object, "MOSAICData", obRIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_FRAMES][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_FRAMES][BUT_DEFAULT]), 1))
						if (RibBound): transformCode.append("Bound "+str(boundB[0])+" "+str(boundB[1])+" "+str(boundB[2])+" "+str(boundB[3])+" "+str(boundB[4])+" "+str(boundB[5])+"\n") #Create bounding box
						if (object.drawType == Blender.Object.DrawTypes.BOUNDBOX): transformCode.extend(ShowBounds(boundB)) #Show bounding box if object draw type is bounding box
						objectCode.extend(RibifyInstance(object, "", object.name, transformCode+instanceCode, Frame, "Attribute Block"))
					else:	objectCode 	= instanceCode
		else:
			print "\t\tProcessing Object Instance:"
			objectState = True		#Automatically make object valid if it is an instance
		if (objectState):					#Only process this object if it actually had any geometry
			headerCode	= []				#Will contain transform and bounds info for object (needs to be separate so dupliobjects are easier to manage)
			boundB		= RibifyBounds(Scene, Object)	#Calculate bounding box for parent object (needed for delayed read archive)
			archiveTYPE	= GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_DEFAULT]])
			if (archiveTYPE == "Delayed Archive" or objectCode): #Only use header if this is a delayed archive or this archive needs to be regenerated!
				headerCode.extend(MotionBlock(Scene, RibifyTransform, Object, [], False, GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_MBLUR][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_MBLUR][BUT_DEFAULT]), GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_FRAMES][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_FRAMES][BUT_DEFAULT]), 1))
				if (RibBound): headerCode.append("Bound "+str(boundB[0])+" "+str(boundB[1])+" "+str(boundB[2])+" "+str(boundB[3])+" "+str(boundB[4])+" "+str(boundB[5])+"\n") #Create bounding box
				if (Object.drawType == Blender.Object.DrawTypes.BOUNDBOX): headerCode.extend(ShowBounds(boundB)) #Show bounding box if object draw type is bounding box
			#If this is a delayed archive we need to put the transform before the archive call so the delayed bounds can use local space, otherwise place it after to put all object code in archive
			if (archiveTYPE == "Delayed Archive"):	objectCode = RibifyInstance(Object, "", Object.name, headerCode+RibifyInstance(Object, "Archives"+sys.sep+"Objects"+sys.sep, "OB"+RIBindex+ObjMATsets+Object.name, objectCode, Frame, archiveTYPE, boundB, TabLevel), Frame, "Attribute Block")
			else:					objectCode = RibifyInstance(Object, "Archives"+sys.sep+"Objects"+sys.sep, "OB"+RIBindex+ObjMATsets+Object.name, RibifyInstance(Object, "", Object.name, headerCode+objectCode, Frame, "Attribute Block"), Frame, archiveTYPE, boundB, TabLevel)
	return objectCode


#### Check passed objects "archive" properties to determine if instance needs to be re-exported, returns True to redo export
def CheckInstance(Object, ObjectName, Frame, noAnim = False, onlySelect = False):
	archiveID	= GetProperty(Object, "MOSAICTemp", "ID"+ObjectName)
	archiveTYPE	= GetProperty(Object, "MOSAICTemp", "TYPE"+ObjectName)
	archiveFRAME	= GetProperty(Object, "MOSAICTemp", "FRAME"+ObjectName)
	archiveLOC	= GetProperty(Object, "MOSAICTemp", "LOC"+ObjectName)
	RIBset		= GetProperty(Blender.Scene.GetCurrent(), "MOSAICRIBset", Object.name+TypeString(Object), "", "", "DEFAULT") #Get which RIBset to use for this object in current scene (if none then use default)
	if (onlySelect and type(Object) == Blender.Types.ObjectType and not Object.sel and
	    (GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_DEFAULT]]) == "Read Archive" or
	     GetProperty(Object, "MOSAICData", RIBset, ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_PROP], "", ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_TITLE][ButtonData[GEOMETRY][WIN_BUTS][GEO_OBJ_ARCH][BUT_DEFAULT]]) == "Delayed Archive")): return False #If object is using onlySelect and is an archive and not selected then dont generate
	if ((noAnim or archiveFRAME == Frame) and archiveTYPE != "Inline Code"  and archiveTYPE != "Instance Object" and archiveLOC and archiveID): return False #If archive is already made or using noAnim then don't generate code
	return True


#### This function will archive the passed code according to the type passed. If this is a read type archive it will search for a archive in directory that has the same data as code unless 'NORIB' is passed.
#### If it finds a match it will reuse the older archive by passing its handle back, if there is no match then it will make a new archive as "ObjectName_Frame.rib". If the type is a attribute
#### block it will just pass back Code with attribute begin and end and proper tabbing. If type is a instance then it will search the main rib for a Code match if no match it will append Code to the main rib.
#### TabLevel will add specified number of tabs to passed code, ForceArchive will force the creation of the archive without checking for a ealier match
#### This function passes info about the coding and archiving of the passed object by adding the following properties to it: archiveID property: [objectId, archiveType, FrameNum, archiveLocation (seekPos or directory)]
def RibifyInstance(Object, Directory, ObjectName, Code, Frame = 1, Type = "Inline Code", BoundingBox = [-1.0, 1.0, -1.0, 1.0, -1.0, 1.0], TabLevel = 0, forceArchive = False):
	global RibOutput, instanceCount, RibExt, RibComments
	if (Code == 'NORIB'):	return []				#If there was an rib code then do nothing	
	
	if (Type == "Read Archive" or Type == "Delayed Archive"):	#File archive type
		archiveName	= "F"+str(Frame)+ObjectName+RibExt	#Create archive name from current information
		archiveID	= GetProperty(Object, "MOSAICTemp", "ID"+ObjectName, "", "", archiveName)
		archiveTYPE	= GetProperty(Object, "MOSAICTemp", "TYPE"+ObjectName, "", "", Type)
		archiveLOC	= GetProperty(Object, "MOSAICTemp", "LOC"+ObjectName, "", "", Directory)
		if (Code):
			if (RibComments):
				Code.insert(0, "##RenderMan RIB-Structure 1.1 Entity\n") #Insert Entity comments
				Code.insert(1, "version 3.03\n")
			if (not forceArchive and sys.exists(archiveLOC+archiveID)): #See if last pointed archive exists
				if (ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUTTON].val):	archive = gzip.open(archiveLOC+archiveID, 'rb')
				else:									archive = open(archiveLOC+archiveID, 'rb')
				archiveList	= archive.readlines()
				archive.close()
				if (archiveList != Code): forceArchive = True
			elif (not forceArchive): forceArchive = True
			if (forceArchive):
				archiveID	= archiveName
				archiveTYPE	= Type
				archiveLOC	= Directory
				if (ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUTTON].val):	archive = gzip.open(Directory+archiveName, 'wb') #Make the archive
				else:									archive = open(Directory+archiveName, 'wb') #Make the archive
				archive.writelines(Code)
				archive.close()
			if (not Object.properties.has_key("MOSAICTemp")):		Object.properties["MOSAICTemp"] = {}
			Object.properties["MOSAICTemp"]["FRAME"+ObjectName]		= Frame
			Object.properties["MOSAICTemp"]["ID"+ObjectName]		= archiveID
			Object.properties["MOSAICTemp"]["TYPE"+ObjectName]		= archiveTYPE
			Object.properties["MOSAICTemp"]["LOC"+ObjectName]		= archiveLOC
		
		if (sys.exists(archiveLOC+archiveID)):			#Be sure archive actually exists before we return a handle to it!
			if (Type == "Read Archive"):
				Code = []
				if (RibComments): Code.append("##Include "+archiveLOC.replace(sys.sep, "/")+archiveID+"\n")
				Code.append("ReadArchive \""+archiveID+"\"\n")
			elif (Type == "Delayed Archive"):
				Code = []
				if (RibComments): Code.append("##Include "+archiveLOC.replace(sys.sep, "/")+archiveID+"\n")
				Code.append("Procedural \"DelayedReadArchive\" [ \""+archiveID+"\" ] [ "+str(BoundingBox[0])+" "+str(BoundingBox[1])+" "+str(BoundingBox[2])+" "+str(BoundingBox[3])+" "+str(BoundingBox[4])+" "+str(BoundingBox[5])+" ]\n")
	elif (Type == "Instance Object"):				#Instance archive type
		archiveID	= GetProperty(Object, "MOSAICTemp", "ID"+ObjectName, "", "", -1)
		archiveTYPE	= GetProperty(Object, "MOSAICTemp", "TYPE"+ObjectName, "", "", Type)
		archiveLOC	= GetProperty(Object, "MOSAICTemp", "LOC"+ObjectName, "", "", 0)
		if (Code and sys.exists(GetProjectFolder()+RibOutput)):
			if (ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUTTON].val):	archive = gzip.open(GetProjectFolder()+RibOutput, 'rb') #Get file to check instances in
			else:									archive = open(GetProjectFolder()+RibOutput, 'rb') #Get file to check instances in
			archive.seek(archiveLOC)			#Point to last instance for this object
			archiveList = archive.readlines()[1:len(Code)+1]
			archive.close()
			Code = AddTabs(Code, 1)				#Go ahead and add tabs to code so it matches instance
			if (Code != archiveList):			#If last object does not match current object then make new instance
				if (ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUTTON].val):	archive = gzip.open(GetProjectFolder()+RibOutput, 'ab') #Append new instance to end of main rib
				else:									archive = open(GetProjectFolder()+RibOutput, 'ab') #Append new instance to end of main rib
				archiveID	= instanceCount
				instanceCount	= instanceCount+1
				archiveTYPE	= Type
				archiveLOC	= int(archive.tell())
				archive.write("ObjectBegin "+str(archiveID)+" #Instance \""+ObjectName+"\"\n")
				archive.writelines(Code)
				archive.write("ObjectEnd\n")
				archive.close()
			if (not Object.properties.has_key("MOSAICTemp")):		Object.properties["MOSAICTemp"] = {}
			Object.properties["MOSAICTemp"]["FRAME"+ObjectName]		= Frame
			Object.properties["MOSAICTemp"]["ID"+ObjectName]		= archiveID
			Object.properties["MOSAICTemp"]["TYPE"+ObjectName]		= archiveTYPE
			Object.properties["MOSAICTemp"]["LOC"+ObjectName]		= archiveLOC
		if (archiveID != -1): Code = ["ObjectInstance "+str(archiveID)+" #Instance \""+ObjectName+"\"\n"]
	elif (Type == "Attribute Block"):				#Pass code straight through but with added attribute block
		if (Code):
			Code.insert(0, "Attribute \"identifier\" \"string name\" [ \""+ObjectName+"\" ]\n")
			Code = AddTabs(Code, 1)
			Code.insert(0, "AttributeBegin\n")
			Code.append("AttributeEnd\n")
	return AddTabs(Code, TabLevel)


#### Prepares project folders and processes shaders and textures, returns 1 if errors otherwise 0
def PrepareProject():
	global RenderDir, lightList, RenderBin, CompilerBin, InfoBin
	OutputDir = GetProjectFolder()
	lightList = []							#Reset light lists for current render pass/s
	
	print "\nStarting export process..."
	
	criticalError	= False
	if (not RenderDir):						#Check if export directory has been set
		criticalError = True
		ErrorPopup("Please set the export directory under the \"MOSAIC Settings\" tab!")
	if (not RenderBin and not CompilerBin and not InfoBin):		#Check if all binaries are not set
		criticalError = True
		ErrorPopup("Please select a renderer preset under the \"MOSAIC Settings\" tab!")
	elif (not RenderBin or not CompilerBin or not InfoBin):		#Check if Renderer, shader compiler and shader info has been set
		criticalError = True
		ErrorPopup("Renderer Binary, Shader Compiler and Shader Info must be set under the \"MOSAIC Settings\" tab!")
	if (criticalError): return 1
	
	print "Setting up output directories..."
	DrawProgressBar(0.0, "Setting up directories...")
	if (SetupDirectories(OutputDir)):				#Make sure output directories exist, if they couldn't be made then abort render
		DrawProgressBar(0.0, "")				#Reset progress bar
		DrawProgressBar(1.0, "")				#Reset progress bar
		return 1	
	return 0


#### Export and process any resources such as shaders and maps
def ProcessResources(CompileShaders = True, ExportMaps = True):
	global Filters, TexmakeBin, EnvmakeBin, TextureExt
	OutputDir = GetProjectFolder()
	
	if (CompileShaders):						#Only output shader source if we are set to compile shaders
		print "Processing shaders..."
		DrawProgressBar(1.0, "Processing shaders...")
		os.chdir(OutputDir+"Shaders")
		for shaderInclude in [text for text in Blender.Text.Get() if text.name.count(Filters[7])]: #Cycle through all text files looking for includes
			if (ExportText(shaderInclude)):
				ErrorPopup("Could not export "+shaderInclude)
		for shader in [text for text in Blender.Text.Get() if text.name.count(Filters[1])]: #Cycle through all text files looking for shaders
			if (CompileShader(shader)):
				ErrorPopup("Could not compile "+shader)
	
	if (ExportMaps):						#Only export maps if we are set to export maps
		print "Processing maps..."
		DrawProgressBar(1.0, "Processing maps...")
		os.chdir(OutputDir+"Maps")
		for image in Blender.Image.Get():
			exportMode		= GetProperty(image, "ExportOption", "", "", "", 2) #Get user export mode, if none then set to export anyway
			if (image.source != Blender.Image.Sources.GENERATED and exportMode > 0): #Only allow images that have data, not generated and user set to export
				originalpath	= sys.dirname(image.getFilename())
				originalfile	= sys.basename(image.getFilename())
				newpath		= OutputDir+"Maps"
				imageList	= []
				
				if (image.source == Blender.Image.Sources.SEQUENCE):
					if (sys.exists(originalpath+sys.sep+originalfile)): #Make sure theres actually still an valid image
						sequenceStarted	= False
						seqName		= ""
						for frame in range(1, 300000): #Count through all possible sequences until we find the lowest range of images
							OLDseqName	= seqName
							seqName		= CreateSeqName(originalfile, frame)
							if (sys.exists(originalpath+sys.sep+seqName) and seqName != OLDseqName): #Make sure the image exists and that we are not repeating ourselves
								imageList.append(seqName)
								sequenceStarted = True
							elif (sequenceStarted): break #If weve found frames and this one doesn't exist then assume there are no more (or at least theres a break)
				else:	imageList = [originalfile]
				
				for imageName in imageList:
					try:				#Write temporary image for render or report error if problems
						if (image.packed or sys.exists(originalpath+sys.sep+imageName) != 1): #If image is packed or its original file doesn't exist then try to save from blender
							print "\tWriting Image "+imageName+"..."
							image.setFilename(newpath+sys.sep+imageName)
							image.save()
						else:			#Otherwise just copy the original image to the maps folder for optimizing
							print "\tCoping Image "+imageName+"..."
							oldFile	= open(originalpath+sys.sep+imageName, 'rb')
							newFile	= open(newpath+sys.sep+imageName, 'wb')
							newFile.writelines(oldFile.readlines())
							newFile.close()
							oldFile.close()
						
						maketexCall	= ""
						inputName	= imageName
						outputName	= sys.splitext(imageName)[0]+TextureExt
						if (exportMode == 2 and TexmakeBin):	maketexCall = TexmakeBin
						if (exportMode == 3 and EnvmakeBin):	maketexCall = EnvmakeBin
						if (maketexCall):
							isIN	= maketexCall.count("<TEXIN>")
							isOUT	= maketexCall.count("<TEXOUT>")
							if (isIN):	maketexCall = maketexCall.replace("<TEXIN>", "\""+inputName+"\"") #Pass input image to token
							if (isOUT):	maketexCall = maketexCall.replace("<TEXOUT>", "\""+outputName+"\"") #Pass output image to token
							if (not isIN and not isOUT): maketexCall = maketexCall+" \""+inputName+"\" \""+outputName+"\"" #If no tokens then setup both input and ouput images
							print "\t"+maketexCall
							os.system(maketexCall)	#Optimize and convert texture
					except: print "\t\tCould not write image "+newpath+sys.sep+imageName
				image.setFilename(originalpath+sys.sep+originalfile) #Be sure to restore original path to image
	
	os.chdir(OutputDir)						#Reset directory
	DrawProgressBar(0.0, "")					#Reset progress bar
	DrawProgressBar(1.0, "")					#Reset progress bar

#### Prepares temporary scene object properties for new export
def CleanupScenes():
	global instanceCount
	instanceCount	= 0
	print "Preparing scenes..."
	DrawProgressBar(0.0, "Preparing scenes...")
	itemNames = []
	for group in [Blender.Mesh.Get(), Blender.Curve.Get(), Blender.Metaball.Get()]: #Cycle through all datablocks and purge temp data
		for subItem in group:
			if (subItem.properties.has_key("MOSAICTemp")):	del subItem.properties["MOSAICTemp"]
	for group in [Blender.Scene.Get(), Blender.Object.Get(), Blender.Material.Get()]: #Cycle through all scenes, objects and materials and clear mosaic render state properties
		for subItem in group:
			itemNames.append(subItem.name+TypeString(subItem)) #Collect data to use for orphaned RIBset purging
			if (subItem.properties.has_key("MOSAICTemp")):	del subItem.properties["MOSAICTemp"]
	for scene in Blender.Scene.Get():				#Cycle through all scenes purging any orphaned RIBsets
		if (scene.properties.has_key("MOSAICRIBset")):		#Make sure scene has RIBsets
			for prop in [k for k, v in scene.properties["MOSAICRIBset"].iteritems()]: #Cycle through any RIBsets
				if (not itemNames.count(prop)):	del scene.properties["MOSAICRIBset"][prop] #Purge em


#### Main scene export code, return render commandline for scene
def RibifyScene(scene, fraStart = 1, fraEnd = 1, RibOutputName = "Mosaic"+RibExt, Preview = False, GenerateCode = True, RIBsetBypass = ""):
	global ButtonData, RenderBin, RibOutput, killExport, lightList, ShaderDir, RibComments, RibFrames, RibWorlds
	RibOutput	= RibOutputName					#Transfer ribs output file name to global
	originalFrame	= scene.render.currentFrame()			#Get current frame so we can reset it later
	OutputDir	= GetProjectFolder()
	ProjectName	= GetProperty(Blender.Scene.Get()[0], "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUT_DEFAULT])
	if (RIBsetBypass):	scRIBset = RIBsetBypass
	else:			scRIBset = GetProperty(scene, "MOSAICRIBset", scene.name+TypeString(scene), "", "", "DEFAULT") #Get which RIBset to use for this object in current scene (if none then use default)
	if (scRIBset == "DEFAULT"):	scRIBindex = "0"
	else:				scRIBindex = str([k for k, v in scene.properties["MOSAICData"].iteritems()].index(scRIBset))
	
	#### Setup the main ribs header in preparation for the frame blocks	
	os.chdir(OutputDir) 						#Change to export directory
	if (Preview or GenerateCode):
		DrawProgressBar(0.0, "Exporting scenes...")
		if (ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUTTON].val):	mainrib = gzip.open(RibOutput, 'wb') #Open main rib for output
		else:									mainrib = open(RibOutput, 'wb') #Open main rib for output
		if (RibComments):
			mainrib.write("##RenderMan RIB-Structure 1.1\n")
			mainrib.write("##Scene: "+scene.name+"\n")
			mainrib.write("##Creator: MOSAIC "+__version__+" for Blender\n")
			mainrib.write("##CreationDate: "+strftime("%I:%M%p %m/%d/%Y", localtime()).lower()+"\n")
			mainrib.write("##For: "+ProjectName+"\n")
			mainrib.write("##Frames: "+str(fraEnd-fraStart+1)+"\n")
			mainrib.write("version 3.03\n")
		rootScene	= Blender.Scene.Get()[0]
		archives	= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_ARCHIVES][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_ARCHIVES][BUT_DEFAULT])
		shaders		= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUT_DEFAULT])
		textures	= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUT_DEFAULT])
		displays	= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_DISPLAYS][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_DISPLAYS][BUT_DEFAULT])
		procedurals	= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_PROCEDURALS][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_PROCEDURALS][BUT_DEFAULT])
		resources	= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_RESOURCES][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_RESOURCES][BUT_DEFAULT])
		if (archives != 'NONE'):	mainrib.write("Option \"searchpath\" \"string archive\" [ \""+archives+"\" ]\n")
		if (shaders == 'NONE'):		shaders = "."
		if (ShaderDir):						#If any custom shader directories specified stack them in shaders list also
			for directory in ShaderDir:
				if (directory[0] != '#'): shaders = shaders+":"+directory.replace(sys.sep, "/")
		if (shaders != "."):		mainrib.write("Option \"searchpath\" \"string shader\" [ \""+shaders+"\" ]\n")
		if (textures != 'NONE'):	mainrib.write("Option \"searchpath\" \"string texture\" [ \""+textures+"\" ]\n")
		if (displays != 'NONE'):	mainrib.write("Option \"searchpath\" \"string display\" [ \""+displays+"\" ]\n")
		if (procedurals != 'NONE'):	mainrib.write("Option \"searchpath\" \"string procedural\" [ \""+procedurals+"\" ]\n")
		if (resources != 'NONE'):	mainrib.write("Option \"searchpath\" \"string resource\" [ \""+resources+"\" ]\n")
		bucketsize		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_BUCKET][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_BUCKET][BUT_DEFAULT])
		gridsize		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_GRID][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_GRID][BUT_DEFAULT])
		eyesplits		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_EYES][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_EYES][BUT_DEFAULT])
		if (bucketsize > 0):	mainrib.write("Option \"limits\" \"int[2] bucketsize\" [ "+str(bucketsize)+" "+str(bucketsize)+" ]\n")
		if (gridsize > 0):	mainrib.write("Option \"limits\" \"int gridsize\" [ "+str(gridsize)+" ]\n")
		if (eyesplits > 0):	mainrib.write("Option \"limits\" \"int eyesplits\" [ "+str(eyesplits)+" ]\n")
		isHeaderCode		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_HEADER_CODE][BUT_PROP])
		if (isHeaderCode and isHeaderCode != 'NONE'): mainrib.writelines(ParseFragment(scene, "", isHeaderCode)) #Write any custom header code
		mainrib.close() #Go ahead and close file, any objects using RiInstance will be appended to file before each frame block is written so... header+RiInstances+frame1+RiInstances+frame2, ect...
		
		#### Main translation loop
		for frame in range(fraStart, fraEnd+1):			#Cycle through scene frames
			print "Exporting scene \""+scene.name+"\" frame "+str(frame)
			#Local Variables
			scene.render.currentFrame(frame)		#Set defined frame
			translationOrder	= [["Lights", "Inline Code", []], ["Objects", "Inline Code", []]] #Ordered object list for translation
			objectCount		= 0
			objectTotal		= 0
			progress		= 0
			DrawProgressBar(progress, "obj:"+str(objectCount)+"-"+str(objectTotal)+" fr:"+str(frame)+"-"+str(fraEnd))
			
			#### Get active camera
			if (Preview):	camera = ""
			else:		camera = scene.objects.camera
			
			#### Collect objects in scene into translationOrder array so we know proper render order and associations
			for Object in scene.objects:
				#Only pass object if it is in a visible layer
				if (not [True for objLayer in Object.layers if scene.getLayers().count(objLayer)]): continue
				objectType = Object.getType()		#Get object type
				if (objectType == "Lamp" and GetProperty(Object, "MOSAICData", GetProperty(scene, "MOSAICRIBset", Object.name+TypeString(Object), "", "", "DEFAULT"), ButtonData[LIGHTS][WIN_BUTS][LIGHT_SHADER][BUT_PROP]) != "NONE"):	#Assign light if using shader
					translationOrder[0][2].insert(0, Object) #Insert standard light at top of list
					objectTotal = objectTotal+1
				elif (objectType == "Curve" or objectType == "Mesh" or objectType == "Surf"):
					if (Object == camera): continue #If active camera is geometry don't draw it
					#If object has a arealight shader in any of its materials then assign object to the lights group
					for material in Object.getData(False, True).materials+Object.getMaterials():
						if (material and material != None):
							result = GetProperty(material, "MOSAICData", GetProperty(scene, "MOSAICRIBset", material.name+TypeString(material), "", "", "DEFAULT"), ButtonData[MATERIALS][WIN_BUTS][MAT_AREA][BUT_PROP])
							if (result and result != "NONE"):
								translationOrder[0][2].append(Object) #Insert area light at bottom of list
								objectTotal = objectTotal+1
								break	#No reason to look at anymore
					else:				#If this is not a arealight then separate geometry by any associated groups
						for group in [groups for groups in Blender.Group.Get() if GetProperty(scene, "MOSAICData", "DEFAULT", groups.name, ButtonData[GROUPS][WIN_BUTS][GRP_ARCH][BUT_PROP]) == "Attribute Block" and list(groups.objects).count(Object)]: #Pass groups with Object and archive type
							groupIndex	= [index for index, item in enumerate(translationOrder) if item[0] == group.name] #See if group already exists in list
							if (groupIndex): #If the group is already in list
								translationOrder[groupIndex[0]][2].append(Object) #Add object to group list
								objectTotal	= objectTotal+1
							else:		#If group does not exist in list
								translationOrder.append([group.name, "Attribute Block", [Object]]) #Create new group in list amd add object
								objectTotal	= objectTotal+1
							break		#Dont look for any other groups for this object
						else:			#If object is not in group
							translationOrder[1][2].append(Object) #Add object to non-group list
							objectTotal	= objectTotal+1
			
			#### Lets process the light list to resolve light handle numbers and illuminate states for normal, area, and dupli lights
			for light in lightList: light[3] = False	#Turn oll lights from previous frames and passes off
			for light in translationOrder[0][2]:		#Create a list of lights for light export and group exclusions
				instanceIndex	= 0			#Keep track of instance index
				parent		= light.getParent()	#Find parent object
				if (parent):	duplis = parent.DupObjects #If theres a parent see if it has duplis
				else:		duplis = [(light, [])]	#Otherwise just use current light
				for instance, matrix in duplis:
					if (instance == light):		#Only allow lamp objects as dupli instance
						if (instance.getType() == "Lamp" and instance.getData().getType() == 4): #If this is an area light then add ID's for light array
							areaSamples	= instance.getData().getRaySamplesX()*instance.getData().getRaySamplesY()
						else:	areaSamples	= 1
						for areaIndex in range(areaSamples):
							if (lightList.count([instance, instanceIndex, areaIndex, False])):
								lightList[lightList.index([instance, instanceIndex, areaIndex, False])][3] = True #Turn this scenes lights back on
							else:	lightList.append([instance, instanceIndex, areaIndex, True]) #If light didn't already exist then add new light
						instanceIndex += 1
			
			#### Build frame block
			frameCode = []
			if (RibFrames): frameCode.append("FrameBegin "+str(frame)+"\n")
			isHider		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_HIDER][BUT_PROP])
			isEmit		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_HIDER_EMIT][BUT_PROP])
			isJitter	= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_HIDER_JITTER][BUT_PROP])
			if (isHider):
				frameCode.append("\tHider \""+isHider+"\"")
				if (isEmit):	frameCode.append(" \"int emit\" [ "+str(isEmit)+" ]")
				if (isJitter):	frameCode.append(" \"int jitter\" [ "+str(isJitter)+" ]")
				frameCode.append("\n")
			isFraBeginCode	= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_BEGINFRAME_CODE][BUT_PROP])
			if (isFraBeginCode and isFraBeginCode != 'NONE'): frameCode.extend(ParseFragment(scene, "", isFraBeginCode, 1)) #Parse frames begin custom code
			## Insert display drivers
			displayList	= GetProperty(scene, "MOSAICData", scRIBset, "DisplayList", "", ButtonData[SCENES][WIN_BUTS][SCENE_ADD_DISPLAY][BUT_DEFAULT]).split("<DIVIDER>")
			for displayCode in displayList:
				if (RibComments or (not RibComments and displayCode[0] != '#')): frameCode.append(ParseTokens(scene, "", "\t"+displayCode+"\n"))
			isQuantize		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_QUANTIZE][BUT_PROP])
			if (isQuantize):	frameCode.append("\tQuantize "+isQuantize+"\n")
			isMaxdepth		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_MAXDEPTH][BUT_PROP])
			if (isMaxdepth):	frameCode.append("\tOption \"trace\" \"int maxdepth\" [ "+str(isMaxdepth)+" ]\n")
			isShadowbias		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_SHADOW_BIAS][BUT_PROP])
			if (isShadowbias):	frameCode.append("\tOption \"shadow\" \"float bias\" [ "+str(isShadowbias)+" ]\n")
			## Insert camera RIB
			frameCode.extend(RibifyObject(scene, camera, frame, 1, True, scRIBset))
			
			## Insert world block
			if (RibWorlds): frameCode.append("\tWorldBegin\n")
			isWorldCode			= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_BEGINWORLD_CODE][BUT_PROP])
			if (isWorldCode and isWorldCode != 'NONE'): frameCode.extend(ParseFragment(scene, "", isWorldCode, 2)) #Parse worlds begin custom code
			isMaxerror			= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_MAXERROR][BUT_PROP])
			if (isMaxerror):		frameCode.append("\t\tAttribute \"irradiance\" \"float maxerror\" [ "+str(isMaxerror)+" ]\n")
			isTracebias			= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_TRACE_BIAS][BUT_PROP])
			if (isTracebias):		frameCode.append("\t\tAttribute \"trace\" \"float bias\" [ "+str(isTracebias)+" ]\n")
			isPhotonmap			= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_GLOBALMAP][BUT_PROP])
			if (isPhotonmap):		frameCode.append("\t\tAttribute \"photon\" \"string globalmap\" \""+isPhotonmap+"\"\n")
			isCausticmap			= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_CAUSTICMAP][BUT_PROP])
			if (isCausticmap):		frameCode.append("\t\tAttribute \"photon\" \"string causticmap\" \""+isCausticmap+"\"\n")
			isSceneAtmoShader		= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_ATMO][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_ATMO][BUT_MENU][ButtonData[SCENES][WIN_BUTS][SCENE_ATMO][BUT_DEFAULT]])
			if (isSceneAtmoShader and isSceneAtmoShader != 'NONE'): frameCode.extend(AddTabs(RibifyShader(scene, "", isSceneAtmoShader), 2)) #Parse atmosphere shader
			for index, group in enumerate(translationOrder): #Cycle through object groups
				groupCode		= []
				isGroupCode		= GetProperty(scene, "MOSAICData", "DEFAULT", translationOrder[index][0], ButtonData[GROUPS][WIN_BUTS][GRP_BEGIN_CODE][BUT_PROP])
				if (isGroupCode and isGroupCode != 'NONE'): groupCode.extend(ParseFragment(scene, "", isGroupCode)) #Parse groups custom begin code
				isGrpAtmoShader		= GetProperty(scene, "MOSAICData", "DEFAULT", translationOrder[index][0], ButtonData[GROUPS][WIN_BUTS][GRP_ATMO][BUT_PROP])
				if (isGrpAtmoShader and isGrpAtmoShader != 'NONE'): groupCode.extend(RibifyShader(scene, "", isGrpAtmoShader)) #Parse atmosphere shader
				for groupObject in translationOrder[index][2]: #Cycle through all objects in current group
					objectCount	= objectCount+1
					progress	= (objectCount/float(objectTotal))-0.1
					DrawProgressBar(progress, "obj:"+str(objectCount)+"-"+str(objectTotal)+" fr:"+str(frame)+"-"+str(fraEnd))
					parent = groupObject
					while (parent.parent): parent = parent.parent #See if base parent object is using dupli's
					if (groupObject.getType() == "Lamp" or groupObject == parent or not parent.DupObjects): #If this is not a dupli root object unless its a lamp

						while QTest():		#Cycle through events looking for an esc
							if (ESCKEY in QRead()): #If user escaped
								killExport = True
						
						if (not Preview or (Preview and (groupObject.sel or groupObject.getType() == "Lamp"))): #If previewing only render selected objects and lights
							print "\tExporting Object: "+groupObject.name
							groupCode.extend(RibifyObject(scene, groupObject, frame, 0, False, scRIBset))
					
						if (killExport):	#If esc was hit then stop translation
							scene.render.currentFrame(originalFrame) #Reset scene and frame
							DrawProgressBar(0.0, "") #Reset progress bar
							DrawProgressBar(1.0, "") #Reset progress bar
							print "!!!Process Canceled!!!"
							return		#Stop translations
				if (index == 0):			#Build light RiIlluminate starts
					if (RibComments): groupCode.append("##Scene light illuminates\n")
					for lightIndex, light in enumerate(lightList):
						if (light[3]): groupCode.append("Illuminate "+str(lightIndex+1)+" 1\n")
				isGroupCode		= GetProperty(scene, "MOSAICData", "DEFAULT", translationOrder[index][0], ButtonData[GROUPS][WIN_BUTS][GRP_END_CODE][BUT_PROP])
				if (isGroupCode and isGroupCode != 'NONE'): groupCode.extend(ParseFragment(scene, "", isGroupCode)) #Parse groups custom end code
				frameCode.extend(RibifyInstance(scene, "", translationOrder[index][0], groupCode, frame, translationOrder[index][1], [], 2))
			isWorldCode			= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_ENDWORLD_CODE][BUT_PROP])
			if (isWorldCode and isWorldCode != 'NONE'): frameCode.extend(ParseFragment(scene, "", isWorldCode, 2)) #Parse worlds end custom code
			if (RibWorlds): frameCode.append("\tWorldEnd\n")
			isFraEndCode	= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_ENDFRAME_CODE][BUT_PROP])
			if (isFraEndCode and isFraEndCode != 'NONE'): frameCode.extend(ParseFragment(scene, "", isFraEndCode, 1)) #Parse frames end custom code
			MakeShadowMap	= GetProperty(scene, "MOSAICData", scRIBset, "MakeShadowMap", "", "").split("<DIVIDER>")
			if (MakeShadowMap and MakeShadowMap[0] and MakeShadowMap[1]): frameCode.append("\tMakeShadow "+" ".join([para for para in MakeShadowMap if para])+"\n")
			MakeLatLongMap	= GetProperty(scene, "MOSAICData", scRIBset, "MakeLatLongMap", "", "").split("<DIVIDER>")
			if (MakeLatLongMap and MakeLatLongMap[0] and MakeLatLongMap[1]): frameCode.append("\tMakeLatLongEnvironment "+" ".join([para for para in MakeLatLongMap if para])+"\n")
			MakeCubeMap	= GetProperty(scene, "MOSAICData", scRIBset, "MakeCubeMap", "", "").split("<DIVIDER>")
			if (MakeCubeMap and MakeCubeMap[0] and MakeCubeMap[1] and MakeCubeMap[2] and MakeCubeMap[3] and MakeCubeMap[4] and MakeCubeMap[5] and MakeCubeMap[6]): frameCode.append("\tMakeCubeFaceEnvironment "+" ".join([para for para in MakeCubeMap if para])+"\n")
			if (RibFrames): frameCode.append("FrameEnd\n")
			
			#Write this frames translations into archive or main RIB
			if (ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUTTON].val):	mainrib = gzip.open(RibOutput, 'ab')
			else:									mainrib = open(RibOutput, 'ab')
			if (Preview):	mainrib.writelines(frameCode) #If previewing write code straight into final main RIB
			else:		mainrib.writelines(RibifyInstance(scene, "Archives"+sys.sep+"Scenes"+sys.sep, "SB"+scRIBindex+scene.name, frameCode, frame, GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_FRAME_ARCH][BUT_PROP], "", ButtonData[SCENES][WIN_BUTS][SCENE_FRAME_ARCH][BUT_TITLE][ButtonData[SCENES][WIN_BUTS][SCENE_FRAME_ARCH][BUT_DEFAULT]]), [], 0, True)) #Add frame to rib
			mainrib.close()
		
		scene.render.currentFrame(originalFrame)		#Reset frame
	
	manualRender	= GetProperty(scene, "MOSAICData", scRIBset, ButtonData[SCENES][WIN_BUTS][SCENE_CUSTOM_RENDER][BUT_PROP]) #Get custom render call if available
	if (manualRender and manualRender.strip()): renderCall = manualRender #If theres a custom render make it active
	else: renderCall = RenderBin					#Otherwise use default render call
	if (renderCall.count("<RIB>")): renderCall = renderCall.replace("<RIB>", "\""+RibOutput+"\"") #Parse any calls to insert rib in render options
	else: renderCall = renderCall+" \""+RibOutput+"\""		#Otherwise just add rib to end of options
	
	return renderCall						#Return render call string so it can be used or stored


####################################################################### START GUI GLOBAL FUNCTIONS
#### Renders current scene in current frame
def RenderFrame():
	global ButtonData, killExport, RibExt
	killExport	= False
	scene		= Blender.Scene.GetCurrent()
	frame		= scene.render.currentFrame()
	Render		= ButtonData[ACTIONS][WIN_BUTS][ACT_RENDER_RIB][BUTTON].val
	Create		= ButtonData[ACTIONS][WIN_BUTS][ACT_CREATE_RIB][BUTTON].val
	Compile		= ButtonData[ACTIONS][WIN_BUTS][ACT_COMPILE_SL][BUTTON].val
	Export		= ButtonData[ACTIONS][WIN_BUTS][ACT_EXPORT_MAPS][BUTTON].val
	startTime	= time()
	
	print "\n===========================================\nExport starting at: "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
	if (not PrepareProject()):
		CleanupScenes()
		MakeDefaultShaders()					#Make sure we have valid default shaders and fragments!
		print "\n-------------------------------------------\nExporting current Scene and Current Frame\n-------------------------------------------\n"
		renderCall = RibifyScene(scene, frame, frame, scene.name+RibExt, False, Create) #Export current scene and frame
		print "\n-------------------------------------------\nProcessing Resources\n-------------------------------------------\n"
		ProcessResources(Compile, Export)			#Export and process shaders and textures
		print "\nExport complete at: "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
		print "Total export time:  "+str(time()-startTime)+" Seconds\n===========================================\n"
		if (Render and renderCall):
			startRender	= time()
			print "===========================================\nRender starting at:   "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower(), "\n-------------------------------------------"
			print "Rendering Frame With: "+renderCall
			os.system(renderCall)				#Lets render it!!!
			print "-------------------------------------------\nRender complete at:   "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
			print "Total render time:    "+str(time()-startTime)+" Seconds\n===========================================\n"


#### Renders current scene from sta to end
def RenderAnimation():
	global ButtonData, killExport, RibExt, instanceCount
	killExport	= False
	renderPassCalls	= []
	Render		= ButtonData[ACTIONS][WIN_BUTS][ACT_RENDER_RIB][BUTTON].val
	Create		= ButtonData[ACTIONS][WIN_BUTS][ACT_CREATE_RIB][BUTTON].val
	Compile		= ButtonData[ACTIONS][WIN_BUTS][ACT_COMPILE_SL][BUTTON].val
	Export		= ButtonData[ACTIONS][WIN_BUTS][ACT_EXPORT_MAPS][BUTTON].val
	userScene	= Blender.Scene.GetCurrent()			#Get current scene so we can return to it later
	startTime	= time()

	print "\n===========================================\nExport starting at: "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
	if (not PrepareProject()):					#If project folders are ready then process animation
		CleanupScenes()						#Reset scene properties before passes so data can be shared between passes
		MakeDefaultShaders()					#Make sure we have valid default shaders and fragments!
		passList		= BuildPassList(Blender.Scene.Get()[0])
		if (not passList or [True for Pass in passList if Pass[0] and Pass[1] != "NONE"] == []): passList = [[True, Blender.Scene.GetCurrent(), "", 0, 0]] #If no passes make current scene and frames as pass
		#PassData = [use pass, scene, ribset, start frame, end frame]
		for passIndex, passData in enumerate(passList):		#Cycle through passes and call export scene per pass
			if (passData[0] and passData[1] != "NONE"):	#If using none selection on pass then skip pass
				if (passData[2] == "RIBSETPASSES"):	#If using RIBset passes then collects RIBsets in scene
					if (not passData[1].properties.has_key("MOSAICData")): RIBsets = ["DEFAULT"]
					else:	RIBsets = [k for k, v in passData[1].properties["MOSAICData"].iteritems() if k != "DEFAULT"]
				else:					RIBsets = [passData[2]] #If not using RIBset passes then just pass RIBset through
				RIBsets.sort()				#Sort RIBset list so they are run in order
				for RIBset in RIBsets:			#Cycle through RIBset passes if used
					instanceCount	= 0		#Reset instance count on each pass
					passData[1].makeCurrent()	#Make renderpass scene current
					if (passData[3] == 0): passData[3] = passData[1].render.sFrame
					if (passData[4] == 0): passData[4] = passData[1].render.eFrame
					if (passData[3] > passData[4]): passData[4] = passData[3]
					print "\n-------------------------------------------\nExporing Pass: "+passData[1].name+"_"+RIBset+"_Pass"+str(passIndex)+"\n-------------------------------------------\n"
					renderPassCalls.append(RibifyScene(passData[1], passData[3], passData[4], passData[1].name+"_"+RIBset+"_Pass"+str(passIndex)+RibExt, False, Create, RIBset)) #Make RIBS and collect rendercalls
					if (killExport): break		#If killExport then stop RIBset passes
			if (killExport): break				#If killExport then stop scene passes
		
		print "\n-------------------------------------------\nProcessing Resources\n-------------------------------------------\n"
		ProcessResources(Compile, Export)			#Export and process shaders and textures
		print "\nExport complete at: "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
		print "Total export time:  "+str(time()-startTime)+" Seconds\n===========================================\n"
		userScene.makeCurrent()					#Return scene user was last on
		
		if (Render and renderPassCalls):			#If we are supposed to lets render passes!
			startRender	= time()
			print "===========================================\nRender starting at:   "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower(), "\n-------------------------------------------"
			for passIndex, renderCall in enumerate(renderPassCalls): #Cycle through render calls
				if (renderCall):			#Make sure theres an actual call
					print "Rendering Pass"+str(passIndex)+" With: "+renderCall
					os.system(renderCall)		#Lets render it!!!
				else:	print "Could not render Pass"+str(passIndex)+"!"
			print "-------------------------------------------\nRender complete at:   "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
			print "Total render time:    "+str(time()-startTime)+" Seconds\n===========================================\n"


#### Renders a preview from last 3d view
def RenderPreview():
	global ButtonData, killExport, RibExt
	killExport	= False
	scene		= Blender.Scene.GetCurrent()
	frame		= scene.render.currentFrame()
	Compile		= ButtonData[ACTIONS][WIN_BUTS][ACT_COMPILE_SL][BUTTON].val
	Export		= ButtonData[ACTIONS][WIN_BUTS][ACT_EXPORT_MAPS][BUTTON].val
	startTime	= time()
	
	print "\n===========================================\nExport starting at: "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
	if (not PrepareProject()):
		CleanupScenes()
		MakeDefaultShaders()					#Make sure we have valid default shaders and fragments!
		print "\n-------------------------------------------\nExporting selected objects for preview\n-------------------------------------------\n"
		renderCall = RibifyScene(scene, frame, frame, "ObjectPreview"+RibExt, True, True) #Export current scene and frame but use 3D view matrix
		print "\n-------------------------------------------\nProcessing Resources\n-------------------------------------------\n"
		ProcessResources(Compile, Export)			#Export and process shaders and textures
		print "\nExport complete at: "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
		print "Total export time:  "+str(time()-startTime)+" Seconds\n===========================================\n"
		if (renderCall):
			print "===========================================\nRender starting at:     "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower(), "\n-------------------------------------------"
			print "Rendering Preview With: "+renderCall
			os.system(renderCall)				#Lets render it!!!
			print "-------------------------------------------\nRender complete at:     "+strftime("%I:%M:%S%p %m/%d/%Y", localtime()).lower()
			print "Total render time:      "+str(time()-startTime)+" Seconds\n===========================================\n"


#### Utility for automatically generating a shader code fragment in blender from a compiled shader file or from shader name in environment variables from OS
#### Pass the name of the "shader" name must be a compiled and accessible shader file
def CreateShaderFrag(shader):
	global Tokens, Filters, DialogData, InfoBin, ShaderExt, ShaderDir, StandardTokens
	shaderTypes	= ["Surface", "Displacement", "Volume", "Imager", "Light"]
	paraClasses	= ["constant", "uniform", "varying"]
	paraTypes	= ["integer", "float", "color", "point", "vector", "normal", "matrix", "hpoint", "string"]
	paraDefaults	= ["[ 1 ]", "[ 1.0 ]", "[ 1 1 1 ]", "[ 0 0 0 ]", "[ 0 1 0 ]", "[ 0 1 0 ]", "[ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ]", "[ 1 0 0 0 ]", "[ \"\" ]"]
	fragmentName	= ""
	shaderName	= ""
	shaderType	= []
	shaderText	= []
	paraClass	= []
	paraType	= []
	paraIndex	= 0
	paraName	= ""
	paraDefault	= ""
	default		= False
	
	if (not InfoBin):
		ErrorPopup("Must set shader info binary under \"MOSAIC setting\" tab!")
		return
	
	if (shader):							#Only process if theres a shader name
		print "Creating shader fragment"
		OutputDir = GetProjectFolder()				#Get the project folder name so we can check it
		if (SetupDirectories(OutputDir)): return		#Setup output directories incase they aren't set yet
		os.chdir(OutputDir+"Cache")				#Make sure current directory is in projects "Cache" folder
		print "\tCleaning Cache Folder..."
		DelTree(OutputDir+"Cache")				#Be sure to clean cache so no ealier files exist
		
		if (sys.splitext(shader)[1] == Filters[1]):		#If set to source then compile shader before getting info
			for shaderInclude in [text for text in Blender.Text.Get() if text.name.count(Filters[7])]: #Cycle through all text files looking for includes
				ExportText(shaderInclude)		#Export all includes together
			try:
				if(CompileShader(Blender.Text.Get(shader))): #Try to get blender text file and compile it
					ErrorPopup("Could not export or compile shader, check console for details!")
					return
				compiledShader = ListTree(OutputDir+"Cache", [ShaderExt], True) #Get name of shader (should be the only compiled shader in directory) and strip extension
				if (compiledShader): shaderName = compiledShader[0]
				else:
					ErrorPopup("Could not compile shader, check console for details!")
					return
			except:
				ErrorPopup("Could not compile shader, check console for details!")
				return
		else:
			if (sys.splitext(shader)[1] == ShaderExt):	#Is this a compiled shader?
				for directory in ShaderDir:		#Cycle through all user specified directories
					if (ListTree(directory, [ShaderExt], True).count(shader)): os.chdir(directory) #Set first directory that has shader in it
			shaderName = shader
		
		shaderName = sys.splitext(shaderName)[0]		#Separate extension if used
		
		print "\tGetting Info For "+shaderName+"..."
		os.system(InfoBin+" \""+shaderName+"\">"+OutputDir+"Cache"+sys.sep+"shaderinfo") #Create a shaderinfo file from shader info binary output
		
		if (not sys.exists(OutputDir+"Cache"+sys.sep+"shaderinfo")): #Make sure shaderinfo was made
			ErrorPopup("Could not compile shader info, check console for details!")
			return
		shaderinfo = open(OutputDir+"Cache"+sys.sep+"shaderinfo", 'rb') #Open shaderinfo to processing
		for line in shaderinfo.readlines():
			if (line.strip()):				#If theres something in this line
				if (not shaderType):			#Make sure we determine shader type first
					shaderType	= [sType for sType in shaderTypes if line.lower().split()[0].count(sType.lower())] #See if first word of this line has the shader type and if so then set type accordingly
					if (shaderType):		#If type has been determined then lets create a shader fragment
						DialogData[DIALOG_FRAG_NAME][0][1].val = (Filters[shaderTypes.index(shaderType[0])+2]+shaderName)[0:21] #Show dialog to make fragment name defaults to filtertype+shadername
						result			= Blender.Draw.PupBlock("Shader Fragment Name", DialogData[DIALOG_FRAG_NAME])
						if (result > 0):	fragmentName = DialogData[DIALOG_FRAG_NAME][0][1].val
						else:			return #Leave if no name given
						if (shaderType[0] == shaderTypes[4]):
							result = PupMenu(CreateMenu("Select Light Shader Type", [""], -1, ["RiLightSource", "RiAreaLightSource"], [""], False)[0], 27) #Ask user to specify what light type to make
							if (result == 1):	shaderType = ["LightSource"]
							elif (result == 2):	shaderType = ["AreaLightSource"]
							else:			return #Leave if no selection
						elif (shaderType[0] == shaderTypes[2]):
							result = PupMenu(CreateMenu("Select Volume Shader Type", [""], -1, ["RiAtmosphere", "RiInterior", "RiExterior"], [""], False)[0], 27) #Ask user to specify what volume type to make
							if (result == 1):	shaderType = ["Atmosphere"]
							elif (result == 2):	shaderType = ["Interior"]
							elif (result == 3):	shaderType = ["Exterior"]
							else:			return #Leave if no selection
						try:
							shaderText = Blender.Text.Get(fragmentName)
							shaderText.clear()
						except:	shaderText = Blender.Text.New(fragmentName)
						shaderText.write("#No usage comments\n") #Write standard no comment line at top of file
						shaderText.write(shaderType[0]+" \""+shaderName+"\"")
						if (shaderType[0] == "LightSource" or shaderType[0] == "AreaLightSource"): shaderText.write(" <LightID_I>") #Add light ID token if this is a light
				elif (line.count("\"") == 4 and not line.count(":") and not line.count("=") and [True for foundType in paraTypes if line.count(foundType)]): #Assume if two sets of quotes and not : or = then this is the parameter line
					if (default):
						shaderText.write(paraDefaults[paraType[0][1]]+" #"+paraDefaults[paraType[0][1]]) #If we are on a new parameter without finding a default then make one
						default = False
					paraWords			= line.replace("\"", "").split() #Split separate words out of current line
					if (len(paraWords) >= 2): 	#Be sure theres enough words for valid parameters
						paraType		= [[paraWords[len(paraWords)-1], index] for index, pType in enumerate(paraTypes) if paraWords[len(paraWords)-1].lower().count(pType)] #Find this parameters type
						paraClass		= [paraWords[len(paraWords)-2] for pClass in paraClasses if paraWords[len(paraWords)-2].lower().count(pClass)] #Find this parameters class
						if (paraType):
							paraName	= line.split()[0].replace("\"", "")
							paraIndex	= paraType[0][1]
							shaderText.write("\n")
							shaderText.write("\t\"")
							if (paraClass): shaderText.write(paraClass[0]+" ")
							shaderText.write(paraType[0][0]+" ")
							shaderText.write(paraName+"\" ")
							default = True
							continue
				elif (default and line.count("Default value:")): #If default then look for default value
					paraDefault	= line.lower().split(":")[1].replace("{", "").replace("}", "").replace("[", "").replace("]", "").replace(",", "") #Make list of values
					if (paraIndex != 8 and paraDefault.count("\"")): paraDefault = paraDefault[paraDefault.rfind("\"")+1:] #If this is not a string type then strip any commented words out
					paraDefault	= "[ "+paraDefault.lstrip().rstrip()+" ]" #Strip and bracket for use
					paraToken	= [foundToken[1] for foundToken in StandardTokens if (paraType[0][0]+" "+paraName).count(foundToken[0])]
					if (paraToken):	shaderText.write(paraToken[0]+" #"+paraDefault)
					else:		shaderText.write(paraDefault+" #"+paraDefault)
					default = False
		shaderinfo.close()
		if (default): shaderText.write(paraDefaults[paraType[0][1]]+" #"+paraDefaults[paraType[0][1]]) #If we couldn't find the last default then make one
		if (not shaderType):
			ErrorPopup("Could not determine shader type, check console for details!")
			return ""		
		else:	print "Shader fragment "+fragmentName+" created"
		return fragmentName


#### Creates a popup menu with selections based on shader and parameter type and returns a token based on user selections
def CreateToken(shaderType, paraType, Default):
	global Tokens, Filters, DialogData
	paraTypes	= ["integer", "float", "color", "point", "vector", "normal", "matrix", "hpoint", "string"]
	shaderType	= shaderType.strip()
	paraType	= paraType.strip()
	if (shaderType and paraType):
		if (paraType == 'NONE'):
			paraType	= "integer"
			paraIndex	= 0
		else:
			try:	paraIndex = paraTypes.index(paraType)
			except:	return ""
		if (shaderType == "LightSource"):									tokenIndex = 0
		elif (shaderType == "Surface" or shaderType == "Displacement" or shaderType == "AreaLightSource"):	tokenIndex = 1
		elif (shaderType == "Imager"):										tokenIndex = 2
		else:													tokenIndex = 4
		tokenMenu	= CreateMenu("Select Token", [""], -1, Tokens[tokenIndex][paraIndex]+Tokens[3][paraIndex], ['Shader Default'], True) #Make token selection menu
		tokenResult	= PupMenu(tokenMenu[0], 27)
		if (tokenResult > 0):
			paraDefault = tokenMenu[tokenResult]
			if (tokenResult == 1): return Default
			if (not paraDefault.count('#')): #If this is not a frame token...
				if (paraDefault.count("_X")): #Show texture channel selection menu if using "_X" in token
					texResult = PupMenu("Select texture slot:%t|First Available|Slot 1|Slot 2|Slot 3|Slot 4|Slot 5|Slot 6|Slot 7|Slot 8|Slot 9|Slot 10|First ColMap|First NorMap|First CspMap|First CmirMap|First RefMap|First SpecMap|First AmbMap|First HardMap|First RayMirMap|First AlphaMap|First EmitMap|First TransLuMap|First DispMap", 27)-1
					if (texResult < 0): texResult = 0 #Assume default if no selection
					paraDefault = paraDefault+str(texResult)
				if (paraIndex < 2): #If this is a integer or float call the range adjust dialog
					rangeIndex = [index for index, item in enumerate(StandardRanges) if item[0] == paraDefault] #See if there are some pre-defined ranges for this control...
					if (rangeIndex): #If so then apply them as default to the range dialog
						DialogData[DIALOG_RANGE_ADJ][0][1].val = StandardRanges[rangeIndex[0]][2]
						DialogData[DIALOG_RANGE_ADJ][1][1].val = StandardRanges[rangeIndex[0]][1]
					else:
						DialogData[DIALOG_RANGE_ADJ][0][1].val = "1.0"
						DialogData[DIALOG_RANGE_ADJ][1][1].val = "0.0"
					stringResult		= Blender.Draw.PupBlock("Adjust control value range", DialogData[DIALOG_RANGE_ADJ])
					paraDefault		= paraDefault+"_M"+str(DialogData[DIALOG_RANGE_ADJ][0][1].val)+"_A"+str(DialogData[DIALOG_RANGE_ADJ][1][1].val)
				paraDefault = paraDefault+"_"+paraTypes[paraIndex][0].upper() #Add type to token
			return "<"+paraDefault+">" #Close out the token to return
	return ""


#### Show script help
def ShowHelp(script = "mosaic.py"):
	Blender.ShowHelp(script)


#### Callback function for render directory selection
def RenderDirCallback(filename):
	global RenderDir, ButtonData
	RenderDir = filename.rstrip()
	ButtonData[SETTINGS][WIN_BUTS][SET_OUTPUT_DIR][BUT_TIP] = "Export Directory: "+RenderDir
	UpdateRegistry()


#### Callback function for render directory selection
def ShaderDirCallback(filename):
	global ShaderDir
	if (type(ShaderDir) == list):	ShaderDir.append(filename.rstrip())
	elif (type(ShaderDir) == str):	ShaderDir = [ShaderDir, filename.rstrip()]
	else:				ShaderDir = [filename.rstrip()]
	UpdateRegistry()
	BuildPathsButtons()


#### Find and select object with Name and make active
def SelectObject(Name=""):
	scene = Blender.Scene.GetCurrent()
	object = [item for item in scene.objects if item.name == Name]
	object[0].select(True)
	scene.objects.selected = object


#### Checks to make sure IDproperty root groups exist, if not then it makes the default one
def CheckRootProps(object):
	currentScene = Blender.Scene.GetCurrent()
	if (not currentScene.properties.has_key("MOSAICRIBset")): currentScene.properties["MOSAICRIBset"] = {}
	if (not object.properties.has_key("MOSAICData")): object.properties["MOSAICData"] = {}
	if (not object.properties["MOSAICData"].has_key("DEFAULT")): object.properties["MOSAICData"]["DEFAULT"] = {}


#### Uses a dialog to create a new user defined RIBset from passed object and menu indices
def CreateSet(object, ArrayIndex, ArrayItem, CreateMenuType):
	result		= Blender.Draw.PupBlock("Type name of new RIBset", DialogData[DIALOG_CREATE_RIBSET]) #Show dialog
	newRIBset	= DialogData[DIALOG_CREATE_RIBSET][0][1].val			#Collect result
	if (result > 0 and newRIBset):					# Make sure something was entered
		if (object.properties["MOSAICData"].has_key(newRIBset)): 	del object.properties["MOSAICData"][newRIBset] #Delete key if it already exists
		currentRIBset = ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUTTON].val]
		if (object.properties["MOSAICData"].has_key(currentRIBset)):	object.properties["MOSAICData"][newRIBset] = object.properties["MOSAICData"][currentRIBset].convert_to_pyobject() #If current RIBset exist then make the new one as a copy
		else:								object.properties["MOSAICData"][newRIBset] = {} #Otherwise make a blank default RIBset
		ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUT_MENU]		= CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUT_PROP], [""], CreateMenuType, [], ["DEFAULT"]) #Create new menu for list button
		ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUTTON].val		= ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUT_MENU].index(newRIBset) #Go ahead and select new key
		SetRIBset(ArrayIndex, object)				#Save new RIBset setting to scene
		UpdateMenuData(ArrayIndex)				#Make sure menus are updated with new selection
		DialogData[DIALOG_CREATE_RIBSET][0][1].val = ""				#Reset dialog for next time


#### Deletes specified RIBset sub key from passed object
def DeleteSet(object, ArrayIndex, ArrayItem):
	if (PupMenu("Really delete this set?%t|Yes|No") == 1):
		del object.properties["MOSAICData"][ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUTTON].val]]
		ButtonData[ArrayIndex][WIN_BUTS][ArrayItem][BUTTON].val = 1
		CheckRootProps(object)
		SetRIBset(ArrayIndex, object)
		UpdateMenuData(ArrayIndex)


#### Saves passed objects selected RIBset to current scene
def SetRIBset(ArrayIndex, selection):
	global ButtonData
	if (not selection): return
	Blender.Scene.GetCurrent().properties["MOSAICRIBset"][selection.name+TypeString(selection)] = ButtonData[ArrayIndex][WIN_BUTS][1][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][1][BUTTON].val]


#### Set ID Properties in ArrayIndex of ButtonData array to object selected in first menu item of choosen subwindow using the RIBset in second menu item
def SetProperties(ArrayIndex, selection):
	global ButtonData
	if (not selection): return
	for index, item in enumerate(ButtonData[ArrayIndex][WIN_BUTS][2:]): #Cycle through all settings under this subwindow and assign there values to an ID property of selected object
		if (ButtonData[ArrayIndex][WIN_BUTS][index+2][BUTTON] and ButtonData[ArrayIndex][WIN_BUTS][index+2][BUT_PROP]): #Make sure button is created and its property has name
			RIBset	= ButtonData[ArrayIndex][WIN_BUTS][1][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][1][BUTTON].val]
			if (ButtonData[ArrayIndex][WIN_BUTS][index+2][BUT_TYPE] == 1): #If this is a list menu and menu has been created then find selection from menu
				if (ButtonData[ArrayIndex][WIN_BUTS][index+2][BUT_MENU]): #Is there even a menu in this list
					selection.properties["MOSAICData"][RIBset][ButtonData[ArrayIndex][WIN_BUTS][index+2][BUT_PROP]] = ButtonData[ArrayIndex][WIN_BUTS][index+2][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][index+2][BUTTON].val] #Write control value to property
			else:						#Otherwise then pass value straight through
				selection.properties["MOSAICData"][RIBset][ButtonData[ArrayIndex][WIN_BUTS][index+2][BUT_PROP]] = ButtonData[ArrayIndex][WIN_BUTS][index+2][BUTTON].val


#### Sets or Creates PropName on all project scenes to value, this makes this property avaible globally
def SetGlobalProp(PropName, value):
	if (PropName):
		for scene in Blender.Scene.Get():
			if (not scene.properties.has_key("MOSAICProject")): scene.properties["MOSAICProject"] = {}
			scene.properties["MOSAICProject"][PropName] = value


#### copies first project global properties found to any scene that doesn't have them
def DistributeGlobals():
	property = ""
	for scene in Blender.Scene.Get():
		if (scene.properties.has_key("MOSAICProject")):
			property = scene.properties["MOSAICProject"].convert_to_pyobject()
			break
	if (property):
		for scene in Blender.Scene.Get():
			if (not scene.properties.has_key("MOSAICProject")):
				scene.properties["MOSAICProject"] = property


#### Update selected sub-window ButtonData values based on current selections and attached object data (also handles object validation, and button/subwindow collapse states)
def UpdateMenuData(ArrayIndex):
	global ButtonData, Filters
	selection = ""
	
	if (ButtonData[ArrayIndex]):
		ArrayItem = ButtonData[ArrayIndex]
		#Figure Buttons
		for index, item in enumerate(ButtonData[ArrayIndex][WIN_BUTS]):
			if (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_SHOW] == True): #Is button set to show
				if (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 1): #If this is supposed to be a list menu...
					#Get old menu information to extract string selection and compare to current selection
					OldMenu = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU]
					MenuIndex = ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val
					
					MakeDefaultShaders()				#Make sure we have valid default shaders and fragments!
					#Create or pass menu based on title selection
					if (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "CodeF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [Filters[0]], 0, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "SourceF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [Filters[1]], 0, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "SurfaceF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [Filters[2]], 0, [], ["ss_MOSAICsurface", "NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "DisplacementF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [Filters[3]], 0, [], ["ds_MOSAICdisplace", "NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "VolumeF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [Filters[4]], 0, [], ["vs_MOSAICfog", "NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "ImageF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [Filters[5]], 0, [], ["is_MOSAICbackground", "NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "LightF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [Filters[6]], 0, [], ["ls_MOSAIClight", "NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "SceneF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 1, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "CameraF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 2, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "GroupF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 3, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "GeometryF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 4, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "LampF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 5, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "MaterialF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 6, [], ["NONE"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "SceneSetF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 7, [], ["DEFAULT"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "CameraSetF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 8, [], ["DEFAULT"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "GeoSetF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 9, [], ["DEFAULT"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "LampSetF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 10, [], ["DEFAULT"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "MaterialSetF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], [""], 11, [], ["DEFAULT"])
					elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE] == "ShadersF"): ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = CreateMenu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], Filters[2:7], 0, [], ["NONE"])
					else: ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU] = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE]
					
					#If previous menu hasnt been initialized then initialize it!
					if (len(OldMenu) == 0): OldMenu = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU]
					
					if (OldMenu != ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU]): #If the old and new menus dont match then we need to correct the selections index
						try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU].index(OldMenu[MenuIndex]) #Find the buttons selection in new menu
						except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If old selection cant be found assume its been deleted and reset menu to default
					
					if (index == 0 and ArrayIndex > 3): #If the first button in sub is a menu and set to NONE then hide all options below button in subwindow
						if (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val] == "NONE"):
							for index2, item2 in enumerate(ButtonData[ArrayIndex][WIN_BUTS][1:]): ButtonData[ArrayIndex][WIN_BUTS][index2+1][BUT_SHOW] = False
						else:		#If this is the first button and not NONE then unhide all following buttons in sub and select object pointed too
							for index2, item2 in enumerate(ButtonData[ArrayIndex][WIN_BUTS][1:]): ButtonData[ArrayIndex][WIN_BUTS][index2+1][BUT_SHOW] = True
							#Select object based on subwindow type
							if (ArrayIndex == SCENES or ArrayIndex == GROUPS): selection = Blender.Scene.Get(ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUT_MENU][ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUTTON].val]) #Scene selction
							elif (ArrayIndex == MATERIALS): selection = Blender.Material.Get(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val]) #Material Selection
							else: selection = Blender.Object.Get(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val]) #Object Selection
					else:			#If this is not the first button get property from object into menu
						if (ArrayIndex == PROJECT): #If this is a project tab control
							try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = Blender.Scene.Get()[0].properties["MOSAICProject"][ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP]] #Pass value straight through
							except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If no property then set button to default
						elif (ArrayIndex == GROUPS): #If this is a subgroup extraction
							try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU].index(selection.properties["MOSAICData"]["DEFAULT"][ButtonData[ArrayIndex][WIN_BUTS][0][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][0][BUTTON].val]][ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP]])
							except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If no property then set button to default
						elif ((ArrayIndex == SCENES or ArrayIndex == CAMERAS or ArrayIndex == GEOMETRY or ArrayIndex == LIGHTS or ArrayIndex == MATERIALS) and index == 1): #If this is the second button of certain tabs then its a RIBset list
							currentScene = Blender.Scene.GetCurrent()
							try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU].index(currentScene.properties["MOSAICRIBset"][selection.name+TypeString(selection)])
							except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If no property then set button to default
							RIBset = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val] #Setup RIBset for any other control that may need it
						else:		#If this is NOT a subgroup extraction or a RIBset list...
							#If theres a selection and it has a property and that property name is in menu then return the index back to menu as new selection for current selection
							try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU].index(selection.properties["MOSAICData"][RIBset][ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP]])
							except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If no property then set button to default
				elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] > 4): continue #If this is a graphic then skip
				elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] != 0):#If this is not a list menu then...
					if (ArrayIndex == PROJECT):
						try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = Blender.Scene.Get()[0].properties["MOSAICProject"][ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP]] #Pass value straight through
						except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If no property then set button to default
					elif (ArrayIndex == GROUPS): #If this is a subgroup extraction
						try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = selection.properties["MOSAICData"]["DEFAULT"][ButtonData[ArrayIndex][WIN_BUTS][0][BUT_MENU][ButtonData[ArrayIndex][WIN_BUTS][0][BUTTON].val]][ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP]]
						except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If no property then set button to default
					else:			#If this is NOT a subgroup extraction
						try: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = selection.properties["MOSAICData"][RIBset][ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP]] #Pass value straight through
						except: ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val = ButtonData[ArrayIndex][WIN_BUTS][index][BUT_DEFAULT] #If no property then set button to default


#### Draws a fancy titled subframe, return the final height of the window (uses global ButtonData draw windows and buttons)
def SubFrame(x = 0, y = 100, width = 100, ArrayIndex = 0): #ArrayIndex is the index in ButtonData to the sub-window to draw in ButtonData array
	global ButtonData, MousePos
	TitleHeight	= 15
	TextOffset	= TitleHeight/2+4
	Bevel		= 6
	ArrowSize	= 4
	WindowGap	= 6
	LineGap		= 15
	PosInc		= y
	
	#Grab colors applied to standard areas of Blender so interface looks built in
	TitleColor	= Theme.Get()[0].get('BUTS').header		#Color of menu title
	TextColor	= Theme.Get()[0].get('BUTS').text_hi		#Color of submenu text
	TextColor2	= Theme.Get()[0].get('ui').menu_text		#Color of menu text
	TabColor	= [TitleColor[0]/4*3, TitleColor[1]/4*3, TitleColor[2]/4*3] #Color of System submenu tabs
	BackColor	= Theme.Get()[0].get('BUTS').panel		#Color of System submenu backgrounds
	
	#Collapse button if left mouse click in title subWindow title area
	if (MousePos[0] > x and MousePos[0] < x+width and MousePos[1] > y-TitleHeight and MousePos[1] < y):
		ButtonData[ArrayIndex][WIN_COLLAPSE] = not ButtonData[ArrayIndex][WIN_COLLAPSE]
	
	#Make sure menu data is revised for visible subs
	if (not ButtonData[ArrayIndex][WIN_COLLAPSE]): UpdateMenuData(ArrayIndex)
	
	BeginAlign()
	#Draw Tab
	glColor3f(TabColor[0]/256.0*ButtonData[ArrayIndex][WIN_COLOR][0], TabColor[1]/256.0*ButtonData[ArrayIndex][WIN_COLOR][1], TabColor[2]/256.0*ButtonData[ArrayIndex][WIN_COLOR][2])
	glBegin(GL_POLYGON)
	glVertex2i(x, y-TitleHeight+Bevel)
	glVertex2i(x, y-Bevel)
	glVertex2i(x+Bevel/3, y-Bevel/3)
	glVertex2i(x+Bevel, y)
	glVertex2i(x+width-Bevel, y)
	glVertex2i(x+width-Bevel/3, y-Bevel/3)
	glVertex2i(x+width, y-Bevel)
	if (ButtonData[ArrayIndex][WIN_COLLAPSE]):			#Change titles bottom radius effect based on collapse state
		glVertex2i(x+width-Bevel/3, y-TitleHeight+Bevel/3)
		glVertex2i(x+width-Bevel, y-TitleHeight)
		glVertex2i(x+Bevel, y-TitleHeight)
		glVertex2i(x+Bevel/3, y-TitleHeight+Bevel/3)
	else:
		glVertex2i(x+width, y-TitleHeight)
		glVertex2i(x, y-TitleHeight)
	glEnd()
		
	PosInc		= PosInc-TitleHeight
	ButX		= x+WindowGap
	
	if (not ButtonData[ArrayIndex][WIN_COLLAPSE]):			#Draw Buttons and Background according to Collapse state
		
		#Draw BackGround Top
		glEnable(GL_BLEND)
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
		glColor4f(BackColor[0]/256.0*ButtonData[ArrayIndex][WIN_COLOR][0], BackColor[1]/256.0*ButtonData[ArrayIndex][WIN_COLOR][1], BackColor[2]/256.0*ButtonData[ArrayIndex][WIN_COLOR][2], BackColor[WIN_COLOR]/256.0*ButtonData[ArrayIndex][WIN_COLOR][3])
		glRecti(x, PosInc, x+width, PosInc-WindowGap)
		glDisable(GL_BLEND)
		
		PosInc = PosInc-WindowGap
				
		#Draw Buttons
		for index, item in enumerate(ButtonData[ArrayIndex][WIN_BUTS]):
			if (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_SHOW] == True):	#Is button set to show
				
				Trigger		= ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TRIGGER] #Are there any special triggers on this button
				Divider		= ButtonData[ArrayIndex][WIN_BUTS][index][BUT_WIDTH_DIV] #Get width ratio for this button
				ButWidth	= int((width-WindowGap*2)*Divider) #Figure button with divider as percent of window width
				if (Divider > 1.0 and Divider < 100.0): ButWidth = int(Divider) #If over 1.0 then use as actual width instead of percent
				if (Divider == 100.0): ButWidth = int(x+width-WindowGap-ButX) #If last button set to tab width
				
				if (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 5): #If this is a line
					if (Trigger):	ButtonHeight = LineGap
					else:		ButtonHeight = WindowGap
				else:								ButtonHeight = 18 #Otherwise this is a button
				
				if (ButX == x+WindowGap):
					#Draw Button BackGround
					glEnable(GL_BLEND)
					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
					glColor4f(BackColor[0]/256.0*ButtonData[ArrayIndex][WIN_COLOR][0], BackColor[1]/256.0*ButtonData[ArrayIndex][WIN_COLOR][1], BackColor[2]/256.0*ButtonData[ArrayIndex][WIN_COLOR][2], BackColor[3]/256.0*ButtonData[ArrayIndex][WIN_COLOR][3])
					glRecti(x, PosInc, x+width, PosInc-ButtonHeight)
					glDisable(GL_BLEND)
					PosInc = PosInc-ButtonHeight
				
				if (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 0): #If this is supposed to be a button...
					ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON] = PushButton(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE], ButtonData[ArrayIndex][WIN_EVENT]+index, ButX, PosInc, ButWidth, ButtonHeight, ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TIP])
				
				elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 1): #If this is supposed to be a list menu...
					#Draw menu description
					glColor3f(TextColor2[0]/256.0, TextColor2[1]/256.0, TextColor2[2]/256.0)
					glRasterPos2d(ButX, PosInc+5)
					if (Trigger):
						Text(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_PROP], 'normal')
						ButX = ButX+Trigger
						ButWidth = ButWidth-Trigger
					#Draw Menu
					ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON] = Menu(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MENU][0], ButtonData[ArrayIndex][WIN_EVENT]+index, ButX, PosInc, ButWidth, ButtonHeight, ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val, ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TIP])
				
				elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 2): #If this is supposed to be a number button...
					ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON] = Number(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE], ButtonData[ArrayIndex][WIN_EVENT]+index, ButX, PosInc, ButWidth, ButtonHeight, ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val, ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MIN], ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MAX], ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TIP])
					
				elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 3): #If this is supposed to be a toggle button...
					ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON] = Toggle(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE], ButtonData[ArrayIndex][WIN_EVENT]+index, ButX, PosInc, ButWidth, ButtonHeight, ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val, ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TIP])
					
				elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 4): #If this is supposed to be a string button...
					if (Trigger):			#If text is all on one line separate description, otherwise show in text
						#Draw text description
						glColor3f(TextColor2[0]/256.0, TextColor2[1]/256.0, TextColor2[2]/256.0)
						glRasterPos2d(ButX, PosInc+5)
						Text(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE], 'normal')
						ButX = ButX+Trigger
						ButWidth = ButWidth-Trigger
						ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON] = String("", ButtonData[ArrayIndex][WIN_EVENT]+index, ButX, PosInc, ButWidth, ButtonHeight, ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val, ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MAX], ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TIP])
					else:
						ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON] = String(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE], ButtonData[ArrayIndex][WIN_EVENT]+index, ButX, PosInc, ButWidth, ButtonHeight, ButtonData[ArrayIndex][WIN_BUTS][index][BUTTON].val, ButtonData[ArrayIndex][WIN_BUTS][index][BUT_MAX], ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TIP])
				elif (ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TYPE] == 5): #If this is supposed to be a line...
					EndAlign()
					if (Trigger):			#Only draw line if trigger is set
						glColor3f(TabColor[0]/256.0*ButtonData[ArrayIndex][WIN_COLOR][0], TabColor[1]/256.0*ButtonData[ArrayIndex][WIN_COLOR][1], TabColor[2]/256.0*ButtonData[ArrayIndex][WIN_COLOR][2])
						endGap = 5
						glLineWidth(1)
						glBegin(GL_LINES)
						glVertex2i(x+endGap, PosInc+2)
						glVertex2i(x+width-endGap, PosInc+2)
						glEnd()
						glRasterPos2d(x+WindowGap, PosInc+4)
						Text(ButtonData[ArrayIndex][WIN_BUTS][index][BUT_TITLE], 'small')
					BeginAlign()
				
				if (Divider == 100.0):	ButX = x+WindowGap #If this is the last button...
				else:			ButX = ButX+ButWidth #Otherwise set next button to the end of last
		
		#Draw BackGround Bottom
		glEnable(GL_BLEND)
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
		glColor4f(BackColor[0]/256.0*ButtonData[ArrayIndex][WIN_COLOR][0], BackColor[1]/256.0*ButtonData[ArrayIndex][WIN_COLOR][1], BackColor[2]/256.0*ButtonData[ArrayIndex][WIN_COLOR][2], BackColor[3]/256.0*ButtonData[ArrayIndex][WIN_COLOR][3])
		glRecti(x, PosInc, x+width, PosInc-WindowGap)
		glDisable(GL_BLEND)
		
		PosInc = PosInc-WindowGap
	
	glColor3f(TextColor[0]/256.0, TextColor[1]/256.0, TextColor[2]/256.0)
	#Draw Arrow (rotate 90deg according to collapse boolean state)
	glPushMatrix()
	glTranslated(x+3*4, y-TitleHeight/2-1, 0)
	glRotated(-90*ButtonData[ArrayIndex][WIN_COLLAPSE], 0, 0, -1)
	glBegin(GL_POLYGON)
	glVertex2i(0, -ArrowSize)
	glVertex2i(-ArrowSize, ArrowSize)
	glVertex2i(ArrowSize, ArrowSize)
	glEnd()
	glPopMatrix()
	
	#Draw Tab Text
	glRasterPos2d(x+4*6, y-TextOffset)
	Text(ButtonData[ArrayIndex][WIN_TITLE], 'small')
	EndAlign()
	return y-PosInc							#Return the final height of sub-window


#### Main drawing routine
def draw():
	global EVENT_NONE, RenderDir, RenderBin, ScrollPos, ScrollState, ButtonData, LastScene, LastObject, LastMaterial
	
	if (not ButtonData[UTILITIES][WIN_COLLAPSE] and ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] > 1): #If utilities is showing and a fragment is selected make sure it still exists
		try:	Blender.Text.Get(ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUTTON].val])
		except:
			ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] = 1
			BuildParamButtons("")
	
	#Make sure current scene is updated if changed
	CurrentScene = Blender.Scene.GetCurrent()
	if (CurrentScene and CurrentScene.name != LastScene):
		DistributeGlobals()
		BuildPassesButtons(Blender.Scene.Get()[0])
		ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUT_MENU]	= CreateMenu(ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUT_PROP], [""], 1, [], [""]) #Create a new menu array from current scene
		ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUTTON].val	= ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUT_MENU].index(CurrentScene.name) #Pass index number of current scene to button
		UpdateMenuData(SCENES)
		BuildDisplaysButtons(CurrentScene)
		if (LastScene):
			CheckRootProps(CurrentScene)			#Make sure root groups are set
			SetProperties(SCENES, CurrentScene)		#Make sure properties are set
		LastScene = CurrentScene.name				#Update last selection
	
	#Make sure current active object is updated if changed
	CurrentObject = CurrentScene.objects.active
	if (CurrentObject and CurrentObject.name != LastObject):
		TypeIndex = 0
		ObjectType = CurrentObject.getType()			#Get object type
		if (ObjectType == "Mesh" or ObjectType == "Curve" or ObjectType == "Surf"): SubIndex = GEOMETRY; TypeIndex = 4
		elif (ObjectType == "Lamp"): SubIndex = LIGHTS; TypeIndex = 5
		elif (ObjectType == "Camera"): SubIndex = CAMERAS; TypeIndex = 2
		if (TypeIndex != 0):
			ButtonData[SubIndex][WIN_BUTS][0][BUT_MENU]	= CreateMenu(ButtonData[SubIndex][WIN_BUTS][0][BUT_PROP], [""], TypeIndex, [], [""]) #Create a new menu array from current selection
			ButtonData[SubIndex][WIN_BUTS][0][BUTTON].val	= ButtonData[SubIndex][WIN_BUTS][0][BUT_MENU].index(CurrentObject.name) #Pass index number of current proper button
			UpdateMenuData(SubIndex)
			if (LastObject):
				CheckRootProps(CurrentObject)		#Make sure root groups are set
				SetProperties(SubIndex, CurrentObject)	#Make sure properties are set
		LastObject = CurrentObject.name				#Update last selection
	
	#Make sure current material is updated if changed
	try:
		CurrentMaterial			= CurrentObject.getMaterials(1)[CurrentObject.activeMaterial-1]
		if (CurrentMaterial == None):	CurrentMaterial = CurrentObject.getData(False, True).materials[CurrentObject.activeMaterial-1]
	except:	CurrentMaterial = ""
	if (CurrentMaterial and CurrentMaterial.name != LastMaterial):
		ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUT_MENU]	= CreateMenu(ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUT_PROP], [""], 6, [], [""]) #Create a new menu array from current material
		ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUTTON].val	= ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUT_MENU].index(CurrentMaterial.name) #Pass index number of current material to button
		UpdateMenuData(MATERIALS)
		if (LastMaterial):
			CheckRootProps(CurrentMaterial)			#Make sure root groups are set
			SetProperties(MATERIALS, CurrentMaterial)	#Make sure properties are set
		LastMaterial = CurrentMaterial.name			#Update last selection
	
	#Local variables
	TitleColor		= Theme.Get()[0].get('BUTS').header	#Color of menu title
	BackColor		= Theme.Get()[0].get('BUTS').back	#Color of menu background
	TextColor		= Theme.Get()[0].get('ui').menu_text	#Color of menu text
	ScrollState		= 0
	AreaDims		= GetAreaSize()				#Get AreaSize for widget placement
	SubPosYInc		= AreaDims[1]+ScrollPos			#Increment by ScrollPos	
	TitleHeight		= 28					#Height of top title bar
	WindowGap		= 6					#Distance between and around sub-windows
	SubPosXInc		= WindowGap
	SubPosYStart		= SubPosYInc-TitleHeight-WindowGap
	SubMinimum		= 300
	if (AreaDims[0] < SubMinimum): SubWidth = AreaDims[0]
	else: SubWidth = AreaDims[0]/int(AreaDims[0]/SubMinimum)
	
	#Clear background
	glClearColor(BackColor[0]/256.0, BackColor[1]/256.0, BackColor[2]/256.0, 1.0)
	glClear(GL_COLOR_BUFFER_BIT)
	
	#Draw Title
	glColor3f(TitleColor[0]/256.0, TitleColor[1]/256.0, TitleColor[2]/256.0)
	glRecti(0, SubPosYInc, AreaDims[0], SubPosYInc-TitleHeight)
	glColor3f(TextColor[0]/256.0, TextColor[1]/256.0, TextColor[2]/256.0)
	glRasterPos2d(10, SubPosYInc-TitleHeight/2-4)
	Text("MOSAIC "+__version__+" RenderMan(R) System")
	SubPosYInc = SubPosYStart
	
	#Draw Subwindows from ButtonData array
	for index, item in enumerate(ButtonData):			#Cycle through all subwindows in ButtonData array
		SubPosYInc = SubPosYInc - SubFrame(SubPosXInc, SubPosYInc, SubWidth-WindowGap*2, index) - WindowGap	#Draw SubWindow
		if (SubPosYInc-ScrollPos-TitleHeight < 0):
			if (ScrollState > SubPosYInc):			#Stop scrolling at last subwindow
				ScrollState = SubPosYInc
			if (SubPosXInc+SubWidth <= AreaDims[0]):	#If area wide stack subwindows from left to right otherwise top down
				SubPosYInc = SubPosYStart
				SubPosXInc = SubPosXInc+SubWidth
	
	#Show scroll down message at bottom if menu is past available area
	if (ScrollState < 0 and ScrollPos == 0 ):
		Toggle("use mouse wheel or arrows to scroll", EVENT_NONE, -5, 0, AreaDims[0]+10, 18, 0)


#### Standard event handler
def event(evt, val):
	global MousePos, ScrollPos, ScrollState, ButtonData, LastObject, LastScene, LastMaterial
	ScrollInc = 25
	
	#Manage GUI events
	if (evt == WHEELDOWNMOUSE):					#Scroll area down
		if (ScrollState < 0):
			ScrollPos = ScrollPos+ScrollInc
		Draw()
	elif (evt == WHEELUPMOUSE):					#Scroll area up
		if (ScrollPos > 0):
			ScrollPos = ScrollPos-ScrollInc
		else: ScrollPos = 0
		Draw()
	if (evt == DOWNARROWKEY):					#Scroll area down
		if (ScrollState < 0):
			ScrollPos = ScrollPos+ScrollInc
		Draw()
	elif (evt == UPARROWKEY):					#Scroll area up
		if (ScrollPos > 0):
			ScrollPos = ScrollPos-ScrollInc
		else: ScrollPos = 0
		Draw()
	elif (evt == LEFTMOUSE and val):				#Calculate mouse position in this area
		areaVert =  [item['vertices'] for item in GetScreenInfo() if item['id'] == GetAreaID()]
		MouseCor = GetMouseCoords()
		MousePos[0] = MouseCor[0]-areaVert[0][0]
		MousePos[1] = MouseCor[1]-areaVert[0][1]
		Draw()
	elif (evt == LEFTMOUSE and not val):				#If button up then clear mouse position
		MousePos[0] = 0
		MousePos[1] = 0
	elif (evt == RIGHTMOUSE and val):				#Collapse or expand all subWindows based on popmenu choice
		result = PupMenu("Render Frame|Render Anim|Expand all|Collapse all|Exit",27)
		if (result == 1):
			RenderFrame()
		if (result == 2):
			RenderAnimation()
		if (result == 3):
			for index, item in enumerate(ButtonData):
				ButtonData[index][WIN_COLLAPSE] = False
			ScrollPos = 0
		if (result == 4):
			for index, item in enumerate(ButtonData):
				ButtonData[index][WIN_COLLAPSE] = True
			ScrollPos = 0
		if (result == 5):
			Shutdown()
		Draw()
	elif (evt == HKEY and not val):
		ShowHelp()
	elif (evt == RKEY and not val):
		RenderFrame()
	elif (evt == PKEY and not val):
		RenderPreview()
	elif (evt == MOUSEX or evt == MOUSEY):				#Update area if mouse is over it and scene or active object has changed
		MousePos[0]			= 0			#Set mouse position to zero to prevent LEFTMOUSE tab collapse flashing while moving
		MousePos[1]			= 0
		CurrentScene			= Blender.Scene.GetCurrent()
		CurrentObject			= CurrentScene.objects.active
		try:
			CurrentMaterial			= CurrentObject.getMaterials(1)[CurrentObject.activeMaterial-1]
			if (CurrentMaterial == None):	CurrentMaterial = CurrentObject.getData(False, True).materials[CurrentObject.activeMaterial-1]
		except:	CurrentMaterial = ""
		if ((CurrentScene and LastScene != CurrentScene.name) or (CurrentObject and LastObject != CurrentObject.name) or (CurrentMaterial and LastMaterial != CurrentMaterial.name)):
			Draw()
	elif (evt == QKEY and not val):
		Shutdown()


#### Button event handler
def buttonevent(evt):
	global EVENT_WIDTH, EVENT_NONE, EVENT_ACTIONS_SET, EVENT_SETTINGS_SET, EVENT_UTILITY_SET, EVENT_SCENE_SET, EVENT_CAMERA_SET, EVENT_GROUP_SET, EVENT_GEOM_SET, EVENT_LIGHT_SET, EVENT_MAT_SET
	global ButtonData, DialogData, Filters, RenderBin, CompilerBin, RenderDir, TexmakeBin, EnvmakeBin, InfoBin, RenderPreset, ShaderExt, ShaderDir, RibExt, PresetEmbed, PresetList
	global RibFrames, RibWorlds, RibScreen, RibClipping, RibColor, RibOpacity, RibVertexCols, RibNormals, RibVertexUVs, RibComments, RibProjection, RibSides, RibBound, TextureExt
	
	#Manage button events as sets of sub-windows with event numbers beginning at windows event set and count up by button order in ButtonArray
	if (evt >= EVENT_ACTIONS_SET and evt < EVENT_ACTIONS_SET+EVENT_WIDTH):
		if (evt == EVENT_ACTIONS_SET+ACT_RENDER): RenderFrame()
		elif (evt == EVENT_ACTIONS_SET+ACT_ANIMATION): RenderAnimation()
		elif (evt == EVENT_ACTIONS_SET+ACT_PREVIEW): RenderPreview()
		elif (evt == EVENT_ACTIONS_SET+ACT_RENDER_RIB): ButtonData[ACTIONS][WIN_BUTS][ACT_RENDER_RIB][BUT_DEFAULT] = ButtonData[ACTIONS][WIN_BUTS][ACT_RENDER_RIB][BUTTON].val
		elif (evt == EVENT_ACTIONS_SET+ACT_CREATE_RIB): ButtonData[ACTIONS][WIN_BUTS][ACT_CREATE_RIB][BUT_DEFAULT] = ButtonData[ACTIONS][WIN_BUTS][ACT_CREATE_RIB][BUTTON].val
		elif (evt == EVENT_ACTIONS_SET+ACT_CREATE_SEL): ButtonData[ACTIONS][WIN_BUTS][ACT_CREATE_SEL][BUT_DEFAULT] = ButtonData[ACTIONS][WIN_BUTS][ACT_CREATE_SEL][BUTTON].val
		elif (evt == EVENT_ACTIONS_SET+ACT_COMPILE_SL): ButtonData[ACTIONS][WIN_BUTS][ACT_COMPILE_SL][BUT_DEFAULT] = ButtonData[ACTIONS][WIN_BUTS][ACT_COMPILE_SL][BUTTON].val
		elif (evt == EVENT_ACTIONS_SET+ACT_EXPORT_MAPS): ButtonData[ACTIONS][WIN_BUTS][ACT_EXPORT_MAPS][BUT_DEFAULT] = ButtonData[ACTIONS][WIN_BUTS][ACT_EXPORT_MAPS][BUTTON].val
		elif (evt == EVENT_ACTIONS_SET+ACT_COMPRESS_RIB):
			ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUT_DEFAULT] = ButtonData[ACTIONS][WIN_BUTS][ACT_COMPRESS_RIB][BUTTON].val
			print "Purging existing RIBs..."
			DelTree(GetProjectFolder(), False)
			print "Project ready..."
		elif (evt == EVENT_ACTIONS_SET+ACT_CLEAN_DIR):
			if (RenderDir and PupMenu("Are you sure you want to purge export directory?%t|Yes|No") == 1):
				try:
					print "Purging export directory..."
					DelTree(GetProjectFolder(), True)
					doneText = "Export directory purged"
					print doneText
					PupMenu(doneText)
				except:
					ErrorPopup("Export directory purged, however some files or folders could not be removed!")
			elif (not RenderDir): ErrorPopup("Export directory is not set, please set export directory under settings tab!")
		elif (evt == EVENT_ACTIONS_SET+ACT_HELP): ShowHelp()
		elif (evt == EVENT_ACTIONS_SET+ACT_QUIT): Shutdown()
		Redraw(1)
	if (evt >= EVENT_SETTINGS_SET and evt < EVENT_SETTINGS_SET+EVENT_WIDTH):
		if (evt == EVENT_SETTINGS_SET+SET_OUTPUT_DIR): FileSelector(RenderDirCallback, "Select Directory", " ")
		elif (evt == EVENT_SETTINGS_SET+SET_TEXT_FILTER):
			result = Blender.Draw.PupBlock("Text Name Filters", DialogData[DIALOG_FILE_FILTER])
			if (result > 0):
				for index, item in enumerate(Filters):
					Filters[index]	= DialogData[DIALOG_FILE_FILTER][index][1].val
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_PRESETS):
			RenderPreset = ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUTTON].val
			ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
			ApplyPresetGlobals()
			UpdatePresetControls()
			UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_RENDER_BIN):
			result = Blender.Draw.PupBlock("Renderer and Options", DialogData[DIALOG_RENDER_BIN])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				RenderBin = DialogData[DIALOG_RENDER_BIN][0][1].val
				ButtonData[SETTINGS][WIN_BUTS][SET_RENDER_BIN][BUT_TIP] = "Renderer: "+RenderBin
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_SHADER_BIN):
			result = Blender.Draw.PupBlock("Shader Compiler and Options", DialogData[DIALOG_COMPILER_BIN])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				CompilerBin = DialogData[DIALOG_COMPILER_BIN][0][1].val
				ButtonData[SETTINGS][WIN_BUTS][SET_SHADER_BIN][BUT_TIP] = "Compiler: "+CompilerBin
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_TEXMAKE_BIN):
			result = Blender.Draw.PupBlock("Tex Optimizer and Options", DialogData[DIALOG_TEX_OPT])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				TexmakeBin = DialogData[DIALOG_TEX_OPT][0][1].val
				ButtonData[SETTINGS][WIN_BUTS][SET_TEXMAKE_BIN][BUT_TIP] = "Texture Optimizer: "+TexmakeBin
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_ENVMAKE_BIN):
			result = Blender.Draw.PupBlock("LatEnv Optimizer and Options", DialogData[DIALOG_ENV_OPT])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				EnvmakeBin = DialogData[DIALOG_ENV_OPT][0][1].val
				ButtonData[SETTINGS][WIN_BUTS][SET_ENVMAKE_BIN][BUT_TIP] = "LatEnv Optimizer: "+EnvmakeBin
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_INFO_BIN):
			result = Blender.Draw.PupBlock("Shader Info and Options", DialogData[DIALOG_INFO_BIN])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				InfoBin = DialogData[DIALOG_INFO_BIN][0][1].val
				ButtonData[SETTINGS][WIN_BUTS][SET_INFO_BIN][BUT_TIP] = "Shader Info: "+InfoBin
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_SHADER_EXT):
			result = Blender.Draw.PupBlock("Compiled Shader Extension", DialogData[DIALOG_SL_EXT])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				ShaderExt = DialogData[DIALOG_SL_EXT][0][1].val
				if (not ShaderExt.count('.')):
					ShaderExt = "."+ShaderExt
					DialogData[DIALOG_SL_EXT][0][1].val = ShaderExt
				ButtonData[SETTINGS][WIN_BUTS][SET_SHADER_EXT][BUT_TIP] = "Shader Extension: "+ShaderExt
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_EXPORTER_SW):
			result = Blender.Draw.PupBlock("Exporter Switches", DialogData[DIALOG_EXPORTER_SW])
			if (result > 0):
				RenderPreset	= 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				RibFrames	= DialogData[DIALOG_EXPORTER_SW][0][1].val
				RibWorlds	= DialogData[DIALOG_EXPORTER_SW][1][1].val
				RibScreen	= DialogData[DIALOG_EXPORTER_SW][2][1].val
				RibProjection	= DialogData[DIALOG_EXPORTER_SW][3][1].val
				RibClipping	= DialogData[DIALOG_EXPORTER_SW][4][1].val
				RibColor	= DialogData[DIALOG_EXPORTER_SW][5][1].val
				RibOpacity	= DialogData[DIALOG_EXPORTER_SW][6][1].val
				RibSides	= DialogData[DIALOG_EXPORTER_SW][7][1].val
				RibBound	= DialogData[DIALOG_EXPORTER_SW][8][1].val
				RibVertexCols	= DialogData[DIALOG_EXPORTER_SW][9][1].val
				RibVertexUVs	= DialogData[DIALOG_EXPORTER_SW][10][1].val
				RibNormals	= DialogData[DIALOG_EXPORTER_SW][11][1].val
				RibComments	= DialogData[DIALOG_EXPORTER_SW][12][1].val
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_EMEBED_PRESET):
			PresetEmbed = ButtonData[SETTINGS][WIN_BUTS][SET_EMEBED_PRESET][BUTTON].val
			ButtonData[SETTINGS][WIN_BUTS][SET_EMEBED_PRESET][BUT_DEFAULT] = PresetEmbed
			if (PresetEmbed):
				Blender.Text.New("MOSAIC Preset")
				UpdateRegistry(2)
			else:
				try:
					Blender.Text.unlink(Blender.Text.Get("MOSAIC Preset"))
					GetRegistry()
					UpdatePresetControls()
				except: GetRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_RIB_EXT):
			result = Blender.Draw.PupBlock("Bytestream File Extension", DialogData[DIALOG_RIB_EXT])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				RibExt = DialogData[DIALOG_RIB_EXT][0][1].val
				if (not RibExt.count('.')):
					RibExt = "."+RibExt
					DialogData[DIALOG_RIB_EXT][0][1].val = RibExt
				ButtonData[SETTINGS][WIN_BUTS][SET_RIB_EXT][BUT_TIP] = "RIB Extension: "+RibExt
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_TEX_EXT):
			result = Blender.Draw.PupBlock("Texture Export Extension", DialogData[DIALOG_TEX_EXT])
			if (result > 0):
				RenderPreset = 1
				ButtonData[SETTINGS][WIN_BUTS][SET_PRESETS][BUT_DEFAULT] = RenderPreset
				TextureExt = DialogData[DIALOG_TEX_EXT][0][1].val
				if (not TextureExt.count('.')):
					TextureExt = "."+TextureExt
					DialogData[DIALOG_TEX_EXT][0][1].val = TextureExt
				ButtonData[SETTINGS][WIN_BUTS][SET_TEX_EXT][BUT_TIP] = "Texture Export Extension: "+TextureExt
				UpdateRegistry()
		elif (evt == EVENT_SETTINGS_SET+SET_CREATE_SHDIR): FileSelector(ShaderDirCallback, "Select Directory", " ")
		elif (evt > EVENT_SETTINGS_SET+SET_CREATE_SHDIR):	#If this is an event from a dynamic button then...
			if (ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET-1][BUT_TITLE] == "Use"):
				pathData	= ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET][BUTTON].val
				oldData		= ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET][BUT_DEFAULT]
				if (oldData and pathData and ShaderDir and type(ShaderDir) == list and ShaderDir.count(oldData)):
					ShaderDir[ShaderDir.index(oldData)]	= pathData
					UpdateRegistry()
					BuildPathsButtons()
			if (ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET][BUT_TITLE] == "Use"):
				pathData	= ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET+1][BUT_DEFAULT]
				if (pathData and ShaderDir and type(ShaderDir) == list and ShaderDir.count(pathData)):
					if (ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET][BUTTON].val):	ShaderDir[ShaderDir.index(pathData)] = pathData.lstrip('#')
					else:										ShaderDir[ShaderDir.index(pathData)] = '#'+pathData
					UpdateRegistry()
					BuildPathsButtons()
			elif (ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET][BUT_TITLE] == "Del"):
				if (PupMenu("Are you sure you want to delete this path?%t|Yes|No") == 1):
					popDir = ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET-2][BUT_DEFAULT]
					if (type(ShaderDir) == list and ShaderDir.count(popDir)):	ShaderDir.pop(ShaderDir.index(popDir))
					else:								ShaderDir = []
					UpdateRegistry()
					BuildPathsButtons()
			elif (ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET][BUT_TITLE] == "Compile"):
				if (PupMenu("Are you sure you want to compile all shaders in this path?%t|Yes|No") == 1):
					try:
						pathData = ButtonData[SETTINGS][WIN_BUTS][evt-EVENT_SETTINGS_SET-1][BUT_DEFAULT].lstrip('#')
						if (sys.exists(pathData) == 2 and CompilerBin):
							shaderList	= ListTree(pathData, [Filters[1]], True, True)
							shaderTotal	= len(shaderList)
							os.chdir(pathData)
							print "Compiling all shader sources in "+pathData+"..."
							DrawProgressBar(0.0, "Compiling shaders...")
							for shaderCount, shader in enumerate(shaderList):
								compileCall = CompilerBin
								if (compileCall.count("<SHADER>")): compileCall = compileCall.replace("<SHADER>", shader)
								else: compileCall = compileCall+" \""+shader+"\""
								DrawProgressBar((shaderCount+1.0)/shaderTotal, "Compiling shaders "+str(shaderCount+1)+" of "+str(shaderTotal))
								print compileCall
								while QTest(): #Cycle through events looking for an esc
									if (ESCKEY in QRead()): #If user escaped
										break
								os.system(compileCall)
							DrawProgressBar(0.0, "")
							DrawProgressBar(1.0, "")
							doneText = "Process complete"
							print doneText
							PupMenu(doneText)
						else: ErrorPopup("Either path is not valid or compiler bin not set!")
					except:
						ErrorPopup("Could not compile shaders in this path see console for details!")
		Redraw(1)
	if (evt >= EVENT_UTILITY_SET and evt < EVENT_UTILITY_SET+EVENT_WIDTH):
		if (evt == EVENT_UTILITY_SET+UTIL_PURGE_PASSES):
			if (PupMenu("Are you sure you want to purge all scenes not in scene pass list?%t|Yes|No") == 1):
				scenePasses	= GetProperty(Blender.Scene.Get()[0], "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_PASSES][BUT_PROP], "", "", "") #Get current scene passes
				if (scenePasses):				#Are there any scene passes to campare too?
					for scene in Blender.Scene.Get():	#Cycle through all scenes
						if (not scenePasses.count(scene.name+"@")): #Is scene name in passes list?
							if (PupMenu("\""+scene.name+"\" not used in passes list, purge it?%t|Yes|No") == 1):
								if (scene != Blender.Scene.GetCurrent()): Blender.Scene.Unlink(scene)
								else: ErrorPopup("Cannot remove active scene, change scenes to remove this one!")
					else: PupMenu("All unreferenced scenes search complete")
				else: ErrorPopup("No render passes to compare with (setup some in \"Project Setup\" tab)!")
		elif (evt == EVENT_UTILITY_SET+UTIL_COPY_PROP):
			if (PupMenu("Are you sure you want to copy properties?%t|Yes|No") == 1):
				try:
					selections = Blender.Object.GetSelected() #Get all current selections
					if (len(selections) > 1):
						for object in selections[1:]:	#Cycle through selections skipping the active selection and only modifing objects with the same type as active object
							if (object.getType() == selections[0].getType()):
								if (object.properties.has_key("MOSAICData")):		del object.properties["MOSAICData"]
								if (selections[0].properties.has_key("MOSAICData")):	object.properties["MOSAICData"] = selections[0].properties["MOSAICData"].convert_to_pyobject()
						PupMenu("Properties copied")
					else: ErrorPopup("Must have more than one object selected!")
				except: ErrorPopup("Could not copy active objects properties to other selections!")
		elif (evt == EVENT_UTILITY_SET+UTIL_CLEAR_PROP):
			try:
				selections = Blender.Object.GetSelected()
				if (selections):			#If there are selected objects then offer to clear their properties
					if (PupMenu("Are you sure you want to clear the selected objects properties?%t|Yes|No") == 1):
						for object in Blender.Object.GetSelected(): #Cycle through selections and clear properties of each
							if (object.properties.has_key("MOSAICData")):	del object.properties["MOSAICData"]
							if (object.properties.has_key("MOSAICTemp")):	del object.properties["MOSAICTemp"]
						PupMenu("Selections properties cleared")
				else:					#If there are no selectins then offer to clear properties for entire scene
					if (PupMenu("Are you sure you want to clear ALL properties in ALL scenes in this ENTIRE project?%t|Yes|No") == 1):
						for group in [Blender.Mesh.Get(), Blender.Curve.Get(), Blender.Metaball.Get()]:
							for subItem in group:
								if (subItem.properties.has_key("MOSAICTemp")):	del subItem.properties["MOSAICTemp"]
								if (subItem.properties.has_key("MOSAICData")):	del subItem.properties["MOSAICData"]
						for group in [Blender.Scene.Get(), Blender.Object.Get(), Blender.Material.Get()]:
							for subItem in group:
								if (subItem.properties.has_key("MOSAICTemp")):		del subItem.properties["MOSAICTemp"]
								if (subItem.properties.has_key("MOSAICData")):		del subItem.properties["MOSAICData"]
								if (subItem.properties.has_key("MOSAICRIBset")):	del subItem.properties["MOSAICRIBset"]
								if (subItem.properties.has_key("MOSAICProject")):	del subItem.properties["MOSAICProject"]
						PupMenu("All properties for project cleared")
			except: ErrorPopup("Could not clear all objects properties!")
		elif (evt == EVENT_UTILITY_SET+UTIL_GENERATE_FRAG):
			menu = CreateMenu("Select Shader", [Filters[1]], 0, ListTree(ShaderDir, [ShaderExt], True), ["MANUALLY ENTER"])
			result = PupMenu(menu[0],27)
			if (result > 0):
				fragmentName	= ""
				if (result == 1):
					result = Blender.Draw.PupBlock("Type shaders name", DialogData[DIALOG_SHADER_NAME])
					if (result > 0):
						fragmentName = CreateShaderFrag(DialogData[DIALOG_SHADER_NAME][0][1].val)
						DialogData[DIALOG_SHADER_NAME][0][1].val = ""
				else:	fragmentName = CreateShaderFrag(menu[result])
				if (fragmentName):
					UpdateMenuData(UTILITIES)
					ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] = ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU].index(fragmentName)
					BuildParamButtons(fragmentName)
					UpdateMenuData(UTILITIES)
		elif (evt == EVENT_UTILITY_SET+UTIL_RELOAD_TEXT):
			if (PupMenu("This may overwrite text changes, proceed?%t|Yes|No") == 1):
				for text in Blender.Text.Get():
					textPath = text.getFilename()
					if (textPath and sys.exists(textPath) == 1):
						try:
							Blender.Text.unlink(text)
							Blender.Text.Load(textPath)
						except: ErrorPopup("Could not retrieve original text file for "+textPath)
				PupMenu("Texts updated from original sources")
		elif (evt == EVENT_UTILITY_SET+UTIL_SAVE_TEXT):
			if (PupMenu("This may overwrite original text files, proceed?%t|Yes|No") == 1):
				for text in Blender.Text.Get():
					textPath = text.getFilename()
					if (textPath and sys.exists(textPath) == 1):
						try:
							textfile = open(textPath, 'wb')
							for line in text.asLines():
								textfile.write(line+"\n")
							textfile.close()
						except: ErrorPopup("Could not write Blender text to "+textPath)
				PupMenu("Original text files saved from Blender texts")
		elif (evt == EVENT_UTILITY_SET+UTIL_SELECT_FRAG):
			fragment = ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUTTON].val
			ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] = fragment
			if (BuildParamButtons(ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][fragment])): ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] = 1
		elif (evt == EVENT_UTILITY_SET+UTIL_RELOAD_FRAG):
			fragment = ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUTTON].val
			if (BuildParamButtons(ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][fragment])): ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] = 1
		elif (evt == EVENT_UTILITY_SET+UTIL_COPY_FRAG):
			fragment = ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUTTON].val]
			if (fragment and fragment != "NONE"):
				DialogData[DIALOG_COPY_FRAG][0][1].val = fragment
				if (Blender.Draw.PupBlock("Copied fragments name", DialogData[DIALOG_COPY_FRAG])):
					try:
						originalFrag	= Blender.Text.Get(fragment)
						newFrag		= Blender.Text.New(DialogData[DIALOG_COPY_FRAG][0][1].val)
						for line in originalFrag.asLines():
							if (line.strip()): newFrag.write(line+"\n")
						UpdateMenuData(UTILITIES)
						if (ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU].count(newFrag.name)):
							ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] = ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU].index(newFrag.name)
							BuildParamButtons(newFrag.name)
							UpdateMenuData(UTILITIES)
						else:
							Blender.Text.unlink(newFrag)
							ErrorPopup("Name not using a valid fragment filter prefix type (see \"Text Fragment Filters\" in \"Settings\" tab)")
					except:	ErrorPopup("Orginal fragment no longer exists")
		elif (evt == EVENT_UTILITY_SET+UTIL_DELETE_FRAG):
			fragment = ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUTTON].val
			if (fragment > 1 and PupMenu("Are you sure you want to delete this fragment?%t|Yes|No") == 1):
				try:
					Blender.Text.unlink(Blender.Text.Get(ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][fragment]))
					ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_DEFAULT] = 1
					BuildParamButtons("")
					UpdateMenuData(UTILITIES)
				except:	ErrorPopup("Could not delete selected fragment")
		elif (evt == EVENT_UTILITY_SET+UTIL_PREVIEW_FRAG):
			fragment = ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUTTON].val
			if (fragment > 1 and Blender.Draw.PupBlock("Preview shader settings", DialogData[DIALOG_PREVIEW])):
				try:	previewMat	= Blender.Material.Get("PREVIEW")
				except:	previewMat	= Blender.Material.New("PREVIEW")
				try:	monkey = Blender.Mesh.Get("PREVIEW")
				except:
					monkey = Blender.Mesh.Primitives.Monkey()
					monkey.name = "PREVIEW"
					monkey.transform(ScaleMatrix(1.5, 4))
				try:
					PrepareProject()
					MakeDefaultShaders()
					OutputDir	= GetProjectFolder()
					os.chdir(OutputDir)
					fragmentText	= Blender.Text.Get(ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][fragment])
					rootScene	= Blender.Scene.Get()[0]
					ProcessResources(ButtonData[ACTIONS][WIN_BUTS][ACT_COMPILE_SL][BUTTON].val, ButtonData[ACTIONS][WIN_BUTS][ACT_EXPORT_MAPS][BUTTON].val)
					previewrib	= open("ShaderPreview"+RibExt, 'wb')
					shaders		= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUT_DEFAULT])
					textures	= GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUT_PROP], "", "", ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUT_DEFAULT])
					if (shaders == 'NONE'): shaders = "."
					if (ShaderDir):
						for directory in ShaderDir:
							if (directory[0] != '#'): shaders = shaders+":"+directory.replace(sys.sep, "/")
					previewrib.write("Option \"searchpath\" \"string shader\" [ \""+shaders+"\" ]\n")
					if (textures != 'NONE'):	previewrib.write("Option \"searchpath\" \"string texture\" [ \""+textures+"\" ]\n")
					if (RibFrames): previewrib.write("FrameBegin 1\n")
					previewrib.writelines(["Display \"0001.tif\" \"framebuffer\" \"rgb\"\n", "Format "+str(DialogData[DIALOG_PREVIEW][0][1].val)+" "+str(DialogData[DIALOG_PREVIEW][0][1].val)+" 1\n", "ShadingRate 2.0\n", "PixelSamples 2 2\n"])
					if (RibProjection): previewrib.write("Projection \"perspective\" \"fov\" [ 49.1343426412 ]\n")
					if (RibScreen): previewrib.write("ScreenWindow -1.0 1.0 -1.0 1.0\n")
					previewrib.write("Transform [ 0.680267989635 -0.368725329638 -0.633464515209 -0.0 0.732883751392 0.354933261871 0.580434262753 0.0 -0.0108168134466 0.859106600285 -0.511682450771 -0.0 -0.0878272429109 0.20783598721 4.22464942932 1.0 ]\n")
					if (RibWorlds): previewrib.write("WorldBegin\n")
					if (DialogData[DIALOG_PREVIEW][2][1].val == 1):
						previewrib.writelines(["LightSource \"pointlight\" 1 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ 3.76316165924 2.24729776382 4.54993391037 ] \"color lightcolor\" [ 1.0 1.0 1.0 ]\n",
								       "LightSource \"pointlight\" 2 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ -4.92012071609 -2.95039510727 2.21557593346 ] \"color lightcolor\" [ 1.0 1.0 1.0 ]\n",
								       "LightSource \"pointlight\" 3 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ 0.283850669861 -5.71731042862 -5.58118677139 ] \"color lightcolor\" [ 1.0 1.0 1.0 ]\n",
								       "LightSource \"pointlight\" 3 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ -6.0 6.0 -4.0 ] \"color lightcolor\" [ 1.0 1.0 1.0 ]\n"])
					elif (DialogData[DIALOG_PREVIEW][2][1].val == 2):
						previewrib.writelines(["LightSource \"pointlight\" 1 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ 0.283850669861 -5.71731042862 -5.20768928528 ] \"color lightcolor\" [ 0.0 1.0 0.0543791651726 ]\n",
								       "LightSource \"pointlight\" 2 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ -4.92012071609 -2.95039510727 2.21557593346 ] \"color lightcolor\" [ 1.0 0.0 0.0 ]\n",
								       "LightSource \"pointlight\" 3 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ 3.76316165924 2.24729776382 4.54993391037 ] \"color lightcolor\" [ 0.715092897415 0.911578536034 1.0 ]\n",
								       "LightSource \"pointlight\" 3 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"point from\" [ -6.0 6.0 -4.0 ] \"color lightcolor\" [ 1.0 1.0 1.0 ]\n"])
					elif (DialogData[DIALOG_PREVIEW][2][1].val == 3):
						previewrib.write("LightSource \"ambientlight\" 1 \"float intensity\" [ "+str(DialogData[DIALOG_PREVIEW][3][1].val)+" ] \"color lightcolor\" [ 1.0 1.0 1.0 ]\n")
					previewrib.write("Transform [ 0.989215552807 0.0176308900118 -0.145401880145 0.0 -2.19392073952e-10 0.992728531361 0.120374560356 0.0 0.146466910839 -0.119076386094 0.98202252388 0.0 0.0 0.0 -0.156824752688 1.0 ]\n")
					previewrib.write(ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_SPECULAR][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_SPECULAR][BUT_DEFAULT]])
					if (RibSides): previewrib.write("Sides 2\n")
					previewrib.write("Surface \"plastic\"\n")
					if (RibColor): previewrib.write("Color 1 0 0\n")
					previewrib.write("GeneralPolygon [ 4 ] \"P\" [ 12.1 12.1 -12.1 12.1 -12.1 -12.1 -12.1 -12.1 -12.1 -12.1 12.1 -12.1 ]\n")
					if (RibColor): previewrib.write("Color 0 1 0\n")
					previewrib.write("GeneralPolygon [ 4 ] \"P\" [ 12.1 12.1 12.1 -12.1 12.1 12.1 -12.1 -12.1 12.1 12.1 -12.1 12.1 ]\n")
					if (RibColor): previewrib.write("Color 0 0 1\n")
					previewrib.write("GeneralPolygon [ 4 ] \"P\" [ 12.1 12.1 -12.1 12.1 12.1 12.1 12.1 -12.1 12.1 12.1 -12.1 -12.1 ]\n")
					if (RibColor): previewrib.write("Color 1 1 0\n")
					previewrib.write("GeneralPolygon [ 4 ] \"P\" [ 12.1 -12.1 -12.1 12.1 -12.1 12.1 -12.1 -12.1 12.1 -12.1 -12.1 -12.1 ]\n")
					if (RibColor): previewrib.write("Color 1 0 1\n")
					previewrib.write("GeneralPolygon [ 4 ] \"P\" [ -12.1 -12.1 -12.1 -12.1 -12.1 12.1 -12.1 12.1 12.1 -12.1 12.1 -12.1 ]\n")
					if (RibColor): previewrib.write("Color 0 1 1\n")
					previewrib.write("GeneralPolygon [ 4 ] \"P\" [ 12.1 12.1 12.1 12.1 12.1 -12.1 -12.1 12.1 -12.1 -12.1 12.1 12.1 ]\n")
					previewrib.write(ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_TRANS][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_TRANS][BUT_DEFAULT]])
					previewrib.write(ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_DIFFUSE][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_VIS_DIFFUSE][BUT_DEFAULT]])
					previewrib.write(ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_TRANS][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_TRANS][BUT_DEFAULT]])
					previewrib.write(ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_SPECULAR][BUT_TITLE][ButtonData[MATERIALS][WIN_BUTS][MAT_SHADE_SPECULAR][BUT_DEFAULT]])
					if (RibColor): previewrib.writelines(RibifyColor(previewMat))
					if (RibOpacity): previewrib.writelines(RibifyOpacity(previewMat))
					previewrib.writelines(RibifyShader(rootScene, previewMat, ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][fragment]))
					previewrib.writelines(["Attribute \"displacementbound\" \"float sphere\" [ 2.0 ] \"string coordinatesystem\" [ \"shader\" ]\n",
							       "PointsPolygons [ 4 ] [ 0 3 2 1 ] \"P\" [ 2.66413164139 6.38577842712 -10.6303691864 -6.20878791809 -2.84712696075 -10.7711486816 -12.5341625214 3.08797168732 -1.34992694855 -3.66123962402 12.3208770752 -1.20914697647 ]\n"])
					if (DialogData[DIALOG_PREVIEW][1][1].val == 1):
						previewrib.write("Sphere 1.5 -1.5 1.5 360\n")
					elif (DialogData[DIALOG_PREVIEW][1][1].val == 2):
						previewrib.write("PointsPolygons [ 4 4 4 4 4 4 ] [ 0 1 2 3 4 7 6 5 0 4 5 1 1 5 6 2 2 6 7 3 4 0 3 7 ] \"P\" [ 1 1 -1 1 -1 -1 -1 -1 -1 -1 1 -1 1 1 1 1 -1 1 -1 -1 1 -1 1 1 ]\n")
					elif (DialogData[DIALOG_PREVIEW][1][1].val == 3):
						previewrib.write("Cone 1.5 1.5 360\n")
					elif (DialogData[DIALOG_PREVIEW][1][1].val == 4):
						previewrib.write("Cylinder 1 -1 1 360\n")
					elif (DialogData[DIALOG_PREVIEW][1][1].val == 5):
						preview = rootScene.objects.new(monkey, 'Preview')
						mods = preview.modifiers
						mods.append(Blender.Modifier.Types.SUBSURF)
						previewrib.writelines(RibifyMesh(preview, [-1, 0, 1]))
						rootScene.objects.unlink(preview)
					elif (DialogData[DIALOG_PREVIEW][1][1].val == 6):
						previewrib.write("ObjectBegin 0\nBasis \"bezier\" 3 \"bezier\" 3\nCurves \"cubic\" [ 4 ] \"nonperiodic\" \"P\" [ 6.98828444001e-08 1.59873306751 2.18575422671e-16 -5.41418165929e-16 0.799366474152 0.799366533756 -6.64516406346e-08 -0.562030076981 0.958206236362 -6.98828444001e-08 -1.59873306751 -2.18575422671e-16 ] \"constantwidth\" [ 0.005 ]\nObjectEnd\nTranslate -1.0 0 -1.0\n")
						for y in range (0, 40):
							for x in range(0, 40):
								previewrib.write("Translate 0.05 0 0\nObjectInstance 0\n")
							previewrib.write("Translate -2.0 0 0.05\n")
					if (RibWorlds): previewrib.write("WorldEnd\n")
					if (RibFrames): previewrib.write("FrameEnd\n")
					previewrib.close()
					renderCall = RenderBin
					if (renderCall.count("<RIB>")): renderCall = renderCall.replace("<RIB>", "\"ShaderPreview"+RibExt+"\"")
					else: renderCall = renderCall+" \"ShaderPreview"+RibExt+"\""
					os.system(renderCall)
				except:	ErrorPopup("Could not preview shader")
		elif (evt > EVENT_UTILITY_SET+UTIL_DIVIDER3):		#If this is an event from a dynamic button then...
			try:
				fragmentName	= ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][UTIL_SELECT_FRAG][BUTTON].val]
				fragment	= Blender.Text.Get(fragmentName)
				fragmentText	= fragment.asLines()
			except:	fragmentName	= ""
			if (fragmentName):				#Make sure we have a valid selection
				if (ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET][BUT_TITLE] == "NOTES"):
					notesResult	= Blender.Draw.PupBlock("Enter paramater notes", DialogData[DIALOG_COMMENTS])
				elif (ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET][BUT_TITLE] == "TW"):
					print ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET-1][BUT_DEFAULT]
					tokenResult	= CreateToken(ButtonData[UTILITIES][WIN_BUTS][UTIL_DIVIDER3+1][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][UTIL_DIVIDER3+1][BUT_DEFAULT]], ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET-4][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET-4][BUT_DEFAULT]], ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET][BUT_PROP])
					if (tokenResult): ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET-1][BUT_DEFAULT] = tokenResult
				else:	ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET][BUT_DEFAULT] = ButtonData[UTILITIES][WIN_BUTS][evt-EVENT_UTILITY_SET][BUTTON].val
				UpdateMenuData(UTILITIES)
				
				fragment.clear()
				fragment.write("#"+DialogData[DIALOG_COMMENTS][0][1].val+"\n")
				shaderType	= ButtonData[UTILITIES][WIN_BUTS][UTIL_DIVIDER3+1][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][UTIL_DIVIDER3+1][BUTTON].val]
				fragment.write(shaderType+"\""+ButtonData[UTILITIES][WIN_BUTS][UTIL_DIVIDER3+2][BUTTON].val+"\"")
				if (shaderType == "LightSource " or shaderType == "AreaLightSource "): fragment.write(" <LightID_I>")
				for butIndex in range(UTIL_DIVIDER3+4, len(ButtonData[UTILITIES][WIN_BUTS]), 7):
					fragment.write("\n")
					paraUse		= ButtonData[UTILITIES][WIN_BUTS][butIndex+0][BUT_DEFAULT]
					paraClass	= ButtonData[UTILITIES][WIN_BUTS][butIndex+1][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][butIndex+1][BUT_DEFAULT]]
					paraType	= ButtonData[UTILITIES][WIN_BUTS][butIndex+2][BUT_MENU][ButtonData[UTILITIES][WIN_BUTS][butIndex+2][BUT_DEFAULT]]+" "
					paraArray	= ButtonData[UTILITIES][WIN_BUTS][butIndex+3][BUT_DEFAULT]+" "
					paraName	= ButtonData[UTILITIES][WIN_BUTS][butIndex+4][BUT_DEFAULT]
					paraValue	= ButtonData[UTILITIES][WIN_BUTS][butIndex+5][BUT_DEFAULT]
					paraDefault	= ButtonData[UTILITIES][WIN_BUTS][butIndex+6][BUT_PROP]
					if (paraUse):			paraUse = ""
					else:				paraUse = "#"
					if (paraClass == 'NONE'):	paraClass = ""
					if (paraType == 'NONE '):	paraType = ""
					if (paraArray == ' '):		paraArray = ""
					fragment.write(paraUse+"\t\""+paraClass+paraType+paraArray+paraName+"\" "+paraValue+" #"+paraDefault)
				BuildParamButtons(fragmentName)
				UpdateMenuData(UTILITIES)
		Redraw(1)
	if (evt >= EVENT_PROJECT_SET and evt < EVENT_PROJECT_SET+EVENT_WIDTH):
		rootScene = Blender.Scene.Get()[0]
		if (evt == EVENT_PROJECT_SET+PROJECT_FOLDER):
			projectFolder = ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUTTON].val
			if (projectFolder):	SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUT_PROP], projectFolder)
			else:			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_FOLDER][BUT_DEFAULT])
		elif (evt == EVENT_PROJECT_SET+PROJECT_ARCHIVES):
			archives = ButtonData[PROJECT][WIN_BUTS][PROJECT_ARCHIVES][BUTTON].val
			if (archives):		SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_ARCHIVES][BUT_PROP], archives)
			else:			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_ARCHIVES][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_ARCHIVES][BUT_DEFAULT])
		elif (evt == EVENT_PROJECT_SET+PROJECT_SHADERS):
			shaders = ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUTTON].val
			if (shaders):		SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUT_PROP], shaders)
			else:			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_SHADERS][BUT_DEFAULT])
		elif (evt == EVENT_PROJECT_SET+PROJECT_TEXTURES):
			textures = ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUTTON].val
			if (textures):		SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUT_PROP], textures)
			else:			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_TEXTURES][BUT_DEFAULT])
		elif (evt == EVENT_PROJECT_SET+PROJECT_DISPLAYS):
			displays = ButtonData[PROJECT][WIN_BUTS][PROJECT_DISPLAYS][BUTTON].val
			if (displays):		SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_DISPLAYS][BUT_PROP], displays)
			else:			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_DISPLAYS][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_DISPLAYS][BUT_DEFAULT])
		elif (evt == EVENT_PROJECT_SET+PROJECT_PROCEDURALS):
			procedurals = ButtonData[PROJECT][WIN_BUTS][PROJECT_PROCEDURALS][BUTTON].val
			if (procedurals):	SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_PROCEDURALS][BUT_PROP], procedurals)
			else:			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_PROCEDURALS][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_PROCEDURALS][BUT_DEFAULT])
		elif (evt == EVENT_PROJECT_SET+PROJECT_RESOURCES):
			resources = ButtonData[PROJECT][WIN_BUTS][PROJECT_RESOURCES][BUTTON].val
			if (resources):		SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_RESOURCES][BUT_PROP], resources)
			else:			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_RESOURCES][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_RESOURCES][BUT_DEFAULT])
		elif (evt == EVENT_PROJECT_SET+PROJECT_TEXTURE_EXPORT):
			options		= ["Completely Ignore", "Export Only", "Export and Optimize", "Export into Environment Map"]
			textureMenu	= CreateMenu("Select Texture", [""], -1, [image.name for image in Blender.Image.Get() if image.source != Blender.Image.Sources.GENERATED], [""], True)
			textureResult	= PupMenu(textureMenu[0])
			if (textureResult > 0):
				image	= Blender.Image.Get(textureMenu[textureResult])
				optionsMenu = CreateMenu("\""+image.name+"\" export options, currently its \""+options[GetProperty(image, "ExportOption", "", "", "", 2)]+"\"", [""], -1, options, [""], False)
				optionsResult = PupMenu(optionsMenu[0])
				if (optionsResult > 0): image.properties["ExportOption"] = optionsResult-1
		elif (evt == EVENT_PROJECT_SET+PROJECT_PASSES):
			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_PASSES][BUT_PROP], ButtonData[PROJECT][WIN_BUTS][PROJECT_PASSES][BUTTON].val)
			BuildPassesButtons(rootScene)
		elif (evt == EVENT_PROJECT_SET+PROJECT_CREATE_PASS):
			scenePasses = GetProperty(rootScene, "MOSAICProject", ButtonData[PROJECT][WIN_BUTS][PROJECT_PASSES][BUT_PROP], "", "", "") #Get current scene passes
			if (scenePasses): scenePasses = scenePasses+","
			scenePasses = scenePasses+"#NONE@DEFAULT:0-0"
			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_PASSES][BUT_PROP], scenePasses)
			BuildPassesButtons(rootScene)
		elif (evt > EVENT_PROJECT_SET+PROJECT_DIVIDER3):	#If this is an event from a dynamic button then...
			if (ButtonData[PROJECT][WIN_BUTS][evt-EVENT_PROJECT_SET][BUT_TITLE] == "Del"):
				if (PupMenu("Are you sure you want to delete this pass?%t|Yes|No") == 1):
					for popCount in range(8):
						ButtonData[PROJECT][WIN_BUTS].pop(evt-EVENT_PROJECT_SET-7)
			elif (ButtonData[PROJECT][WIN_BUTS][evt-EVENT_PROJECT_SET][BUT_TITLE] == "Up"):
				if (evt-EVENT_PROJECT_SET-6 > PROJECT_DIVIDER3):
					buttons = []
					for popCount in range(8): buttons.append(ButtonData[PROJECT][WIN_BUTS].pop(evt-EVENT_PROJECT_SET-5))
					for pushCount in range(7, -1, -1): ButtonData[PROJECT][WIN_BUTS].insert(evt-EVENT_PROJECT_SET-13, buttons[pushCount])
			elif (ButtonData[PROJECT][WIN_BUTS][evt-EVENT_PROJECT_SET][BUT_TITLE] == "Dn"):
				if (evt-EVENT_PROJECT_SET+2 < len(ButtonData[PROJECT][WIN_BUTS])-1):
					buttons = []
					for popCount in range(8): buttons.append(ButtonData[PROJECT][WIN_BUTS].pop(evt-EVENT_PROJECT_SET-6))
					for pushCount in range(7, -1, -1): ButtonData[PROJECT][WIN_BUTS].insert(evt-EVENT_PROJECT_SET+2, buttons[pushCount])
			scenePasses = ""
			for button in ButtonData[PROJECT][WIN_BUTS][PROJECT_DIVIDER3+1:]: #Assemble scene passes string from buttons
				if (button[BUT_TITLE] == "Use"):
					if (scenePasses): scenePasses = scenePasses+","
					if (not button[BUTTON].val):
						scenePasses = scenePasses+'#'
					button[BUT_DEFAULT]	= button[BUTTON].val
				elif (button[BUT_TITLE] == "SceneF"):
					scenePasses		= scenePasses+button[BUT_MENU][button[BUTTON].val]+"@"
					button[BUT_DEFAULT]	= button[BUTTON].val
				elif (button[BUT_PROP] == "RIBset"):
					scenePasses		= scenePasses+button[BUT_MENU][button[BUTTON].val]+":"
					button[BUT_DEFAULT]	= button[BUTTON].val
				elif (button[BUT_TITLE] == "Sta"):
					scenePasses		= scenePasses+str(button[BUTTON].val)+"-"
					button[BUT_DEFAULT]	= button[BUTTON].val
				elif (button[BUT_TITLE] == "End"):
					scenePasses		= scenePasses+str(button[BUTTON].val)
					button[BUT_DEFAULT]	= button[BUTTON].val
			SetGlobalProp(ButtonData[PROJECT][WIN_BUTS][PROJECT_PASSES][BUT_PROP], scenePasses)
			BuildPassesButtons(rootScene)
		Redraw(1)
	if (evt >= EVENT_SCENE_SET and evt < EVENT_SCENE_SET+EVENT_WIDTH):
		try:
			SelectedScene	= Blender.Scene.Get(ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUT_MENU][ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUTTON].val])
			RIBset		= ButtonData[SCENES][WIN_BUTS][SCENE_SELECT_SET][BUT_MENU][ButtonData[SCENES][WIN_BUTS][SCENE_SELECT_SET][BUTTON].val]
			CheckRootProps(SelectedScene)
			if (evt == EVENT_SCENE_SET+SCENE_SELECT):
				DistributeGlobals()
				SelectedScene.makeCurrent()
				UpdateMenuData(SCENES)
			elif (evt == EVENT_SCENE_SET+SCENE_SELECT_SET):
				SetRIBset(SCENES, SelectedScene)
				UpdateMenuData(SCENES)
				BuildDisplaysButtons(SelectedScene)
			elif (evt == EVENT_SCENE_SET+SCENE_CREATE_SET):
				CreateSet(SelectedScene, SCENES, SCENE_SELECT_SET, 7)
				BuildDisplaysButtons(SelectedScene)
			elif (evt == EVENT_SCENE_SET+SCENE_DELETE_SET):
				DeleteSet(SelectedScene, SCENES, SCENE_SELECT_SET)
				BuildDisplaysButtons(SelectedScene)
				BuildPassesButtons(SelectedScene)
			SetProperties(SCENES, SelectedScene)
			if (evt == EVENT_SCENE_SET+SCENE_SHADOW_MAP):
				paraList	= GetProperty(SelectedScene, "MOSAICData", RIBset, "MakeShadowMap", "", "<DIVIDER>").split("<DIVIDER>")
				for paraIndex, para in enumerate(paraList):
					if (len(DialogData[DIALOG_SHADOW]) > paraIndex): DialogData[DIALOG_SHADOW][paraIndex][1].val = para
				result = Blender.Draw.PupBlock("Create Shadow Map", DialogData[DIALOG_SHADOW])
				if (result > 0):
					for paraIndex, para in enumerate(paraList):
						if (len(DialogData[DIALOG_SHADOW]) > paraIndex): paraList[paraIndex] = DialogData[DIALOG_SHADOW][paraIndex][1].val
					SelectedScene.properties["MOSAICData"][RIBset]["MakeShadowMap"] = "<DIVIDER>".join(paraList)
			elif (evt == EVENT_SCENE_SET+SCENE_LATLONG_MAP):
				paraList	= GetProperty(SelectedScene, "MOSAICData", RIBset, "MakeLatLongMap", "", "<DIVIDER><DIVIDER><DIVIDER><DIVIDER>").split("<DIVIDER>")
				for paraIndex, para in enumerate(paraList):
					if (len(DialogData[DIALOG_LATLONG]) > paraIndex): DialogData[DIALOG_LATLONG][paraIndex][1].val = para
				result = Blender.Draw.PupBlock("Create LatLong Env Map", DialogData[DIALOG_LATLONG])
				if (result > 0):
					for paraIndex, para in enumerate(paraList):
						if (len(DialogData[DIALOG_LATLONG]) > paraIndex): paraList[paraIndex] = DialogData[DIALOG_LATLONG][paraIndex][1].val
					SelectedScene.properties["MOSAICData"][RIBset]["MakeLatLongMap"] = "<DIVIDER>".join(paraList)
			elif (evt == EVENT_SCENE_SET+SCENE_CUBE_MAP):
				paraList	= GetProperty(SelectedScene, "MOSAICData", RIBset, "MakeCubeMap", "", "<DIVIDER><DIVIDER><DIVIDER><DIVIDER><DIVIDER><DIVIDER><DIVIDER><DIVIDER><DIVIDER><DIVIDER>").split("<DIVIDER>")
				for paraIndex, para in enumerate(paraList):
					if (len(DialogData[DIALOG_CUBE]) > paraIndex): DialogData[DIALOG_CUBE][paraIndex][1].val = para
				result = Blender.Draw.PupBlock("Create Cube Env Map", DialogData[DIALOG_CUBE])
				if (result > 0):
					for paraIndex, para in enumerate(paraList):
						if (len(DialogData[DIALOG_CUBE]) > paraIndex): paraList[paraIndex] = DialogData[DIALOG_CUBE][paraIndex][1].val
					SelectedScene.properties["MOSAICData"][RIBset]["MakeCubeMap"] = "<DIVIDER>".join(paraList)
			elif (evt >= EVENT_SCENE_SET+SCENE_ADD_DISPLAY): #If this is an event from a dynamic button then...
				displayList	= GetProperty(SelectedScene, "MOSAICData", RIBset, "DisplayList", "", ButtonData[SCENES][WIN_BUTS][SCENE_ADD_DISPLAY][BUT_DEFAULT]).split("<DIVIDER>")
				if (evt == EVENT_SCENE_SET+SCENE_ADD_DISPLAY):
					displayList.append(ButtonData[SCENES][WIN_BUTS][SCENE_ADD_DISPLAY][BUT_DEFAULT].split("<DIVIDER>")[0])
				elif (ButtonData[SCENES][WIN_BUTS][evt-EVENT_SCENE_SET][BUT_TITLE] == "Use"):
					displayIndex = (evt-(EVENT_SCENE_SET+SCENE_ADD_DISPLAY))/3
					if (displayList[displayIndex][0] != '#'):	displayList[displayIndex] = '#'+displayList[displayIndex]
					else:						displayList[displayIndex] = displayList[displayIndex].lstrip('#')
				elif (ButtonData[SCENES][WIN_BUTS][evt-EVENT_SCENE_SET-1][BUT_TITLE] == "Use"):
					displayIndex	= (evt-(EVENT_SCENE_SET+SCENE_ADD_DISPLAY)-1)/3
					newDisplay	= ButtonData[SCENES][WIN_BUTS][evt-EVENT_SCENE_SET][BUTTON].val
					if (newDisplay):	displayList[displayIndex] = newDisplay
					elif (displayIndex == 1):	displayList[displayIndex] = ButtonData[SCENES][WIN_BUTS][SCENE_ADD_DISPLAY][BUT_DEFAULT].split("<DIVIDER>")[1]
					else:				displayList[displayIndex] = ButtonData[SCENES][WIN_BUTS][SCENE_ADD_DISPLAY][BUT_DEFAULT].split("<DIVIDER>")[0]
				elif (ButtonData[SCENES][WIN_BUTS][evt-EVENT_SCENE_SET][BUT_TITLE] == "Del"):
					displayIndex = (evt-(EVENT_SCENE_SET+SCENE_ADD_DISPLAY)-2)/3
					if (displayIndex < 2):
						ErrorPopup("Cannot delete standard File and Framebuffer displays, toggle the \"Use\" button to disable each!")
					else:
						if (PupMenu("Are you sure you want to delete this display driver?%t|Yes|No") == 1):
							displayList.pop(displayIndex)
				SelectedScene.properties["MOSAICData"][RIBset]["DisplayList"] = "<DIVIDER>".join(displayList)
				BuildDisplaysButtons(SelectedScene)
				UpdateMenuData(SCENES)
		except: ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUTTON].val = ButtonData[SCENES][WIN_BUTS][SCENE_SELECT][BUT_DEFAULT]
		if (evt == EVENT_SCENE_SET+SCENE_ATMO_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[SCENES][WIN_BUTS][SCENE_ATMO][BUT_MENU][ButtonData[SCENES][WIN_BUTS][SCENE_ATMO][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		Redraw(1)
	if (evt >= EVENT_CAMERA_SET and evt < EVENT_CAMERA_SET+EVENT_WIDTH):
		try:
			object = Blender.Object.Get(ButtonData[CAMERAS][WIN_BUTS][CAM_SELECT][BUT_MENU][ButtonData[CAMERAS][WIN_BUTS][CAM_SELECT][BUTTON].val])
			CheckRootProps(object)
			if (evt == EVENT_CAMERA_SET+CAM_SELECT):
				SelectObject(object.name)
				UpdateMenuData(CAMERAS)
			elif (evt == EVENT_CAMERA_SET+CAM_SELECT_SET):
				SetRIBset(CAMERAS, object)
				UpdateMenuData(CAMERAS)
			elif (evt == EVENT_CAMERA_SET+CAM_CREATE_SET):
				CreateSet(object, CAMERAS, CAM_SELECT_SET, 8)
			elif (evt == EVENT_CAMERA_SET+CAM_DELETE_SET):
				DeleteSet(object, CAMERAS, CAM_SELECT_SET)
			SetProperties(CAMERAS, object)
		except: ButtonData[CAMERAS][WIN_BUTS][CAM_SELECT][BUTTON].val = ButtonData[CAMERAS][WIN_BUTS][CAM_SELECT][BUT_DEFAULT]
		if (evt == EVENT_CAMERA_SET+CAM_IMAGE_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[CAMERAS][WIN_BUTS][CAM_IMAGE][BUT_MENU][ButtonData[CAMERAS][WIN_BUTS][CAM_IMAGE][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		Redraw(1)
	if (evt >= EVENT_GROUP_SET and evt < EVENT_GROUP_SET+EVENT_WIDTH):
		try:
			if (evt == EVENT_GROUP_SET+GRP_SELECT): UpdateMenuData(GROUPS)
			SelectedScene = Blender.Scene.GetCurrent()
			CheckRootProps(SelectedScene)
			SelectedScene.properties["MOSAICData"]["DEFAULT"][ButtonData[GROUPS][WIN_BUTS][GRP_SELECT][BUT_MENU][ButtonData[GROUPS][WIN_BUTS][GRP_SELECT][BUTTON].val]] = {"Group Begin Code": ButtonData[GROUPS][WIN_BUTS][GRP_BEGIN_CODE][BUT_MENU][ButtonData[GROUPS][WIN_BUTS][GRP_BEGIN_CODE][BUTTON].val],
																						       "Group End Code": ButtonData[GROUPS][WIN_BUTS][GRP_END_CODE][BUT_MENU][ButtonData[GROUPS][WIN_BUTS][GRP_END_CODE][BUTTON].val],
																						       "Atmosphere Shader": ButtonData[GROUPS][WIN_BUTS][GRP_ATMO][BUT_MENU][ButtonData[GROUPS][WIN_BUTS][GRP_ATMO][BUTTON].val],
																						       "Group Block": ButtonData[GROUPS][WIN_BUTS][GRP_ARCH][BUT_MENU][ButtonData[GROUPS][WIN_BUTS][GRP_ARCH][BUTTON].val]}
		except: ButtonData[GROUPS][WIN_BUTS][GRP_SELECT][BUTTON].val = ButtonData[GROUPS][WIN_BUTS][GRP_SELECT][BUT_DEFAULT]
		if (evt == EVENT_GROUP_SET+GRP_ATMO_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[GROUPS][WIN_BUTS][GRP_ATMO][BUT_MENU][ButtonData[GROUPS][WIN_BUTS][GRP_ATMO][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		Redraw(1)
	if (evt >= EVENT_GEOM_SET and evt < EVENT_GEOM_SET+EVENT_WIDTH):
		try:
			object = Blender.Object.Get(ButtonData[GEOMETRY][WIN_BUTS][GEO_SELECT][BUT_MENU][ButtonData[GEOMETRY][WIN_BUTS][GEO_SELECT][BUTTON].val])
			CheckRootProps(object)
			if (evt == EVENT_GEOM_SET+GEO_SELECT):
				SelectObject(object.name)
				UpdateMenuData(GEOMETRY)
			elif (evt == EVENT_GEOM_SET+GEO_SELECT_SET):
				SetRIBset(GEOMETRY, object)
				UpdateMenuData(GEOMETRY)
			elif (evt == EVENT_GEOM_SET+GEO_CREATE_SET):
				CreateSet(object, GEOMETRY, GEO_SELECT_SET, 9)
			elif (evt == EVENT_GEOM_SET+GEO_DELETE_SET):
				DeleteSet(object, GEOMETRY, GEO_SELECT_SET)
			SetProperties(GEOMETRY, object)
		except: ButtonData[GEOMETRY][WIN_BUTS][GEO_SELECT][BUTTON].val = ButtonData[GEOMETRY][WIN_BUTS][GEO_SELECT][BUT_DEFAULT]
		if (evt == EVENT_GEOM_SET+GEO_ATMO_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[GEOMETRY][WIN_BUTS][GEO_ATMO][BUT_MENU][ButtonData[GEOMETRY][WIN_BUTS][GEO_ATMO][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		Redraw(1)
	if (evt >= EVENT_LIGHT_SET and evt < EVENT_LIGHT_SET+EVENT_WIDTH):
		try:
			object = Blender.Object.Get(ButtonData[LIGHTS][WIN_BUTS][LIGHT_SELECT][BUT_MENU][ButtonData[LIGHTS][WIN_BUTS][LIGHT_SELECT][BUTTON].val])
			CheckRootProps(object)
			if (evt == EVENT_LIGHT_SET+LIGHT_SELECT):
				SelectObject(object.name)
				UpdateMenuData(LIGHTS)
			elif (evt == EVENT_LIGHT_SET+LIGHT_SELECT_SET):
				SetRIBset(LIGHTS, object)
				UpdateMenuData(LIGHTS)
			elif (evt == EVENT_LIGHT_SET+LIGHT_CREATE_SET):
				CreateSet(object, LIGHTS, LIGHT_SELECT_SET, 10)
			elif (evt == EVENT_LIGHT_SET+LIGHT_DELETE_SET):
				DeleteSet(object, LIGHTS, LIGHT_SELECT_SET)
			SetProperties(LIGHTS, object)
		except: ButtonData[LIGHTS][WIN_BUTS][LIGHT_SELECT][BUTTON].val = ButtonData[LIGHTS][WIN_BUTS][LIGHT_SELECT][BUT_DEFAULT]
		if (evt == EVENT_LIGHT_SET+LIGHT_SHADER_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[LIGHTS][WIN_BUTS][LIGHT_SHADER][BUT_MENU][ButtonData[LIGHTS][WIN_BUTS][LIGHT_SHADER][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		Redraw(1)
	if (evt >= EVENT_MAT_SET and evt < EVENT_MAT_SET+EVENT_WIDTH):
		try:
			SelectedMaterial = Blender.Material.Get(ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUTTON].val])
			CheckRootProps(SelectedMaterial)
			if (evt == EVENT_MAT_SET+MAT_SELECT):
				UpdateMenuData(MATERIALS)
			elif (evt == EVENT_MAT_SET+MAT_SELECT_SET):
				SetRIBset(MATERIALS, SelectedMaterial)
				UpdateMenuData(MATERIALS)
			elif (evt == EVENT_MAT_SET+MAT_CREATE_SET):
				CreateSet(SelectedMaterial, MATERIALS, MAT_SELECT_SET, 11)
			elif (evt == EVENT_MAT_SET+MAT_DELETE_SET):
				DeleteSet(SelectedMaterial, MATERIALS, MAT_SELECT_SET)
			SetProperties(MATERIALS, SelectedMaterial)
		except: ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUTTON].val = ButtonData[MATERIALS][WIN_BUTS][MAT_SELECT][BUT_DEFAULT]
		if (evt == EVENT_MAT_SET+MAT_SURF_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[MATERIALS][WIN_BUTS][MAT_SURF][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_SURF][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		elif (evt == EVENT_MAT_SET+MAT_DISP_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[MATERIALS][WIN_BUTS][MAT_DISP][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_DISP][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		elif (evt == EVENT_MAT_SET+MAT_INT_VOL_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[MATERIALS][WIN_BUTS][MAT_INT_VOL][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_INT_VOL][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		elif (evt == EVENT_MAT_SET+MAT_EXT_VOL_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[MATERIALS][WIN_BUTS][MAT_EXT_VOL][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_EXT_VOL][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		elif (evt == EVENT_MAT_SET+MAT_AREA_NOTES):
			try:	PupMenu(Blender.Text.Get(ButtonData[MATERIALS][WIN_BUTS][MAT_AREA][BUT_MENU][ButtonData[MATERIALS][WIN_BUTS][MAT_AREA][BUTTON].val]).asLines()[0][1:])
			except:	PupMenu("No notes")
		Redraw(1)


####################################################################### LETS DO IT!
Register(draw, event, buttonevent)
