# --------------------------------------------------------------------------
# Illusoft Collada 1.4 plugin for Blender
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: Illusoft - colladablender@illusoft.com
#    - 2008.08: multiple bugfixes by migius (AKA Remigiusz Fiedler)
#    - 2009.05: bugfixes by jan (AKA Jan Diederich)
#    - 2009.08: bugfixed by nico (AKA Nicolai Wojke, Labor Bilderkennen Uni-Koblenz)
#
# 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 *****
# --------------------------------------------------------------------------

# History
# 2009.08.22 by nico:
# - Fixed a bug where visual scene nodes containing instances of nodes in the nodes library, 
#   which themselves instantiate geometry in the geometry library, where not imported
#   correctly (only the node instantiation was created, not the geometry)
# - Fixed a bug where nodes in the nodes library that have children instantiating other
#   nodes in the nodes library where not resolved properly. Added a post-library-creation
#   phase where DaeInstance object references are updated after the entire library is created
# - Changed nodes library syntax from 'library_NODES' to 'library_nodes'
# 2009.05.17 by jan:
# - More information for the user if an error happened (wrong/missing parenting).
# - Added a progress bar for export (bar for import already exists). 
# 2009.05.11 by jan:
# - Perfected the id renaming to fulfill at 100.0% the COLLADA standard for allowed UTF-8 
#	chars. The new renaming method is also much faster then the old one (benchmarked with
#	Python 2.5).
# - Fixed the skeleton/joint controller!
#	(Corrected the referencing of the 
#	"<skin><source><technique_common>,<accessor source="...">"
#	attribute. It pointed to its <source> node, and not the array in <source>.) 
# 2009.04.16 by jan:
# - Added the possibility to export models with modifiers (mirrors, transformers, etc.).
# - Added helpful messages for users in case something goes wrong, so they know how and
#	where to fix their model.
# - The patch from 2008.08.31, implementing the patch from Dmitri was incomplete.
#	The joints were renamed (replace('.','_')), but not the vertex group names!
# 2008.09.20 by migius:
# - bugfix meshes with more than 16 materials: material index bigger than 15 replaced with 15.
# 2008.08.31 by migius:
# - added support for import IPOs interpolation type: LINEAR,BEZIER
# - include patch jointVertexWeight from Dmitri: http://projects.blender.org/tracker/index.php?func=detail&aid=17427
# - non-armature-animation export/import correted
# - still buggy: armatures-position and armature-animation export&import
# 2008.08.04 by migius:
# - bugfix/refactor localTransformMatrix usage in hierarchies:
#   it preserves local orientation for each child, so imported IPOs are correct working
# 2008.05.08 by migius: modif. for debug mode

from cutils import *
import collada
import Blender
from Blender.Mathutils import *
import math
import datetime
from helperObjects import *

import BPyMesh
import BPyObject

debprn = 0 #--- print debug "print 'deb: ..."
dmitri = 0 #switch for testing patch from Dmitri

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, \
				_applyModifiers):
		
		global __version__, debugMode, usePhysics, useTriangles, usePolygons, \
		bakeMatrices, exportSelection, createNewScene, clearScene, lookAt, \
		replaceNames, exportPhysics, exportCurrentScene, useRelativePaths, \
		useUV, sampleAnimation, onlyMainScene, applyModifiers
		
		#if debprn: print 'deb:class_Translator isImporter=', isImporter #deb---------
		__version__ = version
		debugMode = debugM
		usePhysics = None
		useTriangles = _useTriangles
		usePolygons = _usePolygons
		bakeMatrices = _bakeMatrices
		exportSelection = _exportSelection
		createNewScene = _createNewScene
		clearScene = _clearScene
		lookAt = _lookAt
		exportPhysics = _exportPhysics
		usePhysics = _exportPhysics
		exportCurrentScene = _exportCurrentScene
		useRelativePaths = _exportRelativePaths
		useUV = _useUV
		sampleAnimation = _sampleAnimation
		onlyMainScene= _onlyMainScene
		applyModifiers= _applyModifiers

		replaceNames = clearScene

		self.isImporter = isImporter
		self.fileName = ''
		#if debprn: print 'deb:class_Translator fileName=', fileName #deb---------
		if self.isImporter:
			self.__Import(fileName)
		else:
			self.__Export(fileName)

	def __Import(self,fileName=''):
		#if debprn: print 'deb:translator__Import fileName=', fileName #deb---------
		documentTranslator = DocumentTranslator(fileName)
		documentTranslator.Import(fileName)

	def __Export(self,filename=''):
		documentTranslator = DocumentTranslator(filename)
		documentTranslator.Export(filename)


class DocumentTranslator(object):
	isImport = None
	ids = []
	sceneGraph = None

	# Keep track of the layers on import
	layers = None

	cameraLibrary = None
##	  geometryLibrary = None
	controllersLibrary = None
	animationsLibrary = None
