#!BPY

"""
Name: 'BRay_Baker'
Blender: 248
Group: 'UV'
Tooltip: 'Bake the skin of an object.'
"""

__author__ = "macouno"
__url__ = ("http://www.alienhelpdesk.com")
__version__ = "3.4 16/07/06"

__bpydoc__ = """\

This script renders the current skin of an object into a uv texture

Usage:

Select the object you want to bake the skin of.
Set settings in python interface.
Run script.

Tips:

Don't use specularity (camera angle changes for each face)!
Save & reload after use is advised (twice for total cleanup)!
Object size and rotation are not taken into account, so apply those!
Use a copy of your object because UV coords are changed by the script!

"""
#############################################################
# Code history                                              #
#############################################################
#	version 1 released 31-05-2005

#	version 1.2 released 01-06-2005
#	coded in a mode that allows for rendering to an existing uv texture
#	small update... changed the order in which things are done
#	Now the UV coords for regular render get set after rendering the tiles.

#	version 2 released 12-06-2005
#	Made the render to existing UV coords seamless
#	Did some code cleanup and added a few more comments

#	version 3 released 16-10-2005
#	Made relative tile size render possible
#   Optional to render relative to Edge length, face or uv area.
#	Made render all objects possible
#   The script now takes the object size into account.
#   Also the code has been heavily revised to work in the current cvs.
#   Sepparated the reset settings, reset scene and delete tiles.
#   Changed over the dir functionality to the new expand function.

#   Version 3.3 released 07-01-2006
#   Tiny change... the tiles are now compiled with Key in stead of Premul alpha.

#   Version 3.4 released 16-07-2006
#   made the script compatible with blender 2.42

# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2005: macouno, http://www.macouno.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

import Blender
from Blender import *
import math
import os

#############################################################
# GLOBALS                                                   #
#############################################################
VERSION ='3.4'

BUTTON = {
	'SIZE': Draw.Create(1000),
	'MINSIZE': Draw.Create(1000),
	'MAXSIZE': Draw.Create(2000),
	'MINOB': Draw.Create(0.0),
	'MAXOB': Draw.Create(0.0),
	'FACEMAX': Draw.Create(0.0),
	'FACEMIN': Draw.Create(0.0),
	'TILEMAX': Draw.Create(10),
	'TILEMIN': Draw.Create(10),
	'TILELIMIT': Draw.Create(5000),
	'AREATO': Draw.Create(1),
	'ESTIMATE': Draw.Create(1),
	'RESET': Draw.Create(1),
	'UVAVAIL': Draw.Create(0),
	'FACES': Draw.Create(0),
	'SQUARE': Draw.Create(0.0),
	'OBTOTAL': Draw.Create(0),
	'XFACTOR': Draw.Create(0.0),
	'YFACTOR': Draw.Create(0.0),
	'XCOUNT': Draw.Create(0),
	'YCOUNT': Draw.Create(1),
	'PATH': Draw.Create("a"),
	'FRAME': Draw.Create(0),
	'TYPE': Draw.Create(2),
	'KEEPUV': Draw.Create(0),
	'DELTILES': Draw.Create(1),
	'RESCENE': Draw.Create(1),
	'CLIPSTART': Draw.Create(0.01),
	'MINDIST' : Draw.Create(0.1),
	'CLIPEND': Draw.Create(10.0),
	'FSEL': Draw.Create(1),
	'OBNAME': Draw.Create("a"),
	'MNAME': Draw.Create("a")
	}
STATE = {}

####################################################
# PRESET VARIABLE DATA                             #
####################################################
BUTTON['LAYERS'] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

STATE['LAYERS'] = Window.ViewLayers();

for a in range(len(STATE['LAYERS'])):
	
	BUTTON['LAYERS'][STATE['LAYERS'][a]] = 1;

## Get scene data
cur = Scene.GetCurrent()
cam = cur.objects.camera
STATE['CAMERA'] = cam.getName();

cntx = cur.getRenderingContext()

## Get the render path
pth1 = cntx.getRenderPath()

## Combine the file directory with the render path
BUTTON['PATH'].val = Blender.sys.expandpath(pth1)
	
## Get the current frame
BUTTON['FRAME'].val = cntx.currentFrame()

####################################################
# TRANSFORMATION FUNCTION                          #
####################################################

# Apply a matrix to a vert and return a vector.
def apply_transform(verts, matrix):
	x, y, z = verts
	xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
	return Mathutils.Vector(
	x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,
	x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,
	x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc)

# Apply a matrix to a vert and return a vector.
def normal_transform(verts, matrix):
	matrix = matrix.rotationPart()
	x, y, z = verts
	return Mathutils.Vector(
	x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0],
	x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1],
	x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2])

####################################################
# AREA FUNCTIONS                                   #
####################################################

## Function for getting the area of a face;
def faceArea(face):
	tarObj = Object.Get(BUTTON['OBNAME'].val)
	ObMatrix = Mathutils.Matrix(tarObj.getMatrix('worldspace'));
	## Try to get the area of a quad
	try:
		v1, v2, v3, v4 = face.v 
		v1, v2, v3, v4 = apply_transform(v1.co, ObMatrix), apply_transform(v2.co, ObMatrix), apply_transform(v3.co, ObMatrix), apply_transform(v4.co, ObMatrix) 
		e1 = v1-v2
		e2 = v3-v2
		e3 = v3-v4
		e4 = v4-v1
		cp = Blender.Mathutils.CrossVecs(e1,e2) 
		area = cp.length/2 
		cp2 = Blender.Mathutils.CrossVecs(e3,e4) 
		area2 = cp2.length/2
		area = area + area2
	## If no try to get the area of the tri
	except:
		v1, v2, v3 = face.v 
		v1, v2, v3 = apply_transform(v1.co, ObMatrix), apply_transform(v2.co, ObMatrix), apply_transform(v3.co, ObMatrix)
		e1 = v1-v2 
		e2 = v3-v2 
		cp = Mathutils.CrossVecs(e1,e2) 
		area = cp.length/2
	return area
	
## Function for getting the area of a face's uv coords;
def uvArea(face):

	if NMesh.GetRaw(BUTTON['MNAME'].val).hasFaceUV() == 0:
		area = 1.0;
	else:	

		## Try to get the area of a quad
		try:
			v1 = Mathutils.Vector(face.uv[0][0], face.uv[0][1], 0.0)
			v2 = Mathutils.Vector(face.uv[1][0], face.uv[1][1], 0.0)
			v3 = Mathutils.Vector(face.uv[2][0], face.uv[2][1], 0.0)
			v4 = Mathutils.Vector(face.uv[3][0], face.uv[3][1], 0.0)
			e1 = v1-v2 
			e2 = v3-v2
			e3 = v3-v4
			e4 = v4-v1
			cp = Blender.Mathutils.CrossVecs(e1,e2) 
			area = cp.length/2 
			cp2 = Blender.Mathutils.CrossVecs(e3,e4) 
			area2 = cp2.length/2
			area = area + area2
		## If no try get the area of the tri
		except:
			v1 = Mathutils.Vector(face.uv[0][0], face.uv[0][1], 0.0)
			v2 = Mathutils.Vector(face.uv[1][0], face.uv[1][1], 0.0)
			v3 = Mathutils.Vector(face.uv[2][0], face.uv[2][1], 0.0)
			e1 = v1-v2 
			e2 = v3-v2 
			cp = Mathutils.CrossVecs(e1,e2) 
			area = cp.length/2
	return area

## Function for getting the edge length of a face.
def edgeLength(face):

	length = 0.0;

	tarObj = Object.Get(BUTTON['OBNAME'].val)
	ObMatrix = Mathutils.Matrix(tarObj.getMatrix('worldspace'));
	## Try to get the longest edge of a quad
	try:
		v1, v2, v3, v4 = face.v 
		v1, v2, v3, v4 = apply_transform(v1.co, ObMatrix), apply_transform(v2.co, ObMatrix), apply_transform(v3.co, ObMatrix), apply_transform(v4.co, ObMatrix) 
		e1 = Mathutils.Vector(v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]).length 
		e2 = Mathutils.Vector(v2[0]-v3[0], v2[1]-v3[1], v2[2]-v3[2]).length 
		e3 = Mathutils.Vector(v3[0]-v4[0], v3[1]-v4[1], v3[2]-v4[2]).length 
		e4 = Mathutils.Vector(v4[0]-v1[0], v4[1]-v1[1], v4[2]-v1[2]).length 
		
		if e1 > length:
			length = e1;
		if e2 > length:
			length = e2;
		if e3 > length:
			length = e3;
		if e4 > length:
			length = e4;

	## If no try to get the longest edge of the tri
	except:
		v1, v2, v3 = face.v 
		v1, v2, v3 = apply_transform(v1.co, ObMatrix), apply_transform(v2.co, ObMatrix), apply_transform(v3.co, ObMatrix)
		e1 = Mathutils.Vector(v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]).length 
		e2 = Mathutils.Vector(v2[0]-v3[0], v2[1]-v3[1], v2[2]-v3[2]).length 
		e3 = Mathutils.Vector(v3[0]-v1[0], v3[1]-v1[1], v3[2]-v1[2]).length 
		
		if e1 > length:
			length = e1;
		if e2 > length:
			length = e2;
		if e3 > length:
			length = e3;

	return length
	

