# --------------------------------------------------------------------------
# Illusoft Collada 1.4 plugin for Blender
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Illusoft - colladablender@illusoft.com
# 2008.05.08 modif. for debug mode by migius (AKA Remigiusz Fiedler)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

from cutils import *
import collada
import Blender
from Blender.Mathutils import *
import math
import datetime
from helperObjects import *

class Translator(object):
	isImporter = False

	def __init__(self, isImporter, version, debugM, fileName, _useTriangles, _usePolygons, _bakeMatrices, _exportSelection, _createNewScene, _clearScene, _lookAt, _exportPhysics, _exportCurrentScene, _exportRelativePaths, _useUV, _sampleAnimation, _onlyMainScene):
		global __version__, debugMode, usePhysics, useTriangles, usePolygons, bakeMatrices, exportSelection, createNewScene, clearScene, lookAt, replaceNames, exportPhysics, exportCurrentScene, useRelativePaths, useUV, sampleAnimation, onlyMainScene
		#print 'deb:class_Translator isImporter=', isImporter #deb---------
		__version__ = version
		debugMode = debugM
		usePhysics = None
		useTriangles = _useTriangles
		usePolygons = _usePolygons
		bakeMatrices = _bakeMatrices
		exportSelection = _exportSelection
		createNewScene = _createNewScene
		clearScene = _clearScene
		lookAt = _lookAt
		exportPhysics = _exportPhysics
		usePhysics = _exportPhysics
		exportCurrentScene = _exportCurrentScene
		useRelativePaths = _exportRelativePaths
		useUV = _useUV
		sampleAnimation = _sampleAnimation
		onlyMainScene= _onlyMainScene

		replaceNames = clearScene

		self.isImporter = isImporter
		self.fileName = ''
		#print 'deb:class_Translator fileName=', fileName #deb---------
		if self.isImporter:
			self.__Import(fileName)
		else:
			self.__Export(fileName)

	def __Import(self,fileName=''):
		#print 'deb:translator__Import fileName=', fileName #deb---------
		documentTranslator = DocumentTranslator(fileName)
		documentTranslator.Import(fileName)

	def __Export(self,filename=''):
		documentTranslator = DocumentTranslator(filename)
		documentTranslator.Export(filename)


class DocumentTranslator(object):
	isImport = None
	ids = []
	sceneGraph = None

	# Keep track of the layers on import
	layers = None

	cameraLibrary = None
##	  geometryLibrary = None
	controllersLibrary = None
	animationsLibrary = None
##	  materialLibrary = None
	texturesLibrary = None
	lampsLibrary = None
	colladaDocument = None
	scenesLibrary = None
	fps = 25

	def CreateID(self, name, typeName=None):
		if len(name) > 0 and not name[0].isalpha():
			name = "i"+name

		if not (name in self.ids):
			self.ids.append(name)
			return name
		else:
			tempName = name;
			if not(typeName is None) and name.rfind(typeName) >= 0:
				# Check for existing number at the end?
				return self.IncrementString(tempName, True)
			else:
				# First check if no Blender Object exists with the name 'tempName + typeName'
				if (tempName + typeName) in self.allBlenderNames:
					return self.IncrementString(tempName + typeName, True)
				else:
					return self.CreateID(tempName+typeName, typeName)

	def IncrementString(self, name, checkName):
		tempName = name;
		if name.rfind('.') >= 0:
			while tempName[-1:].isdigit():
				tempName =	tempName[:-1]
			digitStr = name[-(len(name)-len(tempName)):]
			digit = 1
			if len(digitStr) > 0 and len(digitStr) != len(name):
				digit = int(digitStr)+1
			newName = tempName+str(digit).zfill(3)
		else:
			newName = name+'.001'

		if not (newName in self.ids) and (not checkName or not (newName in self.allBlenderNames)):
			self.ids.append(newName)
			return newName
		else:
			return self.IncrementString(newName, checkName)

	def __init__(self, fileName):
		global waitingControllers, armatures
		# Keep track of the controller that are waiting to be applied
		waitingControllers = dict()
		# Keep track of the armatures created
		armatures = dict()

		self.isImport = False
		self.scenesLibrary = ScenesLibrary(self)
		self.sceneGraph = SceneGraph(self)
		self.lampsLibrary = LampsLibrary(self)
		self.colladaDocument = None
		self.texturesLibrary = TexturesLibrary(self)
		self.camerasLibrary = CamerasLibrary(self)
		self.materialsLibrary = MaterialsLibrary(self)
		self.meshLibrary = MeshLibrary(self)
		self.animationsLibrary = AnimationsLibrary(self)
		self.controllersLibrary = ControllersLibrary(self)

		self.filename = None
		self.filePath = ''


		self.currentBScene = Blender.Scene.GetCurrent()

		self.progressCount = 0.4
		self.progressField = (1.0 - self.progressCount)
		self.progressStep = 0.0
		self.progressPartCount = 0.0

		self.tMatOLD = Matrix()
		self._zUpMatrix = Matrix()
		self._yUpMatrix = Matrix(
		[0,0,1,0],
		[1,0,0,0],
		[0,1,0,0],
		[0,0,0,1])

		self.axisTransformMatrix = Matrix()
		self.inverseAxisTransformMatrix  = Matrix()
		self.orgAxiss = ["X","Y","Z"]


	def CreateNameForObject(self, name, replace, myType):
		if not replace:
			return name

		if myType == 'object':
			try:
				ob = Blender.Object.Get(name)
				ob.name = self.CreateNameForObject(self.IncrementString(ob.name, False), True, 'object')
			except ValueError:
				pass
		elif myType == 'mesh':
			try:
				mesh = Blender.Mesh.Get(name)
				if not mesh is None:
					mesh.name = self.CreateNameForObject(self.IncrementString(mesh.name, False), True, 'mesh')
			except ValueError:
				pass
		elif myType == 'armature':
			try:
				armature = Blender.Armature.Get(str(name))
				if not armature is None:
					armature.name = self.CreateNameForObject(self.IncrementString(armature.name, False), True, 'armature')
			except ValueError:
				pass
		elif myType == 'camera':
			try:
				camera = Blender.Camera.Get(str(name))
				if not camera is None:
					camera.name = self.CreateNameForObject(self.IncrementString(camera.name, False), True, 'camera')
			except NameError:
				pass
		elif myType == 'lamp':
			try:
				lamp = Blender.Lamp.Get(str(name))
				if not lamp is None:
					lamp.name = self.CreateNameForObject(self.IncrementString(lamp.name, False), True, 'lamp')
			except NameError:
				pass

		return name

	def Import(self, fileName):
		global debugMode, createNewScene
		#print 'deb:DocumentTranslator_Import fileName', fileName #deb---------
		self.filename = fileName
		self.filePath = Blender.sys.dirname(self.filename) + Blender.sys.sep
		self.isImport = True
		Blender.Window.EditMode(0)
		Blender.Window.DrawProgressBar(0.0, 'Starting Import')

		# Keep track of the 20 layers
		self.layers = [None for x in range(20)]

		if createNewScene:
			self.currentBScene = Blender.Scene.New('Scene')
			self.currentBScene.makeCurrent()
		else:
			self.currentBScene = Blender.Scene.GetCurrent()

		# Create a new Collada document
		Blender.Window.DrawProgressBar(0.1, 'Get Collada Document')
		self.colladaDocument = collada.DaeDocument(debugMode)

		# Setup the libraries
		self.camerasLibrary.SetDaeLibrary(self.colladaDocument.camerasLibrary)
		self.lampsLibrary.SetDaeLibrary(self.colladaDocument.lightsLibrary)
		self.texturesLibrary.SetDaeLibrary(self.colladaDocument.imagesLibrary)
		self.materialsLibrary.SetDaeLibrary(self.colladaDocument.materialsLibrary)
		self.meshLibrary.SetDaeLibrary(self.colladaDocument.geometriesLibrary)
		self.animationsLibrary.SetDaeLibrary(self.colladaDocument.animationsLibrary)
		self.controllersLibrary.SetDaeLibrary(self.colladaDocument.controllersLibrary)

		# Parse the COLLADA file
		self.colladaDocument.LoadDocumentFromFile(fileName)

		self.axiss = ["X", "Y", "Z"]
		if self.colladaDocument.asset.upAxis == collada.DaeSyntax.Y_UP:
			self.tMatOLD[0][0] = 0
			self.tMatOLD[1][1] = 0
			self.tMatOLD[2][2] = 0
			self.tMatOLD[0][1] = 1
			self.tMatOLD[1][2] = 1
			self.tMatOLD[2][0] = 1
			self.axiss = ["Y", "Z", "X"]

		if self.colladaDocument.asset.upAxis == collada.DaeSyntax.Y_UP:
			self.axisTransformMatrix = Matrix(self._yUpMatrix)
			self.axiss = ["Y", "Z", "X"]

		self.inverseAxisTransformMatrix = Matrix(self.axisTransformMatrix).invert()



		self.progressStep = self.progressField/(self.colladaDocument.GetItemCount()+1)

		# Get the animation info
		animations = AnimationInfo.CreateAnimations(self.animationsLibrary, self.fps, self.axiss)

		# Read the COLLADA stucture and build the scene in Blender.
		Blender.Window.DrawProgressBar(0.4, 'Translate Collada 2 Blender')
		self.sceneGraph.LoadFromCollada(self.colladaDocument.visualScenesLibrary.items, self.colladaDocument.scene)

		self.Progress()

	def CalcVector(self, vector):
		if self.colladaDocument.asset.upAxis == collada.DaeSyntax.Y_UP:
			return Vector(vector[2], vector[0], vector[1])
		else:
			return vector


	# Calculate the correct transform matrix dependent of the current UP axis.
	# When Up axis is Yup:
	# orgTrans * vecYup = newVecYup
	# newTrans * vecZup = newVecZup
	# vecZup = tMat * vecYUp
	# vecYup = invtMat * vecZup
	# newVecYup = orgTrans * vecYup = orgTrans * (invtMat * vecZup)
	# newVecZup = tMat * newVecYup = tMat * (orgTrans * (invtMat * vecZup))
	# newTrans = tMat * orgTrans * invtMat
	def CalcMatrix(self, matrix):
		if self.colladaDocument.asset.upAxis == collada.DaeSyntax.Y_UP:
			return self.axisTransformMatrix * matrix * self.inverseAxisTransformMatrix
		else:
			return matrix

	def CalcMatrixReverse(self, matrix):
		if self.colladaDocument.asset.upAxis == collada.DaeSyntax.Y_UP:
			return self.inverseAxisTransformMatrix * matrix * self.axisTransformMatrix
		else:
			return matrix

	def Export(self, fileName):
		global __version__, filename, usePhysics
		filename = fileName
		self.ids = []
		self.isImport = False
		Blender.Window.EditMode(0)

		# Create a new Collada document
		self.colladaDocument = collada.DaeDocument(debugMode)
		daeAsset = collada.DaeAsset()
		daeAsset.upAxis = 'Z_UP'
		daeAsset.created = datetime.datetime.today()
		daeAsset.modified = datetime.datetime.today()
		daeAsset.unit = collada.DaeUnit()
		daeAsset.unit.name = 'centimeter'
		daeAsset.unit.meter = '0.01'
		daeContributor = collada.DaeContributor()
		daeContributor.author = 'Illusoft Collada 1.4.0 plugin for Blender - http://colladablender.illusoft.com'
		daeContributor.authoringTool = 'Blender v:%s - Illusoft Collada Exporter v:%s' % (Blender.Get('version'), __version__)
		daeContributor.sourceData = GetValidFilename(Blender.Get('filename'))
		daeAsset.contributors.append(daeContributor)

		self.colladaDocument.asset = daeAsset

		bObjects = Blender.Object.Get()
		self.allBlenderNames = [x.getData(True) for x in bObjects] + [x.name for x in bObjects]

		daeScene = collada.DaeScene()

		# Loop throug all scenes
		for bScene in Blender.Scene.Get():
			if not exportCurrentScene or self.currentBScene == bScene:
				self.fps = bScene.getRenderingContext( ).framesPerSec()
				daeInstanceVisualScene = collada.DaeVisualSceneInstance()
				if usePhysics:
					daeInstancePhysicsScene = collada.DaePhysicsSceneInstance()

				daeVisualScene = self.colladaDocument.visualScenesLibrary.FindObject(bScene.name)
				if daeVisualScene is None:
					sceneGraph = SceneGraph(self)
					scenesList = sceneGraph.SaveToDae(bScene)
					daeVisualScene = scenesList[0]
					if usePhysics:
						daePhysicsScene = scenesList[1]

				daeInstanceVisualScene.object = daeVisualScene

				#self.colladaDocument.visualScenesLibrary.AddItem(daeIntanceVisualScene)
				if self.currentBScene == bScene:
					daeScene.iVisualScenes.append(daeInstanceVisualScene)
					if usePhysics:
						if not (daePhysicsScene is None):
							daeInstancePhysicsScene.object = daePhysicsScene
							daeScene.iPhysicsScenes.append(daeInstancePhysicsScene)

				#self.colladaDocument.visualScenesLibrary.AddItem(sceneGraph.ObjectToDae(bScene))
				#daeScene = collada.DaeScene()
				#daeScene.AddInstance()


		self.colladaDocument.scene = daeScene

		self.colladaDocument.SaveDocumentToFile(fileName)

	def Progress(self):
		self.progressPartCount = 0.0
		self.progressCount += self.progressStep
		Blender.Window.DrawProgressBar(self.progressCount, 'Creating Blender Nodes...')

	def ProgressPart(self, val, text):
		self.progressPartCount += val
		Blender.Window.DrawProgressBar(self.progressCount+self.progressPartCount*self.progressStep,text)

class SceneGraph(object):

	def __init__(self, document):
		self.document = document
		self.name = ''

		self.childNodes = dict()
		self.rootNodes = []

		self.objectNames = dict()
		# Get the current blender scene
		#self.currentBScene = Blender.Scene.getCurrent()

	def LoadFromCollada(self, visualScenes, colladaScene):
		global debugMode, newScene, clearScene, onlyMainScene
		currentBlenderSceneNames = [x.name for x in Blender.Scene.Get()]


		if visualScenes is None or len(visualScenes) == 0:
			return False

		# When in debugMode, delete everything from the scene before proceding
		if debugMode or clearScene:
			print "Delete everything from the scene.."
			bNodes = Blender.Object.Get()

			count = 0
			newName = "TEMPSCENE"
			newTempName = newName

			colladaSceneNames = [x.name for x in visualScenes]
			while newTempName in currentBlenderSceneNames+colladaSceneNames:
				count = count + 1
				newTempName = newName + str(count).zfill(3)

			tempScene = Blender.Scene.New(newTempName)
			tempScene.makeCurrent()

			if onlyMainScene: # delete only current scene
				Blender.Scene.Unlink(self.document.currentBScene)
			else: # delete all scenes except for the one just created
				for bs in Blender.Scene.Get():
					if not bs.name == newTempName:
						Blender.Scene.Unlink(bs)
			self.document.currentBScene = tempScene

		#if colladaScene == None:
		#	return False

		##//visualScenes = colladaScene.GetVisualScenes()
		##if visualScenes is None:
		##	return
		setDefaultScene = True

		for visualScene in visualScenes:
			if not onlyMainScene or (onlyMainScene and visualScene == colladaScene.GetVisualScene()):
				# Create a new Scene
				newName = visualScene.name
				count = 0
				nameCol = []
				if not clearScene:
					nameCol = nameCol+currentBlenderSceneNames
				while newName in nameCol:
					count = count + 1
					newName = visualScene.name + str(count).zfill(3)
				newScene = Blender.Scene.New(newName)
				self.document.currentBScene = newScene
				if onlyMainScene or (not onlyMainScene and clearScene and not colladaScene is None):
					newScene.makeCurrent()
					setDefaultScene = False

				Blender.Window.DrawProgressBar(0.5,'Build the items on the scene')
				# loop trough all nodes
				for daeNode in visualScene.nodes:
					sceneNode = SceneNode(self.document, None)
					ob = sceneNode.ObjectFromDae(daeNode)
					if ob != None:
						self.objectNames[daeNode.id] = ob.name
					##sceneNode.ObjectFromDae(daeNode)
			if visualScene == colladaScene.GetVisualScene():
				# Now get the physics Scene
				physicsScenes = colladaScene.GetPhysicsScenes()
				if not (physicsScenes is None) and len(physicsScenes) > 0:
					# For now, only pick the fist available physics Scene
					physicsScene = physicsScenes[0]
					for iPhysicsModel in physicsScene.iPhysicsModels:
						physicsNode = PhysicsNode(self.document)
						physicsNode.LoadFromDae(iPhysicsModel, self.objectNames)

		if setDefaultScene:
			Blender.Scene.Get()[0].makeCurrent()
		if clearScene:
			Blender.Scene.Unlink(tempScene)
			tempScene = None

		# Update the current Scene.
		self.document.currentBScene.update(1)

	def SaveToDae(self, bScene):
		global exportSelection, usePhysics
		daeVisualScene = collada.DaeVisualScene()
		daeVisualScene.id = daeVisualScene.name = self.document.CreateID(bScene.name,'-Scene')
		daePhysicsScene = collada.DaePhysicsScene()
		daePhysicsScene.id = daePhysicsScene.name = self.document.CreateID(bScene.name+'-Physics', '-Scene')

		if exportSelection:
			self.rootNodes = Blender.Object.GetSelected()
			self.childNodes = []
		else: # now loop trough all nodes in this scene and create a list with root nodes and children
			for node in bScene.objects:
				pNode = node.parent
				if pNode is None:
					self.rootNodes.append(node)
				else:
					try:
						self.childNodes[pNode.name].append(node)
					except:
						self.childNodes[pNode.name] = [node]

		# Create a new Physics Model.
		daePhysicsModel = collada.DaePhysicsModel();
		daePhysicsModel.id = daePhysicsModel.name = self.document.CreateID(bScene.name,'-PhysicsModel')

		# Create a new Physics Model Instance.
		daePhysicsModelInstance = collada.DaePhysicsModelInstance()

		# Set the Physics Model of this instance.
		daePhysicsModelInstance.object = daePhysicsModel
		# add the physics model to the library.
		if usePhysics:
			self.document.colladaDocument.physicsModelsLibrary.items.append(daePhysicsModel)
		if not daePhysicsModelInstance is None:
		    daePhysicsScene.iPhysicsModels.append(daePhysicsModelInstance)

		# Begin with the rootnodes
		for rootNode in self.rootNodes:
			sceneNode = SceneNode(self.document,self)
			nodeResult = sceneNode.SaveSceneToDae(rootNode,self.childNodes,daePhysicsModel,daePhysicsModelInstance)
			daeNode = nodeResult[0]
			daeVisualScene.nodes.append(daeNode)

		self.document.colladaDocument.visualScenesLibrary.AddItem(daeVisualScene)
		if usePhysics and len(daePhysicsScene.iPhysicsModels) > 0:
			self.document.colladaDocument.physicsScenesLibrary.AddItem(daePhysicsScene)
		else:
			daePhysicsScene = None
			daePhysicsModel = None

		return (daeVisualScene, daePhysicsScene)