##	  materialLibrary = None
	texturesLibrary = None
	lampsLibrary = None
	colladaDocument = None
	scenesLibrary = None
	fps = 25

	def __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 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 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
		#if debprn: print 'deb:DocumentTranslator_Import fileName', fileName #deb---------
		self.filename = fileName
		self.filePath = Blender.sys.dirname(self.filename) + Blender.sys.sep
		self.isImport = True
		Blender.Window.EditMode(0)
		Blender.Window.DrawProgressBar(0.0, 'Starting Import')

		# Keep track of the 20 layers
		self.layers = [None for x in range(20)]

		if createNewScene:
			self.currentBScene = Blender.Scene.New('Scene')
			self.currentBScene.makeCurrent()
		else:
			self.currentBScene = Blender.Scene.GetCurrent()

		# Create a new Collada document
		Blender.Window.DrawProgressBar(0.1, 'Get Collada Document')
		self.colladaDocument = collada.DaeDocument(debugMode)

		# Setup the libraries
		self.camerasLibrary.SetDaeLibrary(self.colladaDocument.camerasLibrary)
		self.lampsLibrary.SetDaeLibrary(self.colladaDocument.lightsLibrary)
		self.texturesLibrary.SetDaeLibrary(self.colladaDocument.imagesLibrary)
		self.materialsLibrary.SetDaeLibrary(self.colladaDocument.materialsLibrary)
		self.meshLibrary.SetDaeLibrary(self.colladaDocument.geometriesLibrary)
		self.animationsLibrary.SetDaeLibrary(self.colladaDocument.animationsLibrary)
		self.controllersLibrary.SetDaeLibrary(self.colladaDocument.controllersLibrary)

		# Parse the COLLADA file
		self.colladaDocument.LoadDocumentFromFile(fileName)

		self.axiss = ["X", "Y", "Z"]
		if self.colladaDocument.asset.upAxis == collada.DaeSyntax.Y_UP:
			self.tMatOLD[0][0] = 0
			self.tMatOLD[1][1] = 0
			self.tMatOLD[2][2] = 0
			self.tMatOLD[0][1] = 1
			self.tMatOLD[1][2] = 1
			self.tMatOLD[2][0] = 1
			self.axiss = ["Y", "Z", "X"]

		if self.colladaDocument.asset.upAxis == collada.DaeSyntax.Y_UP:
			self.axisTransformMatrix = Matrix(self._yUpMatrix)
			self.axiss = ["Y", "Z", "X"]

		self.inverseAxisTransformMatrix = Matrix(self.axisTransformMatrix).invert()

		self.progressStep = self.progressField/(self.colladaDocument.GetItemCount()+1)

		# Get the animation info
		#TODO: for what is this good? (migius)
		if 0:	animations = AnimationInfo.CreateAnimations(self.animationsLibrary, self.fps, self.axiss)

		# Read the COLLADA structure 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)
		Blender.Window.DrawProgressBar(0.0, 'Starting Export')

		# 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'
		daeAsset.unit.name = 'meter'
		daeAsset.unit.meter = '1.00'
		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()

		#---------- Copied from export OBJ -----------------------------
		# Get Container Mesh
		# Remember: is this doesn't work, due to general problems, not especially
		# COLLADA related, OBJ export fails also too! Keep this in sync, but remember
		# that OBJ then still may use "NMesh", while this already uses "Mesh".
		temp_mesh_name = '~tmp-mesh'
		
		# Get the container mesh. - used for applying modifiers and non mesh objects.
		self.containerMesh = temp_mesh = None
		for temp_mesh in Blender.Mesh.Get():
			if temp_mesh.name.startswith(temp_mesh_name):
				if not temp_mesh.users:
					self.containerMesh = temp_mesh
		if not self.containerMesh:
			self.containerMesh = Blender.Mesh.New(temp_mesh_name)
		#------------ [end] Copied from export OBJ ------------------------
		
		# Loop through all scenes
		sceneCount = len(Blender.Scene.Get())
		self.progressStep = self.progressField / sceneCount
		Blender.Window.DrawProgressBar(0.1, \
							'Exporting ' + str(sceneCount) + ' scene(s)')
		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.ProgressExport()


		self.colladaDocument.scene = daeScene
		
		Blender.Window.DrawProgressBar(0.98, 'Saving file to disk...')

		self.colladaDocument.SaveDocumentToFile(fileName)
		
		Blender.Window.DrawProgressBar(1.0, 'Export finished.')

	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)
		
	def ProgressExport(self):
		self.progressPartCount = 0.0
		self.progressCount += self.progressStep
		Blender.Window.DrawProgressBar(self.progressCount, 'Exporting Blender Scenes...')

	def ProgressPartExport(self, val, text):
		self.progressPartCount += val
		Blender.Window.DrawProgressBar(self.progressCount+self.progressPartCount, 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.
			sceneObjects = bScene.objects 
			if len(sceneObjects) > 0:
				progressStep = self.document.progressStep / len(sceneObjects) 
				for node in sceneObjects:
					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]
							
					self.document.ProgressPartExport(progressStep, "Saving node(s)...")

		# 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,bScene)
			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):
	# TODO: class Controller: armature Pose Mode need refactoring
	def __init__(self, document):
		if debprn: print 'deb:class Controller__init__ ---RUN---' #----------
		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):
		if debprn: print 'deb:class Controller_PositionBone() ---RUN---' #----------
		# Get the boneInfo for this bone.
		boneInfo = armature.boneInfos[boneName]
		# Get the jointName for this bone.
		jointName = boneInfo.GetJointName()

		##		headJointName = boneInfo.name
##		tailJointName =

##		print "deb: bone:" , boneName, "- headJoint:", jointName, "- tailJoint:", boneInfo.GetTailName(), "- isEnd:", boneInfo.IsEnd()

		# Get the BindMatrix for the head of this bone.
		headMatrix = bindMatrices[jointName]
		# Get the name of the tail joint.
		tailJointName = boneInfo.GetTailName() ##armature.boneInfos[boneName].tailJointName
		# If there is a tail joint, get the BindMatrix for that joint.

		tailMatrix = bindMatrices[tailJointName]
##		PrintTransforms(headMatrix, boneName)
##		if not boneInfo.IsEnd():
##			tailMatrix = bindMatrices[tailJointName]
		# Get the location of the armature Object.
		armatureLocation = armature.GetLocation()
		# Create a vector at [0,0,0,1]
		nullVec = Vector().resize4D()

		# Calculate the position of the head
		headVec = self.document.CalcVector(headMatrix * nullVec).resize4D() ##- armatureLocation
		headVec = Matrix(armature.GetTransformation()).transpose().invert() * headVec
		# Set the default value for the tail.
		tailVec = headVec + Vector(0,0,1,1)
		# If this bone has a Tail joint, calculate the position of the tail.
		if not boneInfo.IsEnd():
			tailVec = self.document.CalcVector(tailMatrix * nullVec).resize4D() ##- armatureLocation
			tailVec = Matrix(armature.GetTransformation()).transpose().invert() * tailVec
		else:
			parentBone = boneInfo.parent.GetBone()
			tailVec =  2 * headVec - Vector(parentBone.head).resize4D()
##			pass#PrintTransforms(headMatrix, jointName)
			##tailVec = (headMatrix * headVec)-armatureLocation
			##print jointName, headVec, headMatrix
			##print headVec, boneInfo.GetBone().tail - boneInfo.GetBone().head
			##tailVec = headVec + (boneInfo.GetBone().tail - boneInfo.GetBone().head).resize4D()
##			parentBoneInfo = boneInfo.parent
##			print "parentBoneInfo:",parentBoneInfo.name
##			if not parentBoneInfo is None:
##				parentBone = parentBoneInfo.GetBone()
##				tailVec = 2 * parentBone.tail - parentBone.head
##			else:
##				tailVec = Vector(0,0,1,1)

##		if boneInfo.IsRoot():
##			headVec -= Vector(0,0,-0.1,1)

		# Set the head and tail location.
##		if not boneInfo.IsEnd():
			##PrintTransforms(self.document.CalcMatrix(tailMatrix) * Matrix(armature.GetTransformation()).invert(), tailJointName)
##			PrintTransforms(self.document.CalcMatrix(tailMatrix), tailJointName)
			##boneInfo.GetBone().matrix = self.document.CalcMatrix(tailMatrix).transpose() * Matrix(armature.GetTransformation()).invert()
			##if boneName == "root" or boneName == "pelvis" or boneName == "spine":
##			print boneName
##			print boneInfo.GetHead()
##			print boneInfo.GetTail()
##			print headVec
##			print tailVec
##			print
		boneInfo.SetHead(headVec)
		boneInfo.SetTail(tailVec)



		##PrintTransforms(TranslationMatrix(armatureLocation).transpose(),"armature")
		##PrintTransforms(self.document.CalcMatrix(headMatrix)*