####################################################
# RENDERSIZE ESTIMATION                            #
####################################################

## Estimate the tilemax and tilemin values from the image size
def estimate(evt):

	## If estimate is switched on
	if BUTTON['ESTIMATE'].val == 1:
	
		## Calculate non relative render after tile resize
		if BUTTON['AREATO'].val == 1 and evt == 6:
			BUTTON['SIZE'].val = int(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val);
			if BUTTON['SIZE'].val > 10000.0:
				BUTTON['TILEMAX'].val = int(round(10000 / BUTTON['SQUARE'].val));
				BUTTON['SIZE'].val = int(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val);	
			BUTTON['TILEMIN'].val = BUTTON['TILEMAX'].val;

		## Calculate non relative render after size resize
		elif BUTTON['AREATO'].val == 1 and evt == 7:
			BUTTON['TILEMAX'].val = int(math.ceil(BUTTON['SIZE'].val / BUTTON['SQUARE'].val));
			BUTTON['SIZE'].val = int(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val);
			if BUTTON['SIZE'].val > 10000.0:
				BUTTON['TILEMAX'].val = int(round(10000 / BUTTON['SQUARE'].val));
				BUTTON['SIZE'].val = int(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val);
			BUTTON['TILEMIN'].val = BUTTON['TILEMAX'].val;


		## Calculate relative rendersize
		else:
			## Get the object
			me = NMesh.GetRaw(BUTTON['MNAME'].val)

			## Set variables start values
			maxar = 0.0;
			minar = 0.0;
			totar = 0.0;

			## Get the minimum and maximum  areas
			for a in range(len(me.faces)):
				if BUTTON['AREATO'].val == 2:
					Area = uvArea(me.faces[a]);
				elif BUTTON['AREATO'].val == 3:
					Area = faceArea(me.faces[a]);
				elif BUTTON['AREATO'].val == 4:
					Area = edgeLength(me.faces[a]);

				## First pass
				if maxar == 0.0 and minar == 0.0:
					maxar = Area;
					minar = Area;
				## Check for smaller / larger values
				else:
					if Area > maxar:
						maxar = Area;
					if Area < minar:
						minar = Area;

				## Add area to total		
				totar = totar + Area;

			## Calculate min and max factors in case of face relativity
			if BUTTON['AREATO'].val == 3 or BUTTON['AREATO'].val == 4:
				minar = minar / totar;
				maxar = maxar / totar;

			## Render to existing uv coords relative to face area.
			if BUTTON['KEEPUV'].val == 1 and BUTTON['AREATO'].val == 3:

				## Set some variables
				maxuv = 0.0;

				## Get the minimum and maximum  areas
				for a in range(len(me.faces)):
					Area = uvArea(me.faces[a]);

					## First pass
					if maxuv == 0.0:
						maxuv = Area;
					## Check larger values
					else:
						if Area > maxuv:
							maxuv = Area;

				## Recalculate the minimum relative to the uv maximum
				minar = minar / (maxar / maxuv);

				## Set the maximum image factor to match the uv factor
				maxar = maxuv;				

			## If you render to an existing set of uv coords
			if BUTTON['KEEPUV'].val == 1:
				## If the tilemin value was changed
				if evt == 5:
					BUTTON['TILEMAX'].val = int(round((BUTTON['TILEMIN'].val / minar) * maxar));
					BUTTON['SIZE'].val = int(round(BUTTON['TILEMIN'].val / minar));

				## If the tilemax value was changed
				elif evt == 6:
					BUTTON['TILEMIN'].val = int(round((BUTTON['TILEMAX'].val / maxar) * minar));
					BUTTON['SIZE'].val = int(round(BUTTON['TILEMAX'].val / maxar));

				## If the image size was changed
				elif evt == 7:
					BUTTON['TILEMIN'].val = int(round(BUTTON['SIZE'].val * minar));
					BUTTON['TILEMAX'].val = int(round(BUTTON['SIZE'].val * maxar));
					
			## If you render to new uv coords
			else:
				## If the tilemin value was changed
				if evt == 5:
					BUTTON['TILEMAX'].val = int(round((BUTTON['TILEMIN'].val / minar) * maxar));
					BUTTON['SIZE'].val = int(round(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val));

				## If the tilemax value was changed
				elif evt == 6:
					BUTTON['TILEMIN'].val = int(round((BUTTON['TILEMAX'].val / maxar) * minar));
					BUTTON['SIZE'].val = int(round(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val));

				## If the image size was changed
				elif evt == 7:
					BUTTON['TILEMAX'].val = int(round(BUTTON['SIZE'].val / BUTTON['SQUARE'].val));
					BUTTON['TILEMIN'].val = int(round((BUTTON['TILEMAX'].val / maxar) * minar));
					BUTTON['SIZE'].val = int(round(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val));
			
			## Make sure the rendersize is never too big
			if BUTTON['SIZE'].val > 10000:
				maxar = 10000.0 / BUTTON['SIZE'].val;
				BUTTON['TILEMAX'].val = int(round(BUTTON['TILEMAX'].val * maxar));
				BUTTON['TILEMIN'].val = int(round(BUTTON['TILEMIN'].val * maxar));
				BUTTON['SIZE'].val = int(round(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val));
			
			## Make sure the rendersize is never too small
			if BUTTON['TILEMIN'].val < 4:
				BUTTON['TILEMIN'].val = 4;
			if BUTTON['TILEMAX'].val < 4:
				BUTTON['TILEMAX'].val = 4;
	
	## Set and reset the tile image max
	if BUTTON['TILEMAX'].val > BUTTON['TILELIMIT'].val and BUTTON['TILEMAX'].val < 9000:
		BUTTON['TILELIMIT'].val = BUTTON['TILEMAX'].val + 1000;
	elif BUTTON['TILEMAX'].val < 5000:
		BUTTON['TILELIMIT'].val = 5000;

####################################################
# GET THE RELATIVE OBJECT SIZES                    #
####################################################

def objectsizes():

	## Get all objects relative sizes
	## Set some variables
	BUTTON['MINOB'].val = 0.0;
	BUTTON['MAXOB'].val = 0.0;

	for ob in BUTTON['OBJECTLIST']:

		## Get the current object and mesh names
		obname = ob.getName()
		mname = ob.getData(1)

		## Get the object
		me = NMesh.GetRaw(mname)
		tarObj = Object.Get(obname)

		obsurf = 0.0;

		for a in me.faces:

			obsurf = obsurf + faceArea(a);

		if BUTTON['MINOB'].val == 0.0 and BUTTON['MAXOB'].val == 0.0:
			BUTTON['MINOB'].val = obsurf;
			BUTTON['MAXOB'].val = obsurf;
		else:
			if obsurf > BUTTON['MAXOB'].val:
				BUTTON['MAXOB'].val = obsurf;
			if obsurf < BUTTON['MINOB'].val:
				BUTTON['MINOB'].val = obsurf;
		
	BUTTON['MAXOB'].val = BUTTON['MAXOB'].val - BUTTON['MINOB'].val;
				
####################################################
# GET THE RELATIVE CURRENT OBJECT SIZE             #
####################################################

def cursize():

	curob = 0.0;
	obsurf = 0.0;
	
	## Get the object
	me = NMesh.GetRaw(BUTTON['MNAME'].val)
	tarObj = Object.Get(BUTTON['OBNAME'].val)
	
	## Get the nr of faces in the mesh
	BUTTON['FACES'].val = int(len(me.faces));
			
	## Get the square value for the image size
	BUTTON['SQUARE'].val = math.ceil(math.sqrt(BUTTON['FACES'].val));

	for a in me.faces:
		obsurf = obsurf + faceArea(a);

	curob = obsurf;

	## Calculate the factors
	curob = curob - BUTTON['MINOB'].val;

	## Calculate the total rendersize for this object
	BUTTON['SIZE'].val = int(round(((curob / BUTTON['MAXOB'].val) * (BUTTON['MAXSIZE'].val - BUTTON['MINSIZE'].val)) + BUTTON['MINSIZE'].val));