class PhysicsNode(object):
	dynamic = 0
	child = 1
	actor = 2
	inertiaLockX = 3
	inertiaLockY = 4
	inertiaLockZ = 5
	doFH = 6
	rotFH = 7
	anisotropicFriction = 8
	ghost = 9
	rigidBody = 10
	bounds = 11
	collisionResponse = 12

	def __init__(self, document):
		self.document = document

	def LoadFromDae(self, daeInstancePhysicsModel, objectNames):
		global usePhysics
		if not(usePhysics is None) and not usePhysics:
			return
		for iRigidBody in daeInstancePhysicsModel.iRigidBodies:
			# Get the real blender name instead of the collada name.
			realObjectName = objectNames[iRigidBody.targetString]
			# Get the Blender object with the specified name.
			bObject = Blender.Object.Get(realObjectName)
			# Check if physics is supported.
			if usePhysics is None:
				usePhysics = hasattr(bObject, "rbShapeBoundType")
				if not usePhysics:
					return

			# Get the rigid body.
			rigidBody = daeInstancePhysicsModel.object.FindRigidBody(iRigidBody.bodyString)
			##rigidBody = iRigidBody.body
			# Get the common technique of the rigid body.
			rigidBodyT = rigidBody.techniqueCommon
			# Get the physics material.
			physicsMaterial = rigidBodyT.GetPhysicsMaterial()
			# Get the shapes of the bounding volumes in this rigid body.
			shapes = rigidBodyT.shapes

			# The Rigid Body Flags
			rbFlags = 0 + rigidBodyT.dynamic + (1 << self.actor) + (1 << self.rigidBody) + (1 << self.bounds)
			rbShapeBoundType = 0
			# For now only get the first shape
			shape = shapes[0]
			# Check the type of the shape
			if isinstance(shape, collada.DaeGeometryShape):
				##print shape, shape.iGeometry.object.data
				if isinstance(shape.iGeometry.object.data, collada.DaeMesh):
					rbShapeBoundType = 4
				else:
					rbShapeBoundType = 5
			elif isinstance(shape, collada.DaeBoxShape):
				rbShapeBoundType = 0
			elif isinstance(shape, collada.DaeSphereShape):
				rbShapeBoundType = 1
			elif isinstance(shape, collada.DaeCylinderShape):
				rbShapeBoundType = 2
			elif isinstance(shape, collada.DaeTaperedCylinderShape):
				rbShapeBoundType = 3

			bObject.rbFlags = rbFlags
			if not (rigidBodyT.mass is None):
				bObject.rbMass = rigidBodyT.mass

			bObject.rbShapeBoundType = rbShapeBoundType

class Controller(object):
	def __init__(self, document):
		self.document = document
		self.bMesh = None
		self.daeController = None
		self.armatureName = None
		self.modifier = None
		self.bObject = None

	# Recursive method for setting the locations of the bones from their Bind matrices.
	def PositionBone(self, boneName, armature, bindMatrices):
		# Get the boneInfo for this bone.
		boneInfo = armature.boneInfos[boneName]
		# Get the jointName for this bone.
		jointName = boneInfo.GetJointName()

		##		headJointName = boneInfo.name
##		tailJointName =

##		print "deb: bone:" , boneName, "- headJoint:", jointName, "- tailJoint:", boneInfo.GetTailName(), "- isEnd:", boneInfo.IsEnd()

		# Get the BindMatrix for the head of this bone.
		headMatrix = bindMatrices[jointName]
		# Get the name of the tail joint.
		tailJointName = boneInfo.GetTailName()##armature.boneInfos[boneName].tailJointName
		# If there is a tail joint, get the BindMatrix for that joint.

		tailMatrix = bindMatrices[tailJointName]
##		PrintTransforms(headMatrix, boneName)
##		if not boneInfo.IsEnd():
##			tailMatrix = bindMatrices[tailJointName]
		# Get the location of the armature Object.
		armatureLocation = armature.GetLocation()
		# Create a vector at [0,0,0,1]
		nullVec = Vector().resize4D()

		# Calculate the position of the head
		headVec = self.document.CalcVector(headMatrix * nullVec).resize4D() ##- armatureLocation
		headVec = Matrix(armature.GetTransformation()).transpose().invert() * headVec
		# Set the default value for the tail.
		tailVec = headVec + Vector(0,0,1,1)
		# If this bone has a Tail joint, calculate the position of the tail.
		if not boneInfo.IsEnd():
			tailVec = self.document.CalcVector(tailMatrix * nullVec).resize4D() ##- armatureLocation
			tailVec = Matrix(armature.GetTransformation()).transpose().invert() * tailVec
		else:
			parentBone = boneInfo.parent.GetBone()
			tailVec =  2 * headVec - Vector(parentBone.head).resize4D()
##			pass#PrintTransforms(headMatrix, jointName)
			##tailVec = (headMatrix * headVec)-armatureLocation
			##print jointName, headVec, headMatrix
			##print headVec, boneInfo.GetBone().tail - boneInfo.GetBone().head
			##tailVec = headVec + (boneInfo.GetBone().tail - boneInfo.GetBone().head).resize4D()
##			parentBoneInfo = boneInfo.parent
##			print "parentBoneInfo:",parentBoneInfo.name
##			if not parentBoneInfo is None:
##				parentBone = parentBoneInfo.GetBone()
##				tailVec = 2 * parentBone.tail - parentBone.head
##			else:
##				tailVec = Vector(0,0,1,1)

##		if boneInfo.IsRoot():
##			headVec -= Vector(0,0,-0.1,1)

		# Set the head and tail location.
##		if not boneInfo.IsEnd():
			##PrintTransforms(self.document.CalcMatrix(tailMatrix) * Matrix(armature.GetTransformation()).invert(), tailJointName)
##			PrintTransforms(self.document.CalcMatrix(tailMatrix), tailJointName)
			##boneInfo.GetBone().matrix = self.document.CalcMatrix(tailMatrix).transpose() * Matrix(armature.GetTransformation()).invert()
			##if boneName == "root" or boneName == "pelvis" or boneName == "spine":
##			print boneName
##			print boneInfo.GetHead()
##			print boneInfo.GetTail()
##			print headVec
##			print tailVec
##			print
		boneInfo.SetHead(headVec)
		boneInfo.SetTail(tailVec)



		##PrintTransforms(TranslationMatrix(armatureLocation).transpose(),"armature")
		##PrintTransforms(self.document.CalcMatrix(headMatrix)*
##		boneInfo.GetBone().matrix = self.document.CalcMatrix(headMatrix).transpose() ##* TranslationMatrix(armatureLocation).invert()

		# Do the same for each child.
		for childBoneName in boneInfo.childs:
			self.PositionBone(childBoneName, armature, bindMatrices)

	def PoseBone(self, boneName, armature, bindMatrices, bPose, parentBindI = Matrix()):
		boneInfo = armature.boneInfos[boneName]
		bBone = boneInfo.GetBone()
		jointName = boneInfo.GetJointName()
		#print 'deb:class Controller_PoseBone() bindMatrices=', bindMatrices #----------
		bindMatrixCollada = bindMatrices[jointName]
		bindMatrixBlender = self.document.CalcMatrix(bindMatrixCollada)
##		PrintTransforms(bindMatrixBlender, "bind "+boneName)
		bindMatrixBlenderI = Matrix(bindMatrixBlender).invert()

		# calculate the local transform for the current position
		F = boneInfo.localTransformMatrix
##		PrintTransforms(F, "local transform");
		# calculate the transform in bindmode relative to its parent bind pose.
		E = parentBindI * bindMatrixBlender

		deltaBlender = Matrix()
##		if jointName != boneName:
			# calculate the difference between the two transforms
		deltaBlender = Matrix(E).invert() * F
##		PrintTransforms(deltaBlender, "delta")
		deltaBlenderT = Matrix(deltaBlender).transpose()

		# Set the transform
		bPose.bones[boneName].localMatrix = deltaBlenderT

		# Do the same for each child.
		for childBoneName in boneInfo.childs:
			self.PoseBone(childBoneName, armature, bindMatrices, bPose, bindMatrixBlenderI)

	def AnimateBone(self, boneName, armature, bPose, action):
		boneInfo = armature.boneInfos[boneName]
		animationInfo = AnimationInfo.GetAnimationInfo(boneName)
		if not animationInfo is None:
			def pose_rot(anim_data):
				bone_rotation_matrix= Euler(anim_data[0], anim_data[1], anim_data[2]).toMatrix()
				bone_rotation_matrix.resize4x4()
				return tuple(bone_rotation_matrix.toQuat()) # qw,qx,qy,qz

			poseBone = bPose.bones[boneName]
			types = animationInfo.GetTypes(boneInfo.daeNode)
			for time in animationInfo.times.keys():
				poseBone.insertKey(armature.GetBlenderObject(), int(round(time)), types)
				target = animationInfo.times[time]

			actionIpos = action.getAllChannelIpos()
			ipo = actionIpos[boneName]
			for time in animationInfo.times:
				target = animationInfo.times[time]
				for value in target:
					type = animationInfo.GetType(boneInfo.daeNode, value)
					if type[0] == collada.DaeSyntax.TRANSLATE:
						pass
					elif type[0] == collada.DaeSyntax.ROTATE:
						if type[1][1] == "ANGLE":
							pass
##							axis = self.document.axiss[self.document.orgAxiss.index(type[1][0][-1])]
##							curve_wquat = ipo[Blender.Ipo.PO_QUATW]
##							curve_xquat = ipo[Blender.Ipo.PO_QUATX]
##							curve_yquat = ipo[Blender.Ipo.PO_QUATY]
##							pose_rotations = pose_rot([50+time,0,0])
##							print pose_rotations
##							curve_wquat.append((time, pose_rotations[0]))
##							curve_xquat.append((time, pose_rotations[1]))
##							curve_yquat.append((time, pose_rotations[2]))


			##for time in animationinfo.times.keys():


		for childBoneName in boneInfo.childs:
			self.AnimateBone(childBoneName,armature, bPose, action)


	def BindMesh(self):
		global waitingControllers, armatures
		armature = Armature.GetArmature(self.armatureName)
		realArmatureName = armature.realName

		armatureObject = armature.GetBlenderObject()

		self.modifier[Blender.Modifier.Settings.OBJECT] = armatureObject

		bArmature = armature.GetBlenderArmature()
		daeSkin = self.daeController.skin

		# For each bone create a vertex group.
		for boneName in armatureObject.data.bones.keys():
			self.bMesh.addVertGroup(boneName)

		vertexWeights = daeSkin.vertexWeights
		daeJoints = daeSkin.joints
		if not vertexWeights.vcount is None and not vertexWeights.v is None:
			# Get the Joint Source
			jointList = daeSkin.FindSource(vertexWeights.FindInput('JOINT')).source.data
			# Get the weights
			weightList = 		daeSkin.FindSource(vertexWeights.FindInput('WEIGHT')).source.data
			# Get the BindMatrix values
			bindFloats = daeSkin.FindSource(daeJoints.FindInput("INV_BIND_MATRIX")).source.data
			# Create the BindMatrices
			bindMatrices = dict()
			for jointNameIndex in range(len(jointList)):
				jointName = jointList[jointNameIndex]
				bindMatrix = ToMatrix4(bindFloats[jointNameIndex*16:(jointNameIndex+1)*16]).invert()
				bindMatrices[jointName] = bindMatrix

			bPose = armatureObject.getPose()
			# Loop trough each Root bone. Those bones will position their childs.
			for rootBoneName in armature.rootBoneInfos:
				self.PoseBone(rootBoneName, armature, bindMatrices, bPose)

			# Set the bind positions of the bones (in Edit mode)
			armature.MakeEditable(True)
			# Loop trough each Root bone. Those bones will position their childs.
			for rootBoneName in armature.rootBoneInfos:
				self.PositionBone(rootBoneName, armature, bindMatrices)

			armature.MakeEditable(False)


			vIndex = 0
			vertInfos = []
			maxInputOffset = vertexWeights.GetStride()
			for vCountIndex in range(len(vertexWeights.vcount)): # loop trough each element in vcount.
				vcount = vertexWeights.vcount[vCountIndex]
				vertInfo = [vCountIndex,[]]
				for jointIndex in range(vcount): # Get all the info for this vertice.
					vertInfo[1].append([0,0])
					vertJointInfo = vertInfo[1][jointIndex]
					for input in vertexWeights.inputs:
						inputVal = vertexWeights.v[vIndex+input.offset]
						if input.semantic == "JOINT":
							vertJointInfo[0] = jointList[inputVal]
						elif input.semantic == "WEIGHT":
							vertJointInfo[1] = weightList[inputVal]
					vIndex += maxInputOffset
				vertInfos.append(vertInfo)


			bonesList = bArmature.bones.keys()


			jointBoneInfoList = armature.GetJointList()

			for vertInfo in vertInfos:
				for vertJointInfo in vertInfo[1]:
					groupName = vertJointInfo[0]