##		boneInfo.GetBone().matrix = self.document.CalcMatrix(headMatrix).transpose() ##* TranslationMatrix(armatureLocation).invert()

		# Do the same for each child.
		for childBoneName in boneInfo.childs:
			self.PositionBone(childBoneName, armature, bindMatrices)
		if debprn: print 'deb:class Controller_PositionBone() ---END---' #----------


	def PoseBone(self, boneName, armature, bindMatrices, bPose, parentBindI = Matrix()):
		if debprn: print 'deb:class Controller_PoseBone() ---RUN---' #----------
		#if debprn: print 'deb:class Controller_PoseBone() bindMatrices=', bindMatrices #----------
		boneInfo = armature.boneInfos[boneName]
		#if debprn: print 'deb:class Controller_PoseBone() boneInfo     =', boneInfo #----------
		#if debprn: print 'deb:class Controller_PoseBone() dir(boneInfo)=', dir(boneInfo) #----------
		bBone = boneInfo.GetBone()
		#if debprn: print 'deb:class Controller_PoseBone()         bBone=', bBone #----------
		jointName = boneInfo.GetJointName()
		#jointName = u'joint1'
		#if debprn: print 'deb:class Controller_PoseBone()     jointName=', jointName #----------
		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)
		if debprn: print 'deb:class Controller_PoseBone() ---end---' #----------


	def AnimateBone(self, boneName, armature, bPose, action):
		if debprn: print 'deb:class Controller_AnimateBone() ---RUN---' #----------
		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)
		if debprn: print 'deb:class Controller_AnimateBone() ---end---' #----------


	def BindMesh(self):
		if debprn: print 'deb:class Controller_BindMesh() ---RUN---' #----------
		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
			#if debprn: print 'deb: jointList=', jointList #---------------
			#if debprn: print 'deb: jointList[0]=', jointList[0], type(jointList[0] #---------------
			# 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)
		if debprn: print 'deb:class Controller_BindMesh() ---end---' #----------

	def LoadFromDae(self, daeController, daeControllerInstance, bObject):
		if debprn: print 'deb:class Controller_LoadFromDae() ---RUN---' #----------
		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
		if debprn: print 'deb:class Controller_LoadFromDae() ---end---' #----------

	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]
		if (bArmatureObject is None):
			HandleError(ERROR_MESH_ARMATURE_PARENT, meshName)
		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 = jointSourceArray.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 = weightSourceArray.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 = poseSourceArray.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()
			try:
				vws = bMesh.getVertsFromGroup(vertexGroupName,True)
				for vw in vws:
					vwsdict[vw[0]] = vw[1]
			except:
				print("Vertex group '%s' couldn't be handled.\n" \
					"Maybe the group is empty.\n" % vertexGroupName)

		# 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
				# Jan: If we rename the bones/joints/armatures, we must rename the
				#		(corresponding) vertex groups also.
				adjustedName = AdjustName(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)
				if 0:
					bindMatrix = Matrix(bArmature.bones[vertexGroupName].matrix['ARMATURESPACE']).transpose()
					bindMatrix = Matrix(bMeshObject.matrix).transpose() * bindMatrix
				elif dmitri:	#by dmitri: Use ARAMATURE matrix for a global position/orientation
					bindMatrix = Matrix(bArmature.bones[vertexGroupName].matrix["ARMATURESPACE"]).resize4x4().transpose()
					bindMatrix = Matrix(bArmatureObject.getMatrix('localspace')).transpose() * bindMatrix
				else:
					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(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
			vertTotalWeight = 0.0
			jointVertexWeight = dict()

			# Jan: Keep this bone/joints renaming always in snyc with the vertex group
			# renaming!

			#count up the number of joints to get an equal weight
			for vGroup in vGroups:
				if vert.index in vGroups[vGroup]:
					adjustedName = "" + vGroup
					adjustedName = AdjustName(adjustedName)
					found = False
					weight = 0.0
					try :
						jointSourceArray.data.index(adjustedName)
						vi = vGroups[vGroup]
						weight = vi[vert.index]
						found = True
					except:
						found = False
					if found :
						jointCount += 1
						vertJointCount[vert.index] = jointCount
						jointVertexWeight[adjustedName] = weight
						vertTotalWeight+= weight

			#now we know how many, so make an even weight:
			# !!! Update cast3d !!! - even weight distribution only used if vertex total weight == 0
			# otherwise used each joint weight normalised by total weight
			for vGroup in vGroups:
				if vert.index in vGroups[vGroup]:
					adjustedName = "" + vGroup
					adjustedName = AdjustName(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)
						if vertTotalWeight != 0.0:
							jw = jointVertexWeight[adjustedName]
							vw = jw / vertTotalWeight
							weightSourceArray.data.append(vw)
							#print "Joint ", adjustedName, " weight=", jw, "Total weight=",vertTotalWeight, " Final weight=", vw
						else:
							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):
		if debprn: print 'deb:class Animation_LoadFromDae RUN-------:' #------
		# Loop trough all channels
		for channel in daeAnimation.channels:
			if debprn: print 'deb: channel.target=',channel.target #------
			if debprn: print 'deb:     daeNode.id=',daeNode.id #------
			ca = channel.target.split("/",1)
			#if it targets to this daeNode
			if ca[0] == daeNode.id:
				for s in daeAnimation.samplers:
					if debprn: print 'deb:           s.id=',s.id #------
					#if debprn: print 'deb: channel.source=',channel.source #------
#org				if s.id == channel.source[1:]:
					if s.id == channel.source:
						if debprn: print 'deb: BINGO ---> channel.source=s.id' #------
						sampler = s

				if s!=None: #TODO: Animation_bObject sometimes 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
						interpolations = sampler.GetInput("INTERPOLATION")
						interpolationsSource = daeAnimation.GetSource(interpolations.source)
						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 and 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"
								elif type[0] == "rotate":
									cname = "Rot"
								cname += self.document.axiss[self.document.orgAxiss.index(axis)]
								curve = ipo.addCurve(cname)
								curve.interpolation = 1 #LINEAR
								for time in times:
									value = outputSource.source.data[times.index(time) * accessorStride + axiss.index(axis)]
									if type[0] == "rotate":
										value /= 10
#old								curve.addBezier((time,value))
									inter = interpolationsSource.source.data[times.index(time) * accessorStride + axiss.index(axis)]
									if inter=='BEZIER':
										point=Blender.BezTriple.New()
										point.pt=(time, value)
										point.handleTypes=[1,1]
									else: #if inter=='LINEAR': inter=1
										point=(time, value)
									curve.append(point)
								if 1: #TODO: need individual support interpolation type for each point
									#if debprn: print 'deb: dir(curve)=', dir(curve) #--------
									if inter=='LINEAR': inter = 1
									elif inter=='BEZIER': inter = 2
									else: inter = 1
									curve.interpolation = inter
								#if debprn: print 'deb: inter=', inter #--------
								#if debprn: print 'deb: curve.interpolation=', curve.interpolation #--------

	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:
				curName = cur.getName()
				if curName.startswith("Quat"):
					quatKey[curName] = []
					curNameIndex = curName[-1]
					if curNameIndex == 'X':
						for point in cur.bezierPoints:
							quatXList[point.pt[0]] = point.pt[1]
					elif curNameIndex == 'Y':
						for point in cur.bezierPoints:
							quatYList[point.pt[0]] = point.pt[1]
					elif curNameIndex == 'Z':
						for point in cur.bezierPoints:
							quatZList[point.pt[0]] = point.pt[1]
					elif curNameIndex == 'W':
						for point in cur.bezierPoints:
							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 joint is not None:
					if dmitri:
						bindMatrix = Matrix(joint.matrix["ARMATURESPACE"]).resize4x4().transpose()
					else:
						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

					if 1: #migius
						swap = euler.y
						euler.y = - euler.z
						euler.z = swap

					else:
						poseMatrix = Matrix(bParentMatrix).invert() * armMatrix
						poseMatrix.transpose()

						poseEuler = poseMatrix.toEuler()
						euler.x += poseEuler.x
						euler.y += poseEuler.y
						euler.z += poseEuler.z
					#if debprn: print 'deb: getEuler: ', joint.name , poseEuler, euler

				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()
				#interpolation = curve.interpolation
				if debprn: print 'deb: interpolation=', interpolation #--------
				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:
							if dmitri:
								bindMatrix = Matrix(joint.matrix["ARMATURESPACE"]).resize4x4().transpose()
							else:
								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:
			#dimitr: rotation could be full circle, can not use  sum(outputArray.data) != 0:
			if not name.startswith(collada.DaeSyntax.ROTATE) or len(animation) > 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):
		if debprn: print 'deb:class SceneNode_ObjectFromDae ---RUN---' #------------
		global replaceNames, objectList, waitingControllers, armatures
		self.document.Progress()
		self.id = daeNode.id
		self.name = daeNode.name
		self.type = daeNode.type
		if debprn: print 'deb: daeNode.id  =', daeNode.id #------------
		if debprn: print 'deb: daeNode.name=', daeNode.name #------------
		if debprn: print 'deb: daeNode.type=', daeNode.type #------------

		editBone = None
		newObject = None
		dataObject = None
		armature = None
		parentBone = None
		daeInstance = None
		boneName = None
		noninverse = 0

		#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)
		#if debprn: print 'deb: localTransformMatrix:\n' , self.localTransformMatrix #---------
		self.transformMatrix = mat


		if daeNode.IsJoint():#---daeNode is Joint
			if isinstance(self.parentNode, SceneNode):
				self.transformMatrix = self.transformMatrix * self.parentNode.transformMatrix
				#if debprn: print 'deb: transformMatrix:\n' , self.transformMatrix #--------
			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