####################################################
# DRAW THE GUI                                     #
####################################################

def gui():

	try:
		## Create a list of all mesh objects
		BUTTON['OBJECTLIST'] = [ob for ob in Blender.Scene.GetCurrent().objects  if ob.getType() == 'Mesh']

		## Get the total nr of objects
		BUTTON['OBTOTAL'].val = len(BUTTON['OBJECTLIST']);

		## Get the selected object
		BUTTON['OBNAME'].val = Blender.Scene.GetCurrent().getActiveObject().getName()

		## Get the name of the mesh of the selected object
		BUTTON['MNAME'].val = Object.GetSelected()[0].getData(1)

		## Get the mesh
		me = NMesh.GetRaw(BUTTON['MNAME'].val)
		
		## Get the nr of faces in the mesh
		BUTTON['FACES'].val = int(len(me.faces));

		## Get the square value for the image size
		BUTTON['SQUARE'].val = math.ceil(math.sqrt(BUTTON['FACES'].val));

		## If estimate is on
		if BUTTON['ESTIMATE'].val == 1:
			## Get the tile size if using non relative render.
			if BUTTON['AREATO'].val == 1:
				BUTTON['TILEMAX'].val = int(math.ceil(BUTTON['SIZE'].val / BUTTON['SQUARE'].val));

				BUTTON['SIZE'].val = int(BUTTON['TILEMAX'].val * BUTTON['SQUARE'].val);

		if BUTTON['FSEL'].val != 3:
			## Check to see whether the current mesh has uv coords available
			if NMesh.GetRaw(BUTTON['MNAME'].val).hasFaceUV() == 0:
				BUTTON['UVAVAIL'].val = 0;
			else:
				BUTTON['UVAVAIL'].val = 1;
	except:
	
		## No selected mesh
		BUTTON['FACES'].val = 0;
				
	#############################################################
	# Backgrounds                                               #
	#############################################################
	
	BGL.glClearColor(0.5, 0.5, 0.5, 0.0)
	BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
	
	BGL.glColor3f(0, 0, 0)			# Black background
	BGL.glRectf(1, 1, 249, 396)
	
	BGL.glColor3f(0.7, 0.9, 1)		# Light background
	BGL.glRectf(3, 3, 248, 395)
	
	BGL.glColor3f(0, 0, 0)			# Black TOP
	BGL.glRectf(4, 335, 247, 385)
	
	BGL.glColor3f(0.3, 0.3, 0.3)	# Dark purple 1
	BGL.glRectf(4, 57, 247, 334)
	
	BGL.glColor3f(0, 0, 0)			# Black Lowest
	BGL.glRectf(4, 4, 247, 56)
	
	#############################################################
	# TEXT                                                      #
	#############################################################
	
	BGL.glColor3f(0.0, 0.0, 0.0)
	BGL.glRasterPos2d(6, 386)
	Draw.Text("macouno (c) 2006 v 3.4")
	
	BGL.glColor3f(0.8, 0.9, 1)
	
	## Comment if there's no mesh selected
	if BUTTON['FACES'].val == 0:
		BGL.glRasterPos2d(20, 356)
		Draw.Text("No object with faces selected!")
		BGL.glRasterPos2d(20, 341)
		Draw.Text("Select one and press reset!")
	
	## Draw menu data
	else:
		BGL.glRasterPos2d(20, 371)
		Draw.Text("This scene has ")
		Draw.Text(str(BUTTON['OBTOTAL'].val))
		Draw.Text(" mesh objects")
		BGL.glRasterPos2d(20, 356)
		Draw.Text("The selected object is ")
		Draw.Text(str(BUTTON['OBNAME'].val))
		BGL.glRasterPos2d(20, 341)
		Draw.Text("The nr of faces is ")
		Draw.Text(str(BUTTON['FACES'].val))
		
	#############################################################
	# Buttons                                                   #
	#############################################################
	
	BGL.glColor3f(1, 1, 1)

	## Layer selection buttons
	BUTTON['LAYERS'][1] = Draw.Toggle(" ", 1, 20, 310, 20, 15, int(str(BUTTON['LAYERS'][1])), "Render this layer")
	BUTTON['LAYERS'][2] = Draw.Toggle(" ", 1, 40, 310, 20, 15, int(str(BUTTON['LAYERS'][2])), "Render this layer")
	BUTTON['LAYERS'][3] = Draw.Toggle(" ", 1, 60, 310, 20, 15, int(str(BUTTON['LAYERS'][3])), "Render this layer")
	BUTTON['LAYERS'][4] = Draw.Toggle(" ", 1, 80, 310, 20, 15, int(str(BUTTON['LAYERS'][4])), "Render this layer")
	BUTTON['LAYERS'][5] = Draw.Toggle(" ", 1, 100, 310, 20, 15, int(str(BUTTON['LAYERS'][5])), "Render this layer")
	
	BUTTON['LAYERS'][6] = Draw.Toggle(" ", 1, 130, 310, 20, 15, int(str(BUTTON['LAYERS'][6])), "Render this layer")
	BUTTON['LAYERS'][7] = Draw.Toggle(" ", 1, 150, 310, 20, 15, int(str(BUTTON['LAYERS'][7])), "Render this layer")
	BUTTON['LAYERS'][8] = Draw.Toggle(" ", 1, 170, 310, 20, 15, int(str(BUTTON['LAYERS'][8])), "Render this layer")
	BUTTON['LAYERS'][9] = Draw.Toggle(" ", 1, 190, 310, 20, 15, int(str(BUTTON['LAYERS'][9])), "Render this layer")
	BUTTON['LAYERS'][10] = Draw.Toggle(" ", 1, 210, 310, 20, 15,int(str(BUTTON['LAYERS'][10])), "Render this layer")
	
	BUTTON['LAYERS'][11] = Draw.Toggle(" ", 1, 20, 295, 20, 15, int(str(BUTTON['LAYERS'][11])), "Render this layer")
	BUTTON['LAYERS'][12] = Draw.Toggle(" ", 1, 40, 295, 20, 15, int(str(BUTTON['LAYERS'][12])), "Render this layer")
	BUTTON['LAYERS'][13] = Draw.Toggle(" ", 1, 60, 295, 20, 15, int(str(BUTTON['LAYERS'][13])), "Render this layer")
	BUTTON['LAYERS'][14] = Draw.Toggle(" ", 1, 80, 295, 20, 15, int(str(BUTTON['LAYERS'][14])), "Render this layer")
	BUTTON['LAYERS'][15] = Draw.Toggle(" ", 1, 100, 295, 20, 15, int(str(BUTTON['LAYERS'][15])), "Render this layer")
	
	BUTTON['LAYERS'][16] = Draw.Toggle(" ", 1, 130, 295, 20, 15, int(str(BUTTON['LAYERS'][16])), "Render this layer")
	BUTTON['LAYERS'][17] = Draw.Toggle(" ", 1, 150, 295, 20, 15, int(str(BUTTON['LAYERS'][17])), "Render this layer")
	BUTTON['LAYERS'][18] = Draw.Toggle(" ", 1, 170, 295, 20, 15, int(str(BUTTON['LAYERS'][18])), "Render this layer")
	BUTTON['LAYERS'][19] = Draw.Toggle(" ", 1, 190, 295, 20, 15, int(str(BUTTON['LAYERS'][19])), "Render this layer")
	BUTTON['LAYERS'][20] = Draw.Toggle(" ", 1, 210, 295, 20, 15, int(str(BUTTON['LAYERS'][20])), "Render this layer")
	
	## Frame selector
	BUTTON['FRAME'] =  Draw.Number("frame: ", 1, 130, 270, 100, 20, BUTTON['FRAME'].val, 1, 18000, "The frame to render. Current frame is default")
	
	if BUTTON['UVAVAIL'].val == 1:
		## To existing uv toggle
		BUTTON['KEEPUV'] = Draw.Toggle("to uv coords", 8, 130, 245, 100, 20, BUTTON['KEEPUV'].val, "When selected the script renders the created tiles to the UV coords the object already has! (Be carefull when rendering all objects)")
	else:
		BGL.glRasterPos2d(130, 250)
		Draw.Text("No uv coords set!")
		
	## Reset scene toggle
	if BUTTON['FSEL'].val != 3:
		BUTTON['RESCENE'] = Draw.Toggle("R scn", 1, 130, 220, 50, 20, BUTTON['RESCENE'].val, "Reset scene data after render! (Only when not rendering all objects)")
	else:
		BGL.glRasterPos2d(130, 225)
		Draw.Text("Resetting!")
	
	## Tile delete toggle
	BUTTON['DELTILES'] = Draw.Toggle("X tiles", 1, 180, 220, 50, 20, BUTTON['DELTILES'].val, "Delete tile image files after render!")
	
	## Relativity dropdown menu
	types = "Tile size relativity %t|Non relative %x1|Uv area %x2|Face area %x3|Edge length %x4"

	BUTTON['AREATO'] = Draw.Menu(types, 8, 130, 195, 100, 20, BUTTON['AREATO'].val, "Sets whether relative tile size will be calculated and whether to the 3d face size or 2d uv size")

	## Clipstart setting
	BUTTON['CLIPSTART'] = Draw.Number("c-start: ", 1, 20, 270, 100, 20, BUTTON['CLIPSTART'].val, 0.001, 10.0, "The clipstart for render (Should be smaller than the distance and clipend)")
	
	## Minimal distance setting
	BUTTON['MINDIST'] = Draw.Number("c-dist: ", 1, 20, 245, 100, 20, BUTTON['MINDIST'].val, 0.001, 100.0, "The distance from the camera to the closest verticle (Should be bigger than clipstart and smaller than clipend)")
	
	## Clipend setting
	BUTTON['CLIPEND'] = Draw.Number("c-end: ", 1, 20, 220, 100, 20, BUTTON['CLIPEND'].val, 0.1, 1000, "The clipend for render (Should be larger than the clipstart and distance settings)")
	
	## Only if not rendering all objects
	if BUTTON['FSEL'].val != 3:
		## Relative area estimator
		BUTTON['ESTIMATE'] = Draw.Toggle("esimate sizes", 8, 20, 195, 100, 20, BUTTON['ESTIMATE'].val, "Estimate the optimal image and tile sizes when altering values.")

		## Relative render tilemin slider
		if BUTTON['AREATO'].val != 1:
			BUTTON['TILEMIN'] = Draw.Slider("tile min: ", 5, 20, 170, 210, 20, BUTTON['TILEMIN'].val, 4, BUTTON['TILELIMIT'].val, 0, "Minimum tile image size")
	
		## Max tile size slider
		BUTTON['TILEMAX'] = Draw.Slider("tile max: ", 6, 20, 145, 210, 20, BUTTON['TILEMAX'].val, 4, BUTTON['TILELIMIT'].val, 0, "Maximum tile image size")
	
		## Image size slider
		BUTTON['SIZE'] = Draw.Slider("image: ", 7, 20, 120, 210, 20, BUTTON['SIZE'].val, 10, 10000, 0, "Total image size")

	## Only if rendering all objects
	else:
		BGL.glRasterPos2d(20, 200)
		Draw.Text("Estimation is on!")

		## Image size slider
		BUTTON['MINSIZE'] = Draw.Slider("min image: ", 7, 20, 145, 210, 20, BUTTON['MINSIZE'].val, 100, 10000, 0, "Minimum image size relative to object size (Tiles are calculated automaticly)")
		
		## Image size slider
		BUTTON['MAXSIZE'] = Draw.Slider("max image: ", 7, 20, 120, 210, 20, BUTTON['MAXSIZE'].val, 100, 10000, 0, "Maximum image size relative to object size (Tiles are calculated automaticly)")
	
	## Renderpath
	BUTTON['PATH'] = Draw.String("path: ", 1, 20, 95, 210, 20, BUTTON['PATH'].val, 128, "Complete path and image name without extension (When rendering all meshes the mesh name will be added)")
	
	## Render mode dropdown menu
	types = "Render modes %t|All faces %x1|Selected faces %x2|All meshes %x3"
	
	BUTTON['FSEL'] = Draw.Menu(types, 9, 130, 70, 100, 20, BUTTON['FSEL'].val, "Select which faces of the mesh you want to render")
	
	## Image type dropdown menu
	types = "Image type %t|JPG %x1|PNG %x2|Targa %x3"
	
	BUTTON['TYPE'] = Draw.Menu(types, 1, 20, 70, 100, 20, BUTTON['TYPE'].val, "The image type (Will remain set after the script is closed)")
	
	## Run script button
	if BUTTON['FACES'].val != 0:
		Draw.Button("RUN SCRIPT", 2, 20, 20, 90, 20, "Run the script!")
	
	## Reset gui button
	Draw.Button("RESET", 4, 120, 20, 50, 20, "Attempt to (re)acquire a mesh")
	## Exit button
	Draw.Button("EXIT", 3, 180, 20, 50, 20, "Exit the script!")
	