##					if  groupName in jointBoneInfoList:
						##boneName = jointBoneInfoList[groupName].name
					boneName = groupName
					vertIndex = vertInfo[0]
					vertWeight = vertJointInfo[1]
					self.bMesh.assignVertsToGroup(boneName,[vertIndex],vertWeight,'add')

			action = Blender.Armature.NLA.NewAction("Action")
			action.setActive(armature.GetBlenderObject())



			# Apply the animations for the bones (if available)
			for rootBoneName in armature.rootBoneInfos:
				pass#self.AnimateBone(rootBoneName, armature, bPose, action)

	def LoadFromDae(self, daeController, daeControllerInstance, bObject):
		global waitingControllers
		# Check if this controller is a SKIN controller
		if not (daeController.skin is None):
			# Create a new GeometryInstance for getting the mesh for this controller.
			daeGeoInstance = collada.DaeGeometryInstance()
			daeGeoInstance.url = daeController.skin.source
			daeGeoInstance.bindMaterials = daeControllerInstance.bindMaterials
			# Get the Blender Mesh
			self.bMesh = self.document.meshLibrary.FindObject(daeGeoInstance, True)
			self.daeController = daeController
			# Link the mesh to the blenderObject.
			bObject.link(self.bMesh)

			# Set the bObject to the right place.
			bindShapeMatrix =  daeController.skin.bindShapeMatrix
			bindShapeMatrix = self.document.CalcMatrix(bindShapeMatrix)
			bObject.setMatrix(bindShapeMatrix)

			# Create an armature modifier for the Blender Object.
			self.modifier = bObject.modifiers.append(Blender.Modifier.Type.ARMATURE)

			# Set the object skinned to this armature
			self.bObject = bObject

			# Find the armature for this controller
			armature = None
			for jointName in daeControllerInstance.skeletons:
				armature = Armature.FindArmatureWithJoint(jointName[1:])
				if not armature is None:
					self.armatureName = armature.name
					break

			# Check if the armature is already parsed. If not, wait until then.
			if not armature is None:
				# make the armature the parent of the blender object
				armature.GetBlenderObject().makeParent([bObject], 0, 1)
				self.BindMesh()
			else:
				# Add this controller to a to-do list ;) and wait until the armature is parsed.
				##waitingControllers[self.armatureName] = self
				waitingControllers[jointName[1:]] = self



			#return the mesh.
			return self.bMesh
		else: # It's a morph controller. do nothing.
			print "WARNING: Morph is not supported"
			return None

	def SaveToDae(self, bModifier, bMeshObject, meshName):
		bMesh = bMeshObject.getData()
		daeController = collada.DaeController()
		daeController.id = self.document.CreateID(bMesh.name,"-skin")
		# Create a skin
		daeController.skin = daeSkin = collada.DaeSkin()
		daeSkin.source = meshName

		# Set the bindshapematrix
		daeSkin.bindShapeMatrix = Matrix(bMeshObject.matrix).transpose()##bMeshObject.getMatrix('localspace').transpose()

		bArmatureObject = bModifier[Blender.Modifier.Settings.OBJECT]
		bArmature = bArmatureObject.data

		# Create the joints elements
		daeSkin.joints = collada.DaeJoints()
		# Create the vertexWeights element
		daeSkin.vertexWeights = collada.DaeVertexWeights()

		# Create the source for the joints
		jointSource = collada.DaeSource()
		jointSource.id = self.document.CreateID(daeController.id, "-joints")
		jointSource.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		jointSource.source = jointSourceArray = collada.DaeIDREFArray()
		jointSourceArray.id = self.document.CreateID(jointSource.id, "-array")
		jointSource.techniqueCommon.accessor = jointAccessor = collada.DaeAccessor()
		jointAccessor.AddParam("JOINT",collada.DaeSyntax.IDREF)
		jointAccessor.source = jointSource.id
		daeSkin.sources.append(jointSource)
		# And the input for the joints
		jointInput = collada.DaeInput()
		jointInput.semantic = "JOINT"
		jointInput.source = jointSource.id
		jointInput.offset = 0

		jointInput2 = collada.DaeInput()
		jointInput2.semantic = "JOINT"
		jointInput2.source = jointSource.id


		# Create the source for the weights
		weightSource = collada.DaeSource()
		weightSource.id = self.document.CreateID(daeController.id, "-weights")
		weightSource.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		weightSource.source = weightSourceArray = collada.DaeFloatArray()
		weightSourceArray.id = self.document.CreateID(weightSource.id, "-array")
		weightSource.techniqueCommon.accessor = weightAccessor = collada.DaeAccessor()
		weightAccessor.AddParam("WEIGHT","float")
		weightAccessor.source = weightSource.id
		daeSkin.sources.append(weightSource)
		# And the input for the weights
		weightInput = collada.DaeInput()
		weightInput.semantic = "WEIGHT"
		weightInput.source = weightSource.id
		weightInput.offset = 1

		daeSkin.joints.inputs.append(jointInput2)
		daeSkin.vertexWeights.inputs.append(jointInput)
		daeSkin.vertexWeights.inputs.append(weightInput)

		poseSource = collada.DaeSource()
		poseSource.id = self.document.CreateID(daeController.id,"-poses")
		poseSource.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		poseSource.source = poseSourceArray = collada.DaeFloatArray()
		poseSourceArray.id = self.document.CreateID(poseSource.id,"-array")
		poseSource.techniqueCommon.accessor = poseAccessor = collada.DaeAccessor()
		poseAccessor.AddParam("","float4x4")
		poseAccessor.stride = 16;
		poseAccessor.source = poseSource.id
		daeSkin.sources.append(poseSource)
		# Add the input for the poses
		poseInput = collada.DaeInput()
		poseInput.semantic = "INV_BIND_MATRIX"
		poseInput.source = poseSource.id

		# Add this input to the joints
		daeSkin.joints.inputs.append(poseInput)


		# Get all vertextGroups
		vGroups = dict()
		for vertexGroupName in bMesh.getVertGroupNames():
			vwsdict = vGroups[vertexGroupName] = dict()
			vws = bMesh.getVertsFromGroup(vertexGroupName,True)
			for vw in vws:
				vwsdict[vw[0]] = vw[1]

		# Loop through each vertex group.
		for vertexGroupName in bMesh.getVertGroupNames():
			# Check if this vertexgroup has the same name as a bone in the armature.
			if vertexGroupName in bArmature.bones.keys():
				jointAccessor.count += 1
				adjustedName = "" + vertexGroupName;
				if len(adjustedName) > 0 and not adjustedName[0].isalpha():
					adjustedName = "i"+adjustedName
				jointSourceArray.data.append(adjustedName)
				# Get the vertices in this vertexGroup
				verts = bMesh.getVertsFromGroup(vertexGroupName)

##				print
##				PrintTransforms(Matrix(bArmature.bones[vertexGroupName].matrix['ARMATURESPACE']).transpose().invert(), vertexGroupName)
				#bindMatrix = Matrix(bArmature.bones[vertexGroupName].matrix['ARMATURESPACE']).transpose()
				headPos = bArmature.bones[vertexGroupName].head["ARMATURESPACE"]
				bindMatrix = Matrix([1,0,0,headPos.x], [0,1,0,headPos.y], [0,0,1,headPos.z],[0,0,0,1])
				##bindMatrix = Matrix(bMeshObject.matrix).transpose() * bindMatrix
				bindMatrix = Matrix(bArmatureObject.getMatrix('localspace')).transpose() * bindMatrix;

				invBindMatrix = Matrix(bindMatrix).invert()
				poseSourceArray.data.extend(MatrixToList(invBindMatrix))
				poseAccessor.count += 1;
				for vert in verts:
					weightAccessor.count += 1


		vertJointCount = dict();
		weightIndex = 0;
		for vert in bMesh.verts:
			jointCount = 0

			#count up the number of joints to get an equal weight
			for vGroup in vGroups:
				if vert.index in vGroups[vGroup]:
					adjustedName = "" + vGroup;
					if len(adjustedName) > 0 and not adjustedName[0].isalpha():
						adjustedName = "i"+adjustedName
					found = False
					try :
						jointSourceArray.data.index(adjustedName)
						found = True
					except:
						found = False
					if found :
						jointCount += 1
						vertJointCount[vert.index] = jointCount

			#now we know how many, so make an even weight:
			for vGroup in vGroups:
				if vert.index in vGroups[vGroup]:
					adjustedName = "" + vGroup;
					if len(adjustedName) > 0 and not adjustedName[0].isalpha():
						adjustedName = "i"+adjustedName
					found = False
					try :
						jointSourceArray.data.index(adjustedName)
						found = True
					except:
						found = False
					if found :
						daeSkin.vertexWeights.v.append(jointSourceArray.data.index(adjustedName))
						daeSkin.vertexWeights.v.append(weightIndex)
						weightSourceArray.data.append( 1.0 / vertJointCount[vert.index])
						weightIndex += 1

			#update the counts for this vertex
			if jointCount > 0:
				daeSkin.vertexWeights.count += 1
				daeSkin.vertexWeights.vcount.append(jointCount)


		self.document.colladaDocument.controllersLibrary.AddItem(daeController)
		return daeController

class Animation(object):
	def __init__(self, document):
		self.document = document

	def LoadFromDae(self, daeAnimation, daeNode, bObject):
		# Loop trough all channels
		for channel in daeAnimation.channels:
			#print 'deb:class Animation-LoadFromDae channel.target=',channel.target #------
			#print 'deb:class Animation-LoadFromDae daeNode.id=',daeNode.id #------
			ca = channel.target.split("/",1)
			if ca[0] == daeNode.id:
				for s in daeAnimation.samplers:
					#print 'deb:class Animation-LoadFromDae s.id=',s.id #------
					#print 'deb:class Animation-LoadFromDae channel.source=',channel.source #------
#org				if s.id == channel.source[1:]:
					if s.id == channel.source:
						sampler = s
				if not (s is None):
					if bObject.ipo is None:
						ipo = Blender.Ipo.New("Object",daeAnimation.id)
						bObject.setIpo(ipo)
					else:
						ipo = bObject.ipo
					type = self.FindType(ca[1], daeNode)
					input = sampler.GetInput("INPUT")
					inputSource = daeAnimation.GetSource(input.source)
					# Check if the input has a TIME parameter and is the only one.
					if not (type is None) and inputSource.techniqueCommon.accessor.HasParam("TIME") and len(inputSource.techniqueCommon.accessor.params) == 1:
						output = sampler.GetInput("OUTPUT")
						outputSource = daeAnimation.GetSource(output.source)
						accessorCount = outputSource.techniqueCommon.accessor.count
						accessorStride = outputSource.techniqueCommon.accessor.stride
						times = [x*self.document.fps for x in inputSource.source.data]
						if type[0] == "translate" or type[0] == "scale" or (type[0] == "rotate" and type[1][1] == "ANGLE"):
							axiss = []
							if len(type[1]) == 1:
								axiss = ["X", "Y", "Z"]
							elif type[0] == "rotate":
								axiss = [type[1][0][-1]]
							elif len(type[1]) == 2:
								if type[1][1] in ["X", "Y", "Z"]:
									axiss = [type[1][1]]
							for axis in axiss:
								if type[0] == "translate":
									cname = "Loc"
								elif type[0] == "scale":
									cname = "Scale"
								else:
									cname = "Rot"
								cname += self.document.axiss[self.document.orgAxiss.index(axis)]
								curve = ipo.addCurve(cname)
								for time in times:
									val = outputSource.source.data[times.index(time)*accessorStride+axiss.index(axis)]
									if type[0] == "rotate":
										val /= 10
									curve.addBezier((time,val))


	def FindType(self, target, daeNode):
		ta = target.split(".",1)
		for t in daeNode.transforms:
			if t[2] == ta[0]:
				return [t[0],ta]
		return None

	def GetEulerAnimations(self, ipo, targetDaeNode, joint=None, bPose=None, bParentMatrix=None, bArmatureObject=None):
		curves = ipo.getCurves()
		if not curves is None:
			quatXList = dict()
			quatYList = dict()
			quatZList = dict()
			quatWList = dict()

			#collect quats
			quatKey = dict()
			for cur in curves:
				if cur.getName().startswith("Quat"):
					quatKey[cur.getName()] = []

					for point in cur.bezierPoints:
						if cur.getName()[-1] == 'X':
							quatXList[point.pt[0]] = point.pt[1]
						if cur.getName()[-1] == 'Y':
							quatYList[point.pt[0]] = point.pt[1]
						if cur.getName()[-1] == 'Z':
							quatZList[point.pt[0]] = point.pt[1]
						if cur.getName()[-1] == 'W':
							quatWList[point.pt[0]] = point.pt[1]

			quats = dict()
			eulers = dict()

			xKeyList = quatXList.keys()
			yKeyList = quatYList.keys()
			zKeyList = quatZList.keys()
			wKeyList = quatWList.keys()

			#Assumption: All the keys are the same!!
			for xKey in xKeyList:
				if not quats.has_key(xKey):
					quats[xKey] = Quaternion()

			#assign value
			for key in xKeyList:
				quats[key].x = quatXList[key]

			for key in yKeyList:
				quats[key].y = quatYList[key]
			for key in zKeyList:
				quats[key].z = quatZList[key]
			for key in wKeyList:
				quats[key].w = quatWList[key]

			for key in quats:
				euler = quats[key].toEuler();

				if not joint is None:
					headPos = joint.head["ARMATURESPACE"]
					bindMatrix = Matrix([1,0,0,headPos.x], [0,1,0,headPos.y], [0,0,1,headPos.z],[0,0,0,1])
					armMatrix = Matrix(bindMatrix);
					if ( not joint.hasParent() ):
						armMatrix = Matrix(bArmatureObject.getMatrix('localspace')).transpose().invert();
						armMatrix *= bindMatrix

					poseMatrix = Matrix(bParentMatrix).invert() * armMatrix

					poseEuler = poseMatrix.toEuler()
					euler.x += poseEuler.x
					euler.y += poseEuler.y
					euler.z += poseEuler.z

				eulers[key] = euler

			# this nodes list of euler angles:
			return eulers
		return None

	def SaveToDae(self, ipo, targetDaeNode, joint=None, bPose=None, bParentMatrix=None, bArmatureObject=None):
		global sampleAnimation
		animations = None
		curves = ipo.getCurves()
		if not curves is None:
			animations = dict()

			for curve in curves:
				cName = curve.getName()
				interpolation = curve.getInterpolation()
				if cName.startswith("Loc") or cName.startswith("Rot") or cName.startswith("Scale"):
					if cName.startswith("Loc"):
						n = collada.DaeSyntax.TRANSLATE
					elif cName.startswith("Scale"):
						n = collada.DaeSyntax.SCALE
					else:
						n = collada.DaeSyntax.ROTATE+cName[-1]
					ani = animations.setdefault(n,{})

					# Get all the framenumbers for the current curve.
					frames = [bp.pt[0] for bp in curve.bezierPoints]
					if sampleAnimation: ## if the users wants to sample the animation each frame..
						# .. generate a sequence of frames, starting at the first(smallest) framenumber of the current curve
						#  and ending at the last(largest)framenumber.
						frames = range(min(frames), max(frames)+1)
					##print cName, frames
					# Now get the values for each frame
					for frameNumber in frames:
						anit = ani.setdefault(float(frameNumber),{'X':None, 'Y':None, 'Z':None, 'interpolation':interpolation})
						# calculate the value at the current frame.
						timeVal = float(curve[float(frameNumber)])
						##print cName, frameNumber, timeVal
						anit[cName[-1]] = timeVal

						if not joint is None:
							headPos = joint.head["ARMATURESPACE"]
							bindMatrix = Matrix([1,0,0,headPos.x], [0,1,0,headPos.y], [0,0,1,headPos.z],[0,0,0,1])
							armMatrix = bindMatrix;
							if ( not joint.hasParent() ):
								armMatrix = Matrix(bArmatureObject.getMatrix('localspace')).transpose();
								armMatrix *= bindMatrix

							poseMatrix = Matrix(bParentMatrix).invert() * armMatrix

							if cName.startswith("Loc"):
								poseMatrix.transpose()
								jointPosition = poseMatrix.translationPart()

								if cName[-1] == 'X':
									anit['X'] += jointPosition.x
								if cName[-1] == 'Y':
									anit['Y'] += jointPosition.y
								if cName[-1] == 'Z':
									anit['Z'] += jointPosition.z
							if cName.startswith("Scale"):
								poseMatrix.transpose()
								jointPosition = poseMatrix.scalePart()
								if cName[-1] == 'X':
									anit['X'] *= jointPosition.x
								if cName[-1] == 'Y':
									anit['Y'] *= jointPosition.y
								if cName[-1] == 'Z':
									anit['Z'] *= jointPosition.z

						if cName.startswith("Rot"):
							anit[cName[-1]] = anit[cName[-1]]*10 # Multiply the angle times 10 (Blender uses angle/10)
				else:
					pass

		eulers = self.GetEulerAnimations(ipo, targetDaeNode, joint, bPose, bParentMatrix, bArmatureObject)
		eulerKeys = eulers.keys()


		for key in eulerKeys:
			euler = eulers[key]

			aniX = animations.setdefault(str(collada.DaeSyntax.ROTATE) + 'X',{})
			aniY = animations.setdefault(str(collada.DaeSyntax.ROTATE) + 'Y',{})
			aniZ = animations.setdefault(str(collada.DaeSyntax.ROTATE) + 'Z',{})

			anitx = aniX.setdefault(key,{'X':0, 'Y':0, 'Z':0, 'interpolation':interpolation})
			anitx['X'] = euler.x
			anitx['Y'] = euler.y
			anitx['Z'] = euler.z

			anity = aniY.setdefault(key,{'X':0, 'Y':0, 'Z':0, 'interpolation':interpolation})
			anity['X'] = euler.x
			anity['Y'] = euler.y
			anity['Z'] = euler.z

			anitz = aniZ.setdefault(key,{'X':0, 'Y':0, 'Z':0, 'interpolation':interpolation})
			anitz['X'] = euler.x
			anitz['Y'] = euler.y
			anitz['Z'] = euler.z

		# add animations to collada
		for name, animation in animations.iteritems():
			daeAnimation = collada.DaeAnimation()
			daeAnimation.id = daeAnimation.name = self.document.CreateID(targetDaeNode.id+'-'+name,'-Animation')

			daeSourceInput = collada.DaeSource()
			daeSourceInput.id = self.document.CreateID(daeAnimation.id,'-input')
			daeFloatArrayInput = collada.DaeFloatArray()
			daeFloatArrayInput.id = self.document.CreateID(daeSourceInput.id,'-array')
			daeSourceInput.source = daeFloatArrayInput
			daeSourceInput.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
			accessorInput = collada.DaeAccessor()
			daeSourceInput.techniqueCommon.accessor = accessorInput
			accessorInput.source = daeFloatArrayInput.id
			accessorInput.count = len(animation)
			accessorInput.AddParam('TIME','float')

			if name == collada.DaeSyntax.TRANSLATE or name == collada.DaeSyntax.SCALE:
				vals = self.CreateSourceOutput(daeAnimation, len(animation),  "xyz")
			elif name.startswith(collada.DaeSyntax.ROTATE):
				vals = self.CreateSourceOutput(daeAnimation, len(animation),  "angle")

			daeSourceOutput = vals[0]
			outputArray = vals[1]
			daeSourceInterpolation = vals[2]
			interpolationArray = vals[3]

			daeAnimation.sources.append(daeSourceInput)
			daeAnimation.sources.append(daeSourceOutput)
			daeAnimation.sources.append(daeSourceInterpolation)

			animationKeys = animation.keys()
			animationKeys.sort()

			prevX = prevY = prevZ = 0

			for key in animationKeys:
				value = animation[key]

				daeFloatArrayInput.data.append(key/self.document.fps)
				interpolation = value['interpolation']
				if interpolation == 'Constant':
					cInterpolation = 'STEP'
				elif interpolation == 'Linear':
					cInterpolation = 'LINEAR'
				else:
					cInterpolation = 'BEZIER'

				if name == collada.DaeSyntax.TRANSLATE or name == collada.DaeSyntax.SCALE:
					if value['X'] is None:
						value['X'] = prevX
					else:
						prevX = value['X']

					if value['Y'] is None:
						value['Y'] = prevY
					else:
						prevY = value['Y']

					if value['Z'] is None:
						value['Z'] = prevZ
					else:
						prevZ = value['Z']

					outputArray.data.append(value['X'])
					outputArray.data.append(value['Y'])
					outputArray.data.append(value['Z'])

					interpolationArray.data.append(cInterpolation)
					interpolationArray.data.append(cInterpolation)
					interpolationArray.data.append(cInterpolation)
				elif name.startswith(collada.DaeSyntax.ROTATE):
					outputArray.data.append(value[name[-1]])
					interpolationArray.data.append(cInterpolation)

			if not name.startswith(collada.DaeSyntax.ROTATE) or sum(outputArray.data) != 0:
				daeSampler = collada.DaeSampler()
				daeSampler.id = self.document.CreateID(daeAnimation.id,"-sampler")
				daeAnimation.samplers.append(daeSampler)

				daeInputInput = collada.DaeInput()
				daeInputInput.semantic = 'INPUT'
				daeInputInput.source = daeSourceInput.id
				daeSampler.inputs.append(daeInputInput)

				daeInputOutput = collada.DaeInput()
				daeInputOutput.semantic = 'OUTPUT'
				daeInputOutput.source = daeSourceOutput.id
				daeSampler.inputs.append(daeInputOutput)

				daeInputInterpolation = collada.DaeInput()
				daeInputInterpolation.semantic = 'INTERPOLATION'
				daeInputInterpolation.source = daeSourceInterpolation.id
				daeSampler.inputs.append(daeInputInterpolation)

				daeChannel = collada.DaeChannel()
				daeChannel.source = daeSampler

				daeChannel.target = collada.StripString(targetDaeNode.id) +'/'+name
				if name.startswith(collada.DaeSyntax.ROTATE):
					daeChannel.target = daeChannel.target + ".ANGLE"
				daeAnimation.channels.append(daeChannel)

				self.document.colladaDocument.animationsLibrary.AddItem(daeAnimation)

	def CreateSourceOutput(self, daeAnimation, count, type):
		daeSourceOutput = collada.DaeSource()
		daeSourceOutput.id = self.document.CreateID(daeAnimation.id,'-output')
		if type == "xyz" or "angle":
			outputArray = collada.DaeFloatArray()
		else:
			pass

		##daeFloatArrayOutput = collada.DaeFloatArray()
		outputArray.id = self.document.CreateID(daeSourceOutput.id,'-array')
		daeSourceOutput.source = outputArray
		daeSourceOutput.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		accessorOutput = collada.DaeAccessor()
		daeSourceOutput.techniqueCommon.accessor = accessorOutput
		accessorOutput.source = outputArray.id
		accessorOutput.count = count


		daeSourceInterpolation = collada.DaeSource()
		daeSourceInterpolation.id = self.document.CreateID(daeAnimation.id,'-interpolation')
		interpolationArray = collada.DaeNameArray()
		interpolationArray.id = self.document.CreateID(daeSourceInterpolation.id,'-array')
		daeSourceInterpolation.source = interpolationArray
		daeSourceInterpolation.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		accessorInterpolation = collada.DaeAccessor()
		daeSourceInterpolation.techniqueCommon.accessor = accessorInterpolation
		accessorInterpolation.source = interpolationArray.id
		accessorInterpolation.count = count

		if type == "xyz":
			accessorOutput.AddParam('X','float')
			accessorOutput.AddParam('Y','float')
			accessorOutput.AddParam('Z','float')
			accessorInterpolation.AddParam('X','Name')
			accessorInterpolation.AddParam('Y','Name')
			accessorInterpolation.AddParam('Z','Name')

		elif type == "angle":
			accessorOutput.AddParam('ANGLE','float')
			accessorInterpolation.AddParam('ANGLE','Name')

		return [daeSourceOutput, outputArray, daeSourceInterpolation, interpolationArray]