#old			objectName = self.document.CreateNameForObject(self.id, replaceNames, 'object')
				objectName = self.document.CreateNameForObject(self.name, replaceNames, 'object')
				# Create a unique name for the armature data
				armatureName = self.document.CreateNameForObject(objectName, replaceNames, 'armature')
				# Create a new armature
#old			self.armature = Armature.CreateArmature(objectName, self.id, armatureName, daeNode)
				self.armature = Armature.CreateArmature(objectName, self.name, 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):
#old				parentBoneName = str(self.parentNode.parentNode.id)
					parentBoneName = str(self.parentNode.parentNode.name)

				# Create the name for the new bone
#old			boneName = str(self.parentNode.id)
				boneName = str(self.parentNode.name)

				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

#old		if not hasJointChilds:
			if not hasJointChilds and not self.parentNode==None:

				# 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.
#old				parentBoneName = str(self.parentNode.id)
				parentBoneName = str(self.parentNode.name)
				if debprn: print 'deb: i have parentBoneName=', parentBoneName #-----------
				# Create the name for the new bone
#old			boneName = str(self.id)
				boneName = str(self.name)
				if debprn: print 'deb:  add me boneName=', 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().resize3D()
				if debprn: print 'deb:  armatureLoc=', armatureLoc #----------

				# 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 : #---daeNode is not Joint
			if isinstance(self.parentNode, SceneNode):
				self.transformMatrix *= self.parentNode.localTransformMatrix
				#if debprn: print 'deb: transformMatrix:\n' , self.transformMatrix #--------
			daeInstances = daeNode.GetInstances()
			if debprn: print 'deb: daeInstances:\n' , daeInstances #--------
			isController = False
			newObjects = []
			if len(daeInstances):
				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'))
						newObjects.append(newObject)

					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)
						newObject.link(dataObject)
						newObjects.append(newObject)

					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)
						newObject.link(dataObject)
						isController = True
						newObjects.append(newObject)
						if debprn: print 'deb: M E S H isController -------O O O O O:' #--------

					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)
						newObject.link(dataObject)
						newObjects.append(newObject)
						if debprn: print 'deb: M E S H daeInstance -------ooooooooo:' #--------

					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)
						newObject.link(dataObject)
						newObjects.append(newObject)

					elif isinstance(daeInstance,collada.DaeNodeInstance): # Node
						newObject = Blender.Object.New('Empty',self.document.CreateNameForObject(self.id,replaceNames, 'empty'))
						newObjects.append(newObject)

					elif isinstance(daeInstance,collada.DaeVisualSceneInstance): # Visual Scene
						newObject = Blender.Object.New('Empty',self.document.CreateNameForObject(self.id,replaceNames, 'empty'))
						newObjects.append(newObject)

					else:
						print "???   Loading Unknown Instance:", daeInstance
#old					return

				# If there were multiple instance, create an empty. We add the instances to it later.
				#if not isController or len (daeInstances) > 1:
					#if debprn: print 'deb: PROBLEM >>>>>>> make newObject as Empty cointainer: ' #--------
					#newObject = Blender.Object.New('Empty',self.id)

				if newObjects:
					if len(newObjects)==1:
						newObject = newObjects[0]
						if debprn: print 'deb: >>>>>>>bObject: ' , newObject #--------
						self.bObject = newObject
						self.document.currentBScene.link(newObject)
					else:
						newObject = Blender.Object.New('Empty',self.id)
						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 debprn: print 'deb: >>>>>>>newObjects: ' , newObjects #--------
						for newObjectChild in newObjects:
							self.document.currentBScene.link(newObjectChild)
						newObject.makeParent(newObjects, noninverse , 1)

			else:
				if debprn: print 'deb: no daeInstances ? ? ? ?:' #--------
				newObject = Blender.Object.New('Empty',self.id)
				#newObjects.append(newObject)

			#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