####################################################
# RENDERING SETTINGS                               #
####################################################

def setsettings():

	c = Camera.New('ortho')     # create new ortho camera data
	c.scale = 6.0               # set scale value
	cur = Scene.GetCurrent()    # get current scene
	ob = Object.New('Camera')   # make camera object
	ob.link(c)                  # link camera data with this object
	cur.link(ob)                # link object into scene
	cur.setCurrentCamera(ob)    # make this camera the active"
	CamO = cur.objects.camera
	CamG = CamO.getData()

	## Get the render path
	STATE['PATH'] = cntx.getRenderPath()
	
	## Get the image size
	STATE['SIZEX'] = cntx.imageSizeX()
	STATE['SIZEY'] = cntx.imageSizeY()
	
	## Get the current, start and end frames
	STATE['FRAME'] = cntx.currentFrame()
	STATE['STARTFRAME'] = cntx.startFrame()
	STATE['ENDFRAME'] = cntx.endFrame()
	
	## Get the aspect ratio
	STATE['ASPX'] = cntx.aspectRatioX()
	STATE['ASPY'] = cntx.aspectRatioY()
	
	## Set the start and end frames
	cntx.startFrame(BUTTON['FRAME'].val)
	cntx.endFrame(BUTTON['FRAME'].val)
	cntx.currentFrame(BUTTON['FRAME'].val)

	## Set the image render size
	cntx.imageSizeX(BUTTON['TILEMAX'].val)
	cntx.imageSizeY(BUTTON['TILEMAX'].val)
			
	## Set the aspect ratio
	cntx.aspectRatioX(1)
	cntx.aspectRatioY(1)
	
	## Enable extensions
	cntx.enableExtensions(1)
	
####################################################
# RESET SETTINGS                                   #
####################################################
	
def resetsettings():

	cur.setCurrentCamera(cam)

	## Reset the image render size
	cntx.imageSizeX(STATE['SIZEX'])
	cntx.imageSizeY(STATE['SIZEY'])
	
	## Reset the current start and end frames
	cntx.currentFrame(STATE['FRAME'])
	cntx.startFrame(STATE['STARTFRAME'])
	cntx.endFrame(STATE['ENDFRAME'])
	
	## Reset the aspect ratio
	cntx.aspectRatioX(STATE['ASPX'])
	cntx.aspectRatioY(STATE['ASPY'])
		
	## Reset the renderpath
	cntx.setRenderPath(STATE['PATH'])
	
	## Get the object
	Obz = Object.Get(BUTTON['OBNAME'].val)
	
	## Set the object as the selected object
	Obz.select(1)
	
	## Update the scene
	scene = Scene.GetCurrent()
	scene.update()
	
	## Redraw all windows
	Window.RedrawAll()
	
####################################################
# PRE SCRIPT                                       #
####################################################

def prescript():

	## Set all pre run settings
	setsettings()

	## Check for rendering all objects
	if BUTTON['FSEL'].val == 3:
	
		## Get the objects maximum and minimum sizes
		objectsizes()
		
		## Get the total nr of objects
		BUTTON['OBTOTAL'].val = len(BUTTON['OBJECTLIST']);
		
		## Loop through the object list
		for ob in BUTTON['OBJECTLIST']:
			
			## Get the current object and mesh names
			BUTTON['OBNAME'].val = ob.getName()
			BUTTON['MNAME'].val = ob.getData(1)
			
			## Get the relative object size
			cursize()
			
			## Run estimate for tile size calculation relative to total image size
			estimate(7)
			
			## Run the script
			script()
			
	## Rendering just one object
	else:
	
		## Run the script
		script()
	
	## Reset all settings
	resetsettings()
	
	## Finished with the script
	print "done";
		
####################################################
# MAIN SCRIPT                                      #
####################################################