class SceneNode(object):

	def __init__(self, document, sceneNode):
		self.id = ''
		self.type = ''
		self.document = document
		self.transformMatrix = None
		self.localTransformMatrix = None
		self.parentNode = sceneNode

		self.armature = None
		self.isJoint = False

		self.createRootBone = False
		self.createLastBone = False

	def ObjectFromDae(self,daeNode):
		global replaceNames, objectList, waitingControllers, armatures
		self.document.Progress()
		self.id = daeNode.id
		self.type = daeNode.type

		editBone = None
		newObject = None
		dataObject = None
		armature = None
		parentBone = None
		daeInstance = None
		boneName = None
		#Get the transformation
		# TODO, replace all the self.document.tMatOLD and calculate the transformmatrices the correct way using CalcMatrix()
		mat = Matrix().resize4x4()
		for i in range(len(daeNode.transforms)):
			transform = daeNode.transforms[len(daeNode.transforms)-(i+1)]
			type = transform[0]
			data = transform[1]

			if type == collada.DaeSyntax.TRANSLATE:
				mat = mat*TranslationMatrix(Vector(data)* self.document.tMatOLD)
			elif type == collada.DaeSyntax.ROTATE:
				mat = mat*RotationMatrix(data[3] % 360,4,'r',Vector([data[0],data[1],data[2]])* self.document.tMatOLD)
			elif type == collada.DaeSyntax.SCALE:
				skewVec = Vector(data[0],data[1], data[2])*self.document.tMatOLD
				mat = mat * Matrix([skewVec.x,0,0,0],[0,skewVec.y,0,0],[0,0,skewVec.z,0],[0,0,0,1])
			elif type == collada.DaeSyntax.SKEW:
				s = math.tan(data[0]*angleToRadian)
				rotVec = Vector(data[1],data[2],data[3])*self.document.tMatOLD
				transVec = Vector(data[4],data[5],data[6])*self.document.tMatOLD
				fac1 = s*transVec.x
				fac2 = s*transVec.y
				fac3 = s*transVec.z

				mat = mat * Matrix([1+fac1*rotVec.x,fac1*rotVec.y,fac1*rotVec.z,0],[fac2*rotVec.x,1+fac2*rotVec.y,fac2*rotVec.z,0],[fac3*rotVec.x,fac3*rotVec.y,1+fac3*rotVec.z,0],[0,0,0,1])
			elif type == collada.DaeSyntax.LOOKAT:
				# TODO: LOOKAT Transform: use the correct up-axis
				position = Vector([data[0],data[1], data[2]])
				target = Vector([data[3],data[4], data[5]])
				up = Vector([data[6],data[7], data[8]]).normalize()
				front = (position-target).normalize()
				side = -1*CrossVecs(front, up).normalize()
				m = Matrix().resize4x4()

				m[0][0] = side.x
				m[0][1] = side.y
				m[0][2] = side.z

				m[1][0] = up.x
				m[1][1] = up.y
				m[1][2] = up.z

				m[2][0] = front.x
				m[2][1] = front.y
				m[2][2] = front.z

				m[3][0] = position.x
				m[3][1] = position.y
				m[3][2] = position.z

				mat = mat*m

			elif type == collada.DaeSyntax.MATRIX:
				mat = mat * self.document.CalcMatrix(data)## * self.document.tMatOLD

		self.localTransformMatrix = Matrix(mat)
		self.transformMatrix = mat
		if isinstance(self.parentNode, SceneNode):
				self.transformMatrix *= self.parentNode.transformMatrix

		if daeNode.IsJoint():
			currentBoneExists = False
			self.isJoint = True
			# it's a Joint, so check if we have to create a new armature or a bone inside an existing armature.
			if daeNode.parentNode == None or not daeNode.parentNode.IsJoint():
				# Create a unique name for the armature object
				objectName = self.document.CreateNameForObject(self.id,replaceNames, 'object')
				# Create a unique name for the armature data
				armatureName = self.document.CreateNameForObject(objectName,replaceNames, 'armature')
				# Create a new armature
				self.armature = Armature.CreateArmature(objectName, self.id, armatureName, daeNode)

				##print "create armature", armatureName
				# Get the new created Blender Object
				newObject = self.armature.GetBlenderObject()
				# Link the new object to the current scene.
				self.document.currentBScene.link(newObject)

				# Set the position of the armature.
				newObject.setMatrix(self.transformMatrix)
			else:
				self.armature = self.parentNode.armature
				# Make the armature editable, so we can create a new bone.
				self.armature.MakeEditable(True)
				# Get the name of the parent bone of this bone.
				parentBoneName = None
				if isinstance(self.parentNode.parentNode, SceneNode):
					parentBoneName = str(self.parentNode.parentNode.id)

				# Create the name for the new bone
				boneName = str(self.parentNode.id)

				if not self.armature.HasBone(boneName):
					# Add a new bone to the armature.
					boneInfo = self.armature.AddNewBone(boneName, parentBoneName, daeNode)

					# Get the location of the armature.
					armatureLoc = self.armature.GetLocation()

					# Set the correct head and tail positions of this bone.
					headLoc = Vector(0,0,0,1)
					if not boneInfo.parent is None: # The head of this bone starts at the end of it's parent.
##						headLoc = Matrix(self.parentNode.transformMatrix).transpose() * Vector(0,0,0,1) - armatureLoc
						headLoc = Matrix(self.parentNode.transformMatrix).transpose() * Vector(0,0,0,1)
						# Check if the head of this bone is at the same position as the tail of it's parent.


					# Get the location of this node.
					nodeLoc = Matrix(self.transformMatrix).transpose() * Vector(0,0,0,1)
##					tailLoc = (nodeLoc - armatureLoc).resize3D()
					if headLoc == nodeLoc:
						print "zero bone:", boneName
					##print headLoc, nodeLoc
##					if (headLoc - nodeLoc).length < 0.001:
						nodeLoc += Vector(0,0,0.001,1)
					tailLoc = Matrix(self.armature.GetTransformation()).transpose().invert() * nodeLoc.resize4D()


##					print boneName
##					print "headLoc PRE" ,headLoc
					# Undo the armature transformation
					if not boneInfo.parent is None:
						headLoc = Matrix(self.armature.GetTransformation()).transpose().invert() * headLoc.resize4D()
						if (Vector(headLoc).resize3D() - boneInfo.parent.GetTail()).length < 0.001:
							boneInfo.SetConnected()

##					print "headLoc POST", headLoc
##					PrintTransforms(Matrix(self.armature.GetTransformation()).transpose().invert(),"armature")
##					print "invert origin", Matrix(self.armature.GetTransformation()).transpose().invert() * Vector(0,0,0,1)
##					print "nodeLoc PRE:",nodeLoc
##					print "tailLoc POST:", tailLoc

##					print
					# Set the location of the tail to the difference between the NodeLoc and armatureLoc
					boneInfo.SetHead(headLoc)
					boneInfo.SetTail(tailLoc)
					# Store the localTransformMatrix of this joint
					boneInfo.localTransformMatrix = Matrix(self.parentNode.localTransformMatrix).transpose()
					boneInfo.worldTransformMatrix = Matrix(self.parentNode.transformMatrix).transpose()

				else:
					currentBoneExists = True

				self.armature.MakeEditable(False)

			# Check if this is the last Joint
			hasJointChilds = False
			for daeChild in daeNode.nodes:
				if daeChild.IsJoint():
					hasJointChilds = True
					break

#org		if not hasJointChilds:
			if not hasJointChilds and self.parentNode:

				# This is the last joint of the armature.
				# Create one last bone for the last joint.
				# (otherwise pivoting the end point of the last created bone is not possible)
				self.armature.MakeEditable(True)

				# Get the name of the parent bone of this bone.
				#print 'deb: self.parentNode=', self.parentNode #deb:remi-----------
				parentBoneName = str(self.parentNode.id)
				# Create the name for the new bone
				boneName = str(self.id)

				# Add a new bone to the armature.
				boneInfo = self.armature.AddNewBone(boneName, parentBoneName, daeNode)

				# Get the location of the armature.
				armatureLoc = self.armature.GetLocation().resize3D()

				# Set the correct head and tail positons of this bone.
				headLoc = Vector(0,0,0)
				tailLoc = Vector(0,0,1)
				if not parentBoneName is None: # The head of this bone starts at the end of it's parent.
					parentBone = boneInfo.parent.GetBone()

					if currentBoneExists:
						headLoc = self.transformMatrix.translationPart() - armatureLoc
					else:
						headLoc = parentBone.tail
						boneInfo.SetConnected()

					tailLoc = 2 * headLoc - parentBone.head
					boneInfo.localTransformMatrix = Matrix(self.localTransformMatrix).transpose()

				boneInfo.SetHead(headLoc)
				boneInfo.SetTail(tailLoc)

				self.armature.MakeEditable(False)

		else : #its a Node
			daeInstances = daeNode.GetInstances()
			isController = False
			if len(daeInstances) == 0:
				newObject = Blender.Object.New('Empty',self.id)
			else:
				if len (daeInstances) > 1:
					newObjects = []

				for daeInstance in daeInstances:
					# Check which type the instance is
					if isinstance(daeInstance,collada.DaeAnimationInstance): # Animation
						newObject = Blender.Object.New('Empty',self.document.CreateNameForObject(self.id,replaceNames, 'empty'))
					elif isinstance(daeInstance,collada.DaeCameraInstance): # Camera
						newObject = Blender.Object.New('Camera',self.document.CreateNameForObject(self.id,replaceNames, 'camera'))
						dataObject = self.document.camerasLibrary.FindObject(daeInstance,True)
					elif isinstance(daeInstance,collada.DaeControllerInstance): # Controller
						newObject = Blender.Object.New('Mesh',self.document.CreateNameForObject(self.id,replaceNames, 'object'))
						dataObject = self.document.controllersLibrary.FindObject(daeInstance, True, newObject)
						isController = True
					elif isinstance(daeInstance,collada.DaeGeometryInstance): # Geometry
						newObject = Blender.Object.New('Mesh',self.document.CreateNameForObject(self.id,replaceNames, 'object'))
						dataObject = self.document.meshLibrary.FindObject(daeInstance,True)
					elif isinstance(daeInstance,collada.DaeLightInstance): # Light
						newObject = Blender.Object.New('Lamp',self.document.CreateNameForObject(self.id,replaceNames, 'lamp'))
						dataObject = self.document.lampsLibrary.FindObject(daeInstance,True)
					elif isinstance(daeInstance,collada.DaeNodeInstance): # Node
						newObject = Blender.Object.New('Empty',self.document.CreateNameForObject(self.id,replaceNames, 'empty'))
					elif isinstance(daeInstance,collada.DaeVisualSceneInstance): # Visual Scene
						newObject = Blender.Object.New('Empty',self.document.CreateNameForObject(self.id,replaceNames, 'empty'))
					else:
						print "Loading Unknown Instance:"
						print daeInstance
						return

					if dataObject != None:
						newObject.link(dataObject)

					if len (daeInstances) > 1:
						newObjects.append(newObject)
			# If there were multiple instance, create an empty. We add the instances to it later.
			if len (daeInstances) > 1:
				newObject = Blender.Object.New('Empty',self.id)

			if not isController or len (daeInstances) > 1:
				newObject.setMatrix(self.transformMatrix)
			self.bObject = newObject

			# Add the new object to the Blender Scene.
			self.document.currentBScene.link(newObject)
			# If there were more instances in this node, also add all those instances to the Blender Scene
			#  and make them childs of the Empty.
			if len (daeInstances) > 1:
				for newObjectChild in newObjects:
					self.document.currentBScene.link(newObjectChild)
				newObject.makeParent(newObjects, 0, 1)


			#reload properties:
			if len(daeNode.extras) > 0:
				for extra in daeNode.extras:
					for tech in extra.techniques:
						for prop in tech.params:
							self.bObject.addProperty(prop.name, prop.value, prop.type)
							if prop.value is not None:
								if prop.type == 'STRING':
									realValue = prop.value.encode('utf-8')
									self.bObject.getProperty(prop.name).setData(realValue)
								elif prop.type == 'INT':
									realValue = int(prop.value.encode('utf-8'))
									self.bObject.getProperty(prop.name).setData(realValue)
								elif prop.type == 'FLOAT':
									realValue = float(prop.value.encode('utf-8'))
									self.bObject.getProperty(prop.name).setData(realValue)
								elif prop.type == 'BOOL':
									realValue = int(prop.value.encode('utf-8'))
									self.bObject.getProperty(prop.name).setData(realValue)
								elif prop.type == 'TIME':
									realValue = float(prop.value.encode('utf-8'))
									self.bObject.getProperty(prop.name).setData(realValue)


			# TODO: Vertex Colors: MAYBE CHANGE THIS LATER update the mesh..
			if newObject.getType() == 'Mesh':
				newObject.getData().update(1,1,1)
				# Set the vertex colors.
				try:
					for f in newObject.getData(mesh=1).faces:
						for c in f.col:
							c.r = 255
							c.g = 255
							c.b = 255
							c.a = 255
				except ValueError:
					pass