#old	if not self.isJoint and self.armature is None:
#old2	if self.armature is None:

		if 1:	#---Check if the daeNode has some Layer information.
			if len(daeNode.layer):
				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:
			try:
				childSceneNode = SceneNode(self.document,self)
				object = childSceneNode.ObjectFromDae(daeChild)
				if object: childlist.append(object)
			except NameError:
				if debprn: print "a child of node " + daeNode.id + " has no id ? ?"
		for iDaeChild in daeNode.iNodes:
			try:
				childSceneNode = SceneNode(self.document,self)
				object = childSceneNode.ObjectFromDae(iDaeChild.object)
				if object:
					newObject.makeParent([object], noninverse , 1)
					childlist.append(object)
			except NoneType:
				if debprn: print "a child instance of node " + daeNode.id + " has no id ? ?"

		if newObject:
			if not self.isJoint and not self.armature:
				newObject.setMatrix(Matrix().resize4x4())
				newObject.makeParent(childlist, noninverse,1)
				# Set the layers of the new Object.
				newObject.layers = myLayers
				newObject.setMatrix(self.localTransformMatrix)
			elif self.isJoint and self.armature:
				for jointName in waitingControllers:
					armature = Armature.FindArmatureWithJoint(jointName)
					if armature and armature.name == self.armature.name:
						controller = waitingControllers[jointName]
						controller.armatureName = armature.name
						armature.GetBlenderObject().makeParent([controller.bObject], noninverse , 1)
						controller.BindMesh()
						break
			# Check if this node has an animation.
			daeAnimations = self.document.animationsLibrary.GetDaeAnimations(self.id)
			if debprn: print 'deb: O ------- O animation check' #------------
			for daeAnimation in daeAnimations:
				a = Animation(self.document)
				a.LoadFromDae(daeAnimation, daeNode, newObject)
				if debprn: print 'deb: X -------- X an animation is loaded= \n', a #------------

		if debprn: print 'deb:class SceneNode_ObjectFromDae ---end---' #------------
		return newObject

	def SaveSceneToDae(self, bNode, childNodes, daeGlobalPhysicsModel, \
					   daeGlobalPhysicsModelInstance, bScene):
		global bakeMatrices, exportSelection, applyModifiers, debprn
		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:							   
				derivedObjsMatrices = BPyObject.getDerivedObjects(bNode)
				for derivedObject, matrix in derivedObjsMatrices:
					virtualMesh = BPyMesh.getMeshFromObject(derivedObject, \
									self.document.containerMesh, applyModifiers, False, bScene)					
					if debprn:
						print("Virtual mesh: " + str(virtualMesh) )
						# + "; type: " + str(type(virtualMesh)))
					if not virtualMesh:
						# Fallback!
						# Should never happen!
						# (The "mesh=1" param on the getData() method ensures that
						# it gets a "Mesh" instead of a "NMesh".) 
						print("Error while trying to save derived object / apply modifiers. Try saving " \
							  + "more direct, all modifiers will be ignored.")
						daeGeometry = meshNode.SaveToDae(bNode.getData(mesh=1))
					else:
						# Apply original name from untransformed object
						# to transformed object (name is later copied 1:1 to id).
						virtualMesh.name = derivedObject.name
						# _Don't_ apply transformation matrix "matrix"!
						# The transformation will get instead written in the file itself
						# seperately!
						daeGeometry = meshNode.SaveToDae(virtualMesh)
					
			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
					bArmatureObject = bModifier[Blender.Modifier.Settings.OBJECT]
					if (bArmatureObject is None):
						HandleError(ERROR_MESH_ARMATURE_PARENT, meshID)
					bArmature = bArmatureObject.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, bScene)[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]*32
		rbF = bNode.rbFlags
		lastIndex = 0
		# Get the bit flags.
		while rbF > 0:
			val = rbF >> 1
			if val << 1 == rbF:
				##rbFlags.append(0)
				rbFlags[lastIndex] = 0
			else:
				##rbFlags.append(1)
				rbFlags[lastIndex] = 1
			lastIndex += 1
			rbF = val


		daeRigidBody = collada.DaeRigidBody()
		#print "daeNode.id",daeNode.id
		daeRigidBody.id = daeRigidBody.name = daeRigidBody.sid = self.document.CreateID(daeNode.id,'-RigidBody')
		#print "daeRigidBody.sid",daeRigidBody.sid
		daeRigidBodyTechniqueCommon = collada.DaeRigidBody.DaeTechniqueCommon()
		daeRigidBodyTechniqueCommon.dynamic = bool(rbFlags[0])
		if daeRigidBodyTechniqueCommon.dynamic:
				daeRigidBodyTechniqueCommon.mass = bNode.rbMass
		else:
				daeRigidBodyTechniqueCommon.mass = 0 #not dynamic means mass == 0!

		# Check the shape of the rigid body.
		if bNode.rbShapeBoundType == 0 and rbFlags[PhysicsNode.bounds]: # Box
			shape = collada.DaeBoxShape()
			shape.halfExtents = list(bNode.rbHalfExtents)
		elif bNode.rbShapeBoundType == 1  and rbFlags[PhysicsNode.bounds]: # Sphere
			shape = collada.DaeSphereShape()
			shape.radius = bNode.rbRadius
		elif bNode.rbShapeBoundType == 2  and rbFlags[PhysicsNode.bounds]: # Cylinder
			shape = collada.DaeCylinderShape()
			shape.radius = [[bNode.rbRadius],[bNode.rbRadius]]
			shape.height = bNode.rbHalfExtents[2]
		elif bNode.rbShapeBoundType == 3  and rbFlags[PhysicsNode.bounds]: # Cone
			shape = collada.DaeTaperedCylinderShape()
			shape.radius1 = [[bNode.rbRadius],[bNode.rbRadius]]
			shape.radius2 = [0 , 0]
			shape.height = bNode.rbHalfExtents[2]
		else: # Convex hull or # Static Triangle Mesh for static, and # Sphere if dynamic
			if daeRigidBodyTechniqueCommon.dynamic and not rbFlags[PhysicsNode.bounds]:
				shape = collada.DaeSphereShape()
				shape.radius = bNode.rbRadius
			else:
				shape = collada.DaeGeometryShape()
				iGeometry = collada.DaeGeometryInstance()
				if bNode.rbShapeBoundType == 5:
					object = self.document.colladaDocument.geometriesLibrary.FindObject(daeNode.id+'-Convex')
				else:
					object = self.document.colladaDocument.geometriesLibrary.FindObject(meshID)
					if not object.HasOnlyTriangles(): # The geometry contains no triangles
						pass

				if object is None:
					object = collada.DaeGeometry()
					object.id = object.name = self.document.CreateID(daeNode.id,'-ConvexGeom')
					convexMesh = collada.DaeConvexMesh()
					convexMesh.convexHullOf = meshID
					object.data = convexMesh
					self.document.colladaDocument.geometriesLibrary.AddItem(object)
				iGeometry.object = object
				shape.iGeometry = iGeometry

		# Create a physics material.
		daePhysicsMaterial = self.document.colladaDocument.physicsMaterialsLibrary.FindObject(daeNode.id+'-PxMaterial')
		if daePhysicsMaterial is None:
			daePhysicsMaterial = collada.DaePhysicsMaterial()

			physicsMaterials = bNode.getData().getMaterials()
			if (not (physicsMaterials is None)) and len(physicsMaterials) > 0:
				physicsMaterial = physicsMaterials[0]
				if not (physicsMaterial is None):
					daePhysicsMaterial.techniqueCommon.restitution = physicsMaterial.rbRestitution

					# Usually dynamic friction is less than static friction. However, as of Blender 2.42,
					# only a single friction coefficient can be specified. This is used for both
					# static and dynamic friction coefficients.

					daePhysicsMaterial.techniqueCommon.staticFriction = physicsMaterial.rbFriction
					daePhysicsMaterial.techniqueCommon.dynamicFriction = physicsMaterial.rbFriction

			daePhysicsMaterial.id = daePhysicsMaterial.name = self.document.CreateID(daeNode.id, '-PhysicsMaterial')
			self.document.colladaDocument.physicsMaterialsLibrary.AddItem(daePhysicsMaterial)

		# Create a physics material instance.
		daePhysicsMaterialInstance = collada.DaePhysicsMaterialInstance()
		# Set the physics material of this instance
		daePhysicsMaterialInstance.object = daePhysicsMaterial


		# add the shape to the commom technique.
		daeRigidBodyTechniqueCommon.shapes.append(shape)
		# Set the material of the common technique.
		daeRigidBodyTechniqueCommon.iPhysicsMaterial = daePhysicsMaterialInstance
		# Set the common technique of this rigid body.
		daeRigidBody.techniqueCommon = daeRigidBodyTechniqueCommon

		# Add the rigid body to the physics model.
		daeGlobalPhysicsModel.rigidBodies.append(daeRigidBody)
		# Create a new RigidBody instance
		daeRigidBodyInstance = collada.DaeRigidBodyInstance()
		# Set the rigid body of this instance
		daeRigidBodyInstance.body = daeRigidBody
		# Set the node of this instance
		daeRigidBodyInstance.target = daeNode

		# add the rigidbody instance to this physics model instance.
		daeGlobalPhysicsModelInstance.iRigidBodies.append(daeRigidBodyInstance)

		#handle constraints
		for rbconstraint in bNode.constraints:
			if rbconstraint.type == Blender.Constraint.Type.RIGIDBODYJOINT:
				daeRigidConstraint = collada.DaeRigidConstraint()
				daeRigidConstraint.id = daeRigidConstraint.name = daeRigidConstraint.sid = rbconstraint.name

				daeRigidConstraint.attachment = collada.DaeRigidConstraint.DaeAttachment()
				daeRigidConstraint.attachment.rigid_body = daeRigidBody
				daeRigidConstraint.attachment.blenderobject = bNode
				daeRigidConstraint.attachment.pivX = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_PIVX]
				daeRigidConstraint.attachment.pivY = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_PIVY]
				daeRigidConstraint.attachment.pivZ = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_PIVZ]
				daeRigidConstraint.attachment.axX = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_AXX]
				daeRigidConstraint.attachment.axY = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_AXY]
				daeRigidConstraint.attachment.axZ = rbconstraint[Blender.Constraint.Settings.CONSTR_RB_AXZ]

				if not (rbconstraint[Blender.Constraint.Settings.TARGET] is None):
					#find rigidbody that goes with TARGET...
					blendertargetob = rbconstraint[Blender.Constraint.Settings.TARGET]
					targetRbId = blendertargetob.name+'-RigidBody'
					targetrigidbody = daeGlobalPhysicsModel.FindRigidBody(targetRbId)
					if not (targetrigidbody is None):
						daeRigidConstraint.ref_attachment = collada.DaeRigidConstraint.DaeRefAttachment()
						daeRigidConstraint.ref_attachment.rigid_body = targetrigidbody
						daeRigidConstraint.ref_attachment.blenderobject = blendertargetob

						#calculate pivX/pivY/pivZ and axX,axY,axZ for this reference frame
						refObjectWorldMatrix = blendertargetob.matrix
						attachObjectWorldMatrix = bNode.matrix
						euler = Euler(daeRigidConstraint.attachment.axX,daeRigidConstraint.attachment.axY,daeRigidConstraint.attachment.axZ)
						matRot= euler.toMatrix()
						matT1 = TranslationMatrix(Vector(daeRigidConstraint.attachment.pivX,daeRigidConstraint.attachment.pivY,daeRigidConstraint.attachment.pivZ))
						matT = TranslationMatrix(Vector(0,0,0))
						matT[0][0]=matRot[0][0]
						matT[0][1]=matRot[0][1]
						matT[0][2]=matRot[0][2]
						matT[1][0]=matRot[1][0]
						matT[1][1]=matRot[1][1]
						matT[1][2]=matRot[1][2]
						matT[2][0]=matRot[2][0]
						matT[2][1]=matRot[2][1]
						matT[2][2]=matRot[2][2]
						copyMat = Matrix(refObjectWorldMatrix)
						attachLocalMatrix = matT * matT1
						invertedMat = copyMat.invert()
						globalFrameA = attachLocalMatrix * attachObjectWorldMatrix
						refAttachLocalMatrix = globalFrameA * invertedMat
						refPivot = refAttachLocalMatrix.translationPart()
						eulerAngles = refAttachLocalMatrix.toEuler()
						daeRigidConstraint.ref_attachment.pivX = refPivot[0]
						daeRigidConstraint.ref_attachment.pivY = refPivot[1]
						daeRigidConstraint.ref_attachment.pivZ = refPivot[2]
						daeRigidConstraint.ref_attachment.axX = eulerAngles[0]
						daeRigidConstraint.ref_attachment.axY = eulerAngles[1]
						daeRigidConstraint.ref_attachment.axZ = eulerAngles[2]


				#print "constraint type = ",rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE]

				daeRigidConstraintTechniqueCommon = collada.DaeRigidConstraint.DaeTechniqueCommon()

				daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [0,0,0]
				daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [0,0,0]
				daeRigidConstraintTechniqueCommon.limits.angularLimits.min = [0,0,0]
				daeRigidConstraintTechniqueCommon.limits.angularLimits.max = [0,0,0]

				#generic 6 degree-of-freedom joint
				if rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE] == 12:
					daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT0],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT1],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT2]]
					daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT0],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT1],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT2]]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.min = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT3],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT4],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MINLIMIT5]]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.max = [rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT3],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT4],rbconstraint[Blender.Constraint.Settings.CONSTR_RB_MAXLIMIT5]]
				#ball-socket joint
				if rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE] == 1:
					daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.min = ['-INF','-INF','-INF']
					daeRigidConstraintTechniqueCommon.limits.angularLimits.max = ['INF','INF','INF']
				#hinge
				if rbconstraint[Blender.Constraint.Settings.CONSTR_RB_TYPE] == 2:
					daeRigidConstraintTechniqueCommon.limits.linearLimits.min = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.linearLimits.max = [0,0,0]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.min = ['-INF',0,0]
					daeRigidConstraintTechniqueCommon.limits.angularLimits.max = ['INF',0,0]


				#daeRigidConstraintTechniqueCommon.enabled = True
				daeRigidConstraint.techniqueCommon = daeRigidConstraintTechniqueCommon
				daeGlobalPhysicsModel.constraints.append(daeRigidConstraint)

				# Create a new RigidConstraint instance
				daeRigidConstraintInstance = collada.DaeRigidConstraintInstance()
				# Set the rigid body of this instance
				daeRigidConstraintInstance.constraint = daeRigidConstraint

				#add constraint instance
				daeGlobalPhysicsModelInstance.iConstraints.append(daeRigidConstraintInstance)

		return daeRigidBodyInstance