def script():

	## Get your camera
	CamO = cur.getCurrentCamera()
	CamG = CamO.getData()

	## Set the camera clipstart
	CamG.setClipStart(BUTTON['CLIPSTART'].val)
	CamG.setClipEnd(BUTTON['CLIPEND'].val)

	## Set the filetype and extension
	if BUTTON['TYPE'].val == 1:
		cntx.setImageType(Scene.Render.JPEG)
		ext = '.jpg'
	elif BUTTON['TYPE'].val == 3:
		cntx.setImageType(Scene.Render.TARGA)
		ext = '.tga'
	else:
		cntx.setImageType(Scene.Render.PNG)
		ext= '.png'
		
	## Set frame numbers for file correction
	frchk = `BUTTON['FRAME'].val`
	frnmbr = BUTTON['FRAME'].val
	
	## Get the nr that goes before the image nr
	if frnmbr < 10:
		frchk = ('000' + frchk)
	elif frnmbr < 100:
		frchk = ('00' + frchk)
	elif frnmbr < 1000:
		frchk = ('0' + frchk)
		
	## Get the object
	me = NMesh.GetRaw(BUTTON['MNAME'].val)
	tarObj = Object.Get(BUTTON['OBNAME'].val)
	ObMatrix = Mathutils.Matrix(tarObj.getMatrix('worldspace'));
	
	obLoc = [tarObj.LocX, tarObj.LocY, tarObj.LocZ];
	
	## Set selected flag for faces
	SEL = NMesh.FaceFlags['SELECT']
	
	## Make sure these are reset in case of loop.
	BUTTON['XCOUNT'].val = 0;
	BUTTON['YCOUNT'].val = 1;
	
	BUTTON['FACEMAX'].val = 0.0;
	BUTTON['FACEMIN'].val = 0.0;
	
	## Get the minumum and maximum face sizes
	if BUTTON['TILEMIN'].val != BUTTON['TILEMAX'].val and BUTTON['AREATO'].val != 1:

		## Get the minimum and maximum face sizes
		for a in range(len(me.faces)):
			
			## See whether to use uvarea or face area
			if BUTTON['AREATO'].val == 2:
				Area = uvArea(me.faces[a]);
			elif BUTTON['AREATO'].val == 3:
				Area = faceArea(me.faces[a]);
			elif BUTTON['AREATO'].val == 4:
				Area = edgeLength(me.faces[a]);
			
			## First run
			if BUTTON['FACEMAX'].val == 0.0 and BUTTON['FACEMIN'].val == 0.0:
				BUTTON['FACEMAX'].val = Area;
				BUTTON['FACEMIN'].val = Area;
			else:
				if BUTTON['FACEMAX'].val < Area:
					BUTTON['FACEMAX'].val = Area;
				if BUTTON['FACEMIN'].val > Area:
					BUTTON['FACEMIN'].val = Area;
					
	## Get the layers used for render
	RenderLayer = [];
	for a in range(20):
		if int(str(BUTTON['LAYERS'][a])) == 1:
			RenderLayer.append(a);
	
	## Precreate some lists
	TileFiles = [];
	uvFace = [];
	TileUVs = [];
	NewUVList = [];
	
	## Get the selected face
	for a in range(len(me.faces)):
	
		## Get the relative size of the face
		if BUTTON['TILEMIN'].val != BUTTON['TILEMAX'].val and BUTTON['AREATO'].val != 1:
		
			## Set relative area to uv area
			if BUTTON['AREATO'].val == 2:
				if (uvArea(me.faces[a]) - BUTTON['FACEMIN'].val) != 0:
					## Get the % of this face
					facefactor = (BUTTON['FACEMAX'].val - BUTTON['FACEMIN'] .val) / (uvArea(me.faces[a]) - BUTTON['FACEMIN'].val);
					## Apply the % of this face to the tile size
					imfactor = int(round(((BUTTON['TILEMAX'].val - BUTTON['TILEMIN'].val) / facefactor) + BUTTON['TILEMIN'].val));
				else:
					imfactor = BUTTON['TILEMIN'] .val;
			## Set relative area to face area
			elif BUTTON['AREATO'].val == 3:
				if (faceArea(me.faces[a]) - BUTTON['FACEMIN'].val) != 0:
					## Get the % of this face
					facefactor = (BUTTON['FACEMAX'].val - BUTTON['FACEMIN'] .val) / (faceArea(me.faces[a]) - BUTTON['FACEMIN'].val);
					## Apply the % of this face to the tilesize
					imfactor = int(round(((BUTTON['TILEMAX'].val - BUTTON['TILEMIN'].val) / facefactor) + BUTTON['TILEMIN'].val));
				else:
					imfactor = BUTTON['TILEMIN'] .val;
			## Set relative area to edge length
			elif BUTTON['AREATO'].val == 4:
				if (edgeLength(me.faces[a]) - BUTTON['FACEMIN'].val) != 0:
					## Get the % of this face
					facefactor = (BUTTON['FACEMAX'].val - BUTTON['FACEMIN'] .val) / (edgeLength(me.faces[a]) - BUTTON['FACEMIN'].val);
					## Apply the % of this face to the tilesize
					imfactor = int(round(((BUTTON['TILEMAX'].val - BUTTON['TILEMIN'].val) / facefactor) + BUTTON['TILEMIN'].val));
				else:
					imfactor = BUTTON['TILEMIN'] .val;
			
			## Check for absolute minimum/maximum
			if imfactor < 4:
				imfactor = 4;
			elif imfactor > 10000:
				imfactor = 10000;
			
			## Set the image render size
			cntx.imageSizeX(imfactor)
			cntx.imageSizeY(imfactor)
	
		vOld = [0, 0, 0];
		normV = [0,0,0];
		vLoc = [];
		
		## Set the renderpath
		if BUTTON['FSEL'].val == 3:
			pth2 = (BUTTON['PATH'].val + BUTTON['OBNAME'].val + str(a));
		else:	
			pth2 = (BUTTON['PATH'].val + str(a));
		
		## Set the count nr for tile compilation location
		if BUTTON['XCOUNT'].val == BUTTON['SQUARE'].val:
			BUTTON['XCOUNT'].val = 0;
			BUTTON['YCOUNT'].val = BUTTON['YCOUNT'].val + 1;
			
		## Get the list of uvFaces
		uvFace = uvFace[:a] + [me.faces[a].uv];
		
		if me.faces[a].flag & SEL or BUTTON['FSEL'].val == 1 or BUTTON['FSEL'].val == 3:
			
			## Get the face normals for camera direction angle calculation.
			normN = normal_transform(me.faces[a].no, ObMatrix);
			
			normV[0] = normN[0] + normV[0];
			normV[1] = normN[1] + normV[1];
			normV[2] = normN[2] + normV[2];
			
			## Get the verticles for the selected faces.
			for b in range(len(me.faces[a].v)):
			
				## Get the vert locations in worldspace
				vert = apply_transform(me.faces[a].v[b].co, ObMatrix);
				
				## Get the vert's locations relative to the object centre in a list.
				vLoc = vLoc[:b] + [[vert[0], vert[1], vert[2]]];
				
				## Add the current verticle loc tot the previous locs for normal position
				vOld = [vert[0] + vOld[0], vert[1] + vOld[1], vert[2] + vOld[2]];
				
			## Normalise the normal vector
			normVL = math.sqrt(normV[0]*normV[0]+normV[1]*normV[1]+normV[2]*normV[2]);
			normVN = [normV[0]/normVL, normV[1]/normVL, normV[2]/normVL];
			
			## Get the vert position divided by the vert ammount
			vOld[0] = vOld[0] / (b + 1);
			vOld[1] = vOld[1] / (b + 1);
			vOld[2] = vOld[2] / (b + 1);
			
			## Get the relative position for each verticle
			for v in vLoc:
				
				v[0] = v[0] - vOld[0];
				v[1] = v[1] - vOld[1];
				v[2] = v[2] - vOld[2];
				
			####################################################
			# THE CAMERA                                       #
			####################################################
			
			## Get a distance in the horizontal plane for the angle calculation
			if normV[1] != 0:
				normW = math.sqrt(normV[0]*normV[0]+normV[1]*normV[1])
			else:
				normW = normV[0];
			
			## Camera angle calc... x = z/y, z = x/w
			if normV[1] != 0:
				eulZ = math.atan2(normV[0],normV[1])
			else:
				eulZ = math.pi/2;
			if normW != 0:
				eulX = math.atan2(normV[2],normW)
				eulX1 = eulX;
			else:
				eulX = 0;
				eulX1 = math.atan2(normV[2],normV[1])
				
			## Get the minimal camera distance possible
			lensScale = 0;
			minDist = 0;
			NewUV = [];
			NewCoords = [];
			
			for c in range(len(me.faces[a].v)):
				Loc = vLoc[c];
				
				## Get the direct distance from the verticle to the face normal in the horizontal.
				vRelDistZ = math.sqrt(Loc[0] * Loc[0] + Loc[1] * Loc[1])
				testangleZ = math.atan2(Loc[0],Loc[1])
				
				shouldZ = testangleZ + (math.pi - eulZ);	
				
				DistZ = math.sin(shouldZ) * vRelDistZ;
				
				## Get the distance to the verts along the camera angle for distancing and vertical axis length
				DistY = math.cos(shouldZ) * vRelDistZ;
				
				## Get the direct distance from the verticle to the face normal in the vertical.
				vRelDistX = math.sqrt(Loc[2] * Loc[2] + DistY * DistY)
				testangleX = math.atan2(Loc[2],DistY)
				
				shouldX = testangleX + eulX1;
				
				DistX = math.sin(shouldX) * vRelDistX;
				
				DistO = math.cos(shouldX) * vRelDistX;
				
				if DistO < 0:
					DistO = - DistO;
					
				## Get the new uv coords before changing values
				NewUV.append((DistZ, DistX));
				
				if DistO > minDist:
					minDist = DistO;
					
				if DistX < 0:
					DistX = - DistX;
					
				if DistX > lensScale:
					lensScale = DistX;
					
				if DistZ < 0:
					DistZ = - DistZ;
					
				if DistZ > lensScale:
					lensScale = DistZ;
					
			## Adjust the camera because the distance is relative to the midpoint
			lensScale = lensScale * 2;
			
			## Calculate the absolute minimal distance from the plane
			minDist = minDist + BUTTON['MINDIST'].val;
			
			## Calculate the new Camera Vector with the correct minimal length
			NewNormal = [normVN[0] * minDist, normVN[1] * minDist, normVN[2] * minDist]
			
			## Set the camera position according to vector and object location
			vNew = [vOld[0] + NewNormal[0], vOld[1] + NewNormal[1], vOld[2] + NewNormal[2]]
			
			## Get the camera angles in degrees.
			eulX = math.degrees(eulX);
			eulZ = math.degrees(eulZ);
			
			eulZ = - eulZ;
			eulX = - eulX;
			eulX = eulX + 90;
			eulZ = eulZ + 180;
			
			## Fix some special cases
			if normV[0] == 0 and normV[1] == 0 and normV[2] > 0:
				eulX = eulX - 90;
			elif normV[0] == 0 and normV[1] == 0 and normV[2] < 0:
				eulX = eulX + 90;
			
			## Set the camera angle, position and scale
			CamO.setLocation(vNew[0],vNew[1],vNew[2])
			CamO.setEuler(0,0,0)
			
			if BUTTON['KEEPUV'].val != 1:
				CamG.setScale(lensScale/9*10)
			else:
				CamG.setScale(lensScale)
				
			matGlobal = CamO.getMatrix('worldspace');
			
			newEuler = Mathutils.Euler([eulX,0,eulZ]).toMatrix()
			
			newEuler.resize4x4()
			
			newMat = newEuler * matGlobal;
			
			CamO.setMatrix(newMat)
			
			CamO.setLocation(vNew[0],vNew[1],vNew[2]);
			
			####################################################
			# The UV layout                                    #
			####################################################
			
			RecUVS = [];
			tileuvlist = [];
			
			## Loop through the faces
			for d in range(len(me.faces[a].v)):
				
				uvFactor = 1 / lensScale;
				
				BUTTON['XFACTOR'].val = 1 / BUTTON['SQUARE'].val;
				
				BUTTON['YFACTOR'].val = 1 - (BUTTON['XFACTOR'].val * BUTTON['YCOUNT'].val);
				
				BUTTON['XFACTOR'].val = BUTTON['XCOUNT'].val * BUTTON['XFACTOR'].val;
				
				for e in range(len(NewUV[d])):
					
					if NewUV[d][e] == 0:
						RecUVS = RecUVS[:e] + [0.5];
					else:
						RecUVS = RecUVS[:e] + [0.5 + (NewUV[d][e] * uvFactor)];
						
						
				if BUTTON['KEEPUV'].val != 1:
					
					RecUVS[0] = RecUVS[0]/BUTTON['SQUARE'].val*0.9 + BUTTON['XFACTOR'].val + (0.05 * (1 / BUTTON['SQUARE'].val));
					RecUVS[1] = RecUVS[1]/BUTTON['SQUARE'].val*0.9 + BUTTON['YFACTOR'].val + (0.05 * (1 / BUTTON['SQUARE'].val));
					
					NewUV[d] = (RecUVS[0],RecUVS[1])
					
					tileuvlist = tileuvlist[:d] + [(RecUVS[0],RecUVS[1])];
					
				else:
					tileuvlist = tileuvlist[:d] + [[RecUVS[0],RecUVS[1]]];
					
					
			TileUVs = TileUVs[:a] + [tileuvlist];
			
			####################################################
			# PER FACE RENDER                                  #
			####################################################
			
			cntx.setRenderPath(pth2)
			
			Window.ViewLayers(RenderLayer);
			
			scene = Scene.GetCurrent()
			
			scene.update()
			
			## Take a breather cause you don't want the puter to overheat
			## (I found the puter unusable for other tasks during render without this)
			#sys.sleep(50)
			
			print "rendering image", a;
			
			## Render the tile
			cntx.renderAnim()
			
			Window.ViewLayers(STATE['LAYERS']);
			
		## Create a tileuv list entry in case of selected face only render
		elif BUTTON['FSEL'].val == 2:
		
			TileUVs = TileUVs[:a] + [["fakelist"]];
			
		## Add this tile to the list of filenames
		TileFiles = TileFiles[:a] + [(pth2 + frchk + ext)];
		
		BUTTON['XCOUNT'].val = BUTTON['XCOUNT'].val + 1;
		
	####################################################
	# APPLYING NEW UV COORDS                           #
	####################################################
	
	if BUTTON['KEEPUV'].val != 1:
		
		for x in range(len(me.faces)):
			
			if me.faces[x].flag & SEL or BUTTON['FSEL'].val == 1 or BUTTON['FSEL'].val == 3:
				
				me.faces[x].uv = TileUVs[x];
				
	me.update()
				
	####################################################
	# BIG IMAGE RENDER                                 #
	####################################################
	
	oldscene = Scene.GetCurrent()
	
	scene = Scene.New();
	
	scene.makeCurrent()
	
	scene = Scene.GetCurrent()
	
	print "going to tile to texture compilation";
	
	BUTTON['XCOUNT'].val = int(BUTTON['SQUARE'].val);
	
	Meshlist = [];
	MeshNames = [];
	MatNames = [];
	
	for f in range(len(me.faces)):
	
		## Set the x & y locations for regular tile uv positioning.
		if f == 0:
			x1 = 0;
			x2 = 0;
			x3 = 1;
			x4 = 1;
			y1 = -1;
			y2 = 0;
			y3 = 0;
			y4 = -1;
			
		elif f == BUTTON['XCOUNT'].val:
			
			BUTTON['XCOUNT'].val = BUTTON['XCOUNT'].val + int(BUTTON['SQUARE'].val);
			x1 = 0;
			x2 = 0;
			x3 = 1;
			x4 = 1;
			y1 = y1 - 1;
			y2 = y2 - 1;
			y3 = y3 - 1;
			y4 = y4 - 1;
		else:
			x1 = x1 + 1;
			x2 = x2 + 1;
			x3 = x3 + 1;
			x4 = x4 + 1;
		
		## Loop through all faces
		if me.faces[f].flag & SEL or BUTTON['FSEL'].val == 1 or BUTTON['FSEL'].val == 3:
		
			print "creating tile", f;
		
			## Make a new mesh
			NewObject = Object.New('Mesh')
			scene.link(NewObject)
			
			## Get a list of created objects and meshes
			Meshlist = Meshlist[:f] + [NewObject]
			Meshname = NewObject.getData(1);
			MeshNames = MeshNames[:f] + [Meshname]
			
			image = Image.Load(TileFiles[f])
			
			## Get the new object data
			mez = NewObject.getData()
			
			if BUTTON['KEEPUV'].val == 1:
			
				if len(TileUVs[f]) == 4:
					vertlist = [0,0,0,0];
				else:
					vertlist = [0,0,0];
				
				## Create all the planes with textures according to original uv coords.
				vertlist[0] = NMesh.Vert(uvFace[f][0][0],uvFace[f][0][1],0);
				vertlist[1] = NMesh.Vert(uvFace[f][1][0],uvFace[f][1][1],0);
				vertlist[2] = NMesh.Vert(uvFace[f][2][0],uvFace[f][2][1],0);
				
				try:
					vertlist[3] = NMesh.Vert(uvFace[f][3][0],uvFace[f][3][1],0);
					vertnr = 4;
				except:
					vertnr = 3;
				
				## Add the verts and make them a face
				mez.verts.extend(vertlist)
				mez.faces.append(NMesh.Face(vertlist))
				
				## Set the UV coords for the new face
				try:
					mez.faces[-1].uv = [(TileUVs[f][0][0],TileUVs[f][0][1]),(TileUVs[f][1][0],TileUVs[f][1][1]),(TileUVs[f][2][0],TileUVs[f][2][1]),(TileUVs[f][3][0],TileUVs[f][3][1])];
				except:
					mez.faces[-1].uv = [(TileUVs[f][0][0],TileUVs[f][0][1]),(TileUVs[f][1][0],TileUVs[f][1][1]),(TileUVs[f][2][0],TileUVs[f][2][1])];
				
				## Assign the uv image to the new face
				mez.faces[-1].image = image;
				
				mez.update()
				
				comP = [0,0,0,0];
				
				## Check which edges are not shared with any others... if comp == 1 it's not...
				for a in uvFace:
					
					if a.count(uvFace[f][0]) == 1 and a.count(uvFace[f][1]) == 1:
						comP[0] += 1
					if a.count(uvFace[f][1]) == 1 and a.count(uvFace[f][2]) == 1:
						comP[1] += 1
					try:
						if a.count(uvFace[f][2]) == 1 and a.count(uvFace[f][3]) == 1:
							comP[2] += 1
						if a.count(uvFace[f][3]) == 1 and a.count(uvFace[f][0]) == 1:
							comP[3] += 1
					except:	
						if a.count(uvFace[f][2]) == 1 and a.count(uvFace[f][0]) == 1:
							comP[2] += 1
							
				## Find the corresponding face:
				for a in range(len(comP)):
					if comP[a] == 1:
					
						## Set the list length of the face being checked
						if len(uvFace[f]) != 3:
							OldOrder = [0,0,0,0]
						else:
							OldOrder = [0,0,0]
							
						## Get the Vert nrs that match the 2 faces
						OldNr1 = a;
						if len(uvFace[f]) != 3 and a == 3 or len(uvFace[f]) == 3 and a == 2:
							OldNr2 = 0
						else:
							OldNr2 = a + 1
						if OldNr1 == 0 and len(uvFace[f]) != 3:
							OldNr0 = 3
						elif OldNr1 == 0 and len(uvFace[f]) == 3:
							OldNr0 = 2
						else:
							OldNr0 = OldNr1 - 1
						if len(uvFace[f]) != 3:
							if OldNr2 == 3:
								OldNr3 = 0
							else:
								OldNr3 = OldNr2 + 1
								
						OldOrder[OldNr1] = 1;
						OldOrder[OldNr2] = 2;
						
						if len(uvFace[f]) != 3:
							OldOrder[OldNr3] = 3;
							
						for g in range(len(me.faces)):
							
							compV = 0;
							
							for b in range(len(me.faces[g].v)):
							
								## Check to see which verts of the face align
								if str(me.faces[g].v[b].co) == str(me.faces[f].v[OldNr1].co):
									compV += 1
									NewNr1 = b
									
								if str(me.faces[g].v[b].co) == str(me.faces[f].v[OldNr2].co):
									compV += 1
									NewNr2 = b
									
							## If 2 verts match and it's not the original face go create a "seamless copy"
							if compV == 2 and g != f:
								
								## Set the NRs for the new face that match the old one
								if NewNr1 == 3 and len(uvFace[g]) != 3:
									NewNr0 = 0
								elif NewNr1 == 2 and len(uvFace[g]) == 3:
									NewNr0 = 0
								else:
									NewNr0 = NewNr1 + 1
								if len(uvFace[g]) != 3:
									if NewNr2 == 0:
										NewNr3 = 3
									else:
										NewNr3 = NewNr2 - 1	
								
								vertlist = [0,0,0,0];
								
								for c in range(len(OldOrder)):
									
									## Create all the planes with textures according to original uv coords.
									if OldOrder[c] == 1:
										
										locX = uvFace[g][NewNr1][0];
										locY = uvFace[g][NewNr1][1];
										LocZ = 0.0;
										
									elif OldOrder[c] == 2:
										
										locX = uvFace[g][NewNr2][0];
										locY = uvFace[g][NewNr2][1];
										LocZ = 0.0;
										
									elif OldOrder[c] == 0 and len(uvFace[f]) == 3 and len(uvFace[g]) != 3:
										
										locX = uvFace[g][NewNr1][0] + uvFace[g][NewNr2][0] - ((uvFace[g][NewNr0][0] + uvFace[g][NewNr3][0]) * 0.5);
										locY = uvFace[g][NewNr1][1] + uvFace[g][NewNr2][1] - ((uvFace[g][NewNr0][1] + uvFace[g][NewNr3][1]) * 0.5);
										LocZ = -0.1;
										
									elif OldOrder[c] == 0 and len(uvFace[f]) == 3:
										
										locX = uvFace[g][NewNr1][0] + uvFace[g][NewNr2][0] - uvFace[g][NewNr0][0];
										locY = uvFace[g][NewNr1][1] + uvFace[g][NewNr2][1] - uvFace[g][NewNr0][1];
										LocZ = -0.1;
										
									elif OldOrder[c] == 0:
										
										locX = uvFace[g][NewNr1][0] * 2 - uvFace[g][NewNr0][0];
										locY = uvFace[g][NewNr1][1] * 2 - uvFace[g][NewNr0][1];
										LocZ = -0.1;
										
									elif OldOrder[c] == 3 and len(uvFace[g]) == 3:
										
										locX = uvFace[g][NewNr2][0] * 2 - uvFace[g][NewNr0][0];
										locY = uvFace[g][NewNr2][1] * 2 - uvFace[g][NewNr0][1];
										LocZ = -0.1;
										
									elif OldOrder[c] == 3:
										
										locX = uvFace[g][NewNr2][0] * 2 - uvFace[g][NewNr3][0];
										locY = uvFace[g][NewNr2][1] * 2 - uvFace[g][NewNr3][1];
										LocZ = -0.1;
										
									vertlist[c] = NMesh.Vert(locX,locY,LocZ);
								
								if vertlist[3] == 0:
									vertlist = [vertlist[0],vertlist[1],vertlist[2]];
									
								## Add the verts and make them a face
								mez.verts.extend(vertlist)
								mez.faces.append(NMesh.Face(vertlist))

								## Set the UV coords for the new face
								## Add the uv coords to the face
								if len(vertlist) == 3:
									mez.faces[-1].uv = [(TileUVs[f][0][0],TileUVs[f][0][1]),(TileUVs[f][1][0],TileUVs[f][1][1]),(TileUVs[f][2][0],TileUVs[f][2][1])];
								else:
									mez.faces[-1].uv = [(TileUVs[f][0][0],TileUVs[f][0][1]),(TileUVs[f][1][0],TileUVs[f][1][1]),(TileUVs[f][2][0],TileUVs[f][2][1]),(TileUVs[f][3][0],TileUVs[f][3][1])];
								## Assign the uv image to the new face
								mez.faces[-1].image = image;
								
								mez.update()
								
								## Quit the loop since we found and created the correct face for this edge
								break
								
			else:
			
				## Create the vertlist
				vertlist = [0,0,0,0];

				## Create all the planes with textures according to original uv coords.
				vertlist[0] = NMesh.Vert( x1, y1, 0);
				vertlist[1] = NMesh.Vert( x2, y2, 0);
				vertlist[2] = NMesh.Vert( x3, y3, 0);
				vertlist[3] = NMesh.Vert( x4, y4, 0);
				
				## Add the verts and make them a face
				mez.verts.extend(vertlist)
				mez.faces.append(NMesh.Face(vertlist))
				
				## Set the UV coords for the new face
				mez.faces[-1].uv = [(0,0),(0,1),(1,1),(1,0)];
									
				## Assign the uv image to the new face
				mez.faces[-1].image = image;
				
				mez.update()
				
			## New material
			NewMaterial = Material.New('TempMat')
			matname = NewMaterial.getName();
			NewMaterial.mode |= Material.Modes.ZTRANSP
			NewMaterial.mode |= Material.Modes.SHADELESS
			#NewMaterial.mode |= Material.Modes.TEXFACE
			NewMaterial.setAlpha(0.0) 
			#NewMaterial.setEmit(1.0) 
			
			## Assign new material to mesh
			mez.materials = [NewMaterial];
			
			## Get a list of created materials
			MatNames = MatNames[:f] + [matname]
			
			## Texture
			tex = Texture.New()
			tex.setType('Image')
			tex.image = image
			tex.imageFlags |= Texture.ImageFlags['USEALPHA']
			
			## Should be faster without these.
			tex.imageFlags &=~Texture.ImageFlags['INTERPOL']
			tex.imageFlags &=~Texture.ImageFlags['MIPMAP']
			
			## Set the texture modes
			NewMaterial.setTexture(0, tex)
			mtex = NewMaterial.getTextures()[0] # we know theres only one.
			mtex.mapto |= Texture.MapTo['ALPHA']
			mtex.texco = Texture.TexCo['UV']
			
			mez.update()
			
	## Add camera
	camloc = float(BUTTON['SQUARE'].val / 2);
	
	scene.link(CamO)
	
	if BUTTON['KEEPUV'].val == 1:
		CamO.setLocation(0.5,0.5,1.0)
		CamG.setScale(1.0)
	else:
		CamO.setLocation(camloc,-camloc,1.0)
		CamG.setScale(BUTTON['SQUARE'].val)
		
	## Set the Clipstart and end
	CamG.setClipStart(0.1)
	CamG.setClipEnd(5.0)	
	
	## Set camera angle
	CamO.setEuler(0,0,0)
	
	cnts = scene.getRenderingContext()
	
	## Set the image render size
	cnts.imageSizeX(BUTTON['SIZE'].val)
	cnts.imageSizeY(BUTTON['SIZE'].val)
	
	## Set the renderpath
	if BUTTON['FSEL'].val == 3:
		pth3 = (BUTTON['PATH'].val + BUTTON['OBNAME'].val);
	else:	
		pth3 = (BUTTON['PATH'].val);
	
	
	cnts.setRenderPath(pth3)
	
	## Enable extensions
	cnts.enableExtensions(1)
	cnts.enableKey()
	
	if BUTTON['KEEPUV'].val == 1:
		cnts.enableOversampling(1) 
		cnts.setOversamplingLevel(16) 
		
	## Set the start and end frames
	cnts.startFrame(BUTTON['FRAME'].val)
	cnts.endFrame(BUTTON['FRAME'].val)
	cnts.currentFrame(BUTTON['FRAME'].val)
	
	## Set the aspect ratio
	cnts.aspectRatioX(1)
	cnts.aspectRatioY(1)
	
	## Set the image type
	if BUTTON['TYPE'].val == 1:
		cnts.setImageType(Scene.Render.JPEG)
	elif BUTTON['TYPE'].val == 3:
		cnts.setImageType(Scene.Render.TARGA)
		cnts.enableRGBAColor() 
	else:
		cnts.setImageType(Scene.Render.PNG)
		cnts.enableRGBAColor() 
		
	scene.update()
	
	print "rendering final UV texture";
	
	## Render the compilation
	cnts.renderAnim()
	
	####################################################
	# REMOVE TILE MESH & TILES                         #
	####################################################
	
	print "cleaning up";
	
	## Unlink the camera from the new scene
	scene.unlink(CamO)
	
	if BUTTON['RESCENE'].val == 1:
		
		## Unlink textures from materials
		for g in range(len(MatNames)):
			
			clearme = Material.Get(MatNames[g])
			
			clearme.clearTexture(0)
			
		## Unlink materials from mesh & objects from scene
		for h in range(len(Meshlist)):
			
			mezzo = NMesh.GetRaw(MeshNames[h])
			
			mezzo.setMaterials([None]*16)
			
			mezzo.update()
			
			scene.unlink(Meshlist[h])
								
		scene.update()
		
		oldscene.makeCurrent()
		
		## Delete the temporary scene
		Scene.Unlink(scene)
		
	if BUTTON['DELTILES'].val == 1:
		## Delete the tile image files
		for f in range(len(me.faces)):
		
			me.faces[f].image = image;

			if me.faces[f].flag & SEL or BUTTON['FSEL'].val == 1 or BUTTON['FSEL'].val == 3:

				if os.path.isfile(TileFiles[f]):
					os.remove(TileFiles[f]);
		
	else:
		scene.update()
		
		## Reset the scene back to the old one.
		oldscene.makeCurrent()
		
	scene = Scene.GetCurrent()
	
	## Unlink the camera from the new scene
	scene.objects.unlink(CamO)
	
	####################################################
	# CREATE NEW MATERIAL AND TEXTURE                  #
	####################################################
	
	## New material
	NewMaterial = Material.New('BRayBaked')
	NewMaterial.mode |= Material.Modes.ZTRANSP
	NewMaterial.mode |= Material.Modes.SHADELESS
	NewMaterial.setAlpha(0.0) 
	
	## Texture
	NewTexture = Texture.New()
	NewTexture.setType('Image')
	## Set the renderpath
	if BUTTON['FSEL'].val == 3:
		image = Image.Load(BUTTON['PATH'].val + BUTTON['OBNAME'].val + frchk + ext)
	else:	
		image = Image.Load(BUTTON['PATH'].val + frchk + ext)
	
	NewTexture.image = image;
	NewTexture.imageFlags |= Texture.ImageFlags['USEALPHA']
	
	## Should be faster without these.
	NewTexture.imageFlags &=~Texture.ImageFlags['INTERPOL']
	NewTexture.imageFlags &=~Texture.ImageFlags['MIPMAP']
	
	## More material and texture modes
	NewMaterial.setTexture(0, NewTexture)
	mtex = NewMaterial.getTextures()[0]
	
	mtex.mapto |= Texture.MapTo['ALPHA']
	mtex.texco = Texture.TexCo['UV']
	
	Obz = Object.Get(BUTTON['OBNAME'].val)
	
	me = Obz.getData()
	
	me.setMaterials([NewMaterial])
	
	## Set the material for each face in case there were multiple materials assigned before
	for g in range(len(me.faces)):
	
		me.faces[g].mat = (0)
	
	## Update the mesh
	me.update()
	