##		childlist = []
##		for daeChild in daeNode.nodes:
##			childSceneNode = SceneNode(self.document,self)
##			object = childSceneNode.ObjectFromDae(daeChild)
##			if not(object is None):
##				childlist.append(object)

		if not self.isJoint and self.armature is None:
##			newObject.makeParent(childlist,0,1)

			# Check if this node has an animation.
			daeAnimations = self.document.animationsLibrary.GetDaeAnimations(self.id)
			for daeAnimation in daeAnimations:
				a = Animation(self.document)
				a.LoadFromDae(daeAnimation, daeNode, newObject)

			# Check if the daeNode has some Layer information.
			if not len(daeNode.layer) == 0:
				layers = self.document.layers
				# Keep track of the blender layers to which this Node belongs.
				myLayers = []
				# Loop through all layers of this node.
				for layer in daeNode.layer:
					# Check if this layer is used before.
					if layer in layers:
						# If so, the layer to add is the index of that layer + 1.
						layerNo = layers.index(layer)+1
					else:
						# else, create a new layer.
						addLayer = True
						# When the layer is a digit, try to use the same digit in Blender.
						if layer.isdigit():
							# If So, check if this digit is between 1 and 20 AND if this layer is not used before
							digit = int(layer)
							if digit >= 1 and digit <= len(layers) and layers[digit-1] is None:
								# Add the new layer to the list.
								layers[digit-1] = layer
								layerNo = digit
								# Set this flag to false, so further checking is skipped.
								addLayer = False
						# If the layer was not a digit, Create a new one.
						if addLayer:
							layerNo = 1
							# Get the first free spot.
							if None in layers:
								index = layers.index(None)
								layers[index] = layer
								layerNo = index+1
					# When this layerNo is not in myLayers yet, add it to the list.
					if not (layerNo in myLayers):
						myLayers.append(layerNo)
			else:
				# Use the current selected layers.
				myLayers = self.document.currentBScene.layers

		childlist = []
		for daeChild in daeNode.nodes:
			childSceneNode = SceneNode(self.document,self)
			object = childSceneNode.ObjectFromDae(daeChild)
			if not(object is None):
				childlist.append(object)

		if not self.isJoint and self.armature is None:
			newObject.makeParent(childlist,0,1)

			# Set the layers of the new Object.
			newObject.layers = myLayers
		elif self.isJoint and not self.armature is None and not newObject is None:
			for jointName in waitingControllers:
				armature = Armature.FindArmatureWithJoint(jointName)
				if not armature is None and armature.name == self.armature.name:
					controller = waitingControllers[jointName]
					controller.armatureName = armature.name
					armature.GetBlenderObject().makeParent([controller.bObject], 0, 1)
					controller.BindMesh()
					break

		# Return the new Object
		return newObject

	def SaveSceneToDae(self,bNode,childNodes,daeGlobalPhysicsModel,daeGlobalPhysicsModelInstance):
		global bakeMatrices, exportSelection
		daeNode = collada.DaeNode()
		daeNode.id = daeNode.name = self.document.CreateID(bNode.name,'-Node')# +'-node'

		if len(bNode.getAllProperties()) > 0 :
			daeExtra = collada.DaeExtra()
			daeNode.extras.append(daeExtra);

			tech = collada.DaeTechnique()
			daeExtra.techniques.append(tech)

			for property in bNode.getAllProperties():
				tech.AddParam( property.getName(), property.getType(), property.getData())

		# Get the transformations
		mat = bNode.getMatrix('localspace')
		if bakeMatrices :
			mat = Matrix(mat).transpose()
			daeNode.transforms.append([collada.DaeSyntax.MATRIX, mat])
		else:
			loc = mat.translationPart()
			daeNode.transforms.append([collada.DaeSyntax.TRANSLATE, loc])

			euler = mat.toEuler()
			rotxVec = [1,0,0,euler.x]
			rotyVec = [0,1,0,euler.y]
			rotzVec = [0,0,1,euler.z]
			daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotzVec])
			daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotyVec])
			daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotxVec])

			scale = mat.scalePart()
			daeNode.transforms.append([collada.DaeSyntax.SCALE, scale])

		# Get the instance
		type = bNode.getType()
		instance  = None
		meshID = None
		if type == 'Mesh':
			instance = collada.DaeGeometryInstance()
			daeGeometry = self.document.colladaDocument.geometriesLibrary.FindObject(bNode.getData(True))
			meshNode = MeshNode(self.document)
			if daeGeometry is None:
				daeGeometry = meshNode.SaveToDae(bNode.getData())
			meshID = daeGeometry.id
			bindMaterials = meshNode.GetBindMaterials(bNode.getData(), daeGeometry.uvTextures, daeGeometry.uvIndex)
			instance.object = daeGeometry
			instance.bindMaterials = bindMaterials


			instanceController = None
			# Check if this mesh is skinned to an amarture.
			isSkinned = False
			for bModifier in bNode.modifiers:
				if bModifier.type == Blender.Modifier.Type.ARMATURE:
					isSkinned = True
					# An Armature modifier exists, so create a Controller.
					controller = Controller(self.document)
					daeController = controller.SaveToDae(bModifier, bNode, meshID)

					#Get the root bone
					bArmature = bModifier[Blender.Modifier.Settings.OBJECT].getData()
					rootBones = []
					for boneName in bArmature.bones.keys():
						bone = bArmature.bones[boneName]
						if not bone.hasParent():
							rootBones.append(bone)

					instanceController = collada.DaeControllerInstance()
					instanceController.object = daeController
					daeNode.transforms = []
					loc = [0,0,0]
					daeNode.transforms.append([collada.DaeSyntax.TRANSLATE, loc])

					rotxVec = [1,0,0,0]
					rotyVec = [0,1,0,0]
					rotzVec = [0,0,1,0]
					daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotzVec])
					daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotyVec])
					daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotxVec])

					scale = [1,1,1]
					daeNode.transforms.append([collada.DaeSyntax.SCALE, scale])
					#use the rootBone's name for consistancy with vert groups
					instanceController.skeletons.append(rootBones[0].name)
					instanceController.bindMaterials = bindMaterials

			if not isSkinned:  # only add an instance geometry if it is not skinned
				daeNode.iGeometries.append(instance)
			else:
				daeNode.iControllers.append(instanceController)

		elif type == 'Camera':
			instance = collada.DaeCameraInstance()
			daeCamera = self.document.colladaDocument.camerasLibrary.FindObject(bNode.getData(True))
			if daeCamera is None:
				cameraNode = CameraNode(self.document)
				daeCamera = cameraNode.SaveToDae(bNode.getData())
			instance.object = daeCamera
			daeNode.iCameras.append(instance)
		elif type == 'Lamp':
			instance = collada.DaeLightInstance()
			daeLight = self.document.colladaDocument.lightsLibrary.FindObject(bNode.getData(True))
			if daeLight is None:
				lampNode = LampNode(self.document)
				daeLight = lampNode.SaveToDae(bNode.getData())
			instance.object = daeLight
			daeNode.iLights.append(instance)
		elif type == 'Armature':
			daeNode.type = collada.DaeSyntax.TYPE_JOINT
			armatureNode = ArmatureNode(self.document)
			daeArmature = armatureNode.SaveToDae(bNode.getData(),bNode, bNode.getPose())
			daeNode = daeArmature[0]

		# Check if the object has an IPO curve. if so, export animation.
		if not (bNode.ipo is None):
			ipo = bNode.ipo
			animation = Animation(self.document)
			animation.SaveToDae(ipo, daeNode)

		# Export layer information.
		daeNode.layer = ['L'+str(layer) for layer in bNode.layers]

		if not exportSelection:
			myChildNodes = []
			if childNodes.has_key(bNode.name):
				myChildNodes = childNodes[bNode.name]

			for bNode in myChildNodes:
				sceneNode = SceneNode(self.document, self)
				daeNode.nodes.append(sceneNode.SaveSceneToDae(bNode,childNodes,daeGlobalPhysicsModel,daeGlobalPhysicsModelInstance)[0])

		daePhysicsInstance = self.SavePhysicsToDae(bNode, meshID, daeNode,daeGlobalPhysicsModel,daeGlobalPhysicsModelInstance)
		return (daeNode, daePhysicsInstance)

	def SavePhysicsToDae(self, bNode, meshID, daeNode,daeGlobalPhysicsModel,daeGlobalPhysicsModelInstance):
		global usePhysics
		if meshID is None or (not(usePhysics is None) and not usePhysics):
			return None

		# Check if physics is supported.
		if usePhysics is None:
			usePhysics = hasattr(bNode, "rbShapeBoundType")
			if not usePhysics:
				return None

		rbFlags = [0 for a in range(16)]
		rbF = bNode.rbFlags
		lastIndex = 0;
		# Get the bit flags.
		while rbF > 0:
			val = rbF >> 1
			if val << 1 == rbF:
				##rbFlags.append(0)
				rbFlags[lastIndex] = 0
			else:
				##rbFlags.append(1)
				rbFlags[lastIndex] = 1
			lastIndex += 1
			rbF = val


		daeRigidBody = collada.DaeRigidBody();
		#print "daeNode.id",daeNode.id
		daeRigidBody.id = daeRigidBody.name = daeRigidBody.sid = self.document.CreateID(daeNode.id,'-RigidBody')
		#print "daeRigidBody.sid",daeRigidBody.sid
		daeRigidBodyTechniqueCommon = collada.DaeRigidBody.DaeTechniqueCommon()
		daeRigidBodyTechniqueCommon.dynamic = bool(rbFlags[0])
		if daeRigidBodyTechniqueCommon.dynamic:
				daeRigidBodyTechniqueCommon.mass = bNode.rbMass
		else:
				daeRigidBodyTechniqueCommon.mass = 0 #not dynamic means mass == 0!

		# Check the shape of the rigid body.
		if bNode.rbShapeBoundType == 0 and rbFlags[PhysicsNode.bounds]: # Box
			shape = collada.DaeBoxShape()
			shape.halfExtents = list(bNode.rbHalfExtents)
		elif bNode.rbShapeBoundType == 1  and rbFlags[PhysicsNode.bounds]: # Sphere
			shape = collada.DaeSphereShape()
			shape.radius = bNode.rbRadius
		elif bNode.rbShapeBoundType == 2  and rbFlags[PhysicsNode.bounds]: # Cylinder
			shape = collada.DaeCylinderShape()
			shape.radius = [[bNode.rbRadius],[bNode.rbRadius]]
			shape.height = bNode.rbHalfExtents[2]
		elif bNode.rbShapeBoundType == 3  and rbFlags[PhysicsNode.bounds]: # Cone
			shape = collada.DaeTaperedCylinderShape()
			shape.radius1 = [[bNode.rbRadius],[bNode.rbRadius]]
			shape.radius2 = [0 , 0]
			shape.height = bNode.rbHalfExtents[2]
		else: # Convex hull or # Static Triangle Mesh for static, and # Sphere if dynamic
			if daeRigidBodyTechniqueCommon.dynamic and not rbFlags[PhysicsNode.bounds]:
				shape = collada.DaeSphereShape()
				shape.radius = bNode.rbRadius
			else:
				shape = collada.DaeGeometryShape()
				iGeometry = collada.DaeGeometryInstance()
				if bNode.rbShapeBoundType == 5:
					object = self.document.colladaDocument.geometriesLibrary.FindObject(daeNode.id+'-Convex')
				else:
					object = self.document.colladaDocument.geometriesLibrary.FindObject(meshID)
					if not object.HasOnlyTriangles(): # The geometry contains no triangles
						pass

				if object is None:
					object = collada.DaeGeometry()
					object.id = object.name = self.document.CreateID(daeNode.id,'-ConvexGeom')
					convexMesh = collada.DaeConvexMesh()
					convexMesh.convexHullOf = meshID
					object.data = convexMesh
					self.document.colladaDocument.geometriesLibrary.AddItem(object)
				iGeometry.object = object
				shape.iGeometry = iGeometry

		# Create a physics material.
		daePhysicsMaterial = self.document.colladaDocument.physicsMaterialsLibrary.FindObject(daeNode.id+'-PxMaterial')
		if daePhysicsMaterial is None:
			daePhysicsMaterial = collada.DaePhysicsMaterial()

			physicsMaterials = bNode.getData().getMaterials()
			if (not (physicsMaterials is None)) and len(physicsMaterials) > 0:
				physicsMaterial = physicsMaterials[0]
				if not (physicsMaterial is None):
					daePhysicsMaterial.techniqueCommon.restitution = physicsMaterial.rbRestitution

					# Usually dynamic friction is less than static friction. However, as of Blender 2.42,
					# only a single friction coefficient can be specified. This is used for both
					# static and dynamic friction coefficients.

					daePhysicsMaterial.techniqueCommon.staticFriction = physicsMaterial.rbFriction
					daePhysicsMaterial.techniqueCommon.dynamicFriction = physicsMaterial.rbFriction

			daePhysicsMaterial.id = daePhysicsMaterial.name = self.document.CreateID(daeNode.id, '-PhysicsMaterial')
			self.document.colladaDocument.physicsMaterialsLibrary.AddItem(daePhysicsMaterial)

		# Create a physics material instance.
		daePhysicsMaterialInstance = collada.DaePhysicsMaterialInstance()
		# Set the physics material of this instance
		daePhysicsMaterialInstance.object = daePhysicsMaterial


		# add the shape to the commom technique.
		daeRigidBodyTechniqueCommon.shapes.append(shape)
		# Set the material of the common technique.
		daeRigidBodyTechniqueCommon.iPhysicsMaterial = daePhysicsMaterialInstance
		# Set the common technique of this rigid body.
		daeRigidBody.techniqueCommon = daeRigidBodyTechniqueCommon

		# Add the rigid body to the physics model.
		daeGlobalPhysicsModel.rigidBodies.append(daeRigidBody)
		# Create a new RigidBody instance
		daeRigidBodyInstance = collada.DaeRigidBodyInstance()
		# Set the rigid body of this instance
		daeRigidBodyInstance.body = daeRigidBody
		# Set the node of this instance
		daeRigidBodyInstance.target = daeNode

		# add the rigidbody instance to this physics model instance.
		daeGlobalPhysicsModelInstance.iRigidBodies.append(daeRigidBodyInstance)

		#handle constraints
		for rbconstraint in bNode.constraints:
			if rbconstraint.type == Blender.Constraint.Type.RIGIDBODYJOINT:
				daeRigidConstraint = collada.DaeRigidConstraint();
				daeRigidConstraint.id = daeRigidConstraint.name = daeRigidConstraint.sid = rbconstraint.name

				daeRigidConstraint.attachment = collada.DaeRigidConstraint.DaeAttachment()
				daeRigidConstraint.attachment.rigid_body = daeRigidBody
				daeRigidConstraint.attachment.blenderobject = bNode
				daeRigidConstraint.attachment.pivX = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_PIVX]
				daeRigidConstraint.attachment.pivY = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_PIVY]
				daeRigidConstraint.attachment.pivZ = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_PIVZ]
				daeRigidConstraint.attachment.axX = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_AXX]
				daeRigidConstraint.attachment.axY = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_AXY]
				daeRigidConstraint.attachment.axZ = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_AXZ]

				if not (rbconstraint[Blender.Constraint.Settings.TARGET] is None):
					#find rigidbody that goes with TARGET...
					blendertargetob = rbconstraint[Blender.Constraint.Settings.TARGET]
					targetRbId = blendertargetob.name+'-RigidBody'
					targetrigidbody = daeGlobalPhysicsModel.FindRigidBody(targetRbId)
					if not (targetrigidbody is None):
						daeRigidConstraint.ref_attachment = collada.DaeRigidConstraint.DaeRefAttachment()
						daeRigidConstraint.ref_attachment.rigid_body = targetrigidbody
						daeRigidConstraint.ref_attachment.blenderobject = blendertargetob

						#calculate pivX/pivY/pivZ and axX,axY,axZ for this reference frame
						refObjectWorldMatrix = blendertargetob.matrix
						attachObjectWorldMatrix = bNode.matrix
						euler = Euler(daeRigidConstraint.attachment.axX,daeRigidConstraint.attachment.axY,daeRigidConstraint.attachment.axZ);
						matRot= euler.toMatrix()
						matT1 = TranslationMatrix(Vector(daeRigidConstraint.attachment.pivX,daeRigidConstraint.attachment.pivY,daeRigidConstraint.attachment.pivZ))
						matT = TranslationMatrix(Vector(0,0,0))
						matT[0][0]=matRot[0][0]
						matT[0][1]=matRot[0][1]
						matT[0][2]=matRot[0][2]
						matT[1][0]=matRot[1][0]
						matT[1][1]=matRot[1][1]
						matT[1][2]=matRot[1][2]
						matT[2][0]=matRot[2][0]
						matT[2][1]=matRot[2][1]
						matT[2][2]=matRot[2][2]
						copyMat = Matrix(refObjectWorldMatrix);
						attachLocalMatrix = matT * matT1
						invertedMat = copyMat.invert()
						globalFrameA = attachLocalMatrix * attachObjectWorldMatrix
						refAttachLocalMatrix = globalFrameA * invertedMat
						refPivot = refAttachLocalMatrix.translationPart()
						eulerAngles = refAttachLocalMatrix.toEuler()
						daeRigidConstraint.ref_attachment.pivX = refPivot[0]
						daeRigidConstraint.ref_attachment.pivY = refPivot[1]
						daeRigidConstraint.ref_attachment.pivZ = refPivot[2]
						daeRigidConstraint.ref_attachment.axX = eulerAngles[0]
						daeRigidConstraint.ref_attachment.axY = eulerAngles[1]
						daeRigidConstraint.ref_attachment.axZ = eulerAngles[2]


				#print "constraint type = ",rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE]

				daeRigidConstraintTechniqueCommon = collada.DaeRigidConstraint.DaeTechniqueCommon()

				daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [0,0,0]
				daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [0,0,0]
				daeRigidConstraintTechniqueCommon.limits.angularLimits.min = [0,0,0]
				daeRigidConstraintTechniqueCommon.limits.angularLimits.max = [0,0,0]

				#generic 6 degree-of-freedom joint
				if rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE] == 12:
					daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT0],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT1],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT2]]
					daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT0],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT1],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT2]]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.min = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT3],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT4],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT5]]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.max = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT3],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT4],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT5]]
				#ball-socket joint
				if rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE] == 1:
					daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.min = ['-INF','-INF','-INF']
					daeRigidConstraintTechniqueCommon.limits.angularLimits.max = ['INF','INF','INF']
				#hinge
				if rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE] == 2:
					daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.min = ['-INF',0,0]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.max = ['INF',0,0]


				#daeRigidConstraintTechniqueCommon.enabled = True
				daeRigidConstraint.techniqueCommon = daeRigidConstraintTechniqueCommon
				daeGlobalPhysicsModel.constraints.append(daeRigidConstraint)

				# Create a new RigidConstraint instance
				daeRigidConstraintInstance = collada.DaeRigidConstraintInstance()
				# Set the rigid body of this instance
				daeRigidConstraintInstance.constraint = daeRigidConstraint

				#add constraint instance
				daeGlobalPhysicsModelInstance.iConstraints.append(daeRigidConstraintInstance)





		return daeRigidBodyInstance