class ArmatureNode(object):
	def __init__(self, document):
		self.document = document

	def SaveToDae(self, bArmature, bArmatureObject, bPose):
		daeNodes = []
		# Get the root bones
		rootBones = []

		for boneName in bArmature.bones.keys():
			bone = bArmature.bones[boneName]
			if not bone.hasParent():
				rootBones.append(bone)

		# Only take the first root and ignore it.
		if len(rootBones) > 0 and not rootBones[0].children is None:
			daeNodes.append(self.BoneToDae(rootBones[0], bPose,Matrix(), bArmatureObject))

			##for childBone in rootBones[0].children:
##				print PrintTransforms(Matrix(bPose.bones[rootBones[0].name].poseMatrix).transpose(),rootBones[0].name)
			##	poseMatrix = Matrix(bPose.bones[rootBones[0].name].poseMatrix).transpose()
			##	poseMatrixRotInv = poseMatrix.rotationPart().invert().resize4x4()
				##poseMatrixNoRot = poseMatrix * poseMatrixRotInv

			##	print rootBones[0]
			##	print Matrix(bArmatureObject.matrix).transpose().invert()
				##daeNodes.append(self.BoneToDae(rootBones[0], bPose, Matrix(bArmatureObject.matrix).transpose().invert(),poseMatrixRotInv, bArmatureObject))

		if len(rootBones) > 1:
			print("Please use only a single root for proper export.\n" \
				"Nr. of root bones: %i.\n" \
				"List of root bones:" % len(rootBones))
			for rootBone in rootBones:
				print("\t%s" % rootBone.__str__())

		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
		if dmitri:
			bindMatrix = Matrix(bBone.matrix["ARMATURESPACE"]).resize4x4().transpose()
		else:
			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()
		#PrintTransforms(mat, "ARMATURESPACE: " + bBone.name)

		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

		if isinstance(daeGeometry.data,collada.DaeMesh): # check if it's a mesh
			# Create a new meshObject
			bMesh2 = Blender.NMesh.New(self.document.CreateNameForObject(meshID,replaceNames,'mesh'))

			materials = []
			for matName, material in self.materials.iteritems():
				materials.append(material)
			bMesh2.materials = materials
			if len(materials)>16:
				print 'Warning: Mesh-Object:"%s" has more than 16 materials:' %meshName

			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")
							norInput = primitive.FindInput("NORMAL")

							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
						if isinstance(primitive, collada.DaePolygons): #patch from tera_api
							vertCount = len(p)/maxOffset
							realVertCount = vertCount
						# 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 #TODO: support for normals

							if vertCount > 2:
								if isinstance(primitive, collada.DaeTriFans):
									faceCount = 1
								else:
									faceCount = 1 + (realVertCount-4) / 2 + (realVertCount-4) % 2
									#print 'deb: VertCount/realVertCount/faceCount:',VertCount,' / ',realVertCount,' / ',faceCount # ---------
								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
									#bMesh2.addFace(newFace)
									faces.append(newFace)
									# Add the material to this face
									if primitive.material != '':
										if self.materials.has_key(primitive.material):
											#print 'deb: primitive.material:', primitive.material # ---------
											# Find the material index.
											matIndex = self.FindMaterial(bMesh2.materials, self.materials[primitive.material].name)
											# Set the material index for the new face.
											if 15 > matIndex > -1:
												newFace.materialIndex = matIndex
											else:
												newFace.materialIndex = 15 #TODO: fake for all material index bigger than 15
												print 'material Index:%s, outside specification! set to 15 ----' %matIndex # ---------
											textures = self.materials[primitive.material].getTextures()
											#if len(textures) > 0 and textures[0]!=None:
											for texture in textures: #searching for any texture-image
												if texture is not None:
													image = texture.tex.getImage()
													if image is not None:
														newFace.image = image
														break
										else:
											print "Warning: Cannot find material:", primitive.material
							elif vertCount == 2:
								bMesh2.addEdge(curFaceVerts2[0], curFaceVerts2[1])
							else: pass
							# update the index
							if isinstance(primitive, collada.DaeTriFans) or isinstance(primitive, collada.DaeTriStrips):
								pIndex += maxOffset
							else:
								pIndex += realVertCount * maxOffset

				bMesh2.faces = faces
			return bMesh2
		return

	def SaveToDae(self, mesh):
		global useTriangles, usePolygons, useUV

		uvTextures = dict()
		uvIndex = dict()

		daeGeometry = collada.DaeGeometry()
		daeGeometry.id = daeGeometry.name = self.document.CreateID(mesh.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(mesh.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 ( mesh.vertexColors ) :
			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 mesh.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


		# Loop trough all the faces
		for face in mesh.faces:
			matIndex = -1
			if not useUV and mesh.materials and len(mesh.materials) > 0:
				matIndex = face.mat
			elif mesh.faceUV and (useUV or mesh.materials is None or len(mesh.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

			# Now use that AddVerts(...) function exactly in this "if"-block
			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 all 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 all 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 all 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 mesh.materials is None and len(mesh.materials) > 0 and k >= 0:
					daeTriangles.material = mesh.materials[k].name
				elif mesh.faceUV and (useUV or mesh.materials is None or len(mesh.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 mesh.materials is None and len(mesh.materials) > 0 and k >= 0:
					daePolygons.material = getattr(mesh.materials[k], 'name', "")
				elif mesh.faceUV and (useUV or mesh.materials is None or len(mesh.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 shader.transparent.color!=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 shader.transparent.texture!=None: # Texture
						textureSampler = shader.transparent.texture.texture
						if debprn: print "shader:" #---------
						if debprn: print shader.transparent.texture #---------
						if debprn: print "shader end" #---------
						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, Blender.Texture.MapTo.ALPHA)
				elif shader.transparency:
					alpha = 1 - shader.transparency.float
				if shader.reflective:
					if shader.reflective.color:
						# TODO: bug: shader.reflective.color.rgba raise error NoneType with file F40.DAE
						if debprn: print 'deb: shader.reflective.color=',shader.reflective.color #-------
						if debprn: print 'deb: shader.reflective.color.rgba=',shader.reflective.color.rgba #-------
						color = shader.reflective.color.rgba
						bMat.setMirCol(color[0], color[1], color[2])
				if shader.reflectivity:
					bMat.setRayMirr(shader.reflectivity.float)

				if isinstance(shader,collada.DaeFxShadeLambert) or isinstance(shader, collada.DaeFxShadeBlinn) or isinstance(shader, collada.DaeFxShadePhong):
					bMat.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_LAMBERT)
					if shader.diffuse:
						##print shader.diffuse.color.rgba, shader.diffuse.color
						if not (shader.diffuse.color is None):
							color = shader.diffuse.color.rgba
							bMat.setRGBCol(color[0],color[1], color[2])
						if not (shader.diffuse.texture is None): # Texture
							textureSampler = shader.diffuse.texture.texture
							if not (textureSampler is None):
								#support 1.4.0:
								texture = textureSampler

								#support 1.4.1
								for newParam in daeEffect.profileCommon.newParams:
									if newParam.sid == textureSampler:
										surfaceID = newParam.sampler.source
										for newSurface in daeEffect.profileCommon.newParams:
											if newSurface.sid == surfaceID:
												texture = newSurface.surface.initfrom

								texture = self.document.colladaDocument.imagesLibrary.FindObject(texture)
								bTexture = self.document.texturesLibrary.FindObject(texture, True)
								if not bTexture is None:
									bMat.setTexture(0, bTexture, Blender.Texture.TexCo.UV)

					bMat.setSpec(0)

				if isinstance(shader, collada.DaeFxShadeBlinn) or isinstance(shader, collada.DaeFxShadePhong):
					if not isinstance(shader, collada.DaeFxShadePhong):
						bMat.setSpecShader(Blender.Material.Shaders.SPEC_BLINN)
						if shader.indexOfRefraction:
							shader.indexOfRefraction.float
							bMat.setRefracIndex(shader.indexOfRefraction.float)
					else:
						bMat.setSpecShader(Blender.Material.Shaders.SPEC_PHONG)
					if shader.specular:
						if not (shader.specular.color is None): #it's a color and not a texture
							specColor = shader.specular.color.rgba
							bMat.setSpecCol(specColor[0], specColor[1], specColor[2])
					bMat.setSpec(1)
					if shader.shininess:
						bMat.setHardness(int(shader.shininess.float) * 4)

		return bMat

	def GenerateShader(self, bMaterial, updateShader):
		shader = updateShader
		previousDiffuse = None

		if shader != None:
			try:
				previousDiffuse = shader.diffuse
			except:
				pass

		if bMaterial.getSpec() > 0.0:
			if bMaterial.getSpecShader() == Blender.Material.Shaders.SPEC_BLINN:
				shader = collada.DaeFxShadeBlinn()
				shader.AddValue(collada.DaeFxSyntax.INDEXOFREFRACTION, bMaterial.getRefracIndex())
			else:
				shader = collada.DaeFxShadePhong()
			shader.AddValue(collada.DaeFxSyntax.SPECULAR, [col * bMaterial.getSpec() for col in bMaterial.getSpecCol()]+[1])
			shader.AddValue(collada.DaeFxSyntax.SHININESS, bMaterial.getHardness() * 0.25)
		else:
			shader = collada.DaeFxShadeLambert()

		shader.AddValue(collada.DaeFxSyntax.DIFFUSE,bMaterial.getRGBCol()+[1])
		shader.AddValue(collada.DaeFxSyntax.TRANSPARENCY, 1 - bMaterial.alpha)
		shader.AddValue(collada.DaeFxSyntax.TRANSPARENT, [1,1,1,1])
		mainColor = bMaterial.getRGBCol()
		white = [1.0,1.0,1.0]

		shader.AddValue(collada.DaeFxSyntax.EMISSION, [col * bMaterial.getEmit() for col in white] + [1])
		shader.AddValue(collada.DaeFxSyntax.AMBIENT, [col * bMaterial.getAmb() for col in mainColor] + [1])
		shader.AddValue(collada.DaeFxSyntax.REFLECTIVE, bMaterial.getMirCol() + [1])
		shader.AddValue(collada.DaeFxSyntax.REFLECTIVITY, bMaterial.getRayMirr())

		if previousDiffuse != None:
			shader.diffuse = previousDiffuse

		return shader

	def SaveToDae(self, bMaterial):
		global useRelativePaths, filename
		daeMaterial = collada.DaeFxMaterial()
		daeMaterial.id = daeMaterial.name = self.document.CreateID(bMaterial.name, '-Material')

		instance = collada.DaeFxEffectInstance()
		daeEffect = self.document.colladaDocument.effectsLibrary.FindObject(bMaterial.name+'-fx')
		meshNode = MeshNode(self.document)
		if daeEffect is None:
			daeEffect = collada.DaeFxEffect()
			daeEffect.id = daeEffect.name = self.document.CreateID(bMaterial.name , '-fx')

			# Check if a texture is used for color
			textures = bMaterial.getTextures()
			for mTex in textures:
				# Check if this texture is mapped to Color
				if not mTex is None and mTex.mapto == Blender.Texture.MapTo.COL and mTex.tex.image != None:
					texture = mTex.tex
					textureNode = TextureNode(self.document)
					textureNode.AddImageTexture(daeEffect, texture.image)

			shader = self.GenerateShader(bMaterial, daeEffect.profileCommon.technique.shader)
			daeEffect.AddShader(shader)

			self.document.colladaDocument.effectsLibrary.AddItem(daeEffect)
		instance.object = daeEffect

		daeMaterial.iEffects.append(instance)

		self.document.colladaDocument.materialsLibrary.AddItem(daeMaterial)
		return daeMaterial

class CameraNode(object):
	def __init__(self,document):
		self.document = document

	def LoadFromDae(self, daeCamera):
		camID = daeCamera.id
		camName = daeCamera.name
		camType = 'persp'
		clipStart = daeCamera.optics.techniqueCommon.znear
		clipEnd = daeCamera.optics.techniqueCommon.zfar

		if daeCamera.optics.techniqueCommon.GetType() == collada.DaeSyntax.ORTHOGRAPHIC:
			camType = 'ortho'

		camera = Blender.Camera.New(camType,camID)
		camera.clipStart = clipStart
		camera.clipEnd = clipEnd
		return camera


	def SaveToDae(self, bCamera):
		daeCamera = collada.DaeCamera()
		daeCamera.id = daeCamera.name = self.document.CreateID(bCamera.name,'-Camera')
		daeOptics = collada.DaeOptics()
		daeTechniqueCommon = None
		if bCamera.type == 1: # orthographic
			daeTechniqueCommon = collada.DaeOptics.DaeOrthoGraphic()
		else: # perspective
			daeTechniqueCommon = collada.DaeOptics.DaePerspective()
			lens = bCamera.getLens( )
			daeTechniqueCommon.yfov = 2 * ( math.atan( 16.0 / lens ) ) * radianToAngle

		daeTechniqueCommon.znear = bCamera.clipStart
		daeTechniqueCommon.zfar = bCamera.clipEnd

		daeOptics.techniqueCommon = daeTechniqueCommon
		daeCamera.optics = daeOptics

		self.document.colladaDocument.camerasLibrary.AddItem(daeCamera)
		return daeCamera

class LampNode(object):
	def __init__(self,document):
		self.document = document

	def LoadFromDae(self, daeLight):

		lampID = daeLight.id
		lampName = daeLight.name

		# Create a new lampObject
		lamp = Blender.Lamp.New('Sun',lampID)

		if daeLight.techniqueCommon.GetType() == collada.DaeSyntax.DIRECTIONAL:
			lamp.type = Blender.Lamp.Types.Sun
		elif daeLight.techniqueCommon.GetType() == collada.DaeSyntax.POINT:
			lamp.type = Blender.Lamp.Types.Lamp
			# Get the attenuation
			constAtt = daeLight.techniqueCommon.constantAttenuation
			linAtt = daeLight.techniqueCommon.linearAttenuation
			# set the attenuation
			lamp.energy = 1-constAtt
			if linAtt > 0.0:
				lamp.dist = (lamp.energy/2)/ linAtt
			else:
				lamp.dist = 5000.0
		elif daeLight.techniqueCommon.GetType() == collada.DaeSyntax.SPOT:
			lamp.type = Blender.Lamp.Types.Spot
			# Get the attenuation
			constAtt = daeLight.techniqueCommon.constantAttenuation
			linAtt = daeLight.techniqueCommon.linearAttenuation
			# set the attenuation
			lamp.energy = 1-constAtt
			if linAtt > 0.0:
				lamp.dist = (0.5 - constAtt)/ linAtt
			else:
				lamp.dist = 5000.0
			lamp.spotSize = daeLight.techniqueCommon.falloffAngle
			lamp.spotBlend = daeLight.techniqueCommon.falloffExponent
		elif daeLight.techniqueCommon.GetType() == collada.DaeSyntax.AMBIENT:
			lamp.type = Blender.Lamp.Types.Hemi


		# Set the color
		lamp.col = daeLight.techniqueCommon.color

		return lamp

	def SaveToDae(self, bLamp):
		daeLight = collada.DaeLight()
		daeLight.id = daeLight.name = self.document.CreateID(bLamp.name,'-Light')

		daeTechniqueCommon = None
		if bLamp.type == Blender.Lamp.Types.Hemi: # Ambient
			daeTechniqueCommon = collada.DaeLight.DaeAmbient()
		elif bLamp.type == Blender.Lamp.Types.Lamp: # Point light
			daeTechniqueCommon = collada.DaeLight.DaePoint()
		elif bLamp.type == Blender.Lamp.Types.Spot: # Spot
			daeTechniqueCommon = collada.DaeLight.DaeSpot()
			daeTechniqueCommon.constantAttenuation = 1-bLamp.energy
			daeTechniqueCommon.linearAttenuation = (0.5 - daeTechniqueCommon.constantAttenuation)/bLamp.dist
			# Export the falloff Angle.
			daeTechniqueCommon.falloffAngle = bLamp.getSpotSize()
		elif bLamp.type == Blender.Lamp.Types.Sun: # Directional
			daeTechniqueCommon = collada.DaeLight.DaeDirectional()
		else: # area
			daeTechniqueCommon = collada.DaeOptics.DaeTechniqueCommon()

		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):
		if debprn: print 'deb:class AnimationsLibrary <<    <<LoadFromDae' #------------
		daeAnimation = self.daeLibrary.FindObject(animationName)
		if daeAnimation is None:
			return
		animationID = daeAnimation.id
		animationName = daeAnimation.name

		animation = Animation(self.document)
		animation.LoadFromDae(daeAnimation)
		##self.objects[animationID] = [animation, animation.name]
		return animation

	def GetDaeAnimations(self, daeNodeId):
		#if debprn: print 'deb:class AnimationsLibrary -------- GetDaeAnimations:' #------------
		#if debprn: print 'deb:----> daeNodeId=',daeNodeId #---------
		daeAnimations = []
		for daeAnimation in self.daeLibrary.items:
			#if debprn: print 'deb: daeAnimation=', daeAnimation #-----------
			for channel in daeAnimation.channels:
				ta = channel.target.split("/", 1)
				#if debprn: print 'deb:------> ta=', ta #---------
				if ta[0] == daeNodeId:
					daeAnimations.append(daeAnimation)
		#if debprn: print 'deb:--> daeAnimations=', daeAnimations #------------
		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

