# --------------------------------------------------------------------------
# Illusoft Collada 1.4 plugin for Blender
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Illusoft - colladablender@illusoft.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 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
		__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 = ''
		if self.isImporter:
			self.__Import(fileName)
		else:
			self.__Export(fileName)
	
	def __Import(self,fileName=''):
		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
		
		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 "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()
		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:
			ca = channel.target.split("/",1)
			if ca[0] == daeNode.id:		
				for s in daeAnimation.samplers:
					if s.id == channel.source[1:]:
						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
			
			if not hasJointChilds:
				
				# 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.
				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):
				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:
					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