class ArmatureNode(object):
	def __init__(self, document):
		self.document = document

	def SaveToDae(self, bArmature, bArmatureObject, bPose):
		daeNodes = []
		# Get the root bones
		rootBones = []

		for boneName in bArmature.bones.keys():
			bone = bArmature.bones[boneName]
			if not bone.hasParent():
				rootBones.append(bone)

		# Only take the first root and ignore it.
		if len(rootBones) > 0 and not rootBones[0].children is None:
			daeNodes.append(self.BoneToDae(rootBones[0], bPose,Matrix(), bArmatureObject))

			##for childBone in rootBones[0].children:
##				print PrintTransforms(Matrix(bPose.bones[rootBones[0].name].poseMatrix).transpose(),rootBones[0].name)
			##	poseMatrix = Matrix(bPose.bones[rootBones[0].name].poseMatrix).transpose()
			##	poseMatrixRotInv = poseMatrix.rotationPart().invert().resize4x4()
				##poseMatrixNoRot = poseMatrix * poseMatrixRotInv

			##	print rootBones[0]
			##	print Matrix(bArmatureObject.matrix).transpose().invert()
				##daeNodes.append(self.BoneToDae(rootBones[0], bPose, Matrix(bArmatureObject.matrix).transpose().invert(),poseMatrixRotInv, bArmatureObject))

		if len(rootBones) > 1:
			print "Please use only a single root for proper export"

		return daeNodes

	def BoneToDae(self, bBone, bPose, parentMatrix, bArmatureObject, bParentBind=None):
		daeNode = collada.DaeNode()
		daeNode.id = daeNode.name = daeNode.sid = self.document.CreateID(bBone.name, '-Joint')
		daeNode.type = collada.DaeSyntax.TYPE_JOINT

		# Get the transformations
		headPos = bBone.head["ARMATURESPACE"]
		bindMatrix = Matrix([1,0,0,headPos.x], [0,1,0,headPos.y], [0,0,1,headPos.z],[0,0,0,1])
		armMatrix = bindMatrix;

		if ( not bBone.hasParent() ):
			armMatrix = Matrix(bArmatureObject.getMatrix('localspace')).transpose();
			armMatrix *= bindMatrix

		try :
			armAction = bArmatureObject.getAction()
			ipList = armAction.getAllChannelIpos()

			ip_bone_channel = ipList[bBone.name]
			ip_bone_name = ip_bone_channel.getName()
			ipo = Blender.Ipo.Get(ip_bone_name)

			if not (ipo is None):
				animation = Animation(self.document)
				if bParentBind is None:
					animation.SaveToDae(ipo, daeNode, bBone, bPose, parentMatrix, bArmatureObject)
				else:
					animation.SaveToDae(ipo, daeNode, bBone, bPose, bParentBind, bArmatureObject)
		except:
			pass

		mat = Matrix(parentMatrix).invert() * armMatrix
		boneMatrix = Matrix(bindMatrix)
		mat.transpose()

		if bakeMatrices :
			mat = Matrix(mat).transpose()
			daeNode.transforms.append([collada.DaeSyntax.MATRIX, mat])
		else:
			translation = mat.translationPart()

			daeNode.transforms.append([collada.DaeSyntax.TRANSLATE, translation])

			euler = mat.toEuler()
##			print euler
			rotxVec = [1,0,0,euler.x]
			rotyVec = [0,1,0,euler.y]
			rotzVec = [0,0,1,euler.z]

##			print rotxVec[3], rotyVec[3], rotzVec[3]

			daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotzVec])
			daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotyVec])
			daeNode.transforms.append([collada.DaeSyntax.ROTATE, rotxVec])

			scale = mat.scalePart()
			daeNode.transforms.append([collada.DaeSyntax.SCALE, scale])


		if not bBone.children is None:
			for childBone in bBone.children:
				daeNode.nodes.append(self.BoneToDae(childBone, bPose, boneMatrix, bArmatureObject, boneMatrix))
		return daeNode