####################################################
# CHECK FOR THE ESCAPE KEY                         #
####################################################

def event(evt, val):
	if (evt == Draw.QKEY and not val): Draw.Exit()
	
####################################################
# ACTION AFTER THE BUTTON HAS BEEN PRESSED         #
####################################################

## Global BUTTON
def bevent(evt):
	## Exit the script
	if (evt ==  3):
		Draw.Exit()
	## Redraw the gui
	elif (evt == 4):
		## If estimate is switched on
		if BUTTON['ESTIMATE'].val == 1 and BUTTON['AREATO'].val != 1:
			estimate(7)
		Draw.Redraw()
	## Run the script
	elif (evt == 2):
		prescript()
		Draw.Redraw()
	## Recalculate the sizes after changing the tilemin value
	elif (evt == 5):
		estimate(evt)
		Draw.Redraw()
	## Recalculate the sizes after changing the tilemax value
	elif (evt == 6):
		estimate(evt)		
		Draw.Redraw()
	## Recalculate the sizes after changin the size value
	elif (evt == 7):
		estimate(evt)
		Draw.Redraw()
	## Force reestimation after changing relative render
	elif (evt == 8):
		if BUTTON['ESTIMATE'].val == 1 and BUTTON['AREATO'].val != 1:
			estimate(7)
		Draw.Redraw()
	## Set the reset scene value to off if you're doing all mesh render
	elif (evt == 9):
		if BUTTON['FSEL'].val == 3:
			BUTTON['RESCENE'].val = 1;
			BUTTON['ESTIMATE'].val = 1;
		
			## Check whether all meshes have uv coords set
			for ob in BUTTON['OBJECTLIST']:

				Mesh = ob.getData(1)

				if NMesh.GetRaw(Mesh).hasFaceUV() == 0:
					BUTTON['UVAVAIL'].val = 0;
					BUTTON['KEEPUV'].val = 0;
		else:
			## Make uv render available again
			BUTTON['UVAVAIL'].val = 1;
			
		Draw.Redraw()
	elif (evt == 10):
		Draw.Redraw()
		
####################################################
# REGISTER THE FUNCTIONS                           #
####################################################

Draw.Register(gui, event, bevent)