class MeshNode(object):
	def __init__(self,document):
		self.document = document
		self.materials = []
		self.verts = []

	def FindMaterial(self, bMaterials,name):
		for i in range(len(bMaterials)):
			if bMaterials[i].name == name:
				return i
		return -1

	def LoadFromDae(self, daeGeometry):
		global replaceNames
		meshID = daeGeometry.id
		meshName = daeGeometry.name

		# Create a new meshObject
		bMesh2 = Blender.NMesh.New(self.document.CreateNameForObject(meshID,replaceNames,'mesh'))

		if isinstance(daeGeometry.data,collada.DaeMesh): # check if it's a mesh
			materials = []
			for matName, material in self.materials.iteritems():
				materials.append(material)
			bMesh2.materials = materials

			faces = []

			daeMesh = daeGeometry.data
			daeVertices = daeMesh.vertices

			# Get all the sources
			sources = dict()

			for source in daeMesh.sources:
				sources[source.id] = source.vectors

			# Get the Position Input
			vPosInput = daeVertices.FindInput('POSITION')
			if not (daeMesh.FindSource(vPosInput).techniqueCommon is None):

				# Get the Normal Input
				vNorInput = daeVertices.FindInput('NORMAL')


				# Keep track of the Blender Vertices
				pVertices = []

				self.document.ProgressPart(0.0,'Create Vertices')

				vertIndex = 0
				self.verts = range(len(sources[vPosInput.source]))
				# Create all the vertices.
				for i in sources[vPosInput.source]:
					vPosVector = Vector(i[0], i[1], i[2]) * self.document.tMatOLD
					bVert = Blender.NMesh.Vert(vPosVector.x, vPosVector.y, vPosVector.z)
					self.verts[vertIndex] = bVert
					pVertices.append(bVert)
					vertIndex += 1

				bMesh2.verts = pVertices

				faceVerts = [] # The list of vertices for each face to add
				edgeVerts = [] # The list of vertices for each edge to add

				# Now create the primitives
				self.document.ProgressPart(0.5,'Create Primitives')
				daePrimitives = daeMesh.primitives
				for primitive in daePrimitives:
					# Get the UV Input
					vUvInput = primitive.FindInput('TEXCOORD')
					uvs = []
					if not (vUvInput is None):
						for i in sources[vUvInput.source]:
							vUvVector = Vector(i[0],i[1])
							uvs.append(vUvVector)
					inputs = primitive.inputs
					maxOffset = primitive.GetStride() # The number of values for one vertice
					vertCount = 0 # The number of vertices for one primitive
					realVertCount = 0 # The number of vertices for one primitive
					plist = [] # The list with all primitives
					if isinstance(primitive, collada.DaePolygons): # Polygons
						plist = primitive.polygons
						vertCount = 4
					elif isinstance(primitive, collada.DaeTriangles): # Triangles
						plist.append(primitive.triangles)
						vertCount = 3
					elif isinstance(primitive, collada.DaeLines): # Lines
						plist.append(primitive.lines)
						vertCount = 2
					elif isinstance(primitive, collada.DaePolylist): # Polylist
						plist.append(primitive.polygons)
						vertCount = 5
					elif isinstance(primitive, collada.DaeTriFans): #TriFan
						plist = primitive.trifans
						vertCount = 3
					elif isinstance(primitive, collada.DaeTriStrips): #TriStrip
						plist = primitive.tristrips
						vertCount = 3

					realVertCount = vertCount
					# Loop through each P (primitive)
					for p in plist:
						# for PolyList: Keep track of the index of the polygon
						polyListIndex = -1
						if isinstance(primitive, collada.DaeTriFans) or isinstance(primitive, collada.DaeTriStrips):
							pIndex = maxOffset * 2
							vertexInput = primitive.FindInput("VERTEX")
							uvInput = primitive.FindInput("TEXCOORD")

							if not vertexInput is None:
								firstVertIndex = p[vertexInput.offset]
								prevVertIndex = p[maxOffset + vertexInput.offset]

							if not uvInput is None:
								firstUVIndex = p[uvInput.offset]
								prevUVIndex = p[maxOffset + uvInput.offset]
							realVertCount = 1
						else:
							pIndex = 0
						# A list with edges in this face
						faceEdges = []
						# a list to store all the created faces in to add them to the mesh afterwards.
						allFaceVerts = []
						# loop through all the values in this 'p'
						while pIndex < len(p):
							# update the realVertCount
							if vertCount == 5:
								polyListIndex += 1
								realVertCount = primitive.vcount[polyListIndex]

							# Keep track of the verts in this face
							curFaceVerts2 = []
							uvList	= []
							# for every vertice for this primitive
							for i in range(realVertCount):
								# Check all the inputs and do the right thing
								for input in inputs:
									inputVal = p[pIndex+(i*maxOffset)+input.offset]
									if input.semantic == "VERTEX":
										vert2 = pVertices[inputVal]
										if isinstance(primitive, collada.DaeTriFans):
											firstVert = pVertices[firstVertIndex]
											prevVert = pVertices[prevVertIndex]
											curFaceVerts2.append(firstVert)
											curFaceVerts2.append(prevVert)
											curFaceVerts2.append(vert2)
											prevVertIndex = inputVal
										elif isinstance(primitive, collada.DaeTriStrips):
											firstVert = pVertices[firstVertIndex]
											prevVert = pVertices[prevVertIndex]
											curFaceVerts2.append(firstVert)
											curFaceVerts2.append(prevVert)
											curFaceVerts2.append(vert2)
											firstVertIndex = prevVertIndex
											prevVertIndex = inputVal
										else:
											curFaceVerts2.append(vert2)
									elif input.semantic == "TEXCOORD":
										uv2 = uvs[inputVal]
										if isinstance(primitive, collada.DaeTriFans):
											firstUV = uvs[firstUVIndex]
											prevUV = uvs[prevUVIndex]
											uvList.append((firstUV[0],firstUV[1]))
											uvList.append((prevUV[0],prevUV[1]))
											uvList.append((uv2[0],uv2[1]))
											prevUVIndex = inputVal
										elif isinstance(primitive, collada.DaeTriStrips):
											firstUV = uvs[firstUVIndex]
											prevUV = uvs[prevUVIndex]
											uvList.append((firstUV[0],firstUV[1]))
											uvList.append((prevUV[0],prevUV[1]))
											uvList.append((uv2[0],uv2[1]))
											firstUVIndex = prevUVIndex
											prevUVIndex = inputVal
										else:
											uvList.append((uvs[inputVal][0],uvs[inputVal][1]))
									elif input.semantic == "NORMAL":
										pass
							if vertCount > 2:
								if isinstance(primitive, collada.DaeTriFans):
									faceCount = 1
								else:
									faceCount = 1 + (realVertCount-4) / 2 + (realVertCount-4) % 2
								firstIndex = 2
								lastIndex = 1
								for a in range(faceCount):
									if isinstance(primitive, collada.DaeTriFans):
										newFirstIndex = (firstIndex + 1) % vertCount
										newLastIndex = (lastIndex -1) % vertCount
									else:
										newFirstIndex = (firstIndex + 1) % realVertCount
										newLastIndex = (lastIndex -1) % realVertCount

									fuv = []
									if newFirstIndex != newLastIndex:
										fv = [curFaceVerts2[firstIndex]] + [curFaceVerts2[newFirstIndex]] + [curFaceVerts2[newLastIndex]] +  [curFaceVerts2[lastIndex]]
										if len(uvList) == realVertCount:
											fuv = [uvList[firstIndex]] + [uvList[newFirstIndex]] + [uvList[newLastIndex]] + [uvList[lastIndex]]
									else:
										fv = [curFaceVerts2[firstIndex]] + [curFaceVerts2[newFirstIndex]] + [curFaceVerts2[lastIndex]]
										if len(uvList) == realVertCount:
											fuv = [uvList[firstIndex]] + [uvList[newFirstIndex]] + [uvList[lastIndex]]
									firstIndex = newFirstIndex
									lastIndex = newLastIndex
									# Create a new Face.
									newFace = Blender.NMesh.Face(fv)
									# Set the UV Coordinates
									newFace.uv = fuv
									# Add the new face to the list
									faces.append(newFace)
									# Add the material to this face
									if primitive.material != '':
										if self.materials.has_key(primitive.material):
											# Find the material index.
											matIndex = self.FindMaterial(bMesh2.materials, self.materials[primitive.material].name)
											# Set the material index for the new face.
											newFace.materialIndex = matIndex
											textures = self.materials[primitive.material].getTextures()
											if len(textures) > 0 and not (textures[0] is None):
												texture = textures[0]
												image = texture.tex.getImage()
												if not image is None:
													newFace.image = image
										else:
											print "Warning: Cannot find material:", primitive.material
							else:
								bMesh2.addEdge(curFaceVerts2[0], curFaceVerts2[1])

							# update the index
							if isinstance(primitive, collada.DaeTriFans) or isinstance(primitive, collada.DaeTriStrips):
								pIndex += maxOffset
							else:
								pIndex += realVertCount * maxOffset


						bMesh2.faces = faces
		return bMesh2

	def SaveToDae(self, bMesh):
		global useTriangles, usePolygons, useUV

		uvTextures = dict()
		uvIndex = dict()

		daeGeometry = collada.DaeGeometry()
		daeGeometry.id = daeGeometry.name = self.document.CreateID(bMesh.name,'-Geometry')

		daeMesh = collada.DaeMesh()

		# Keep track of the edges in faces
		faceEdges = []

		daeSource = collada.DaeSource()
		daeSource.id = self.document.CreateID(daeGeometry.id,'-Position')
		daeFloatArray = collada.DaeFloatArray()
		daeFloatArray.id = self.document.CreateID(daeSource.id,'-array')
		daeSource.source = daeFloatArray
		daeSource.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		accessor = collada.DaeAccessor()
		daeSource.techniqueCommon.accessor = accessor
		accessor.source = daeFloatArray.id
		accessor.count = len(bMesh.verts)
		accessor.AddParam('X','float')
		accessor.AddParam('Y','float')
		accessor.AddParam('Z','float')

		daeSourceNormals = collada.DaeSource()
		daeSourceNormals.id = self.document.CreateID(daeGeometry.id,'-Normals')
		daeFloatArrayNormals = collada.DaeFloatArray()
		daeFloatArrayNormals.id = self.document.CreateID(daeSourceNormals.id,'-array')
		daeSourceNormals.source = daeFloatArrayNormals
		daeSourceNormals.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		accessorNormals = collada.DaeAccessor()
		daeSourceNormals.techniqueCommon.accessor = accessorNormals
		accessorNormals.source = daeFloatArrayNormals.id
		accessorNormals.count = 0
		accessorNormals.AddParam('X','float')
		accessorNormals.AddParam('Y','float')
		accessorNormals.AddParam('Z','float')

		daeSourceTextures = collada.DaeSource()
		daeSourceTextures.id = self.document.CreateID(daeGeometry.id , '-UV')
		daeFloatArrayTextures = collada.DaeFloatArray()
		daeFloatArrayTextures.id = self.document.CreateID(daeSourceTextures.id,'-array')
		daeSourceTextures.source = daeFloatArrayTextures
		daeSourceTextures.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
		accessorTextures = collada.DaeAccessor()
		daeSourceTextures.techniqueCommon.accessor = accessorTextures
		accessorTextures.source = daeFloatArrayTextures.id
		accessorTextures.AddParam('S','float')
		accessorTextures.AddParam('T','float');


		daeVertices = collada.DaeVertices()
		daeVertices.id = self.document.CreateID(daeGeometry.id,'-Vertex')
		daeInput = collada.DaeInput()
		daeInput.semantic = 'POSITION'
		daeInput.source = daeSource.id
		daeVertices.inputs.append(daeInput)
		daeInputNormals = collada.DaeInput()
		daeInputNormals.semantic = 'NORMAL'
		daeInputNormals.source = daeSourceNormals.id
		daeInputNormals.offset = 1
		## daeVertices.inputs.append(daeInputNormals)
		daeMesh.vertices = daeVertices

		hasColor = False
		#Vertex colors:
		if ( bMesh.hasVertexColours() ) :
			hasColor = True
			daeSourceColors = collada.DaeSource()
			daeSourceColors.id = self.document.CreateID(daeGeometry.id , '-color')
			daeFloatArrayColors = collada.DaeFloatArray()
			daeFloatArrayColors.id = self.document.CreateID(daeSourceColors.id,'-array')
			daeSourceColors.source = daeFloatArrayColors
			daeSourceColors.techniqueCommon = collada.DaeSource.DaeTechniqueCommon()
			accessorColors = collada.DaeAccessor()
			daeSourceColors.techniqueCommon.accessor = accessorColors
			accessorColors.source = daeFloatArrayColors.id
			accessorColors.AddParam('R','float')
			accessorColors.AddParam('G','float');
			accessorColors.AddParam('B','float');
			accessorColors.AddParam('A','float');

		for vert in bMesh.verts:
			#print vert
			for co in vert.co:
				daeFloatArray.data.append(co)
			## for no in vert.no:
			##	daeFloatArrayNormals.data.append(no)


		daePolygonsDict = dict()
		daeTrianglesDict = dict()
		daeLines = None

		mesh = Blender.Mesh.Get(bMesh.name);

		# Loop trough all the faces
		for face in mesh.faces:
			matIndex = -1
			if not useUV and bMesh.materials and len(bMesh.materials) > 0:
				matIndex = face.mat
			elif mesh.faceUV and (useUV or bMesh.materials is None or len(bMesh.materials) == 0):
				if not face.image is None:
					matIndex = face.image.name

			vertCount = len(face.verts)

			# Create a new function which adds vertices to a list.
			def AddVerts(verts,prlist,smooth,secondTriangle=False):
				secondTriangleIndex = [2,3,0]

				prevVert = None
				lastVert = verts[-1]
				for v_index in range(len(verts)):
					# Get the vertice
					vert = verts[v_index]
					vert_index = v_index
					# Add the vertice to the end of the list.
					prlist.append(vert.index)

					# Add the normals of these verts
					if smooth:
						for no in vert.no:
							daeFloatArrayNormals.data.append(no);
						accessorNormals.count = accessorNormals.count + 1

					#prlist.append(len(daeFloatArrayNormals.data)/3-1)
					prlist.append(accessorNormals.count - 1)


					if hasColor:
						if secondTriangle:
							vert_index = secondTriangleIndex[vert_index]
						daeFloatArrayColors.data.append(face.col[vert_index].r / 255.0)
						daeFloatArrayColors.data.append(face.col[vert_index].g / 255.0)
						daeFloatArrayColors.data.append(face.col[vert_index].b / 255.0)
						daeFloatArrayColors.data.append(face.col[vert_index].a / 255.0)
						prlist.append(len(daeFloatArrayColors.data)/4-1)
						accessorColors.count = accessorColors.count + 1
						vert_index = v_index

					# If the mesh has UV-coords, add these to the textures array.
					if mesh.faceUV:
						if secondTriangle:
							vert_index = secondTriangleIndex[vert_index]
						daeFloatArrayTextures.data.append(face.uv[vert_index][0])
						daeFloatArrayTextures.data.append(face.uv[vert_index][1])
						prlist.append(len(daeFloatArrayTextures.data)/2-1)
						accessorTextures.count = accessorTextures.count + 1

					# Add the edge to the faceEdges list.
					if prevVert != None:
						faceEdges.append(mesh.findEdges(prevVert, vert))
					else:
						faceEdges.append(mesh.findEdges([(vert, lastVert)]))
					# Update the prevVert vertice.
					prevVert = vert

			if (vertCount == 3 and not usePolygons) or (useTriangles and vertCount == 4): # triangle
				# Iff a Triangle Item for the current material not exists, create one.
				daeTrianglesDict.setdefault(matIndex, collada.DaeTriangles())
				if not face.smooth:
					# Add the face normal to the normals source
					for no in face.no:
						daeFloatArrayNormals.data.append(no)
					accessorNormals.count = accessorNormals.count + 1
				if vertCount == 3:
					# Add al the vertices to the triangle list.
					AddVerts(face.verts,daeTrianglesDict[matIndex].triangles, face.smooth )
					# Update the vertice count for the trianglelist.
					daeTrianglesDict[matIndex].count += 1
				else: # Convert polygon to triangles
					verts1 = face.verts[:3]
					verts2 = face.verts[2:] + tuple([face.verts[0]])
					# Add al the vertices to the triangle list.
					AddVerts(verts1,daeTrianglesDict[matIndex].triangles, face.smooth)
					AddVerts(verts2, daeTrianglesDict[matIndex].triangles,face.smooth,True)
					# Update the vertice count for the trianglelist.
					daeTrianglesDict[matIndex].count += 2
			else: # polygon
				# Iff a Polygon Item for the current material not exists, create one.
				daePolygonsDict.setdefault(matIndex, collada.DaePolygons())
				# for each polygon, create a new P element
				pverts = []
				if not face.smooth:
					# Add the face normal to the normals source
					for no in face.no:
						daeFloatArrayNormals.data.append(no)
					accessorNormals.count = accessorNormals.count + 1
				# Add al the vertices to the pverts list.
				AddVerts(face.verts,pverts, face.smooth)
				# Add the pverts list to the polygons list.
				daePolygonsDict[matIndex].polygons.append(pverts)
				# Update the vertice count for the polygonlist.
				daePolygonsDict[matIndex].count += 1
			if mesh.faceUV:
				if not face.image is None:
					if not face.image.name in uvTextures:
						uvIndex[face.image.name] = face.mat;
						uvTextures[face.image.name] = self.document.CreateID(face.image.name, "-Material")
		# Loop through all the edges
		for edge in mesh.edges:
			if not edge.index in faceEdges:
				if daeLines == None: daeLines = collada.DaeLines()
				daeLines.count += 1
				daeLines.lines.append(edge.v1.index)
				daeLines.lines.append(edge.v2.index)

		daeInput = collada.DaeInput()
		daeInput.semantic = 'VERTEX'
		daeInput.offset = 0
		daeInput.source = daeVertices.id

		daeInputUV = collada.DaeInput()
		daeInputUV.semantic = 'TEXCOORD'
		daeInputUV.offset = 2
		daeInputUV.source = daeSourceTextures.id

		if hasColor:
			daeInputColor = collada.DaeInput()
			daeInputColor.semantic = 'COLOR'
			daeInputColor.offset = 3
			daeInputColor.source = daeSourceColors.id

		materialName = ''

		for k, daeTriangles in daeTrianglesDict.iteritems():
			##print k
			if k != -1:
				if not useUV and not bMesh.materials is None and len(bMesh.materials) > 0 and k >= 0:
					daeTriangles.material = bMesh.materials[k].name
				elif mesh.faceUV and (useUV or bMesh.materials is None or len(bMesh.materials) == 0):
					daeTriangles.material = uvTextures[k]
			offsetCount = 0;
			daeInput.offset = offsetCount
			daeTriangles.inputs.append(daeInput)
			offsetCount += 1;

			daeInputNormals.offset = offsetCount;
			daeTriangles.inputs.append(daeInputNormals);
			offsetCount += 1;

			if mesh.faceUV:
				daeInputUV.offset = offsetCount;
				daeTriangles.inputs.append(daeInputUV)
				offsetCount += 1;
			if hasColor:
				daeInputColor.offset = offsetCount;
				daeTriangles.inputs.append(daeInputColor)
				offsetCount += 1;
			daeMesh.primitives.append(daeTriangles)
		for k, daePolygons in daePolygonsDict.iteritems():
			if k != -1:
				if not useUV and not bMesh.materials is None and len(bMesh.materials) > 0 and k >= 0:
					daePolygons.material = bMesh.materials[k].name
				elif mesh.faceUV and (useUV or bMesh.materials is None or len(bMesh.materials) == 0):
					daePolygons.material = uvTextures[k]
			offsetCount = 0;
			daeInput.offset = offsetCount
			daePolygons.inputs.append(daeInput)
			offsetCount += 1;

			daeInputNormals.offset = offsetCount;
			daePolygons.inputs.append(daeInputNormals);
			offsetCount += 1;

			if mesh.faceUV:
				daeInputUV.offset = offsetCount;
				daePolygons.inputs.append(daeInputUV)
				offsetCount += 1;
			if hasColor:
				daeInputColor.offset = offsetCount;
				daePolygons.inputs.append(daeInputColor)
				offsetCount += 1;
			daeMesh.primitives.append(daePolygons)

		if daeLines != None:
			daeLines.inputs.append(daeInput)
			daeMesh.primitives.append(daeLines)

		daeMesh.sources.append(daeSource)
		daeMesh.sources.append(daeSourceNormals)
		if mesh.faceUV:
			daeMesh.sources.append(daeSourceTextures)
		if hasColor:
			daeMesh.sources.append(daeSourceColors)

		daeGeometry.data = daeMesh

		self.document.colladaDocument.geometriesLibrary.AddItem(daeGeometry)
		daeGeometry.uvTextures = uvTextures
		daeGeometry.uvIndex = uvIndex
		return daeGeometry

	def GetBindMaterials(self, bMesh, uvTextures, uvIndex):
		global useUV

		bindMaterials = []
		mesh = Blender.Mesh.Get(bMesh.name);
		# now check the materials


		if (not useUV) and bMesh.materials and len(bMesh.materials) > 0:
			daeBindMaterial = collada.DaeFxBindMaterial()
			for bMaterial in bMesh.materials:
				instance = collada.DaeFxMaterialInstance()
				daeMaterial = self.document.colladaDocument.materialsLibrary.FindObject(bMaterial.name)
				if daeMaterial is None:
					materialNode = MaterialNode(self.document)
					daeMaterial = materialNode.SaveToDae(bMaterial)
				instance.object = daeMaterial
				daeBindMaterial.techniqueCommon.iMaterials.append(instance)
			# now we have to add this bindmaterial to the intance of this geometry
			bindMaterials.append(daeBindMaterial)
		elif mesh.faceUV and (useUV or bMesh.materials is None or len(bMesh.materials) == 0):
			daeBindMaterial = collada.DaeFxBindMaterial()
			for imageName, imageNameUnique in uvTextures.iteritems():
				image = Blender.Image.Get(imageName)
				instance = collada.DaeFxMaterialInstance()
				daeMaterial = self.document.colladaDocument.materialsLibrary.FindObject(imageNameUnique)
				if daeMaterial is None:
					textureNode = TextureNode(self.document)
					daeMaterial = textureNode.SaveToDae(image)
					daeMaterial.id = daeMaterial.name = imageNameUnique

					if len(bMesh.materials) > 0 :
						materialIndex = uvIndex[imageName];
						bMaterial = bMesh.materials[materialIndex];

						materialNode = MaterialNode(self.document);
						materialShader = materialNode.GenerateShader(bMaterial, False);
						textureDiffuse = daeMaterial.iEffects[0].object.profileCommon.technique.shader.diffuse
						materialShader.diffuse = textureDiffuse;
						daeMaterial.iEffects[0].object.AddShader(materialShader);


				instance.object = daeMaterial
				daeBindMaterial.techniqueCommon.iMaterials.append(instance)
			# now we have to add this bindmaterial to the intance of this geometry
			bindMaterials.append(daeBindMaterial)
		return bindMaterials

class TextureNode(object):
	def __init__(self, document):
		self.document = document

	def LoadFromDae(self, daeImage):
		imageID = daeImage.id
		imageName = daeImage.name

		bTexture = Blender.Texture.New(imageID)

		filename = ''
		if isinstance(daeImage.initFrom, str):
			if Blender.sys.exists(daeImage.initFrom):
				filename = daeImage.initFrom
			elif Blender.sys.exists(self.document.filePath + daeImage.initFrom):
				filename = self.document.filePath + daeImage.initFrom

		if filename <> '':
			bTexture.setType('Image')
			img = Blender.Image.Load(filename)
			bTexture.setImage(img)
		else:
			print 'image not found: %s'%(daeImage.initFrom)

		return bTexture


	def AddImageTexture(self, daeEffect, bImage):
		#creating surface
		daeSurfaceParam = collada.DaeFxNewParam();
		surfaceId = self.document.CreateID(bImage.name,'-surface');
		daeSurfaceParam.sid = surfaceId;

		daeSurface = collada.DaeFxSurface();
		daeSurfaceParam.surface = daeSurface;
		daeSurface.initfrom = bImage.name + "-img";
		daeEffect.profileCommon.newParams.append( daeSurfaceParam )

		#creating Sampler
		daeSamplerParam = collada.DaeFxNewParam();
		samplerId = self.document.CreateID(bImage.name,'-sampler');
		daeSamplerParam.sid = samplerId;

		daeSampler = collada.DaeFxSampler2D();

		daeSamplerParam.sampler = daeSampler;
		daeSampler.source.value = surfaceId;
		daeEffect.profileCommon.newParams.append( daeSamplerParam )

		shader = collada.DaeFxShadeLambert()
		daeImage = self.document.colladaDocument.imagesLibrary.FindObject(bImage.name)
		if daeImage is None: # Create the image
			daeImage = collada.DaeImage()
			daeImage.id = daeImage.name = bImage.name + "-img";

			daeImage.initFrom = Blender.sys.expandpath(bImage.filename)
			if useRelativePaths:
				daeImage.initFrom = CreateRelativePath(filename, daeImage.initFrom)
			self.document.colladaDocument.imagesLibrary.AddItem(daeImage)
			daeTexture = collada.DaeFxTexture()
			daeTexture.texture = samplerId;
			shader.AddValue(collada.DaeFxSyntax.DIFFUSE, daeTexture)

		daeEffect.AddShader(shader)
		return;

	def SaveToDae(self, bImage):
		daeMaterial = collada.DaeFxMaterial()
		##daeMaterial.id = daeMaterial.name = self.document.CreateID(bImage.name, '-Material')
		self.document.colladaDocument.materialsLibrary.AddItem(daeMaterial)

		instance = collada.DaeFxEffectInstance()
		daeEffect = self.document.colladaDocument.effectsLibrary.FindObject(bImage.name+'-fx')

		if daeEffect is None:
			daeEffect = collada.DaeFxEffect()
			daeEffect.id = daeEffect.name = self.document.CreateID(bImage.name , '-fx')

			#Add the texture stuff!!
			self.AddImageTexture(daeEffect, bImage);

			self.document.colladaDocument.effectsLibrary.AddItem(daeEffect)
		instance.object = daeEffect

		daeMaterial.iEffects.append(instance)

		return daeMaterial

class MaterialNode(object):
	def __init__(self, document):
		self.document = document

	def LoadFromDae(self, daeMaterial):
		materialID = daeMaterial.id
		materialName = daeMaterial.name

		bMat = Blender.Material.New(materialID)
		for i in daeMaterial.iEffects:
			daeEffect = self.document.colladaDocument.effectsLibrary.FindObject(i.url)
			if not (daeEffect.profileCommon is None):
				shader = daeEffect.profileCommon.technique.shader
				if shader.transparent:
					if not (shader.transparent.color is None):
						tcol = shader.transparent.color.rgba
						tkey = 1
						if shader.transparency:
							tkey = shader.transparency.float
						alpha = 1 - tkey * (tcol[0]*0.21 + tcol[1]*0.71 + tcol[2]*0.08)
						bMat.setAlpha(alpha)
					if not (shader.transparent.texture is None): # Texture
						texture = shader.transparent.texture.texture
						if not(texture is None):
							bTexture = self.document.texturesLibrary.FindObject(texture, True)
							if not bTexture is None:
								bMat.setTexture(0, bTexture, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.ALPHA)
				elif shader.transparency:
					alpha = 1 - shader.transparency.float
				if shader.reflective:
					color = shader.reflective.color.rgba
					bMat.setMirCol(color[0], color[1], color[2])
				if shader.reflectivity:
					bMat.setRayMirr(shader.reflectivity.float)

				if isinstance(shader,collada.DaeFxShadeLambert) or isinstance(shader, collada.DaeFxShadeBlinn) or isinstance(shader, collada.DaeFxShadePhong):
					bMat.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_LAMBERT)
					if shader.diffuse:
						##print shader.diffuse.color.rgba, shader.diffuse.color
						if not (shader.diffuse.color is None):
							color = shader.diffuse.color.rgba
							bMat.setRGBCol(color[0],color[1], color[2])
						if not (shader.diffuse.texture is None): # Texture
							textureSampler = shader.diffuse.texture.texture;
							if not (textureSampler is None):
								#support 1.4.0:
								texture = textureSampler;

								#support 1.4.1
								for newParam in daeEffect.profileCommon.newParams:
									if newParam.sid == textureSampler:
										surfaceID = newParam.sampler.source;
										for newSurface in daeEffect.profileCommon.newParams:
											if newSurface.sid == surfaceID:
												texture = newSurface.surface.initfrom;

								texture = self.document.colladaDocument.imagesLibrary.FindObject(texture)
								bTexture = self.document.texturesLibrary.FindObject(texture, True)
								if not bTexture is None:
									bMat.setTexture(0, bTexture, Blender.Texture.TexCo.UV)

					bMat.setSpec(0)

				if isinstance(shader, collada.DaeFxShadeBlinn) or isinstance(shader, collada.DaeFxShadePhong):
					if not isinstance(shader, collada.DaeFxShadePhong):
						bMat.setSpecShader(Blender.Material.Shaders.SPEC_BLINN)
						if shader.indexOfRefraction:
							shader.indexOfRefraction.float
							bMat.setRefracIndex(shader.indexOfRefraction.float)
					else:
						bMat.setSpecShader(Blender.Material.Shaders.SPEC_PHONG)
					if shader.specular:
						if not (shader.specular.color is None): #it's a color and not a texture
							specColor = shader.specular.color.rgba
							bMat.setSpecCol(specColor[0], specColor[1], specColor[2])
					bMat.setSpec(1)
					if shader.shininess:
						bMat.setHardness(int(shader.shininess.float) * 4)

		return bMat

	def GenerateShader(self, bMaterial, updateShader):
		shader = updateShader;
		previousDiffuse = None;

		if shader != None:
			try:
				previousDiffuse = shader.diffuse;
			except:
				pass

		if bMaterial.getSpec() > 0.0:
			if bMaterial.getSpecShader() == Blender.Material.Shaders.SPEC_BLINN:
				shader = collada.DaeFxShadeBlinn()
				shader.AddValue(collada.DaeFxSyntax.INDEXOFREFRACTION, bMaterial.getRefracIndex())
			else:
				shader = collada.DaeFxShadePhong()
			shader.AddValue(collada.DaeFxSyntax.SPECULAR, [col * bMaterial.getSpec() for col in bMaterial.getSpecCol()]+[1])
			shader.AddValue(collada.DaeFxSyntax.SHININESS, bMaterial.getHardness() * 0.25)
		else:
			shader = collada.DaeFxShadeLambert()

		shader.AddValue(collada.DaeFxSyntax.DIFFUSE,bMaterial.getRGBCol()+[1])
		shader.AddValue(collada.DaeFxSyntax.TRANSPARENCY, 1 - bMaterial.alpha)
		shader.AddValue(collada.DaeFxSyntax.TRANSPARENT, [1,1,1,1])
		mainColor = bMaterial.getRGBCol();
		white = [1.0,1.0,1.0];

		shader.AddValue(collada.DaeFxSyntax.EMISSION, [col * bMaterial.getEmit() for col in white] + [1])
		shader.AddValue(collada.DaeFxSyntax.AMBIENT, [col * bMaterial.getAmb() for col in mainColor] + [1])
		shader.AddValue(collada.DaeFxSyntax.REFLECTIVE, bMaterial.getMirCol() + [1])
		shader.AddValue(collada.DaeFxSyntax.REFLECTIVITY, bMaterial.getRayMirr())

		if previousDiffuse != None:
			shader.diffuse = previousDiffuse;

		return shader;

	def SaveToDae(self, bMaterial):
		global useRelativePaths, filename
		daeMaterial = collada.DaeFxMaterial()
		daeMaterial.id = daeMaterial.name = self.document.CreateID(bMaterial.name, '-Material')

		instance = collada.DaeFxEffectInstance()
		daeEffect = self.document.colladaDocument.effectsLibrary.FindObject(bMaterial.name+'-fx')
		meshNode = MeshNode(self.document)
		if daeEffect is None:
			daeEffect = collada.DaeFxEffect()
			daeEffect.id = daeEffect.name = self.document.CreateID(bMaterial.name , '-fx')

			# Check if a texture is used for color
			textures = bMaterial.getTextures()
			for mTex in textures:
				# Check if this texture is mapped to Color
				if not mTex is None and mTex.mapto == Blender.Texture.MapTo.COL and mTex.tex.image != None:
					texture = mTex.tex
					textureNode = TextureNode(self.document);
					textureNode.AddImageTexture(daeEffect, texture.image);

			shader = self.GenerateShader(bMaterial, daeEffect.profileCommon.technique.shader);
			daeEffect.AddShader(shader)

			self.document.colladaDocument.effectsLibrary.AddItem(daeEffect)
		instance.object = daeEffect

		daeMaterial.iEffects.append(instance)

		self.document.colladaDocument.materialsLibrary.AddItem(daeMaterial)
		return daeMaterial

class CameraNode(object):
	def __init__(self,document):
		self.document = document

	def LoadFromDae(self, daeCamera):
		camID = daeCamera.id
		camName = daeCamera.name
		camType = 'persp'
		clipStart = daeCamera.optics.techniqueCommon.znear
		clipEnd = daeCamera.optics.techniqueCommon.zfar

		if daeCamera.optics.techniqueCommon.GetType() == collada.DaeSyntax.ORTHOGRAPHIC:
			camType = 'ortho'

		camera = Blender.Camera.New(camType,camID)
		camera.clipStart = clipStart
		camera.clipEnd = clipEnd
		return camera


	def SaveToDae(self, bCamera):
		daeCamera = collada.DaeCamera()
		daeCamera.id = daeCamera.name = self.document.CreateID(bCamera.name,'-Camera')
		daeOptics = collada.DaeOptics()
		daeTechniqueCommon = None
		if bCamera.type == 1: # orthographic
			daeTechniqueCommon = collada.DaeOptics.DaeOrthoGraphic()
		else: # perspective
			daeTechniqueCommon = collada.DaeOptics.DaePerspective()
			lens = bCamera.getLens( )
			daeTechniqueCommon.yfov = 2 * ( math.atan( 16.0 / lens ) ) * radianToAngle

		daeTechniqueCommon.znear = bCamera.clipStart
		daeTechniqueCommon.zfar = bCamera.clipEnd

		daeOptics.techniqueCommon = daeTechniqueCommon
		daeCamera.optics = daeOptics

		self.document.colladaDocument.camerasLibrary.AddItem(daeCamera)
		return daeCamera

class LampNode(object):
	def __init__(self,document):
		self.document = document

	def LoadFromDae(self, daeLight):

		lampID = daeLight.id
		lampName = daeLight.name

		# Create a new lampObject
		lamp = Blender.Lamp.New('Sun',lampID)

		if daeLight.techniqueCommon.GetType() == collada.DaeSyntax.DIRECTIONAL:
			lamp.type = Blender.Lamp.Types.Sun
		elif daeLight.techniqueCommon.GetType() == collada.DaeSyntax.POINT:
			lamp.type = Blender.Lamp.Types.Lamp
			# Get the attenuation
			constAtt = daeLight.techniqueCommon.constantAttenuation
			linAtt = daeLight.techniqueCommon.linearAttenuation
			# set the attenuation
			lamp.energy = 1-constAtt
			if linAtt > 0.0:
				lamp.dist = (lamp.energy/2)/ linAtt
			else:
				lamp.dist = 5000.0
		elif daeLight.techniqueCommon.GetType() == collada.DaeSyntax.SPOT:
			lamp.type = Blender.Lamp.Types.Spot
			# Get the attenuation
			constAtt = daeLight.techniqueCommon.constantAttenuation
			linAtt = daeLight.techniqueCommon.linearAttenuation
			# set the attenuation
			lamp.energy = 1-constAtt
			if linAtt > 0.0:
				lamp.dist = (0.5 - constAtt)/ linAtt
			else:
				lamp.dist = 5000.0
			lamp.spotSize = daeLight.techniqueCommon.falloffAngle
			lamp.spotBlend = daeLight.techniqueCommon.falloffExponent
		elif daeLight.techniqueCommon.GetType() == collada.DaeSyntax.AMBIENT:
			lamp.type = Blender.Lamp.Types.Hemi


		# Set the color
		lamp.col = daeLight.techniqueCommon.color

		return lamp

	def SaveToDae(self, bLamp):
		daeLight = collada.DaeLight()
		daeLight.id = daeLight.name = self.document.CreateID(bLamp.name,'-Light')

		daeTechniqueCommon = None
		if bLamp.type == Blender.Lamp.Types.Hemi: # Ambient
			daeTechniqueCommon = collada.DaeLight.DaeAmbient()
		elif bLamp.type == Blender.Lamp.Types.Lamp: # Point light
			daeTechniqueCommon = collada.DaeLight.DaePoint()
		elif bLamp.type == Blender.Lamp.Types.Spot: # Spot
			daeTechniqueCommon = collada.DaeLight.DaeSpot()
			daeTechniqueCommon.constantAttenuation = 1-bLamp.energy
			daeTechniqueCommon.linearAttenuation = (0.5 - daeTechniqueCommon.constantAttenuation)/bLamp.dist
			# Export the falloff Angle.
			daeTechniqueCommon.falloffAngle = bLamp.getSpotSize()
		elif bLamp.type == Blender.Lamp.Types.Sun: # Directional
			daeTechniqueCommon = collada.DaeLight.DaeDirectional()
		else: # area
			daeTechniqueCommon = collada.DaeOptics.TechniqueCommon()

		daeTechniqueCommon.color = bLamp.col
		daeLight.techniqueCommon = daeTechniqueCommon

		self.document.colladaDocument.lightsLibrary.AddItem(daeLight)
		return daeLight

class Library(object):
	def __init__(self, document):
		self.objects = dict()
		self.document = document
		self.daeLibrary = None

	def SetDaeLibrary(self, daeLibrary):
		self.daeLibrary = daeLibrary

	def FindObject(self, daeInstance, fromDae, bObject = None):
		for k in self.objects:

			if 'url' in dir(daeInstance) and k == daeInstance.url:
				return self.objects[k][0]
			elif 'target' in dir(daeInstance) and k == daeInstance.target:
				return self.objects[k][0]
			elif isinstance(daeInstance, str):
				return self.objects[k][0]

		if fromDae:
			# dataObject not in library, so add it
			return self.LoadFromDae(daeInstance, bObject)
		else:
			return self.SaveToDae(daeIntance)

	def FindObjectTotal(self, daeInstance):
		for k in self.objects:
			if 'url' in dir(daeInstance) and k == daeInstance.url:
				return self.objects[k]
			elif 'target' in dir(daeInstance) and k == daeInstance.target:
				return self.objects[k]
			elif isinstance(daeInstance, str):
				return self.objects[k]
		return None

	def FindObjectEx(self, bObject):
		for k in self.objects:
			if k == id:
				return self.objects[k][0]

		return self.SaveToDae(bObject)


	def LoadFromDae(self, daeInstance):
		Debug.Debug('Library: Please override this method','WARNING')

	def SaveToDae(self, bScene):
		Debug.Debug('Library: Please override this method','WARNING')

class ScenesLibrary(Library):

	def LoadFromDae(self, daeInstance, bObject):
		daeVisualScene = self.daeLibrary.FindObject(daeInstance.url)
		# TODO: Scene: implement multiple scenes
		return None

	def SaveToDae(self, id):
		pass
		#print bScene

class CamerasLibrary(Library):

	def LoadFromDae(self, daeInstance, bObject):
		daeCamera = self.daeLibrary.FindObject(daeInstance.url)
		if daeCamera is None:
			Debug.Debug('CamerasLibrary: Object with this ID does not exist','ERROR')
			return

		camID = daeCamera.id
		camName = daeCamera.name

		cameraNode = CameraNode(self.document)
		camera = cameraNode.LoadFromDae(daeCamera)

		self.objects[camID] = [camera,camera.name]
		return camera

	def SaveToDae(self, id):
		pass

class LampsLibrary(Library):

	def LoadFromDae(self, daeInstance, bObject):
		daeLight = self.daeLibrary.FindObject(daeInstance.url)
		if daeLight is None:
			Debug.Debug('LightsLibrary: Object with this ID does not exist','ERROR')
			return
		lampID = daeLight.id
		lampName = daeLight.name

		lampNode = LampNode(self.document)
		lamp = lampNode.LoadFromDae(daeLight)

		self.objects[lampID] = [lamp,lamp.name]
		return lamp

	def SaveToDae(self, id):
		pass

class MeshLibrary(Library):

	def LoadFromDae(self, daeInstance, bObject):
		daeGeometry = None
		if isinstance(daeInstance, collada.DaeInstance):
			daeGeometry = self.daeLibrary.FindObject(daeInstance.url)
		else:
			##print daeInstance
			daeGeometry = self.daeLibrary.FindObject(daeInstance)
		if daeGeometry is None:
			Debug.Debug('MeshLibrary: Object with this ID does not exist: %s'%(daeInstance.url),'ERROR')
			return
		meshID = daeGeometry.id
		meshName = daeGeometry.name

		meshNode = MeshNode(self.document)

		# Get the materials ( only get the first one right now)
		bMaterials = daeInstance.bindMaterials
		meshNode.materials = dict()
		if bMaterials:
			for bMaterial in bMaterials:
				for iMaterial in bMaterial.techniqueCommon.iMaterials:
					Material = self.document.materialsLibrary.FindObject(iMaterial,True)
					meshNode.materials[iMaterial.symbol] = Material

		bMesh = meshNode.LoadFromDae(daeGeometry)

		# Add this mesh in this library, under it's real name
		self.objects[meshID] = [bMesh,bMesh.name, meshNode]
		return bMesh

	def SaveToDae(self, id):
		pass

class MaterialsLibrary(Library):

	def LoadFromDae(self, daeInstance, bObject):
		daeMaterial = self.daeLibrary.FindObject(daeInstance.target)
		if daeMaterial is None:
			Debug.Debug('MaterialLibrary: Object with this TARGET:%s does not exist'%(daeInstance.target),'ERROR')
			return
		materialID = daeMaterial.id
		materialName = daeMaterial.name

		materialNode = MaterialNode(self.document)

		bMaterial = materialNode.LoadFromDae(daeMaterial)

		# Add this mesh in this library, under it's real name
		self.objects[materialID] = [bMaterial,bMaterial.name]
		return bMaterial

	def SaveToDae(self, id):
		pass

class TexturesLibrary(Library):

	def LoadFromDae(self, daeImage, bObject):
		if daeImage is None:
			Debug.Debug('TexturesLibrary: Object with this TARGET:%s does not exist'%(daeImage),'ERROR')
			return
		imageID = daeImage.id
		imageName = daeImage.name

		textureNode = TextureNode(self.document)
		bTexture = textureNode.LoadFromDae(daeImage)
		bTexture.setType('Image')

		# Add this texture in this library, under it's real name
		self.objects[imageID] = [bTexture,bTexture.name]
		return bTexture

	def SaveToDae(self, id):
		pass

class AnimationsLibrary(Library):

	def LoadFromDae(self, animationName, bObject):
		daeAnimation = self.daeLibrary.FindObject(animationName)
		if animation is None:
			return;
		animationID = animation.id
		animationName = animation.name

		animation = Animation(self.document)
		animation.LoadFromDae(daeAnimation)
		##self.objects[animationID] = [animation, animation.name]
		return animation

	def GetDaeAnimations(self, daeNodeId):
		daeAnimations = []
		for daeAnimation in self.daeLibrary.items:
			for channel in daeAnimation.channels:
				ta = channel.target.split("/", 1)
				##print daeNodeId, ta
				if ta[0] == daeNodeId:
					daeAnimations.append(daeAnimation)
		return daeAnimations

class ControllersLibrary(Library):

	def LoadFromDae(self, daeInstance, bObject):
		daeController = self.daeLibrary.FindObject(daeInstance.url)
		if daeController is None:
			Debug.Debug('ControllersLibrary: Object with this TARGET:%s does not exist'%(daeInstance.target),'ERROR')
			return
		controllerID = daeController.id
		controllerName = daeController.name

		controller = Controller(self.document)
		bMesh = controller.LoadFromDae(daeController, daeInstance, bObject)

		# Add this mesh in this library, under it's real name
		self.objects[controllerID] = [bMesh, bMesh.name]

		return bMesh