//********************************************************************
// Newton Game dynamics 
// copyright 2000-2004
// By Julio Jerez
// VC: 6.0
// basic Hierarchical Scene Node Class
//********************************************************************


#include <dAnimationStdAfx.h>
#include <time.h>

#include <dBone.h>
#include <dMesh.h>
#include <dModel.h>
#include <dAnimationClip.h>
#include <dSkinModifier.h>
#include <dGlueToCollada.h>



//#include <toolbox_stdafx.h>
//#include "dCRC.h"

//#include "dVector.h"
//#include "dMatrix.h"
//#include "OpenGlUtil.h"
//#include "dSceneNode.h"

//#include "planecollision.h"
//#include "RenderPrimitive.h"
//#include "TargaToOpenGl.h"

//#include "CustomGear.h"
//#include "Custom6DOF.h"
//#include "CustomHinge.h"
//#include "CustomPulley.h"
//#include "CustomSlider.h"
//#include "CustomUpVector.h"
//#include "CustomWormGear.h"
//#include "CustomCorkScrew.h"
//#include "CustomUniversal.h"
//#include "CustomBallAndSocket.h"

#include <dae.h>
#include <dae/domAny.h>
#include <dom/domCOLLADA.h>
#include <dom/domConstants.h>
#include <dom/domProfile_COMMON.h>


#define D_SKIN_POS_FIX					"_skin"
#define D_ANIMATION_PREFIX_NAME			"anim_"
#define D_TEXTURE_PREFIX_NAME			"texture_"
#define D_MATERIAL_PREFIX_NAME			"material_"
#define D_MATERIAL_PREFIX_NAME_EFFECT	"materialFx_"
#define	D_ROOT_NODE_NAME				"root_"
#define	D_NODE_NAME						"node_"



#ifdef _LINUX_VER 
//#define cdom::strcasecmp strcasecmp
#endif


class dColladaFileParcel
{

	class MeshPoint
	{
		public: 
		dFloat m_vertex[3];
		dFloat m_normal[3];
		dFloat m_uv[2];
		dFloat m_originalIndex;
	};


	class SourceBuffer
	{
		public: 
		int m_count;
		int m_stride;
		const char* m_id;
		domFloat *m_data;
	};


	class CollImage
	{
		public: 
		char m_textureName[D_NAME_STRING_LENGTH];
		char m_texturePathName[D_NAME_STRING_LENGTH * 4];
	};

	class CollImageCache: public dTree<CollImage, int>
	{
		public: 
		CollImageCache()
			:dTree<CollImage, int>()
		{
		}

		void AddTexture (const char* name)
		{
			CollImage texture;
			const char* ptr;

			ptr = strrchr (name, '/');
			if (ptr) {
				ptr ++;
			} else {
				ptr = strrchr (name, '\\');
				if (ptr) {
					ptr ++;
				} else {
					ptr = name;
				}
			}

//			LoadTexture(ptr, texture.m_texture);
			sprintf (texture.m_textureName, "%s", ptr);
			sprintf (texture.m_texturePathName, "%s", name);
			Insert (texture, dCRC(name));
		}

		const CollImage& GetTexture (const char* name)  const
		{
			dTreeNode* node;

			node = Find (dCRC(name));
			_ASSERTE (node);
			return node->GetInfo();
		}
	};


	class CollMaterial
	{
		public:
		//	GLuint m_texture;
		//	char m_name[64];
		CollImage m_texture;
	};

	class CollMaterialCache: public dTree<CollMaterial, int>
	{
		public: 
		CollMaterialCache()
			:dTree<CollMaterial, int>()
		{
		}

		void AddMaterial (const CollMaterial& material, const char* name)
		{
			Insert (material, dCRC(name));
		}

		CollMaterial* GetMaterial (const char* name) const
		{
			dTreeNode* node;

			node = Find (dCRC(name));
			return node ? &node->GetInfo() : NULL;
		}
	};

	class VerterMap
	{
		public:
		int m_vertexIndexInColladaMesh;
		int m_vertexIndexInDMesh;
	};

	class ModifierVertexCache: public dTree<VerterMap*, dMesh*>
	{
		public:
		ModifierVertexCache()
		{
		}

		~ModifierVertexCache()
		{	
			Iterator iter (*this);
			for (iter.Begin(); iter; iter ++) {
				VerterMap* map = (*iter);
				delete[] map;
			}
		}
	};

	class CollGeoCache: public dTree<dMesh*, domGeometry*>
	{
		public:
		dMesh* FindByName (const char* name) const
		{
			domGeometry* key;
			Iterator iter (*this);
			for (iter.Begin(); iter; iter ++) {
				key = iter.GetKey();
				if (!cdom::strcasecmp (name, key->getId())) {
					return iter.GetNode()->GetInfo();
				}
			}
			return NULL;
		}

		~CollGeoCache ()
		{
			dMesh* geometry;

			while (GetRoot()) {
				geometry = GetRoot()->GetInfo();
				Remove(GetRoot());
				_ASSERTE (geometry);
				geometry->Release();
			}
		}
	};

#if 0
	enum JointType
	{
		m_gear,
		m_hinge,
		m_slider,
		m_pulley,
		m_upVetor,
		m_wormGear,
		m_universal,
		m_corkScrew,
		m_ballsocket,
		m_generic6DOF,
	};


	class NewtonJointList: public dTree<domRigid_constraint*, const NewtonJoint*>
	{
		public:
		static void JointIterator (const NewtonJoint* joint)
		{
			const NewtonBody* body;
			NewtonJointRecord info;
			NewtonJointList* list;
			
			NewtonJointGetInfo (joint, &info);

			body = info.m_attachBody_0;
			if (!body) {
				body = info.m_attachBody_1;
			}
			
			// get the collada database and add this bod y to the world
			list = (NewtonJointList*) NewtonWorldGetUserData(NewtonBodyGetWorld(body));
			list->Insert ((domRigid_constraint*) NULL, joint);
		}
	};

	class NewtonFloatExt: public domTargetableFloat
	{
		public:
		NewtonFloatExt ()
		{
		}
	};


	void AddCameraLibrary (daeDocument* document, dSceneNode* rootNode)
	{
		domCOLLADA *domRoot;
		CameraNode* camera;
		domLibrary_cameras *library;
		domCamera::domOptics* optics;
		domCamera::domOptics::domTechnique_common* technique;
		domCamera::domOptics::domTechnique_common::domPerspective* perpective;

		camera = (CameraNode*) rootNode->Find(CAMERA_NAME);
//		_ASSERTE (camera);
		if (camera) {
			domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());

			library = daeSafeCast<domLibrary_cameras>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_CAMERAS));

			m_collCamera = daeSafeCast<domCamera>(library->createAndPlace(COLLADA_ELEMENT_CAMERA));
			m_collCamera->setId(CAMERA_NAME);
			optics = daeSafeCast<domCamera::domOptics>(m_collCamera->createAndPlace(COLLADA_ELEMENT_OPTICS));
			technique = daeSafeCast<domCamera::domOptics::domTechnique_common>(optics->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			perpective = daeSafeCast<domCamera::domOptics::domTechnique_common::domPerspective>(technique->createAndPlace(COLLADA_ELEMENT_PERSPECTIVE));

			domTargetableFloat* fov; 
			domTargetableFloat* aspect; 
			domTargetableFloat* farPlane;
			domTargetableFloat* nearPlane;
			
			fov = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_YFOV));
			aspect = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_ASPECT_RATIO));
			nearPlane = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_ZNEAR));
			farPlane = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_ZFAR));

			fov->setValue(camera->m_fov);
			aspect->setValue(camera->m_aspect);
			nearPlane->setValue(camera->m_nearPlane);
			farPlane->setValue(camera->m_farPlane);
		}
	}




	domPhysics_material* AddPhysicsMaterialLibrary(daeDocument* document, const NewtonBody* newtonBody, int enumID)
	{
		char name[256];
		domCOLLADA *domRoot;
		dSceneNode* primitive;
		domPhysics_material* material;
		domLibrary_physics_materials* library;
		domPhysics_material::domTechnique_common* technique;

		ColladaFrictionRestituionMaterial* frictionRestituionMaterial;


		// scan the image library and save each texture
		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot->getLibrary_physics_materials_array().getCount());
		library = domRoot->getLibrary_physics_materials_array()[0];
		_ASSERTE (library);

		sprintf (name, "%s%d", D_PHYSICS_MATERIAL_NAME, enumID);

		material = daeSafeCast<domPhysics_material>(library->createAndPlace(COLLADA_ELEMENT_PHYSICS_MATERIAL));
		material->setId (name);

		technique = daeSafeCast<domPhysics_material::domTechnique_common>(material->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
		_ASSERTE (technique);

		daeSafeCast<domTargetableFloat>(technique->createAndPlace(COLLADA_ELEMENT_RESTITUTION));
		daeSafeCast<domTargetableFloat>(technique->createAndPlace(COLLADA_ELEMENT_STATIC_FRICTION));
		daeSafeCast<domTargetableFloat>(technique->createAndPlace(COLLADA_ELEMENT_DYNAMIC_FRICTION));

		// get the graphic object form the rigid body
		primitive = (RenderPrimitive*) NewtonBodyGetUserData (newtonBody);
		if (primitive  && primitive->GetUserData()) {
			frictionRestituionMaterial = (ColladaFrictionRestituionMaterial*) primitive->GetUserData();
			technique->getRestitution()->setValue(frictionRestituionMaterial->m_restitution);
			technique->getStatic_friction()->setValue(frictionRestituionMaterial->m_staticFriction);
			technique->getDynamic_friction()->setValue(frictionRestituionMaterial->m_dynamicFriction);
		} else {
			technique->getRestitution()->setValue(0.3f);
			technique->getStatic_friction()->setValue(0.6f);
			technique->getDynamic_friction()->setValue(0.4f);
		}

		return material;
	}



	domRigid_constraint* AddRigidConstraint (
		daeDocument* document, 
		domRigid_body* sentinel,
		domPhysics_model* model, 
		const NewtonJoint* newtonJoint, 
		int enumID)
	{
		int i;
		const NewtonBody* body0;
		const NewtonBody* body1;
		domRigid_body* rigidBody0;
		domRigid_body* rigidBody1;
		domRigid_constraint* rigidConstraint;
		domRigid_constraint::domAttachment* ref0;
		domRigid_constraint::domRef_attachment* ref1;

		domRigid_constraint::domTechnique_common* techniqueCommon;
		NewtonJointRecord info;
		char tmpName[256];

		_ASSERTE (sentinel);

		NewtonJointGetInfo (newtonJoint, &info);
		rigidConstraint = daeSafeCast<domRigid_constraint>(model->createAndPlace(COLLADA_ELEMENT_RIGID_CONSTRAINT));
		sprintf (tmpName, "%s%04d", D_PHYSICS_RIGIDCONSTRAINT_NAME, enumID);
		rigidConstraint->setSid(tmpName);


//		domExtra* extra;
//		domTechnique *technique;
//		extra = daeSafeCast<domExtra>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_EXTRA ));
//		technique = daeSafeCast<domTechnique>(extra->createAndPlace(COLLADA_ELEMENT_TECHNIQUE));
//		technique->setProfile(info.m_discriptionType);

		JointType jointType;

		jointType = m_generic6DOF;
		if (!cdom::strcasecmp (info.m_discriptionType, "gear")) {
			jointType = m_pulley;
		} else if (!cdom::strcasecmp (info.m_discriptionType, "pulley")) {
			jointType = m_gear;
		} else if (!cdom::strcasecmp (info.m_discriptionType, "wormGear")) {
			jointType = m_wormGear;
//		} else if (!cdom::strcasecmp (technique->getProfile(), "pulley")) {
//			jointType = m_upVetor;
//		} else if (!cdom::strcasecmp (technique->getProfile(), "hinge")) {
//			jointType = m_hinge;
//		} else if (!cdom::strcasecmp (technique->getProfile(), "slider")) {
//			jointType = m_slider;
//		} else if (!cdom::strcasecmp (technique->getProfile(), "corkScrew")) {
//			jointType = m_corkScrew;
//		} else if (!cdom::strcasecmp (technique->getProfile(), "universal")) {
//			jointType = m_universal;
//		} else if (!cdom::strcasecmp (technique->getProfile(), "generic6dof")) {
//			jointType = m_universal;
//		} else if (!cdom::strcasecmp (technique->getProfile(), "generic6dof")) {
//			jointType = m_generic6DOF;
		}

		switch (jointType) 
		{
			case m_gear:
			case m_pulley:
			case m_wormGear:
			{
				domExtra* extra;
				daeElement* element;
				domTechnique *technique;
				domAny *domExtraExtension;
				char tmpName[512];

				extra = daeSafeCast<domExtra>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_EXTRA));
				technique = daeSafeCast<domTechnique>(extra->createAndPlace(COLLADA_ELEMENT_TECHNIQUE));
				technique->setProfile("Newton");

				element = (daeElement*)technique->createAndPlace( "SpecialConstraint" ); 
				domExtraExtension = (domAny*)element; 
				domExtraExtension->setValue (info.m_discriptionType);

				tmpName[0] = 0;
				for (int i = 0; i < sizeof (info.m_extraParameters) / sizeof (info.m_extraParameters[0]); i ++) {
					char text[64];
					sprintf (text, "%f ", info.m_extraParameters[i]);
					strcat (tmpName, text);
				}

				element = (daeElement*)technique->createAndPlace( "parameters" ); 
				domExtraExtension = (domAny*)element; 
				domExtraExtension->setValue (tmpName);
				break;
			}

		}


		rigidBody0 = NULL;
		ref1 = daeSafeCast<domRigid_constraint::domRef_attachment>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_REF_ATTACHMENT));
		body1 = info.m_attachBody_1;
		if (body1) {
			rigidBody1 = m_bodyList.Find(body1)->GetInfo();
		} else {
			rigidBody1 = sentinel;
		}
		daeURI uri1(rigidBody1->getSid());
		ref1->setRigid_body(uri1);
		dMatrix& matrix1 = *((dMatrix*) &info.m_attachmenMatrix_1);
		AddOffssetMatrix (ref1, matrix1);
		
		rigidBody0 = NULL;
		ref0 = daeSafeCast<domRigid_constraint::domAttachment>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_ATTACHMENT));
		body0 = info.m_attachBody_0;
		if (body0) {
			rigidBody0 = m_bodyList.Find(body0)->GetInfo();
		} else {
			rigidBody0 = sentinel;
		}
		daeURI uri0 (rigidBody0->getSid());
//		uri.setElement (rigidBody0);
//		uri.resolveURI();
		ref0->setRigid_body(uri0);
		dMatrix& matrix0 = *((dMatrix*) &info.m_attachmenMatrix_0);
		AddOffssetMatrix (ref0, matrix0);

		// add rigid constraint info
		techniqueCommon = daeSafeCast<domRigid_constraint::domTechnique_common>(rigidConstraint->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
		_ASSERTE (techniqueCommon);

		if (NewtonJointGetCollisionState (newtonJoint)) {
			domRigid_constraint::domTechnique_common::domInterpenetrate* collEnable;
			collEnable = daeSafeCast<domRigid_constraint::domTechnique_common::domInterpenetrate>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_INTERPENETRATE));
			collEnable->setValue(false);
		}

		domRigid_constraint::domTechnique_common::domLimits* limits;
		limits = daeSafeCast<domRigid_constraint::domTechnique_common::domLimits>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_LIMITS));

		if (!info.m_bodiesCollisionOn) {
			domRigid_constraint::domTechnique_common::domInterpenetrate* interpenetrate;

			interpenetrate = daeSafeCast<domRigid_constraint::domTechnique_common::domInterpenetrate>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_INTERPENETRATE));
			interpenetrate->setValue(true);
		}

		domTargetableFloat3* minLinear;
		domTargetableFloat3* maxLinear;
		domTargetableFloat3* minAngular;
		domTargetableFloat3* maxAngular;

		domRigid_constraint::domTechnique_common::domLimits::domLinear* linear; 
		domRigid_constraint::domTechnique_common::domLimits::domSwing_cone_and_twist* angular; 
		linear = daeSafeCast<domRigid_constraint::domTechnique_common::domLimits::domLinear>(limits->createAndPlace(COLLADA_ELEMENT_LINEAR));
		minLinear = daeSafeCast<domTargetableFloat3>(linear->createAndPlace(COLLADA_ELEMENT_MIN));
		maxLinear = daeSafeCast<domTargetableFloat3>(linear->createAndPlace(COLLADA_ELEMENT_MAX));

		angular = daeSafeCast<domRigid_constraint::domTechnique_common::domLimits::domSwing_cone_and_twist>(limits->createAndPlace(COLLADA_ELEMENT_SWING_CONE_AND_TWIST));
		minAngular = daeSafeCast<domTargetableFloat3>(angular->createAndPlace(COLLADA_ELEMENT_MIN));
		maxAngular = daeSafeCast<domTargetableFloat3>(angular->createAndPlace(COLLADA_ELEMENT_MAX));

		dVector minLinearDof (info.m_minLinearDof[0], info.m_minLinearDof[1], info.m_minLinearDof[2]);
		dVector maxLinearDof (info.m_maxLinearDof[0], info.m_maxLinearDof[1], info.m_maxLinearDof[2]);
		dVector minAngularDof (info.m_minAngularDof[0], info.m_minAngularDof[1], info.m_minAngularDof[2]);
		dVector maxAngularDof (info.m_maxAngularDof[0], info.m_maxAngularDof[1], info.m_maxAngularDof[2]);

		minLinearDof = m_axisRotation.TransformVector(minLinearDof);
		maxLinearDof = m_axisRotation.TransformVector(maxLinearDof);
		minAngularDof = m_axisRotation.TransformVector(minAngularDof);
		maxAngularDof = m_axisRotation.TransformVector(maxAngularDof);
		for (i = 0; i < 3; i ++) {
			minLinear->getValue().append (minLinearDof[i]);
			maxLinear->getValue().append (maxLinearDof[i]);
			minAngular->getValue().append (minAngularDof[i]);
			maxAngular->getValue().append (maxAngularDof[i]);
		}

		return rigidConstraint;
	}





	void LoadCamera(daeDocument *document)
	{
		CameraNode* camera;
		domCOLLADA *domRoot;
		domLibrary_cameras *library;
		domCamera::domOptics* optics;
		domCamera::domOptics::domTechnique_common* technique;
		domCamera::domOptics::domTechnique_common::domPerspective* perpective;

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		if (domRoot->getLibrary_cameras_array().getCount()) {
			camera = (CameraNode*) m_rootNode->Find(CAMERA_NAME);
			_ASSERTE (camera);
			if (camera) {
				library = domRoot->getLibrary_cameras_array()[0];
				if (library->getCamera_array().getCount()) {
					m_collCamera = library->getCamera_array()[0];

					optics = m_collCamera->getOptics();
					if (optics) {
						technique = optics->getTechnique_common();
						if (technique) {
							perpective = technique->getPerspective();
							if (perpective) {
								domTargetableFloat* fov; 
								domTargetableFloat* aspect; 
								domTargetableFloat* farPlane;
								domTargetableFloat* nearPlane;

								fov = perpective->getYfov(); 
								if (fov) {
									camera->m_fov = dFloat (fov->getValue());
								}
								aspect = perpective->getAspect_ratio();
								if (aspect) {
									camera->m_aspect = dFloat (aspect->getValue());
								}

								farPlane = perpective->getZfar();
								if (farPlane) {
									camera->m_farPlane = dFloat (farPlane->getValue());
								}

								nearPlane = perpective->getZnear();
								if (nearPlane) {
									camera->m_nearPlane = dFloat (nearPlane->getValue());
								}
							}
						}
					}
				}
			}
		}
	}

	void LoadRigidConstraint (domRigid_constraint* rigidConstraint)
	{

		int j;
		int k;
		int interpenetrate;
		dFloat gearRatio;
		domExtra* extra;
		NewtonBody* body0;
		NewtonBody* body1;
		NewtonCustomJoint* customJoint;
		JointType jointType;
		domRigid_body* rigidBody0;
		domRigid_body* rigidBody1;
		domRigid_constraint::domAttachment* ref0;
		domRigid_constraint::domRef_attachment* ref1;
		domRigid_constraint::domTechnique_common* techniqueCommon;
		domRigid_constraint::domTechnique_common::domLimits* limits;
		
		gearRatio = 1.0f;
		jointType = m_generic6DOF;
		domExtra_Array& extraArray = rigidConstraint->getExtra_array();
		if (extraArray.getCount()) {
			for (j = 0; j < int (extraArray.getCount()); j ++) {
				extra = extraArray[j];
				const domTechnique_Array& techniqueArray = extra->getTechnique_array();
				for (k = 0; k < int (techniqueArray.getCount()); k ++) {
					domTechnique *technique;
					technique = techniqueArray[k];

					if (!cdom::strcasecmp (technique->getProfile(), "newton")) {
						daeElement* element;
						domAny *domExtraExtension;
//						char tmpName[512];


// createAndPlace( "SpecialConstraint" ); 
						const daeElementRefArray& array = technique->getContents();
						element = array[0];

						domExtraExtension = (domAny*)element; 
						if (!cdom::strcasecmp (domExtraExtension->getValue(), "gear")) {
							jointType = m_gear;
							element = array[1];
							domExtraExtension = (domAny*)element; 
							sscanf (domExtraExtension->getValue(), "%f", &gearRatio);

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "pulley")) {
							jointType = m_pulley;
							element = array[1];
							domExtraExtension = (domAny*)element; 
							sscanf (domExtraExtension->getValue(), "%f", &gearRatio);

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "wormGear")) {
							jointType = m_wormGear;
							element = array[1];
							domExtraExtension = (domAny*)element; 
							sscanf (domExtraExtension->getValue(), "%f", &gearRatio);


						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "upVector")) {
							jointType = m_upVetor;

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "ballsocket")) {
							jointType = m_ballsocket;

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "hinge")) {
							jointType = m_hinge;

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "slider")) {
							jointType = m_slider;

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "corkScrew")) {
							jointType = m_corkScrew;

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "universal")) {
							jointType = m_universal;

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "generic6dof")) {
							jointType = m_universal;

						} else if (!cdom::strcasecmp (domExtraExtension->getValue(), "generic6dof")) {
							jointType = m_generic6DOF;
						} else {
	//						_ASSERTE (0);
						}

					}
				}
			}
		}

		ref0 = rigidConstraint->getAttachment();
		ref1 = rigidConstraint->getRef_attachment();
		dMatrix localMatrix0 (GetOffssetMatrix (ref0->getTranslate_array(), ref0->getRotate_array()));
		dMatrix localMatrix1 (GetOffssetMatrix (ref1->getTranslate_array(), ref1->getRotate_array()));

		const daeURI& uri0(ref0->getRigid_body());
		const daeURI& uri1(ref1->getRigid_body());
		rigidBody0 = m_rigidBodyCache.Find (dCRC (uri0.getOriginalURI()))->GetInfo();
		rigidBody1 = m_rigidBodyCache.Find (dCRC (uri1.getOriginalURI()))->GetInfo();

		body0 = m_rigidBodyMap.Find(rigidBody0)->GetInfo();
		body1 = m_rigidBodyMap.Find(rigidBody1)->GetInfo();

		techniqueCommon = rigidConstraint->getTechnique_common();
		_ASSERTE (techniqueCommon);
		
		limits = techniqueCommon->getLimits();
		_ASSERTE (limits);

		dVector minLinearLimits;
		dVector maxLinearLimits;
		dVector minAngularLimits;
		dVector maxAngularLimits;
		for (j = 0; j < 3; j ++) {
			minLinearLimits[j] = limits->getLinear()->getMin()->getValue()[j];
			maxLinearLimits[j] = limits->getLinear()->getMax()->getValue()[j];
			minAngularLimits[j] = limits->getSwing_cone_and_twist()->getMin()->getValue()[j];
			maxAngularLimits[j] = limits->getSwing_cone_and_twist()->getMax()->getValue()[j];
		}

		minLinearLimits = m_axisRotation.RotateVector(minLinearLimits);
		maxLinearLimits = m_axisRotation.RotateVector(maxLinearLimits);
		minAngularLimits = m_axisRotation.RotateVector(minAngularLimits.Scale (3.14159265f / 180.0f));
		maxAngularLimits = m_axisRotation.RotateVector(maxAngularLimits.Scale (3.14159265f / 180.0f));

		customJoint = NULL;
		switch (jointType)
		{
			case m_gear:
			{
				dMatrix matrix0;
				dMatrix matrix1;
				CustomGear* joint;
				NewtonBodyGetMatrix (body0, &matrix0[0][0]);
				NewtonBodyGetMatrix (body1, &matrix1[0][0]);
				matrix0 =  localMatrix0 * matrix0;
				matrix1 =  localMatrix1 * matrix1;
				joint = new CustomGear(gearRatio, matrix0.m_front, matrix1.m_front, body0, body1); 
				customJoint = joint;
				break;
			}

			case m_pulley:
			{
				dMatrix matrix0;
				dMatrix matrix1;
				CustomPulley* joint;
				NewtonBodyGetMatrix (body0, &matrix0[0][0]);
				NewtonBodyGetMatrix (body1, &matrix1[0][0]);
				matrix0 =  localMatrix0 * matrix0;
				matrix1 =  localMatrix1 * matrix1;
				joint = new CustomPulley(gearRatio, matrix0.m_front, matrix1.m_front, body0, body1); 
				customJoint = joint;
				break;
			}

			case m_wormGear:
			{
				dMatrix matrix0;
				dMatrix matrix1;
				CustomWormGear* joint;
				NewtonBodyGetMatrix (body0, &matrix0[0][0]);
				NewtonBodyGetMatrix (body1, &matrix1[0][0]);
				matrix0 =  localMatrix0 * matrix0;
				matrix1 =  localMatrix1 * matrix1;
				joint = new CustomWormGear(gearRatio, matrix0.m_front, matrix1.m_front, body0, body1); 
				customJoint = joint;
				break;
			}


			case m_upVetor:
			{
				dMatrix matrix;
				CustomUpVector* joint;
				NewtonBodyGetMatrix (body0, &matrix[0][0]);
				matrix =  localMatrix0 * matrix;
				joint = new CustomUpVector (matrix.m_front, body0); 
				customJoint = joint;
				break;
			}

			case m_ballsocket:
			{
				dMatrix matrix;
				CustomBallAndSocket* joint;
				NewtonBodyGetMatrix (body0, &matrix[0][0]);
				matrix =  localMatrix0 * matrix;
				joint = new CustomBallAndSocket (matrix, body0, body1); 
				customJoint = joint;
				break;
			}

			case m_hinge:
			{
				dMatrix matrix;
				CustomHinge* joint;
				NewtonBodyGetMatrix (body0, &matrix[0][0]);
				matrix =  localMatrix0 * matrix;
				joint = new CustomHinge (matrix, body0, body1); 
				if ((minAngularLimits[0] > -1000.0f) || (maxAngularLimits[0] < 1000.0f)) {
					 joint->EnableLimits(true);
					 joint->SetLimis (minAngularLimits[0], maxAngularLimits[0]);
				}
				customJoint = joint;
				break;
			}

			case m_slider:
			{
				dMatrix matrix;
				CustomSlider* joint;
				NewtonBodyGetMatrix (body0, &matrix[0][0]);
				matrix =  localMatrix0 * matrix;
				joint = new CustomSlider (matrix, body0, body1); 
				if ((minLinearLimits[0] > -1000.0f) || (maxLinearLimits[0] < 1000.0f)) {
					joint->EnableLimits(true);
					joint->SetLimis (minLinearLimits[0], maxLinearLimits[0]);
				}
				customJoint = joint;
				break;
			}

			case m_corkScrew:
			{
				dMatrix matrix;
				CustomCorkScrew* joint;
				NewtonBodyGetMatrix (body0, &matrix[0][0]);
				matrix =  localMatrix0 * matrix;
				joint = new CustomCorkScrew (matrix, body0, body1); 
				if ((minLinearLimits[0] > -1000.0f) || (maxLinearLimits[0] < 1000.0f)) {
					joint->EnableLinearLimits(true);
					joint->SetLinearLimis (minLinearLimits[0], maxLinearLimits[0]);
				}

				if ((minAngularLimits[0] > -1000.0f) || (maxAngularLimits[0] < 1000.0f)) {
					joint->EnableAngularLimits(true);
					joint->SetAngularLimis (minAngularLimits[0], maxAngularLimits[0]);
				}
				customJoint = joint;
				break;
			}

			case m_universal:
			{
				dMatrix matrix0;
				dMatrix matrix1;
				CustomUniversal* joint;
				NewtonBodyGetMatrix (body0, &matrix0[0][0]);
				NewtonBodyGetMatrix (body1, &matrix1[0][0]);
				matrix0 =  localMatrix0 * matrix0;
				matrix1 =  localMatrix1 * matrix1;
				matrix0.m_up = matrix1.m_up; 
				matrix0.m_right = matrix0.m_front * matrix0.m_up;
				joint = new CustomUniversal (matrix0, body0, body1); 

				if ((minAngularLimits[0] > -1000.0f) || (maxAngularLimits[0] < 1000.0f)) {
					joint->EnableLimit_0(true);
					joint->SetLimis_0 (minAngularLimits[0], maxAngularLimits[0]);
				}

				if ((minAngularLimits[1] > -1000.0f) || (maxAngularLimits[1] < 1000.0f)) {
					joint->EnableLimit_1(true);
					joint->SetLimis_1 (minAngularLimits[1], maxAngularLimits[1]);
				}
				customJoint = joint;
				break;
			}

			case m_generic6DOF:
			{
				dMatrix matrix0;
				dMatrix matrix1;
				Custom6DOF* joint;
				NewtonBodyGetMatrix (body0, &matrix0[0][0]);
				NewtonBodyGetMatrix (body1, &matrix1[0][0]);
				matrix0 = localMatrix0 * matrix0;
				matrix1 = localMatrix1 * matrix1;
				joint = new Custom6DOF (matrix0, matrix1, 
										minLinearLimits, maxLinearLimits,
										minAngularLimits, maxAngularLimits,
										body0, body1); 
				customJoint = joint;
				break;
			}
		}

		if (customJoint) {
			interpenetrate = 0;
			if (techniqueCommon->getInterpenetrate()) {
				interpenetrate = techniqueCommon->getInterpenetrate()->getValue() ? 1 : 0;
			}

			_ASSERTE (customJoint);
			customJoint->SetBodiesCollisionState (!interpenetrate);
		}

	}

	void LoadPhysicsModelInstance (domInstance_physics_model* instancePhysicsModel, const dTree<domRigid_constraint*, unsigned>& constraintCache)
	{
		int m;
		int physicsRigidBodyCount;
		int physicsRigidConstraintCount;
		domRigid_constraint* rigidConstraint;
		domInstance_rigid_body* instanceRigidBody; 
		domInstance_rigid_constraint* instanceRigidConstraint; 

		// load individual rigid bodies instances
		const domInstance_rigid_body_Array& instanceRigidBodyArray = instancePhysicsModel->getInstance_rigid_body_array();
		physicsRigidBodyCount = int (instanceRigidBodyArray.getCount());
		for (m = 0 ; m < physicsRigidBodyCount; m ++) {
			instanceRigidBody = instanceRigidBodyArray[m];
			LoadRigidBody (instanceRigidBody);
		}

		// load all joints
		const domInstance_rigid_constraint_Array& instanceRigidConstraintArray = instancePhysicsModel->getInstance_rigid_constraint_array();
		physicsRigidConstraintCount = int (instanceRigidConstraintArray.getCount());
		for (m = 0 ; m < physicsRigidConstraintCount; m ++) {
			instanceRigidConstraint = instanceRigidConstraintArray[m];
			rigidConstraint = constraintCache.Find(dCRC (instanceRigidConstraint->getConstraint()))->GetInfo();
			LoadRigidConstraint (rigidConstraint);
		}
	}



	void LoadPhysicsScene(daeDocument* document)
	{
		int i;
		int j;
		int k;
		int m;
		int bodyCount; 
		int jointCount; 
		int modelCount; 
		int physicsSceneCount;
		int physicsModelsCount;
		int libraryPhysicsSceneCount;
		domCOLLADA *domRoot;
		domPhysics_model* model;
		domRigid_body* rigidBody;
		const daeElement* element;
		domPhysics_scene* physicsScene;
		domRigid_constraint* rigidConstraint;
		domLibrary_physics_models* modelLibrary;
		domLibrary_physics_scenes* libraryPhysicsScene;
		domInstance_physics_model* instancePhysicsModel; 
		dTree<domRigid_constraint*, unsigned> constraintCache;

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot);
		physicsModelsCount = int (domRoot->getLibrary_physics_models_array().getCount());
		for (i = 0; i < physicsModelsCount; i ++ ) {
			modelLibrary = domRoot->getLibrary_physics_models_array()[0];
			const domPhysics_model_Array &modelArray = modelLibrary->getPhysics_model_array();
			modelCount = int (modelArray.getCount());
			for (j = 0; j < modelCount; j ++) {
				model = modelArray[j];

				const domRigid_body_Array &bodyArray = model->getRigid_body_array();
				bodyCount = int (bodyArray.getCount());
				for (k = 0; k < bodyCount; k ++) {
					rigidBody = bodyArray[k];
					m_rigidBodyCache.Insert(rigidBody, dCRC (rigidBody->getSid()));
				}

				const domRigid_constraint_Array &jointArray = model->getRigid_constraint_array();
				jointCount = int (jointArray.getCount());
				for (k = 0; k < jointCount; k ++) {
					rigidConstraint = jointArray[k];
					constraintCache.Insert(rigidConstraint, dCRC (rigidConstraint->getSid()));
				}
			}
		}

		const domLibrary_physics_scenes_Array &libraryPhysicsScenesArray = domRoot->getLibrary_physics_scenes_array();
		libraryPhysicsSceneCount = int (libraryPhysicsScenesArray.getCount());
		for (i = 0; i < libraryPhysicsSceneCount; i ++ ) {
			libraryPhysicsScene = libraryPhysicsScenesArray[i];
			const domPhysics_scene_Array& physicsSceneArray = libraryPhysicsScene->getPhysics_scene_array();
			physicsSceneCount = int (physicsSceneArray.getCount()); 
			for (j = 0 ; j < physicsSceneCount; j ++) {
				physicsScene = physicsSceneArray[j];
				domInstance_physics_model_Array& instanceModelArray = physicsScene->getInstance_physics_model_array();
				physicsModelsCount = int (instanceModelArray.getCount());
				for (k = 0 ; k < physicsModelsCount; k ++) {
					instancePhysicsModel = instanceModelArray[k];
					LoadPhysicsModelInstance (instancePhysicsModel, constraintCache);
					
					const daeURI& uri = instancePhysicsModel->getUrl();
					element = uri.getElement();
					if (element) {
						model = (domPhysics_model*) element;

						//if this is a model instance then it will have some other models
						const domInstance_physics_model_Array& instanceModelsArray = model->getInstance_physics_model_array();
						if (instanceModelsArray .getCount()) {
							modelCount = int (instanceModelsArray.getCount());
							for (m = 0 ; m < modelCount; m ++) {
								LoadPhysicsModelInstance (instanceModelsArray[m], constraintCache);
							}
						}
					}
				}
			}
		}
	}

	void ReplaceVisulaMeshWithCollisionProxis()
	{
		int proxiNumber;
		NewtonBody* body;		
		dGeometry* proxiMesh;
		dSceneNode* visualMesh;
		NewtonCollision* collision;
		dTree<dGeometry*,  NewtonCollision*> collisionCache;

		proxiNumber = 0;
		dRigidBodyMap::Iterator iter (m_rigidBodyMap);
		for (iter.Begin(); iter; iter ++) {
			body = iter.GetNode()->GetInfo();
			collision = NewtonBodyGetCollision(body);
			if (!collisionCache.Find(collision)) {
				proxiMesh = dGeometry::MakeMeshFromCollision (m_world, collision, NULL);
				collisionCache.Insert(proxiMesh, collision);
				sprintf (proxiMesh->m_name, "proxi%04d", proxiNumber);
				proxiNumber ++;
			}
			proxiMesh = collisionCache.Find(collision)->GetInfo();
			if (proxiMesh->m_vertexCount == 0) {
				proxiMesh = NULL;
			}
			visualMesh = (RenderPrimitive*) NewtonBodyGetUserData (body);
			if (visualMesh) {
				visualMesh->SetGeometry(proxiMesh);
			}
		}

		dTree<dGeometry*,  NewtonCollision*>::Iterator cacheIter (collisionCache);
		for (cacheIter.Begin(); cacheIter; cacheIter ++) {
			proxiMesh = cacheIter.GetNode()->GetInfo();
			proxiMesh->Release();
		}
	}


#endif

	public:
	dColladaFileParcel (DAE* collada, const dMatrix& globalRotation, dFloat scale)
		:m_globalRotation (globalRotation), m_scale (scale) 
	{
		m_nodeIndex = 0;
		m_collada = collada; 
	}

	~dColladaFileParcel ()
	{
	}

	void SceneToCollada (dModel* model)
	{
		daeInt error;
		daeDatabase* database;
		daeDocument *document;
		dTree<domNode*, dModel*> nodeMap; 
		dTree<unsigned, unsigned> uniqueNameFilter;

		document = NULL;
		database = m_collada->getDatabase();
		error = database->insertDocument ("mainDoc", &document);

		_ASSERTE (error == DAE_OK);
		_ASSERTE (document);

		document = database->getDocument(daeUInt (0));

		// save graphical part
		AddAsset (document);
		AddCameraLibrary (document, model);
		AddImageLibrary (document, model);
		AddMaterialLibrary (document, model);
		AddGeometryLibrary (document, model);
		AddControllerLibrary(document, model);

		AddAnimationLibrary(document, model);
		
		AddVisualSceneLibrary (document, model, nodeMap, uniqueNameFilter);

		// add the scene instance
		AddScene (document);
	}


	void SceneToCollada (dSceneModelList& sceneList)
	{
		daeInt error;
		daeDatabase* database;
		daeDocument *document;
		dTree<domNode*, dModel*> nodeMap; 

		document = NULL;
		database = m_collada->getDatabase();
		error = database->insertDocument ("mainDoc", &document);

		_ASSERTE (error == DAE_OK);
		_ASSERTE (document);

		document = database->getDocument(daeUInt (0));

		// save graphical part
		AddAsset (document);

		dTree<unsigned, unsigned> uniqueNameFilter;
		for (dSceneModelList::dListNode* node = sceneList.GetFirst(); node; node = node->GetNext()) {
			dModel* model = node->GetInfo();			
			AddCameraLibrary (document, model);
			AddImageLibrary (document, model);
			AddMaterialLibrary (document, model);
			AddGeometryLibrary (document, model);
			AddControllerLibrary(document, model);
			AddAnimationLibrary(document, model);

			AddVisualSceneLibrary (document, model, nodeMap, uniqueNameFilter);
		}

		// add the scene instance
		AddScene (document);
	}


	void SceneToCollada (NewtonWorld* world)
	{
		daeInt error;
		daeDatabase* database;
		daeDocument *document;

		document = NULL;
		database = m_collada->getDatabase();
		error = database->insertDocument ("mainDoc", &document);

		_ASSERTE (error == DAE_OK);
		_ASSERTE (document);

		document = database->getDocument(daeUInt (0));

		// save graphical part
		AddAsset (document);


		dTree<domNode*, dModel*> nodeMap;
		dTree<unsigned, unsigned> uniqueNameFilter;
		for (const NewtonBody* body = NewtonWorldGetFirstBody (world); body; body = NewtonWorldGetNextBody(world, body)) {
			dModel* model = (dModel*) NewtonBodyGetUserData(body);
			if (model) {
				_ASSERTE (model->IsType (dModel::GetRttiType()));

				AddCameraLibrary (document, model);
				AddImageLibrary (document, model);
				AddMaterialLibrary (document, model);
				AddGeometryLibrary (document, model);
				AddControllerLibrary(document, model);
				AddAnimationLibrary(document, model);

				AddVisualSceneLibrary (document, model, nodeMap, uniqueNameFilter);
			}
		}


		// find all bodies forming any kind of contraction
		dTree<const NewtonBody*, const NewtonBody*> bodyFilter;

		dTree<domGeometry *, const NewtonCollision*> shapeFilter;

		int modelID = 0;
		for (const NewtonBody* body = NewtonWorldGetFirstBody (world); body; body = NewtonWorldGetNextBody(world, body)) {
			if (!bodyFilter.Find(body)) {
				dList<const NewtonBody*> bodyList;
				int count;
				const NewtonBody* stack[2048];

				stack[0] = body;
				count = 1;
				while (count) {
					count --;
					const NewtonBody* modelBody = stack[count];

					bodyFilter.Insert(body, modelBody);
					bodyList.Append(modelBody);
					for (NewtonJoint* joint = NewtonBodyGetFirstJoint (modelBody); joint; joint = NewtonBodyGetNextJoint (body, joint)) {
						NewtonBody* body0 = NewtonJointGetBody0(joint);
						if (bodyFilter.Find(body0)) {
							stack[count] = body0;
							count ++;
						}

						NewtonBody* body1 = NewtonJointGetBody1(joint);
						if (bodyFilter.Find(body1)) {
							stack[count] = body1;
							count ++;
						}
					}
				}

				char name[256];
				dModel* model = (dModel*) NewtonBodyGetUserData (bodyList.GetFirst()->GetInfo());
				if (model) {               
					_ASSERTE (model->IsType(dModel::GetRttiType()));
					sprintf (name, "%s_%03d", model->m_name, modelID);
				} else {
					sprintf (name, "%model_%x", bodyList.GetFirst()->GetInfo());
				}
				AddPhysicsModelLibrary (document, bodyList, name, shapeFilter, nodeMap);

				modelID ++;
			}
		}

		// add the scene instance
		AddScene (document);
	}


	void ColladatToScene (dModel* model, dLoaderContext* context)
	{
		domAsset *asset;
		domCOLLADA *domRoot;
		daeDatabase* database;
		daeDocument *document;
		CollGeoCache meshCache;
		CollImageCache imageCache;
		domAsset::domUnit* unit;
		domAsset::domUp_axis* axis;
		CollMaterialCache materialCache;
//		ColladaNodeTodSceneNodeMap nodeMap;
		ModifierVertexCache modifierVertexMapCache;

		database = m_collada->getDatabase();
		_ASSERTE (database);
		document = database->getDocument(daeUInt (0));
		_ASSERTE (document);

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot);

		asset = domRoot->getAsset();
		_ASSERTE (domRoot);

		unit = asset->getUnit();
		if (unit) {
			m_scale *= dFloat (unit->getMeter());
		}

		axis = asset->getUp_axis();
		if (axis) {
			const domUpAxisType& value = axis->getValue();
			switch (value)
			{
				case UPAXISTYPE_X_UP:
				{
					m_globalRotation = dYawMatrix(3.14159265f * 0.5f) * m_globalRotation;
					break;
				}

				case UPAXISTYPE_Z_UP:
				{
					m_globalRotation = dPitchMatrix(-3.14159265f * 0.5f) * m_globalRotation;
					break;
				}

				case UPAXISTYPE_Y_UP:
				default:
				{
				}
			}
		}

/*

//		LoadCamera(document);
		LoadTextures(document, imageCache);
		LoadMaterials(document, imageCache, materialCache);
		LoadGeometries(document, model, modifierVertexMapCache, meshCache, materialCache, context);

//		switch (mode)
//		{
//			case m_meshOnly:
//			{
//				LoadVisualScene(document);
//				break;
//			}
//
//			case m_fullScene:
//			{
//				LoadVisualScene(document);
//
//				// set default material properties
//				if (colladaMaterialIndex == -1) {
//					colladaMaterialIndex = NewtonMaterialCreateGroupID (m_world);
//					NewtonMaterialSetCollisionCallback (m_world, colladaMaterialIndex, colladaMaterialIndex, NULL, ColladaContactBegin, ColladaContactProcess, ColladaContactEnd); 
//				}
//				LoadPhysicsScene(document);
//				break;
//			}
//			case m_physicCollisionAndVisual:
//			{
//				LoadVisualScene(document);
//
//				// set default material properties
//				if (colladaMaterialIndex == -1) {
//					colladaMaterialIndex = NewtonMaterialCreateGroupID (m_world);
//					NewtonMaterialSetCollisionCallback (m_world, colladaMaterialIndex, colladaMaterialIndex, NULL, ColladaContactBegin, ColladaContactProcess, ColladaContactEnd); 
//				}
//				LoadPhysicsScene(document);

//				ReplaceVisulaMeshWithCollisionProxis();
//				break;
//			}
//		}
*/

		LoadVisualScene(document, model, context, meshCache, modifierVertexMapCache, materialCache, imageCache);
		context->LoaderFixup (model);
	}


	void ColladatToScene (dSceneModelList& sceneList, dLoaderContext* context)
	{
		domAsset *asset;
		domCOLLADA *domRoot;
		daeDatabase* database;
		daeDocument *document;
		CollGeoCache meshCache;
		CollImageCache imageCache;
		domAsset::domUnit* unit;
		domAsset::domUp_axis* axis;
		CollMaterialCache materialCache;
//		ColladaNodeTodSceneNodeMap nodeMap;
		ModifierVertexCache modifierVertexMapCache;

		database = m_collada->getDatabase();
		_ASSERTE (database);
		document = database->getDocument(daeUInt (0));
		_ASSERTE (document);

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot);

		asset = domRoot->getAsset();
		_ASSERTE (domRoot);

		unit = asset->getUnit();
		if (unit) {
			m_scale *= dFloat (unit->getMeter());
		}

		axis = asset->getUp_axis();
		if (axis) {
			const domUpAxisType& value = axis->getValue();
			switch (value)
			{
				case UPAXISTYPE_X_UP:
				{
					m_globalRotation = dYawMatrix(3.14159265f * 0.5f) * m_globalRotation;
					break;
				}

				case UPAXISTYPE_Z_UP:
				{
					m_globalRotation = dPitchMatrix(-3.14159265f * 0.5f) * m_globalRotation;
					break;
				}

				case UPAXISTYPE_Y_UP:
				default:
				{
				}
			}
		}

		LoadVisualScene(document, sceneList, context, meshCache, modifierVertexMapCache, materialCache, imageCache);
		for (dSceneModelList::dListNode* node = sceneList.GetFirst(); node; node = node->GetNext()) {
			dModel* model = node->GetInfo();
			context->LoaderFixup (model);
		}
	}


	void ColladatToScene (dSceneModelList& sceneList, NewtonWorld* world, dLoaderContext* context)
	{
		domAsset *asset;
		domCOLLADA *domRoot;
		daeDatabase* database;
		daeDocument *document;
		CollGeoCache meshCache;
		CollImageCache imageCache;
		domAsset::domUnit* unit;
		domAsset::domUp_axis* axis;
		CollMaterialCache materialCache;
		ModifierVertexCache modifierVertexMapCache;

		database = m_collada->getDatabase();
		_ASSERTE (database);
		document = database->getDocument(daeUInt (0));
		_ASSERTE (document);

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot);

		asset = domRoot->getAsset();
		_ASSERTE (domRoot);

		unit = asset->getUnit();
		if (unit) {
			m_scale *= dFloat (unit->getMeter());
		}

		axis = asset->getUp_axis();
		if (axis) {
			const domUpAxisType& value = axis->getValue();
			switch (value)
			{
				case UPAXISTYPE_X_UP:
				{
					m_globalRotation = dYawMatrix(3.14159265f * 0.5f) * m_globalRotation;
					break;
				}

				case UPAXISTYPE_Z_UP:
				{
					m_globalRotation = dPitchMatrix(-3.14159265f * 0.5f) * m_globalRotation;
					break;
				}

				case UPAXISTYPE_Y_UP:
				default:
				{
				}
			}
		}

		LoadPhysicScene(document, world, sceneList, context, meshCache, modifierVertexMapCache, materialCache, imageCache);
		for (dSceneModelList::dListNode* node = sceneList.GetFirst(); node; node = node->GetNext()) {
			dModel* model = node->GetInfo();
			context->LoaderFixup (model);
		}
	}




	private:

	dMatrix GetMatrix (domNode* node) const
	{
		dMatrix matrix (GetIdentityMatrix());
		domMatrix_Array matrixArray = node->getMatrix_array();
		if (matrixArray.getCount()) {
			// parce the matrix by concatenating each of the individual components	
			for (int i = 0; i < int (matrixArray.getCount()); i ++) {
				const domFloat4x4& data = matrixArray[i]->getValue();
				dMatrix colladaMatrix; 
				for (int j = 0; j < 4; j ++) {
					for (int k = 0; k < 4; k ++) {
						colladaMatrix[k][j] = dFloat (data[j * 4 + k]);
					}
				}
				matrix = colladaMatrix * matrix;
			}
		} else {
			// or parse the matrix by concatenating each of the individual components
			domTranslate_Array &translationArray = node->getTranslate_array();
			for (int i = 0; i < int (translationArray.getCount()); i ++) {
				const domFloat3& data = translationArray[i]->getValue();
				matrix[3][0] += dFloat (data[0]);
				matrix[3][1] += dFloat (data[1]);
				matrix[3][2] += dFloat (data[2]);
			}

			domRotate_Array &rotationArray = node->getRotate_array();
			for (int i = 0; i < int (rotationArray.getCount()); i ++) {
				dFloat angle;
				const domFloat4& data = rotationArray[i]->getValue();
				angle = dFloat (data[3]) * 3.1316f / 180.0f;
				dFloat x = dFloat (data[0]);
				dFloat y = dFloat (data[1]);
				dFloat z = dFloat (data[2]);
				dVector axis (x, y, z, 0.0f);
				axis = axis.Scale (1.0f / sqrtf (axis % axis));
				dQuaternion rot (axis, angle);
				dMatrix colladaMatrix (rot, dVector (0.0f, 0.0f, 0.0f, 1.0f));
				matrix = colladaMatrix * matrix;
			}
		}
		return matrix;
	}


	void AddAsset (daeDocument *document)
	{
		domAsset *asset;
		domCOLLADA *domRoot;
		domAsset::domCreated *created;
		domAsset::domModified *modified;
		domAsset::domUnit *unit;
		domAsset::domUp_axis* axis;
		domAsset::domContributor* contributor;
		domAsset::domContributor::domAuthor* autor;

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		asset = daeSafeCast<domAsset>(domRoot->createAndPlace(COLLADA_ELEMENT_ASSET));


		contributor = daeSafeCast<domAsset::domContributor>(asset->createAndPlace(COLLADA_ELEMENT_CONTRIBUTOR));
		autor = daeSafeCast<domAsset::domContributor::domAuthor>(contributor->createAndPlace(COLLADA_ELEMENT_AUTHOR));
		autor->setValue("Newton Game Dynamics 2.00 Collada Export");

		created = daeSafeCast<domAsset::domCreated>(asset->createAndPlace(COLLADA_ELEMENT_CREATED));

		time_t rawtime;
		tm * ptm;
		time ( &rawtime );
		ptm = gmtime ( &rawtime );

		char date[256];
		sprintf (date, "%d-%02d-%02dT%02d:%02d:%02dZ", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

		//created->setValue("2010-01-04T15:56:43Z");
		created->setValue(date);

		modified = daeSafeCast<domAsset::domModified>(asset->createAndPlace(COLLADA_ELEMENT_MODIFIED));
		modified->setValue(date);

		unit = daeSafeCast<domAsset::domUnit>(asset->createAndPlace(COLLADA_ELEMENT_UNIT));
		unit->setName("meter");
		unit->setMeter (1.0);

		axis = daeSafeCast<domAsset::domUp_axis>(asset->createAndPlace(COLLADA_ELEMENT_UP_AXIS));
		axis->setValue(UPAXISTYPE_Y_UP);
//		axis->setValue(UPAXISTYPE_Z_UP);
	}


	void AddCameraLibrary (daeDocument* document, const dModel* model)
	{
/*
		domCOLLADA *domRoot;
		CameraNode* camera;
		domLibrary_cameras *library;
		domCamera::domOptics* optics;
		domCamera::domOptics::domTechnique_common* technique;
		domCamera::domOptics::domTechnique_common::domPerspective* perpective;

		camera = (CameraNode*) rootNode->Find(CAMERA_NAME);
		//		_ASSERTE (camera);
		if (camera) {
			domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());

			library = daeSafeCast<domLibrary_cameras>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_CAMERAS));

			m_collCamera = daeSafeCast<domCamera>(library->createAndPlace(COLLADA_ELEMENT_CAMERA));
			m_collCamera->setId(CAMERA_NAME);
			optics = daeSafeCast<domCamera::domOptics>(m_collCamera->createAndPlace(COLLADA_ELEMENT_OPTICS));
			technique = daeSafeCast<domCamera::domOptics::domTechnique_common>(optics->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			perpective = daeSafeCast<domCamera::domOptics::domTechnique_common::domPerspective>(technique->createAndPlace(COLLADA_ELEMENT_PERSPECTIVE));

			domTargetableFloat* fov; 
			domTargetableFloat* aspect; 
			domTargetableFloat* farPlane;
			domTargetableFloat* nearPlane;

			fov = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_YFOV));
			aspect = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_ASPECT_RATIO));
			nearPlane = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_ZNEAR));
			farPlane = daeSafeCast<domTargetableFloat>(perpective->createAndPlace(COLLADA_ELEMENT_ZFAR));

			fov->setValue(camera->m_fov);
			aspect->setValue(camera->m_aspect);
			nearPlane->setValue(camera->m_nearPlane);
			farPlane->setValue(camera->m_farPlane);
		}
*/
	}


	void AddImageLibrary (daeDocument* document, const dModel* model)
	{
		domCOLLADA *domRoot;
		domLibrary_images* library;

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		if (domRoot->getLibrary_images_array().getCount()) {
			library = domRoot->getLibrary_images_array()[0];
		} else {
			library = daeSafeCast<domLibrary_images>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_IMAGES));
		}

		for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) { 
			dMeshInstance& intance = node->GetInfo();
			if (!intance.IsIntance()) {
				dMesh* mesh = intance.m_mesh;
				for (dMesh::dListNode* subMeshNode = mesh->GetFirst(); subMeshNode; subMeshNode = subMeshNode->GetNext()) {
					int crcCode;
					char name[256];
					char texName[256];
					dSubMesh* subMesh = &subMeshNode->GetInfo();
					
					mesh->GetTextureName(subMesh, texName);
					crcCode = dCRC (texName);

					sprintf (name, "%s%x", D_TEXTURE_PREFIX_NAME, crcCode);
					if (!FindImage (library, name)) {
						domImage* image = daeSafeCast<domImage>(library->createAndPlace(COLLADA_ELEMENT_IMAGE));
						image->setId (name);

						domImage::domInit_from* imagefrom = daeSafeCast<domImage::domInit_from>(image->createAndPlace(COLLADA_ELEMENT_INIT_FROM));
						imagefrom->setValue (texName);
					}
				}
			}
		}
	}


	void AddDefaultMaterial (domLibrary_effects* effectLibrary, domLibrary_materials* materialLibrary)
	{
		domEffect *effect;
		domMaterial* material;
		domInstance_effect *instanceEffect;
		char materialName[128];

		sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME, dCRC (0));

		material = daeSafeCast<domMaterial>(materialLibrary->createAndPlace(COLLADA_ELEMENT_MATERIAL));
		material->setId (materialName);

		// create an effect and add instance to the material
		effect = daeSafeCast<domEffect>(effectLibrary->createAndPlace(COLLADA_ELEMENT_EFFECT));
		sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME_EFFECT, dCRC (0));
		effect->setId (materialName);

		instanceEffect = daeSafeCast<domInstance_effect>(material->createAndPlace(COLLADA_ELEMENT_INSTANCE_EFFECT ));
		daeURI uri (*effect);
		uri.set("", "", "", "", effect->getId());
		//uri.setElement (effect);
		//uri.resolveURI();
		instanceEffect->setUrl (uri);

		// add properties to the effect
		// need to copy the material properties into the effect, 
		//const dgMaxMaterial& myMaterial = *iter;
		domProfile_COMMON *profile = daeSafeCast<domProfile_COMMON>(effect->createAndPlace(COLLADA_ELEMENT_PROFILE_COMMON));

		domProfile_COMMON::domTechnique *technique = daeSafeCast<domProfile_COMMON::domTechnique>(profile->createAndPlace(COLLADA_ELEMENT_TECHNIQUE));
		technique->setSid("common");
		domProfile_COMMON::domTechnique::domLambert *lambert = daeSafeCast<domProfile_COMMON::domTechnique::domLambert>(technique->createAndPlace(COLLADA_ELEMENT_LAMBERT));

		domCommon_color_or_texture_type *diffuse = daeSafeCast<domCommon_color_or_texture_type>(lambert->createAndPlace(COLLADA_ELEMENT_DIFFUSE));
		domCommon_color_or_texture_type::domColor *color = daeSafeCast<domCommon_color_or_texture_type::domColor>(diffuse->createAndPlace(COLLADA_ELEMENT_COLOR));
		domFx_color_common& value = color->getValue();
		color->getValue().append(0.7f);
		color->getValue().append(0.7f);
		color->getValue().append(0.7f);
		color->getValue().append(1.0f);
		value.setCount(4);
		value[0] = 0.7f;
		value[1] = 0.7f;
		value[2] = 0.7f;
		value[3] = 1.0f;
	}


	void AddMaterialLibrary (daeDocument* document, const dModel* model)
	{
		domCOLLADA *domRoot;
		domLibrary_effects* effectLibrary;
		domLibrary_materials* materialLibrary;

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot() );

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());

		// create an material and effect library
		if (domRoot->getLibrary_effects_array().getCount()) {
			effectLibrary = domRoot->getLibrary_effects_array()[0];
		} else {
			effectLibrary = daeSafeCast<domLibrary_effects>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_EFFECTS));
		}

		if (domRoot->getLibrary_materials_array().getCount()) {
			materialLibrary = domRoot->getLibrary_materials_array()[0];
		} else {
			materialLibrary = daeSafeCast<domLibrary_materials>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_MATERIALS));
			AddDefaultMaterial (effectLibrary, materialLibrary);
		}

		for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) { 
			dMeshInstance& instance = node->GetInfo();
			if (!instance.IsIntance()) {
				dMesh* mesh = instance.m_mesh;
				for (dMesh::dListNode* subMeshNode = mesh->GetFirst(); subMeshNode; subMeshNode = subMeshNode->GetNext()) {
					dMesh* mesh = node->GetInfo().m_mesh;
					int crcCode;
					dSubMesh* subMesh = &subMeshNode->GetInfo();

					char name[256];
					char materialName[256];

					mesh->GetTextureName(subMesh, name);
					crcCode = dCRC (name);
					sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME, crcCode);

					if (!FindMaterial(materialLibrary, materialName)) {
						domEffect *effect;
						domMaterial* material;
						domInstance_effect *instanceEffect;

						material = daeSafeCast<domMaterial>(materialLibrary->createAndPlace(COLLADA_ELEMENT_MATERIAL));
						material->setId (materialName);

						// create an effect and add instance to the material
						effect = daeSafeCast<domEffect>(effectLibrary->createAndPlace(COLLADA_ELEMENT_EFFECT));
						sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME_EFFECT, crcCode);
						effect->setId (materialName);

						instanceEffect = daeSafeCast<domInstance_effect>(material->createAndPlace(COLLADA_ELEMENT_INSTANCE_EFFECT ));
						daeURI uri (*effect);
						uri.set("", "", "", "", effect->getId());
						//						uri.resolveURI();
						instanceEffect->setUrl( uri );

						// add properties to the effect
						// need to copy the material properties into the effect, 
						//const dgMaxMaterial& myMaterial = *iter;
						domProfile_COMMON *profile = daeSafeCast<domProfile_COMMON>(effect->createAndPlace(COLLADA_ELEMENT_PROFILE_COMMON));

						domProfile_COMMON::domTechnique *technique = daeSafeCast<domProfile_COMMON::domTechnique>(profile->createAndPlace(COLLADA_ELEMENT_TECHNIQUE));
						technique->setSid("common");
						domProfile_COMMON::domTechnique::domLambert *lambert = daeSafeCast<domProfile_COMMON::domTechnique::domLambert>(technique->createAndPlace(COLLADA_ELEMENT_LAMBERT));

						domCommon_color_or_texture_type *diffuse = daeSafeCast<domCommon_color_or_texture_type>(lambert->createAndPlace(COLLADA_ELEMENT_DIFFUSE));
						if (!crcCode) {
							domCommon_color_or_texture_type::domColor *color = daeSafeCast<domCommon_color_or_texture_type::domColor>(diffuse->createAndPlace(COLLADA_ELEMENT_COLOR));
							domFx_color_common& value = color->getValue();
							value.setCount(4);
							value[0] = 0.7f;
							value[1] = 0.7f;
							value[2] = 0.7f;
							value[3] = 1.0f;
//							domCommon_color_or_texture_typeRef elemEmission;
//							domCommon_color_or_texture_typeRef elemAmbient;
//							domCommon_color_or_texture_typeRef elemDiffuse;
//							domCommon_color_or_texture_typeRef elemReflective;
//							domCommon_float_or_param_typeRef elemReflectivity;
//							domCommon_transparent_typeRef elemTransparent;
//							domCommon_float_or_param_typeRef elemTransparency;
//							domCommon_float_or_param_typeRef elemIndex_of_refraction;

						} else {
							char nameID [128];
							char nameIDimage [128];
							domCommon_newparam_type *np;

							sprintf (nameID, "%s%x", D_TEXTURE_PREFIX_NAME, crcCode);							
							sprintf (nameIDimage, "%s_image", nameID);

							np = daeSafeCast<domCommon_newparam_type>(profile->createAndPlace(COLLADA_ELEMENT_NEWPARAM));
							np->setSid (nameIDimage);
							domFx_surface_common *surface = daeSafeCast<domFx_surface_common>(np->createAndPlace(COLLADA_ELEMENT_SURFACE));
							surface->setType( FX_SURFACE_TYPE_ENUM_2D );
							domFx_surface_init_from_common *surfIF = daeSafeCast<domFx_surface_init_from_common>(surface->createAndPlace(COLLADA_ELEMENT_INIT_FROM));
							surfIF->setValue (nameID);
							domFx_surface_common_complexType::domFormat *format = daeSafeCast<domFx_surface_common_complexType::domFormat>(surface->createAndPlace(COLLADA_ELEMENT_FORMAT));
							format->setValue("A8R8G8B8");

							np = daeSafeCast<domCommon_newparam_type>(profile->createAndPlace(COLLADA_ELEMENT_NEWPARAM));
							//np->setSid( "sampler" );
							np->setSid (nameID);
							domFx_sampler2D_common *sampler = daeSafeCast<domFx_sampler2D_common>(np->createAndPlace(COLLADA_ELEMENT_SAMPLER2D));
							domFx_sampler2D_common::domSource *sampSrc = daeSafeCast<domFx_sampler2D_common::domSource>(sampler->createAndPlace(COLLADA_ELEMENT_SOURCE));
							sampSrc->setValue( nameIDimage );

							domCommon_color_or_texture_type::domTexture *texture = daeSafeCast<domCommon_color_or_texture_type::domTexture>(diffuse->createAndPlace(COLLADA_ELEMENT_TEXTURE));
							texture->setTexture( nameID );
							texture->setTexcoord ("CHANNEL1");
						}
					}
				}
			}
		}
	}



	domGeometry *AddConvexGeometry (daeDocument* document, const dMesh* geometry)
	{
		domLibrary_geometries *library;

		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		if (domRoot->getLibrary_geometries_array().getCount()) {
			library = domRoot->getLibrary_geometries_array()[0];
		} else {
			library = daeSafeCast<domLibrary_geometries>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_GEOMETRIES));
		}
		_ASSERTE (library);

		domGeometry *collGeometry = daeSafeCast<domGeometry>(library->createAndPlace(COLLADA_ELEMENT_GEOMETRY ));


		char meshName[256];
		geometry->GetName(meshName);
		collGeometry->setId(meshName);
		domConvex_mesh *colladaMesh = daeSafeCast<domConvex_mesh>(collGeometry->createAndPlace(COLLADA_ELEMENT_CONVEX_MESH));


		domVertices *verts;
		int* vertexArrayIndexList = new int[geometry->m_vertexCount];
		{
			// add the vertices
			char text[256];
			int vertexCount;
			domSource *posSource;
			float* floatPool = new float[geometry->m_vertexCount * 3];

			posSource = daeSafeCast<domSource>(colladaMesh->createAndPlace(COLLADA_ELEMENT_SOURCE));
			sprintf (text, "%s_position", meshName);
			posSource->setId (text);

			for (int i = 0; i < geometry->m_vertexCount; i ++) {
				floatPool[i * 3 + 0] = m_scale * geometry->m_vertex[i * 3 + 0];
				floatPool[i * 3 + 1] = m_scale * geometry->m_vertex[i * 3 + 1];
				floatPool[i * 3 + 2] = m_scale * geometry->m_vertex[i * 3 + 2];
			}

			vertexCount = dModel::PackVertexArray (floatPool, 3, 3 * sizeof (dFloat), geometry->m_vertexCount, vertexArrayIndexList);
			m_globalRotation.TransformTriplex(floatPool, sizeof (float) * 3, floatPool, sizeof (float) * 3, geometry->m_vertexCount);

			domFloat_array *fa = daeSafeCast<domFloat_array>(posSource->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
			strcat (text, "Array");
			fa->setId( text );
			fa->setCount (vertexCount * 3);

			domListOfFloats &posSrcArray = fa->getValue();
			for (int i = 0; i < vertexCount; i ++) {
				posSrcArray.append3( floatPool[i * 3 + 0], floatPool[i * 3 + 1], floatPool[i * 3 + 2]);
			}

			//create the accessor
			domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(posSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
			acc->setCount (vertexCount);
			acc->setStride (3);
			daeURI uri(*fa);
			uri.set("", "", "", "", fa->getId());
			acc->setSource( uri );

			domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "x" );
			param->setType( "float" );
			param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "y" );
			param->setType( "float" );
			param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "z" );
			param->setType( "float" );

			verts = daeSafeCast<domVertices>(colladaMesh->createAndPlace(COLLADA_ELEMENT_VERTICES));
			sprintf (text, "%sVertices", geometry->m_name);
			verts->setId (text);
			domInputLocal *inputLocal = daeSafeCast<domInputLocal>(verts->createAndPlace(COLLADA_ELEMENT_INPUT));
			inputLocal->setSemantic (COMMON_PROFILE_INPUT_POSITION);
			daeURI uri1(*posSource);
			uri1.set("", "", "", "", posSource->getId());
			inputLocal->setSource (uri1);

			delete[] floatPool;
		}


		for (dMesh::dListNode* node = geometry->GetFirst(); node; node = node->GetNext()) {
			char texName[256];
			char materialName[256];
			domTriangles *polys1;
			domInputLocalOffset *input;

			const dSubMesh& subMesh = node->GetInfo();
			geometry->GetTextureName(&subMesh, texName);
			sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME, dCRC (texName));

			polys1 = daeSafeCast<domTriangles>(colladaMesh->createAndPlace(COLLADA_ELEMENT_TRIANGLES));
			polys1->setCount (subMesh.m_indexCount / 3);
			polys1->setMaterial (materialName);

			input = daeSafeCast<domInputLocalOffset>(polys1->createAndPlace(COLLADA_ELEMENT_INPUT ));
			input->setSemantic( COMMON_PROFILE_INPUT_VERTEX);
			input->setOffset (0);
			daeURI uri (*verts);
			uri.set("", "", "", "", verts->getId());
			input->setSource (uri);

//			input = daeSafeCast<domInputLocalOffset>(polys1->createAndPlace(COLLADA_ELEMENT_INPUT));
//			input->setSemantic( COMMON_PROFILE_INPUT_NORMAL );
//			input->setOffset (1);
//			daeURI uri1 (*normalSrc);
//			uri1.set("", "", "", "", normalSrc->getId());
//			input->setSource (uri1);

//			input = daeSafeCast<domInputLocalOffset>(polys1->createAndPlace(COLLADA_ELEMENT_INPUT));
//			input->setSemantic (COMMON_PROFILE_INPUT_TEXCOORD);
//			input->setOffset (2);
//			input->setSet (0);
//			daeURI uri2 (*uvSource);
//			uri2.set("", "", "", "", uvSource->getId());
//			input->setSource (uri2);

			domP *p = daeSafeCast<domP>(polys1->createAndPlace(COLLADA_ELEMENT_P));
			domListOfUInts &indices = p->getValue();
			for (int i = 0; i < subMesh.m_indexCount; i ++) {
				int index = subMesh.m_indexes[i];
				indices.append (vertexArrayIndexList[index]);
			}
		}

		delete[] vertexArrayIndexList;

		return collGeometry;
	}



	domGeometry *AddGeometry (daeDocument* document, const dMesh* geometry)
	{
		domLibrary_geometries *library;

		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		if (domRoot->getLibrary_geometries_array().getCount()) {
			library = domRoot->getLibrary_geometries_array()[0];
		} else {
			library = daeSafeCast<domLibrary_geometries>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_GEOMETRIES));
		}
		_ASSERTE (library);

		domGeometry *collGeometry = daeSafeCast<domGeometry>(library->createAndPlace(COLLADA_ELEMENT_GEOMETRY ));

		char meshName[256];
		geometry->GetName(meshName);
		collGeometry->setId(meshName);
		domMesh *colladaMesh = daeSafeCast<domMesh>(collGeometry->createAndPlace(COLLADA_ELEMENT_MESH ));

		domVertices *verts;
		int* vertexArrayIndexList = new int[geometry->m_vertexCount];
		{
			// add the vertices
			char text[256];
			int vertexCount;
			domSource *posSource;
			float* floatPool = new float[geometry->m_vertexCount * 3];

			posSource = daeSafeCast<domSource>(colladaMesh->createAndPlace(COLLADA_ELEMENT_SOURCE));
			sprintf (text, "%s_position", meshName);
			posSource->setId (text);

			for (int i = 0; i < geometry->m_vertexCount; i ++) {
				floatPool[i * 3 + 0] = m_scale * geometry->m_vertex[i * 3 + 0];
				floatPool[i * 3 + 1] = m_scale * geometry->m_vertex[i * 3 + 1];
				floatPool[i * 3 + 2] = m_scale * geometry->m_vertex[i * 3 + 2];
			}

			vertexCount = dModel::PackVertexArray (floatPool, 3, 3 * sizeof (dFloat), geometry->m_vertexCount, vertexArrayIndexList);
			m_globalRotation.TransformTriplex(floatPool, sizeof (float) * 3, floatPool, sizeof (float) * 3, geometry->m_vertexCount);

			domFloat_array *fa = daeSafeCast<domFloat_array>(posSource->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
			strcat (text, "Array");
			fa->setId( text );
			fa->setCount (vertexCount * 3);

			domListOfFloats &posSrcArray = fa->getValue();
			for (int i = 0; i < vertexCount; i ++) {
				posSrcArray.append3( floatPool[i * 3 + 0], floatPool[i * 3 + 1], floatPool[i * 3 + 2]);
			}

			//create the accessor
			domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(posSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
			acc->setCount (vertexCount);
			acc->setStride (3);
			daeURI uri(*fa);
			uri.set("", "", "", "", fa->getId());
			//uri.setElement (fa);
			//uri.resolveURI();
			acc->setSource( uri );

			domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "x" );
			param->setType( "float" );
			param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "y" );
			param->setType( "float" );
			param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "z" );
			param->setType( "float" );


			verts = daeSafeCast<domVertices>(colladaMesh->createAndPlace(COLLADA_ELEMENT_VERTICES));
			sprintf (text, "%sVertices", geometry->m_name);
			verts->setId (text);
			domInputLocal *inputLocal = daeSafeCast<domInputLocal>(verts->createAndPlace(COLLADA_ELEMENT_INPUT));
			inputLocal->setSemantic (COMMON_PROFILE_INPUT_POSITION);
			//uri.setElement (posSource);
			daeURI uri1(*posSource);
			uri1.set("", "", "", "", posSource->getId());
			//uri.resolveURI();
			inputLocal->setSource (uri1);

			delete[] floatPool;
		}


		domSource *normalSrc;
		int* normalArrayIndexList = new int[geometry->m_vertexCount];
		{
			char text[256];
			int vertexCount;
			float* floatPool = new float[geometry->m_vertexCount * 3];

			normalSrc = daeSafeCast<domSource>(colladaMesh->createAndPlace(COLLADA_ELEMENT_SOURCE));
			sprintf (text, "%s_normal", meshName);
			normalSrc->setId (text);

			for (int i = 0; i < geometry->m_vertexCount; i ++) {
				floatPool[i * 3 + 0] = geometry->m_normal[i * 3 + 0];
				floatPool[i * 3 + 1] = geometry->m_normal[i * 3 + 1];
				floatPool[i * 3 + 2] = geometry->m_normal[i * 3 + 2];
			}
			vertexCount = dModel::PackVertexArray (floatPool, 3, 3 * sizeof (dFloat), geometry->m_vertexCount, normalArrayIndexList);
			dMatrix rot (m_globalRotation);
			rot.m_posit = dVector (0.0f, 0.0f, 0.0f, 1.0f);
			rot.TransformTriplex(floatPool, sizeof (float) * 3, floatPool, sizeof (float) * 3, geometry->m_vertexCount);

			domFloat_array *fa = daeSafeCast<domFloat_array>(normalSrc->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
			strcat (text, "Array");
			fa->setId (text);
			fa->setCount (vertexCount * 3);

			domListOfFloats &posSrcArray = fa->getValue();
			for (int i = 0; i < vertexCount; i ++) {
				posSrcArray.append3( floatPool[i * 3 + 0], floatPool[i * 3 + 1], floatPool[i * 3 + 2]);
			}

			//create the accessors
			domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(normalSrc->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
			acc->setCount (vertexCount);
			acc->setStride (3);
			daeURI uri(*fa);
			uri.set("", "", "", "", fa->getId());
			//uri.setElement (fa);
			//uri.resolveURI();
			acc->setSource( uri );

			domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "x" );
			param->setType( "float" );
			param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "y" );
			param->setType( "float" );
			param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "z" );
			param->setType( "float" );

			delete[] floatPool;
		}

		domSource *uvSource;
		int* uv0ArrayIndexList = new int[geometry->m_vertexCount];
		{
			char text[256];
			int vertexCount;
			float* floatPool = new float[geometry->m_vertexCount * 3];

			uvSource = daeSafeCast<domSource>(colladaMesh->createAndPlace(COLLADA_ELEMENT_SOURCE));
			sprintf (text, "%s_uv", meshName);
			uvSource->setId (text);
			for (int i = 0; i < geometry->m_vertexCount; i ++) {
				floatPool[i * 3 + 0] = geometry->m_uv[i * 2 + 0];
				floatPool[i * 3 + 1] = geometry->m_uv[i * 2 + 1];
				floatPool[i * 3 + 2] = 0.0f;
			}
			vertexCount = dModel::PackVertexArray (floatPool, 3, 3 * sizeof (dFloat), geometry->m_vertexCount, uv0ArrayIndexList);

			domFloat_array *fa = daeSafeCast<domFloat_array>(uvSource->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
			strcat (text, "Array");
			fa->setId (text);
			fa->setCount(vertexCount * 2);
			domListOfFloats &posSrcArray = fa->getValue();
			for (int i = 0; i < vertexCount; i ++) {
				posSrcArray.append2( floatPool[i * 3 + 0], floatPool[i * 3 + 1]);
			}

			domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(uvSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
			acc->setCount (vertexCount);
			acc->setStride( 2 );
			daeURI uri(*fa);
			uri.set("", "", "", "", fa->getId());
			//uri.setElement( fa );
			//uri.resolveURI();
			acc->setSource( uri );

			domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "s" );
			param->setType( "float" );
			param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName( "t" );
			param->setType( "float" );

			delete[] floatPool;
		}

		for (dMesh::dListNode* node = geometry->GetFirst(); node; node = node->GetNext()) {
			char texName[256];
			char materialName[256];
			domTriangles *polys1;
			domInputLocalOffset *input;


			const dSubMesh& subMesh = node->GetInfo();
//			sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME, dCRC (subMesh.m_textureName));
			geometry->GetTextureName(&subMesh, texName);
			sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME, dCRC (texName));

			polys1 = daeSafeCast<domTriangles>(colladaMesh->createAndPlace(COLLADA_ELEMENT_TRIANGLES));
			polys1->setCount (subMesh.m_indexCount / 3);
			polys1->setMaterial (materialName);


			input = daeSafeCast<domInputLocalOffset>(polys1->createAndPlace(COLLADA_ELEMENT_INPUT ));
			input->setSemantic( COMMON_PROFILE_INPUT_VERTEX );
			input->setOffset( 0 );
			daeURI uri (*verts);
			uri.set("", "", "", "", verts->getId());
			//uri.setElement (verts);
			//uri.resolveURI();
			input->setSource (uri);


			input = daeSafeCast<domInputLocalOffset>(polys1->createAndPlace(COLLADA_ELEMENT_INPUT));
			input->setSemantic( COMMON_PROFILE_INPUT_NORMAL );
			input->setOffset (1);
			daeURI uri1 (*normalSrc);
			uri1.set("", "", "", "", normalSrc->getId());
			//uri.setElement (normalSrc);
			//uri.resolveURI();
			input->setSource (uri1);

			input = daeSafeCast<domInputLocalOffset>(polys1->createAndPlace(COLLADA_ELEMENT_INPUT));
			input->setSemantic (COMMON_PROFILE_INPUT_TEXCOORD);
			input->setOffset (2);
			//			input->setSet (1);
			input->setSet (0);
			daeURI uri2 (*uvSource);
			uri2.set("", "", "", "", uvSource->getId());
			//uri.setElement (uvSource);
			//uri.resolveURI();
			input->setSource (uri2);

			domP *p = daeSafeCast<domP>(polys1->createAndPlace(COLLADA_ELEMENT_P));
			domListOfUInts &indices = p->getValue();
			for (int i = 0; i < subMesh.m_indexCount; i ++) {
				int index = subMesh.m_indexes[i];
				indices.append3 (vertexArrayIndexList[index], normalArrayIndexList[index], uv0ArrayIndexList[index]);
			}
		}

		delete[] uv0ArrayIndexList;
		delete[] normalArrayIndexList;
		delete[] vertexArrayIndexList;

		return collGeometry;
	}


	void AddGeometryLibrary (daeDocument* document, const dModel* model)
	{
		for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) { 
			dMeshInstance& instance = node->GetInfo();
			if (!instance.IsIntance()) {
				dMesh* mesh = node->GetInfo().m_mesh;
				domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
				if (domRoot->getLibrary_geometries_array().getCount()) {
					domLibrary_geometries *library = domRoot->getLibrary_geometries_array()[0];
					char meshName[256];
					//sprintf (meshName, "%s", mesh->GetName());
					mesh->GetName(meshName);
					if (!FindGeometry (library, meshName)) {
						AddGeometry (document, mesh);
					}

				} else {
					AddGeometry (document, mesh);
				}
			}
		}
	}


	void AddAnimation (daeDocument* document, dAnimationClip* clip, const dModel* model)
	{
		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());

		if (!domRoot->getLibrary_animations_array().getCount()) {
			daeSafeCast<domLibrary_animations>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_ANIMATIONS));
		}

		domLibrary_animations *library = domRoot->getLibrary_animations_array()[0];
		_ASSERTE (library);

		domAnimation *animation = daeSafeCast<domAnimation>(library->createAndPlace(COLLADA_ELEMENT_ANIMATION ));

		char nameID[256];
		sprintf (nameID, "%s_anim", clip->m_name);							
		animation->setId(nameID);
		animation->setName(clip->m_name);

		for (dAnimationClip::dListNode* node = clip->GetFirst(); node; node = node->GetNext()) {
			char text[256];

			dKeyFrames* track = &node->GetInfo();
			domSource *timeSource = daeSafeCast<domSource>(animation->createAndPlace(COLLADA_ELEMENT_SOURCE));
			{
				sprintf (text, "%s_anim_time", track->m_bindName);
				timeSource->setId (text);
				domFloat_array *fa = daeSafeCast<domFloat_array>(timeSource->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
				strcat (text, "Array");
				fa->setId (text);
				fa->setCount (track->m_keyFrameCounts);
				domListOfFloats &posSrcArray = fa->getValue();
				for (int i = 0; i < track->m_keyFrameCounts; i ++) {
					posSrcArray.append(track->m_keys[i]);
				}

				//create the accessor
				domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(timeSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
				domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
				acc->setCount (track->m_keyFrameCounts);
				acc->setStride (1);
				daeURI uri(*fa);
				uri.set("", "", "", "", fa->getId());
				acc->setSource( uri );

				domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
				param->setName( "key" );
				param->setType( "float" );
			}


			domSource *transfromSource = daeSafeCast<domSource>(animation->createAndPlace(COLLADA_ELEMENT_SOURCE));
			{
				sprintf (text, "%s_anim_transform", track->m_bindName);
				transfromSource->setId (text);
				domFloat_array *fa = daeSafeCast<domFloat_array>(transfromSource->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
				strcat (text, "Array");
				fa->setId (text);
				fa->setCount (track->m_keyFrameCounts * 16);
				domListOfFloats &posSrcArray = fa->getValue();
				for (int i = 0; i < track->m_keyFrameCounts; i ++) {
					dMatrix matrix (track->m_rotation[i], track->m_posit[i]);
					matrix.m_posit = matrix.m_posit.Scale (m_scale);
					matrix.m_posit.m_w = 1.0f;
					matrix = (m_globalRotation.Inverse() * matrix * m_globalRotation);
					for (int j = 0; j < 4; j ++) {
						for (int k = 0; k < 4; k ++) {
							posSrcArray.append(matrix[k][j]);
						}
					}
				}

				//create the accessor
				domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(transfromSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
				domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
				acc->setCount (track->m_keyFrameCounts);
				acc->setStride (16);
				daeURI uri(*fa);
				uri.set("", "", "", "", fa->getId());
				acc->setSource( uri );

				domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
				param->setName( "matrix" );
				param->setType( "float4x4" );
			}

			domSource *interpSource = daeSafeCast<domSource>(animation->createAndPlace(COLLADA_ELEMENT_SOURCE));
			{
				sprintf (text, "%s_anim_transform_intepolation", track->m_bindName);
				interpSource->setId (text);

				domName_array *interpNames = daeSafeCast<domName_array>(interpSource->createAndPlace(COLLADA_ELEMENT_NAME_ARRAY));
				strcat (text, "Array");
				interpNames->setId (text);
				interpNames->setCount (track->m_keyFrameCounts);
				domListOfNames &srcArray = interpNames->getValue();
				for (int i = 0; i < track->m_keyFrameCounts; i ++) {
					const char* name = "LINEAR";
					srcArray.append(name);
				}

				//create the accessor
				domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(interpSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
				domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
				acc->setCount (track->m_keyFrameCounts);
				acc->setStride (1);
				daeURI uri (*interpNames);
				uri.set("", "", "", "", interpNames->getId());
				acc->setSource (uri);
				domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
				param->setName( "interpolation" );
				param->setType( "name" );
			}

			domSampler *sampler = daeSafeCast<domSampler>(animation->createAndPlace(COLLADA_ELEMENT_SAMPLER));
			sprintf (text, "%s_anim_sample", track->m_bindName);
			sampler->setId (text);

			domInputLocal *inputLocal = daeSafeCast<domInputLocal>(sampler->createAndPlace(COLLADA_ELEMENT_INPUT));
			inputLocal->setSemantic (COMMON_PROFILE_INPUT_INPUT);
			daeURI uri0 (*timeSource);
			uri0.set("", "", "", "", timeSource->getId());
			inputLocal->setSource (uri0);

			inputLocal = daeSafeCast<domInputLocal>(sampler->createAndPlace(COLLADA_ELEMENT_INPUT));
			inputLocal->setSemantic (COMMON_PROFILE_INPUT_OUTPUT);
			daeURI uri1 (*transfromSource);
			uri1.set("", "", "", "", transfromSource->getId());
			inputLocal->setSource (uri1);

			inputLocal = daeSafeCast<domInputLocal>(sampler->createAndPlace(COLLADA_ELEMENT_INPUT));
			inputLocal->setSemantic (COMMON_PROFILE_INPUT_INTERPOLATION);
			daeURI uri2 (*interpSource);
			uri2.set("", "", "", "", interpSource->getId());
			inputLocal->setSource (uri2);


			domChannel *channel = daeSafeCast<domChannel>(animation->createAndPlace(COLLADA_ELEMENT_CHANNEL));
			daeURI uri3 (*sampler);
			uri3.set("", "", "", "", sampler->getId());
			channel->setSource (uri3);
			sprintf (text, "%s%s", D_NODE_NAME,track->m_bindName);
			channel->setTarget (text);
		}
	}


	void AddAnimationLibrary(daeDocument* document, const dModel* model)
	{
		for (dList<dAnimationClip*>::dListNode* node = model->m_animations.GetFirst(); node; node = node->GetNext()) { 
			dAnimationClip* clip = node->GetInfo();
			domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
			if (domRoot->getLibrary_animations_array().getCount()) {
				domLibrary_animations *library = domRoot->getLibrary_animations_array()[0];
				if (!FindAnimation (library, clip->m_name)) {
					AddAnimation (document, clip, model);
				}

			} else {
				AddAnimation (document, clip, model);
			}
		}
	}



	void AddController (daeDocument* document, dMeshInstance* meshInstance, const dModel* model)
	{
		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		if (!domRoot->getLibrary_controllers_array().getCount()) {
			daeSafeCast<domLibrary_geometries>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_CONTROLLERS));
		}
		domLibrary_controllers *controllerLibrary = domRoot->getLibrary_controllers_array()[0];
		_ASSERTE (controllerLibrary);

		domLibrary_geometries *geometryLibrary = domRoot->getLibrary_geometries_array()[0];
		_ASSERTE (geometryLibrary);
		
		const dMesh* mesh = meshInstance->m_mesh;
		dSkinModifier* skinData = (dSkinModifier*) meshInstance->GetModifier();
		const dBone** boneList = skinData->m_skinnedBones;
		dMatrix* bindingMatrices = skinData->m_bindingMatrices;

		domController *controller = daeSafeCast<domController>(controllerLibrary->createAndPlace(COLLADA_ELEMENT_CONTROLLER ));

		
		char text[256];
		char meshName[256];
//		const char* meshName = meshInstance->m_mesh->GetName(mesh);
		mesh->GetName(meshName);
		sprintf (text, "%s%s", meshName, D_SKIN_POS_FIX);
		controller->setId(text);

		domSkin* skin = daeSafeCast<domSkin>(controller->createAndPlace(COLLADA_TYPE_SKIN));

		domGeometry* geoSource = NULL;
		const domGeometry_Array& array = geometryLibrary->getGeometry_array();
		for (int i = 0; i < int (array.getCount()); i ++) {
			geoSource = array[i];
			if (!cdom::strcasecmp (meshName, geoSource->getId())) {
				break;
			}
		}

		daeURI uri (*geoSource);
		uri.set("", "", "", "", geoSource->getId());
		skin->setSource (uri);

		domSkin::domBind_shape_matrix* bindMatrix;
		bindMatrix = daeSafeCast<domSkin::domBind_shape_matrix>(skin->createAndPlace(COLLADA_TYPE_BIND_SHAPE_MATRIX));
		domFloat4x4& value = bindMatrix->getValue();
		value.setCount(16);
		dMatrix matrix (skinData->m_shapeBindMatrix);
		matrix = m_globalRotation.Inverse() * matrix * m_globalRotation;
		matrix.m_posit = matrix.m_posit.Scale (m_scale);
		for (int j = 0; j < 4; j ++) {
			for (int i = 0; i < 4; i ++) {
				value[j * 4 + i] = matrix[i][j];
			}
		}

		domSource *boneSource;
		domSource *bindSource;
		domSource *weightsSource;
		int* weightsIndexMap = new int[mesh->m_vertexCount * 4];
		{
			char text[256];
			bindSource = daeSafeCast<domSource>(skin->createAndPlace(COLLADA_ELEMENT_SOURCE));
			sprintf (text, "%s_bindpose", meshName);
			bindSource->setId (text);

			domFloat_array *boneMatrix = daeSafeCast<domFloat_array>(bindSource->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
			strcat (text, "Array");
			boneMatrix->setId (text);
			boneMatrix->setCount (skinData->m_bonesCount * 16);
			domListOfFloats &boneSrcArray = boneMatrix->getValue();
			for (int i = 0; i < skinData->m_bonesCount; i ++) {
				dMatrix matrix (bindingMatrices[i]);
//				matrix = matrix.Transpose4X4();
				matrix = m_globalRotation.Inverse() * matrix * m_globalRotation;
				matrix.m_posit = matrix.m_posit.Scale (m_scale);
//				float* data = &matrix[0][0];
//				for (int j = 0; j < 16; j ++) {
//					boneSrcArray.append(data[j]);
//				}
				for (int j = 0; j < 4; j ++) {
					for (int i = 0; i < 4; i ++) {
						boneSrcArray.append (matrix[i][j]);
					}
				}
			}

			//create the accessor
			domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(bindSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
			acc->setCount (skinData->m_bonesCount);
			acc->setStride (16);
//			uri.setElement (bindSource);
			daeURI uri (*boneMatrix);
//			uri.resolveURI();
			uri.set("", "", "", "", boneMatrix->getId());
			acc->setSource (uri);
			domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName ("bindMatrix");
			param->setType ("float4x4");
		}


		{
			char text[256];

			boneSource = daeSafeCast<domSource>(skin->createAndPlace(COLLADA_ELEMENT_SOURCE));
			sprintf (text, "%s_bones", meshName);
			boneSource->setId (text);

			domName_array *boneNames = daeSafeCast<domName_array>(boneSource->createAndPlace(COLLADA_ELEMENT_NAME_ARRAY));
			strcat (text, "Array");
			boneNames->setId (text);
			boneNames->setCount (skinData->m_bonesCount);
			domListOfNames &boneSrcArray = boneNames->getValue();
			for (int i = 0; i < skinData->m_bonesCount; i ++) {
				const char* name = boneList[i]->GetName();
				boneSrcArray.append(name);
			}

			//create the accessor
			domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(boneSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
			acc->setCount (skinData->m_bonesCount);
			acc->setStride (1);
//			uri.setElement (boneNames);
			daeURI uri (*boneNames);
//			uri.resolveURI();
			uri.set("", "", "", "", boneNames->getId());
			acc->setSource (uri);
			domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName ("bone");
			param->setType ("Name");
		}

		{
			char text[256];
			weightsSource = daeSafeCast<domSource>(skin->createAndPlace(COLLADA_ELEMENT_SOURCE));
			sprintf (text, "%s_weights", meshName);
			weightsSource->setId (text);

			dVector* weightData = new dVector [mesh->m_vertexCount * 4];
			for (int i = 0; i < mesh->m_vertexCount; i ++) {
				for (int j = 0; j < 4; j ++) {
					weightData[i * 4 + j].m_x = skinData->m_vertexWeight[i][j];
					weightData[i * 4 + j].m_y = 0.0f;
					weightData[i * 4 + j].m_z = 0.0f;
				}
			}
			int indexCount = dModel::PackVertexArray (&weightData[0].m_x, 3, sizeof (dVector), mesh->m_vertexCount * 4, weightsIndexMap);

			domFloat_array *weights = daeSafeCast<domFloat_array>(weightsSource->createAndPlace(COLLADA_ELEMENT_FLOAT_ARRAY));
			strcat (text, "Array");
			weights->setId (text);
			weights->setCount (indexCount);
			domListOfFloats &weightsSrcArray = weights->getValue();
			for (int i = 0; i < indexCount; i ++) {
				weightsSrcArray.append(weightData[i].m_x);
			}
			delete[] weightData;

			//create the accessor
			domSource::domTechnique_common *srcTeqC = daeSafeCast<domSource::domTechnique_common>(weightsSource->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domAccessor *acc = daeSafeCast<domAccessor>(srcTeqC->createAndPlace(COLLADA_ELEMENT_ACCESSOR));
			acc->setCount (indexCount);
			acc->setStride (1);
//			uri.setElement (weightsSource);
			daeURI uri (*weights);
//			uri.resolveURI();
			uri.set("", "", "", "", weights->getId());
			acc->setSource (uri);
			domParam *param = daeSafeCast<domParam>(acc->createAndPlace(COLLADA_ELEMENT_PARAM));
			param->setName ("weight");
			param->setType ("float");
		}


		domSkin::domJoints *joints = daeSafeCast<domSkin::domJoints>(skin->createAndPlace(COLLADA_ELEMENT_JOINTS));
		domInputLocal *inputLocal = daeSafeCast<domInputLocal>(joints->createAndPlace(COLLADA_ELEMENT_INPUT));
		inputLocal->setSemantic (COMMON_PROFILE_INPUT_JOINT);
//		uri.setElement (boneSource);
		daeURI uri0 (*boneSource);
//		uri.resolveURI();
		uri0.set("", "", "", "", boneSource->getId());
		inputLocal->setSource (uri0);

		inputLocal = daeSafeCast<domInputLocal>(joints->createAndPlace(COLLADA_ELEMENT_INPUT));
		inputLocal->setSemantic (COMMON_PROFILE_INPUT_INV_BIND_MATRIX);
//		uri.setElement (bindSource);
		daeURI uri1 (*bindSource);
//		uri.resolveURI();
		uri1.set("", "", "", "", bindSource->getId());
		inputLocal->setSource (uri1);


		domSkin::domVertex_weights *vertexWeights = daeSafeCast<domSkin::domVertex_weights>(skin->createAndPlace(COLLADA_ELEMENT_VERTEX_WEIGHTS));
		domInputLocalOffset* localInputOffset = daeSafeCast<domInputLocalOffset>(vertexWeights->createAndPlace(COLLADA_ELEMENT_INPUT));
		localInputOffset->setSemantic (COMMON_PROFILE_INPUT_JOINT);
		localInputOffset->setOffset (0);
//		uri.setElement (boneSource);
		daeURI uri2 (*boneSource);
//		uri.resolveURI();
		uri2.set("", "", "", "", boneSource->getId());
		localInputOffset->setSource (uri2);

		localInputOffset = daeSafeCast<domInputLocalOffset>(vertexWeights->createAndPlace(COLLADA_ELEMENT_INPUT));
		localInputOffset->setSemantic (COMMON_PROFILE_INPUT_WEIGHT);
		localInputOffset->setOffset (1);
//		uri.setElement (weightsSource);
		daeURI uri3 (*weightsSource);
//		uri.resolveURI();
		uri3.set("", "", "", "", weightsSource->getId());
		localInputOffset->setSource (uri3);


		int* vertexArrayIndexList = new int[mesh->m_vertexCount];
		dVector* floatPool = new dVector[mesh->m_vertexCount];
		for (int i = 0; i < mesh->m_vertexCount; i ++) {
			floatPool[i] = dVector (mesh->m_vertex[i * 3 + 0], mesh->m_vertex[i * 3 + 1], mesh->m_vertex[i * 3 + 2], dFloat(i));
		}
		int vertexCount = dModel::PackVertexArray (&floatPool[0].m_x, 3, sizeof (dVector), mesh->m_vertexCount, vertexArrayIndexList);

		vertexWeights->setCount(vertexCount);
		domSkin::domVertex_weights::domV *v;
		domSkin::domVertex_weights::domVcount *vCount;
		v = daeSafeCast<domSkin::domVertex_weights::domV>(vertexWeights->createAndPlace(COLLADA_ELEMENT_V));
		vCount = daeSafeCast<domSkin::domVertex_weights::domVcount>(vertexWeights->createAndPlace(COLLADA_ELEMENT_VCOUNT));

		domListOfInts &vIndices = v->getValue();
		domListOfUInts &vCountIndices = vCount->getValue();
//		for (int i = 0; i < mesh->m_vertexCount; i ++) {
		for (int i = 0; i < vertexCount; i ++) {
			int index;
			index = int (floatPool[i].m_w);
			int count = 0;
			for (int j = 0; j < 4; j ++) {
				count += (skinData->m_vertexWeight[index][j] > 0.0f) ? 1 : 0;
			}
			vCountIndices.append(count);

			for (int j = 0; j < count; j ++) {
				int boneIndex = skinData->m_boneWeightIndex[index].m_index[j];
				vIndices.append(boneIndex);
				vIndices.append(weightsIndexMap[index * 4 + j]);
			}
		}

		delete[] floatPool; 
		delete[] vertexArrayIndexList;
		delete[] weightsIndexMap;
	}


	void AddControllerLibrary(daeDocument* document, const dModel* model)
	{
		for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) { 
			dMeshInstance& instance = node->GetInfo();
			if (instance.m_modifier) {
//				dMesh* mesh = node->GetInfo().m_mesh;
				AddController (document, &instance, model);
			}
		}
	}


	

	domNode *AddNodes(daeDocument* document, dBone* rootNode, daeElement *parent, const dModel* model, dTree<unsigned, unsigned>& uniqueNameFilter)
	{
		char name[256];

		if (rootNode->GetName()[0]) {
			sprintf (name, "%s%s", D_NODE_NAME, rootNode->GetName());
		} else {
			sprintf (name, "%s%04d", D_NODE_NAME, m_nodeIndex);
			m_nodeIndex ++;
		}


		domNode *tmChild = daeSafeCast<domNode>(parent->createAndPlace(COLLADA_ELEMENT_NODE));

		char uniqueName[256];
		strcpy (uniqueName, name);
		for (int i = 0; uniqueNameFilter.Find(dCRC (uniqueName)); i ++) {
			sprintf (uniqueName, "%s%03d", name, i);
		}
		int n = 0;
		uniqueNameFilter.Insert(n, dCRC (uniqueName));

//		dTree<domNode *, domNode *>& uniqueNameFilter
		tmChild->setId (uniqueName);
		tmChild->setSid(rootNode->GetName());
		tmChild->setType ((rootNode->GetType() == dBone::m_bone) ? NODETYPE_JOINT : NODETYPE_NODE);


	// add this node to the map
	//		domInstance_camera* cameraIntance;
	//		m_visualNodeMap.Insert (tmChild, mesh);
	//	if this is a camera node add the camera instance
	//		if ((mesh == m_cameraNode) && m_collCamera) {
	//			cameraIntance = daeSafeCast<domInstance_camera>(tmChild->createAndPlace(COLLADA_ELEMENT_INSTANCE_CAMERA));
	//			uri.setElement (m_collCamera);
	//			uri.resolveURI();
	//			cameraIntance->setUrl (uri);
	//		}

		dMatrix matrix (m_globalRotation.Inverse() * rootNode->GetMatrix() * m_globalRotation);

		domTranslate* position = daeSafeCast<domTranslate>(tmChild->createAndPlace(COLLADA_ELEMENT_TRANSLATE));
		domFloat3& positValue = position->getValue();
		positValue.setCount(3);
		positValue[0] = matrix.m_posit.m_x * m_scale;
		positValue[1] = matrix.m_posit.m_y * m_scale;
		positValue[2] = matrix.m_posit.m_z * m_scale;

		domRotate* rotation = daeSafeCast<domRotate>(tmChild->createAndPlace(COLLADA_ELEMENT_ROTATE));
		domFloat4& rotateValue = rotation->getValue();
		rotateValue.setCount(4);
		dQuaternion rot (matrix);
		dVector dir (rot.m_q1, rot.m_q2, rot.m_q3, 0.0f);
		float mag2 = dir % dir;
		if (mag2 > 1.0e-6f) {
			dir = dir.Scale (1.0f / dSqrt (mag2));
		} else {
			dir = dVector (1.0f, 0.0f, 0.0f, 0.0f);
		}
		rotateValue[0] = dir.m_x;
		rotateValue[1] = dir.m_y;
		rotateValue[2] = dir.m_z;
		rotateValue[3] = (2.0f * dAcos (rot.m_q0)) * (180.0f / 3.14159265f);

//		dMesh* mesh;
//		mesh = model->FindMesh(rootNode->GetName());
//		if (mesh) {
//			if (mesh->GetType() == dMesh::D_STATIC_MESH) {
//				AddMeshInstance (document, tmChild, mesh);
//			} else {
//				AddControllerInstance (document, tmChild, mesh);
//			}
//		}

		for (dBone* ptr = rootNode->GetChild(); ptr; ptr = ptr->GetSibling()) {
			AddNodes(document, ptr, tmChild, model, uniqueNameFilter);
		}

		return tmChild;
	}


	domNode* FindNodeNodeByName (domNode *root, const char* name)
	{
		int count;
		char nodeName[256];
		domNode* array[1024];

		
		sprintf (nodeName, "%s%s", D_NODE_NAME, name);
		int lenght = int (strlen (nodeName));
		count = 1;
		array[0] = root;
		while (count) {
			domNode* node;
			count --;

			node = array[count];
			if (!strncmp (nodeName, node->getId(), lenght)) {
				return node;
			}

			daeTArray<daeSmartRef<daeElement> > nodes;
			node->getChildren (nodes);
			for (int i = 0; i < int (nodes.getCount()); i ++) {
				daeElement* data = nodes[i];
				if (data->getElementType() == COLLADA_TYPE::NODE) {
					array[count] = (domNode*) data;
					count ++;
				}
			}
		}
		return NULL;
	}


	void AddMeshInstance (daeDocument* document, daeElement *node, dMesh* mesh)
	{
		int geometryCount;
		domCOLLADA *domRoot;
		domLibrary_materials *materialLibrary;
		domLibrary_geometries *geometryLibrary;

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		materialLibrary = domRoot->getLibrary_materials_array()[0];
		geometryLibrary = domRoot->getLibrary_geometries_array()[0];
		const domGeometry_Array &geometryArray =  geometryLibrary->getGeometry_array();
		geometryCount = int (geometryArray.getCount());

		for (int i = 0; i < geometryCount; i ++) {
			char name[256];
			domGeometry *meshGeometry;
			meshGeometry = geometryArray[i];

			mesh->GetName(name);
			if (!cdom::strcasecmp (meshGeometry->getId(), name)) {

				domInstance_geometry *meshInstance = daeSafeCast<domInstance_geometry>(node->createAndPlace(COLLADA_ELEMENT_INSTANCE_GEOMETRY));
				daeURI uri(*meshGeometry);
				uri.set("", "", "", "", meshGeometry->getId());
				meshInstance->setUrl (uri);

				domMesh *colladaMesh = meshGeometry->getMesh();
				const domTriangles_Array &trianglesArray = colladaMesh->getTriangles_array();
				int polyCount = int (trianglesArray.getCount());

				domBind_material *bindMat = daeSafeCast<domBind_material>(meshInstance->createAndPlace(COLLADA_ELEMENT_BIND_MATERIAL));
				domBind_material::domTechnique_common *bmtc = daeSafeCast<domBind_material::domTechnique_common>(bindMat->createAndPlace (COLLADA_ELEMENT_TECHNIQUE_COMMON));

				for (int j = 0; j < polyCount; j ++) {
					domMaterial* material;
					domTriangles* triangles; 
					domInstance_material *instMat;

					triangles = trianglesArray[j];
					instMat = daeSafeCast<domInstance_material>(bmtc->createAndPlace(COLLADA_ELEMENT_INSTANCE_MATERIAL ));
					material = FindMaterial (materialLibrary, triangles->getMaterial());
					_ASSERTE (material);
					daeURI uri(*material);
					uri.set("", "", "", "", material->getId());
					//uri.setElement (material);
					//uri.resolveURI();
					instMat->setSymbol(triangles->getMaterial());
					instMat->setTarget (uri);
				}
				break;
			}
		}
	}



	void AddControllerInstance (daeDocument* document, domNode *root, domNode *node, dMeshInstance* meshInstance)
	{
		char name[256];
		char meshName[256];
		dMesh* mesh = meshInstance->m_mesh;
		mesh->GetName(meshName);		
//		sprintf (name, "%s_skin", context->GetMeshName (mesh));
		sprintf (name, "%s%s", meshName, D_SKIN_POS_FIX);

		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		domLibrary_controllers *controllerLibrary = domRoot->getLibrary_controllers_array()[0];
		const domController_Array &controllerArray = controllerLibrary->getController_array();

		int controllersCount = int (controllerArray.getCount());
		for (int i = 0; i < controllersCount; i ++) {
			domController *meshController = controllerArray[i];
			if (!cdom::strcasecmp (meshController->getId(), name)) {
				domInstance_controller *controllerInstance = daeSafeCast<domInstance_controller>(node->createAndPlace(COLLADA_ELEMENT_INSTANCE_CONTROLLER));

				daeURI uri (*meshController);
				uri.set("", "", "", "", meshController->getId());
				controllerInstance->setUrl (uri);

				domInstance_controller::domSkeleton* skeleton = daeSafeCast<domInstance_controller::domSkeleton>(controllerInstance->createAndPlace(COLLADA_ELEMENT_SKELETON));

				dBone* modelRootBone = ((dSkinModifier*)meshInstance->GetModifier())->m_skinnedBones[0]->GetRoot();
				domNode* rootBone = FindNodeNodeByName (root, modelRootBone->GetName());
				daeURI uri1 (*rootBone);
				uri1.set("", "", "", "", rootBone->getId());
				skeleton->setValue(uri1);
				
				domLibrary_materials *materialLibrary = domRoot->getLibrary_materials_array()[0];
				domLibrary_geometries *geometryLibrary = domRoot->getLibrary_geometries_array()[0];
				const domGeometry_Array &geometryArray = geometryLibrary->getGeometry_array();
				int geometryCount = int (geometryArray.getCount());

				for (int i = 0; i < geometryCount; i ++) {
					domGeometry *meshGeometry = geometryArray[i];

					if (!cdom::strcasecmp (meshGeometry->getId(), meshName)) {
						domMesh *colladaMesh = meshGeometry->getMesh();
						const domTriangles_Array &trianglesArray = colladaMesh->getTriangles_array();
						int polyCount = int (trianglesArray.getCount());

						domBind_material *bindMat = daeSafeCast<domBind_material>(controllerInstance->createAndPlace(COLLADA_ELEMENT_BIND_MATERIAL));
						domBind_material::domTechnique_common *bmtc = daeSafeCast<domBind_material::domTechnique_common>(bindMat->createAndPlace (COLLADA_ELEMENT_TECHNIQUE_COMMON));

						for (int j = 0; j < polyCount; j ++) {
							domTriangles* triangles = trianglesArray[j];
							domInstance_material *instMat = daeSafeCast<domInstance_material>(bmtc->createAndPlace(COLLADA_ELEMENT_INSTANCE_MATERIAL ));
							domMaterial* material = FindMaterial (materialLibrary, triangles->getMaterial());
							_ASSERTE (material);
							daeURI uri2 (*material);
							uri2.set("", "", "", "", material->getId());
							instMat->setSymbol(triangles->getMaterial());
							instMat->setTarget (uri2);
						}
						break;
					}
				}

				break;
			}
		}
	}



	void AddMeshInstaceToScene(daeDocument* document, daeElement *parent, const dModel* model, dMeshInstance* meshInstance)
	{
//		if (meshInstance->m_mesh->m_hasBone) {
			dBone* bone;
			domNode* node;
			bone = model->FindBone(meshInstance->m_boneID);
			_ASSERTE (bone);
			node = FindNodeNodeByName ((domNode *)parent, bone->GetName());
			_ASSERTE (node);
			if (meshInstance->m_modifier) {
				AddControllerInstance (document, (domNode*) parent, node, meshInstance);
			} else {
				AddMeshInstance (document, node, meshInstance->m_mesh);
			}
//		} else {
//			_ASSERTE (0);
//			dBone tmpBone(NULL);
//			tmpBone.SetMatrix(model->m_matrix);
//			tmpBone.SetNameID(context->GetMeshName(mesh));
//			AddNodes(document, &tmpBone, parent, model, context);
//			node = FindNodeNodeByName ((domNode *)parent, context->GetMeshName(mesh));
//		}
	}


	void AddVisualSceneLibrary (daeDocument* document, dModel* model, 
								dTree<domNode*, dModel*>& nodeMap, dTree<unsigned, unsigned>& uniqueNameFilter)
	{
		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		
			// save skeleton hierarchy 
		if (model->m_skeleton.GetCount()) {
			domLibrary_visual_scenes *library;
			if (!domRoot->getLibrary_visual_scenes_array().getCount()) {
				library = daeSafeCast<domLibrary_visual_scenes>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_VISUAL_SCENES ));
			} else {
				library = domRoot->getLibrary_visual_scenes_array()[0];
			}

			int sceneNumber = int (library->getVisual_scene_array().getCount());
			char sceneName [256];
			sprintf (sceneName, "%svisual%03d", D_ROOT_NODE_NAME, sceneNumber);
			domVisual_scene *scene = daeSafeCast<domVisual_scene>(library->createAndPlace(COLLADA_ELEMENT_VISUAL_SCENE));
			scene->setId (sceneName);

			for (dList<dBone*>::dListNode* node = model->m_skeleton.GetFirst(); node; node = node->GetNext()) {
				dBone* rootNode = node->GetInfo();
				domNode* colNode = AddNodes(document, rootNode, scene, model, uniqueNameFilter);
				nodeMap.Insert (colNode, model);
			}

			// save all mesh referenced by each node
			for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) { 
				AddMeshInstaceToScene(document, scene, model, &node->GetInfo());
			}
		} else {
			if (model->m_meshList.GetCount()) {

				// this is a special case of a model with no bones
				domLibrary_visual_scenes *library;
				if (!domRoot->getLibrary_visual_scenes_array().getCount()) {
					library = daeSafeCast<domLibrary_visual_scenes>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_VISUAL_SCENES ));
				} else {
					library = domRoot->getLibrary_visual_scenes_array()[0];
				}

				int sceneNumber = int (library->getVisual_scene_array().getCount());
				char sceneName [256];
				sprintf (sceneName, "%sVisual%03d", D_ROOT_NODE_NAME, sceneNumber);
				domVisual_scene *scene = daeSafeCast<domVisual_scene>(library->createAndPlace(COLLADA_ELEMENT_VISUAL_SCENE));
				scene->setId (sceneName);

				for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) {

					char name[256];

					node->GetInfo().m_mesh->GetName(name);

					dBone* rootNode = new dBone(NULL);

					int hasBoneState = node->GetInfo().m_mesh->m_hasBone;
					node->GetInfo().m_mesh->m_hasBone = 1;
					//rootNode->SetMatrix(model->m_matrix);
					rootNode->SetMatrix(GetIdentityMatrix());
					rootNode->SetNameID (name);
					rootNode->m_type = dBone::m_sceneNode;
					rootNode->m_boneID = node->GetInfo().m_mesh->m_boneID;

					model->AddSkeleton(rootNode);
					rootNode->Release();

					domNode* colNode = AddNodes(document, rootNode, scene, model, uniqueNameFilter);
					nodeMap.Insert (colNode, model);

					AddMeshInstaceToScene(document, scene, model, &node->GetInfo());
					model->RemoveSkeleton(rootNode);
					node->GetInfo().m_mesh->m_hasBone = hasBoneState;
				}
			}
		}
	}


	void AddOffssetMatrix  (daeElement* parent, const dMatrix& offsetMatrix)
	{
		dMatrix matrix (m_globalRotation * offsetMatrix * m_globalRotation);
		matrix.m_posit = matrix.m_posit.Scale (m_scale);

		dQuaternion rot (matrix);
		dFloat angle = 2.0f * acosf (rot.m_q0);
		dVector dir (rot.m_q1, rot.m_q2, rot.m_q3, 0.0f);

		dFloat mag2 = dir % dir;
		if (mag2 > 1.0e-6f) {
			dir = dir.Scale(1.0f / sqrtf (dir % dir));
		} else {
			dir = dVector (1.0f, 0.0f, 0.0f, 0.0f);
		}

		domTranslate* translation = daeSafeCast<domTranslate>(parent->createAndPlace(COLLADA_ELEMENT_TRANSLATE)); 
		translation->getValue().append (matrix.m_posit.m_x);
		translation->getValue().append (matrix.m_posit.m_y);
		translation->getValue().append (matrix.m_posit.m_z);

		domRotate* rotation = daeSafeCast<domRotate>(parent->createAndPlace(COLLADA_ELEMENT_ROTATE)); 
		rotation->getValue().append (dir.m_x);
		rotation->getValue().append (dir.m_y);
		rotation->getValue().append (dir.m_z);
		rotation->getValue().append (angle * 180.0f / 3.14159265f);
	}

	void ApplyMatrixAligment (dMatrix& matrix)
	{
		matrix = dRollMatrix(-0.5f * 3.14159265f) * matrix;
	}

	void UnapplyMatrixAligment (dMatrix& matrix)
	{
		matrix = dRollMatrix(0.5f * 3.14159265f) * matrix;
	}




//	void AddShape (daeDocument* document, domRigid_body::domTechnique_common* technique, const NewtonBody* newtonBody)
	void AddShape (daeDocument* document, domRigid_body::domTechnique_common* technique, 
				   const NewtonCollision* collision, dTree<domGeometry *, const NewtonCollision*>& shapeCache)
	{
		// get the collision information
		NewtonCollisionInfoRecord collisionInfo;
		NewtonCollisionGetInfo (collision, &collisionInfo);

		domRigid_body::domTechnique_common::domShape *shape = NULL;

		dMatrix& matrix = *((dMatrix*) &collisionInfo.m_offsetMatrix[0][0]);
		switch (collisionInfo.m_collisionType)
		{
			case SERIALIZE_ID_BOX:
			{
				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domBox* box = daeSafeCast<domBox>(shape->createAndPlace(COLLADA_ELEMENT_BOX)); 
				domBox::domHalf_extents* halfExtend = daeSafeCast<domBox::domHalf_extents>(box->createAndPlace(COLLADA_ELEMENT_HALF_EXTENTS)); 

				dVector size (collisionInfo.m_box.m_x, collisionInfo.m_box.m_y, collisionInfo.m_box.m_z, 0.0f);
				size = size.Scale (m_scale * 0.5f);
				halfExtend->getValue().append (size.m_x);
				halfExtend->getValue().append (size.m_y);
				halfExtend->getValue().append (size.m_z);
				break;
			}

			case SERIALIZE_ID_SPHERE:
			{
				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domSphere* sphere = daeSafeCast<domSphere>(shape->createAndPlace(COLLADA_ELEMENT_SPHERE)); 
				domSphere::domRadius* halfExtend = daeSafeCast<domSphere::domRadius>(sphere->createAndPlace(COLLADA_ELEMENT_RADIUS)); 
				halfExtend->setValue(collisionInfo.m_sphere.m_r0 * m_scale);

				domExtra* extra = daeSafeCast<domExtra>(sphere->createAndPlace(COLLADA_ELEMENT_EXTRA));
				domTechnique *extraTechnique = daeSafeCast<domTechnique>(extra->createAndPlace(COLLADA_ELEMENT_TECHNIQUE));
				extraTechnique->setProfile("ellipse");

				daeElement* element = (daeElement*)extraTechnique->createAndPlace( "radios" ); 
				domAny *domExtraExtension = (domAny*)element; 
				char radios[256];
				sprintf (radios, "%f %f %f", collisionInfo.m_sphere.m_r0 * m_scale, collisionInfo.m_sphere.m_r1 * m_scale, collisionInfo.m_sphere.m_r2 * m_scale);
				domExtraExtension->setValue (radios);
				break;
			}

			case SERIALIZE_ID_CAPSULE:
			{
				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domCapsule* capsule = daeSafeCast<domCapsule>(shape->createAndPlace(COLLADA_ELEMENT_CAPSULE)); 

				domCapsule::domHeight* height = daeSafeCast<domCapsule::domHeight>(capsule->createAndPlace(COLLADA_ELEMENT_HEIGHT)); 
				dFloat h = (collisionInfo.m_capsule.m_height * 0.5f - collisionInfo.m_capsule.m_r0) * m_scale;
				height->setValue(h);

				domCapsule::domRadius* radius = daeSafeCast<domCapsule::domRadius>(capsule->createAndPlace(COLLADA_ELEMENT_RADIUS)); 
				radius->getValue().append(collisionInfo.m_capsule.m_r0 * m_scale);
				radius->getValue().append(collisionInfo.m_capsule.m_r1 * m_scale);

				ApplyMatrixAligment (matrix);
				break;
			}


			case SERIALIZE_ID_CONE:
			{
				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domTapered_cylinder* cone = daeSafeCast<domTapered_cylinder>(shape->createAndPlace(COLLADA_ELEMENT_TAPERED_CYLINDER)); 

				domTapered_cylinder::domHeight* height = daeSafeCast<domTapered_cylinder::domHeight>(cone->createAndPlace(COLLADA_ELEMENT_HEIGHT)); 
				height->setValue(collisionInfo.m_cone.m_height * m_scale * 0.5f);

				domTapered_cylinder::domRadius1* radius1 = daeSafeCast<domTapered_cylinder::domRadius1>(cone->createAndPlace(COLLADA_ELEMENT_RADIUS1)); 
				radius1->getValue().append(collisionInfo.m_cone.m_r * m_scale);
				radius1->getValue().append(collisionInfo.m_cone.m_r * m_scale);

				domTapered_cylinder::domRadius2* radius2 = daeSafeCast<domTapered_cylinder::domRadius2>(cone->createAndPlace(COLLADA_ELEMENT_RADIUS2)); 
				radius2->getValue().append(0.0f);
				radius2->getValue().append(0.0f);

				ApplyMatrixAligment (matrix);
				break;
			}

			case SERIALIZE_ID_CYLINDER:
			{
				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domCylinder* cylinder = daeSafeCast<domCylinder>(shape->createAndPlace(COLLADA_ELEMENT_CYLINDER)); 

				domCylinder::domHeight* height = daeSafeCast<domCylinder::domHeight>(cylinder->createAndPlace(COLLADA_ELEMENT_HEIGHT)); 
				height->setValue(collisionInfo.m_cylinder.m_height * m_scale * 0.5f);

				domCylinder::domRadius* radius = daeSafeCast<domCylinder::domRadius>(cylinder->createAndPlace(COLLADA_ELEMENT_RADIUS)); 
				radius->getValue().append(collisionInfo.m_cylinder.m_r0 * m_scale);
				radius->getValue().append(collisionInfo.m_cylinder.m_r0 * m_scale);

				ApplyMatrixAligment (matrix);
				break;
			}

			case SERIALIZE_ID_CHAMFERCYLINDER:
			{
				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domCylinder* cylinder = daeSafeCast<domCylinder>(shape->createAndPlace(COLLADA_ELEMENT_CYLINDER)); 

				domCylinder::domHeight* height = daeSafeCast<domCylinder::domHeight>(cylinder->createAndPlace(COLLADA_ELEMENT_HEIGHT)); 
				height->setValue(collisionInfo.m_chamferCylinder.m_height * m_scale * 0.5);

				domCylinder::domRadius* radius = daeSafeCast<domCylinder::domRadius>(cylinder->createAndPlace(COLLADA_ELEMENT_RADIUS)); 
				radius->getValue().append(collisionInfo.m_chamferCylinder.m_r * m_scale);
				radius->getValue().append(collisionInfo.m_chamferCylinder.m_r * m_scale);

				domExtra* extra = daeSafeCast<domExtra>(cylinder->createAndPlace(COLLADA_ELEMENT_EXTRA));
				domTechnique *extraTechnique = daeSafeCast<domTechnique>(extra->createAndPlace(COLLADA_ELEMENT_TECHNIQUE));
				extraTechnique->setProfile("chamferCylinder");

				ApplyMatrixAligment (matrix);
				break;
			}


			case SERIALIZE_ID_COMPOUND:
			{
				for (int i = 0; i < collisionInfo.m_compoundCollision.m_chidrenCount; i ++) {
					AddShape (document, technique, collisionInfo.m_compoundCollision.m_chidren[i], shapeCache);
				}
				break;
			}


			case SERIALIZE_ID_CONVEXHULL:
			{
				dTree<domGeometry *, const NewtonCollision*>::dTreeNode* node = shapeCache.Find(collision);
				if (!node) {
					// create a helper mesh from the collision collision
					NewtonMesh* newtMesh = NewtonMeshCreateFromCollision(collision);

					char name[256];
					sprintf (name, "convexShape%x", collision);
					dMesh* mesh = new dMesh(name);

					// extract vertex data  from the newton mesh		
					int vertexCount = NewtonMeshGetVertexCount (newtMesh); 
					mesh->AllocVertexData(vertexCount);
					NewtonMeshGetVertexStreams (newtMesh, 3 * sizeof (dFloat), (dFloat*) mesh->m_vertex,
														  3 * sizeof (dFloat), (dFloat*) mesh->m_normal,
														  2 * sizeof (dFloat), (dFloat*) mesh->m_uv, 
														  2 * sizeof (dFloat), (dFloat*) mesh->m_uv);

					// extract the materials index array for mesh
					void* geometryHandle = NewtonMeshBeginHandle (newtMesh); 
					for (int handle = NewtonMeshFirstMaterial (newtMesh, geometryHandle); handle != -1; handle = NewtonMeshNextMaterial (newtMesh, geometryHandle, handle)) {
						//int material = NewtonMeshMaterialGetMaterial (newtMesh, geometryHandle, handle); 
						int indexCount = NewtonMeshMaterialGetIndexCount (newtMesh, geometryHandle, handle); 

						dSubMesh* segment = mesh->AddSubMesh();
						segment->m_textureHandle = 0;

						segment->AllocIndexData (indexCount);
						NewtonMeshMaterialGetIndexStream (newtMesh, geometryHandle, handle, (int*)segment->m_indexes); 
					}
					NewtonMeshEndHandle (newtMesh, geometryHandle); 
					NewtonMeshDestroy(newtMesh);

		//			collGeometry = AddGeometry (document, geometry);
					domGeometry *collGeometry = AddConvexGeometry (document, mesh);

					node = shapeCache.Insert(collGeometry, collision);
					mesh->Release();
				}

				domGeometry *collGeometry = node->GetInfo();

				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domInstance_geometry *meshInstance = daeSafeCast<domInstance_geometry>(shape->createAndPlace(COLLADA_ELEMENT_INSTANCE_GEOMETRY));
				daeURI uri(*collGeometry);
				uri.set("", "", "", "", collGeometry->getId());
				meshInstance->setUrl (uri);

//				domBind_material *bindMat = daeSafeCast<domBind_material>(instance->createAndPlace(COLLADA_ELEMENT_BIND_MATERIAL));
//				domBind_material::domTechnique_common *bmtc = daeSafeCast<domBind_material::domTechnique_common>(bindMat->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON ));
//				domInstance_material *instMat = daeSafeCast<domInstance_material>(bmtc->createAndPlace(COLLADA_ELEMENT_INSTANCE_MATERIAL ));
//				sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME, dCRC (0));
//				domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot() );
//				materialLibrary = domRoot->getLibrary_materials_array()[0];
//				material = FindMaterial (materialLibrary, materialName);
//				_ASSERTE (material);
//				uri.setElement (material);
//				uri.resolveURI();
//				instMat->setSymbol(materialName);
//				instMat->setTarget (uri);

				break;
			}

			case SERIALIZE_ID_TREE:
			{
				dTree<domGeometry *, const NewtonCollision*>::dTreeNode* node = shapeCache.Find(collision);
				if (!node) {
					const dFloat* vertexArray;
					int vertexCount;
					int vertexStride;

					int* indexArray = new int [collisionInfo.m_collisionTree.m_indexCount];
					int* faceAttribute = new int [collisionInfo.m_collisionTree.m_indexCount / 3];
					dVector minBox (-1.0e10f, -1.0e10f, -1.0e10f);
					dVector maxBox ( 1.0e10f,  1.0e10f,  1.0e10f);

					int triangleCount = NewtonTreeCollisionGetVertexListIndexListInAABB (collision, &minBox.m_x, &maxBox.m_x,
																					  &vertexArray, &vertexCount, &vertexStride, 
																					  indexArray, collisionInfo.m_collisionTree.m_indexCount,
																					  faceAttribute); 

					_ASSERTE (vertexCount == collisionInfo.m_collisionTree.m_vertexCount);

					char name[256];
					sprintf (name, "collisionTree%x", collision);
					dMesh* mesh = new dMesh (name);

					// pack the vertex list
					int *vertexMask = new int [vertexCount];
					memset (vertexMask, -1, vertexCount * sizeof (int));

					vertexStride = vertexStride / sizeof (dFloat);
					mesh->AllocVertexData(vertexCount);

					int newVertexCount = 0;
					for (int i = 0; i < triangleCount * 3; i ++) {
						int j = indexArray[i];
						if (vertexMask[j] == -1) {
							vertexMask[j] = newVertexCount;
							mesh->m_vertex[newVertexCount * 3 + 0] = dFloat (vertexArray[j * vertexStride + 0]);
							mesh->m_vertex[newVertexCount * 3 + 1] = dFloat (vertexArray[j * vertexStride + 1]);
							mesh->m_vertex[newVertexCount * 3 + 2] = dFloat (vertexArray[j * vertexStride + 2]);
							mesh->m_normal[newVertexCount * 3 + 0] = dFloat (0.0f);
							mesh->m_normal[newVertexCount * 3 + 1] = dFloat (1.0f);
							mesh->m_normal[newVertexCount * 3 + 2] = dFloat (0.0f);
							mesh->m_normal[newVertexCount * 2 + 0] = dFloat (0.0f);
							mesh->m_normal[newVertexCount * 2 + 1] = dFloat (0.0f);
							newVertexCount ++;
						}
					}

					mesh->m_vertexCount = newVertexCount;

					int count;
					do {
						int id = 0;
						count = 0;
						for (int i = 0; i < triangleCount; i ++) {
							if (faceAttribute[i] != -1) {
								if (faceAttribute[i] != id) {
									id = faceAttribute[i];
								}
								count ++;
							}
						}

						if (count) {
							dSubMesh* segment = mesh->AddSubMesh();
							segment->AllocIndexData (count * 3);

							int index = 0;
							for (int i = 0; i < triangleCount; i ++) {
								if (faceAttribute[i] == id) {
									faceAttribute[i] = -1;
									segment->m_indexes[index * 3 + 0] = vertexMask[indexArray[i * 3 + 0]];
									segment->m_indexes[index * 3 + 1] = vertexMask[indexArray[i * 3 + 1]];
									segment->m_indexes[index * 3 + 2] = vertexMask[indexArray[i * 3 + 2]];
									index ++;
								}
							}
						}
					} while (count);

					domGeometry *collGeometry = AddGeometry (document, mesh);
					node = shapeCache.Insert(collGeometry, collision);
					mesh->Release();

					delete[] vertexMask;
					delete[] indexArray;
					delete[] faceAttribute;
				}

				domGeometry *collGeometry = node->GetInfo();

				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domInstance_geometry *meshInstance = daeSafeCast<domInstance_geometry>(shape->createAndPlace(COLLADA_ELEMENT_INSTANCE_GEOMETRY));
				daeURI uri(*collGeometry);
				uri.set("", "", "", "", collGeometry->getId());
				meshInstance->setUrl (uri);

//				bindMat = daeSafeCast<domBind_material>(instance->createAndPlace(COLLADA_ELEMENT_BIND_MATERIAL));
//				bmtc = daeSafeCast<domBind_material::domTechnique_common>(bindMat->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON ));
//				instMat = daeSafeCast<domInstance_material>(bmtc->createAndPlace (COLLADA_ELEMENT_INSTANCE_MATERIAL));
//				sprintf (materialName, "%s%x", D_MATERIAL_PREFIX_NAME, dCRC (0));
//				domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot() );
//				materialLibrary = domRoot->getLibrary_materials_array()[0];
//				material = FindMaterial (materialLibrary, materialName);
//				_ASSERTE (material);
//				uri.setElement (material);
//				uri.resolveURI();
//				instMat->setSymbol(materialName);
//				instMat->setTarget (uri);
				break;
			}


			case D_PLANE_COLLISON_ID:
			{
				shape = daeSafeCast<domRigid_body::domTechnique_common::domShape>(technique->createAndPlace(COLLADA_ELEMENT_SHAPE));
				domPlane* plane = daeSafeCast<domPlane>(shape->createAndPlace(COLLADA_ELEMENT_PLANE)); 
				domPlane::domEquation* equation = daeSafeCast<domPlane::domEquation>(plane->createAndPlace(COLLADA_ELEMENT_EQUATION)); 

				dVector surface (collisionInfo.m_paramArray[0], collisionInfo.m_paramArray[1], collisionInfo.m_paramArray[2], collisionInfo.m_paramArray[3]);
				surface = m_globalRotation.TransformPlane (surface);
				equation->getValue().append (surface.m_x);
				equation->getValue().append (surface.m_y);
				equation->getValue().append (surface.m_z);
				equation->getValue().append (surface.m_w * m_scale);
				break;
			}


			default: 
				_ASSERTE (0);
		}

		AddOffssetMatrix (shape, matrix);

	}



//	domRigid_body* AddRigidBody (daeDocument* document, const NewtonBody* newtonBody)
	domRigid_body* AddRigidBody (daeDocument* document, domPhysics_model* model, const NewtonBody* newtonBody, const char* name, dTree<domGeometry *, const NewtonCollision*>& shapeFilter)
	{
//		daeURI uri;
//		domCOLLADA *domRoot;
//		domPhysics_material* material;
//		domInstance_physics_material* intanceMaterial;
//		domLibrary_physics_materials* materialLibrary;

		// create the image library
//		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot() );

		// add a body to this model
		domRigid_body* rigidBody = daeSafeCast<domRigid_body>(model->createAndPlace(COLLADA_ELEMENT_RIGID_BODY));
		rigidBody->setSid(name);

		// add rigid body info
		domRigid_body::domTechnique_common* techniqueCommon = daeSafeCast<domRigid_body::domTechnique_common>(rigidBody->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
		_ASSERTE (techniqueCommon);


		// set the mass and the body type
		dFloat mass;
		dVector inertia;
		NewtonBodyGetMassMatrix (newtonBody, &mass, &inertia.m_x, &inertia.m_y, &inertia.m_z);

		bool isDynamic = (mass > 1.0e-3f) ? true : false; 

		domRigid_body::domTechnique_common::domDynamic* dynamicBody = daeSafeCast<domRigid_body::domTechnique_common::domDynamic>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_DYNAMIC));
		dynamicBody->setValue(isDynamic);

		domTargetableFloat* bodyMass = daeSafeCast<domTargetableFloat>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_MASS));
		bodyMass->setValue(mass);

		dVector com;
		NewtonBodyGetCentreOfMass (newtonBody, &com.m_x);
		domRigid_body::domTechnique_common::domMass_frame* massFrame = daeSafeCast<domRigid_body::domTechnique_common::domMass_frame>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_MASS_FRAME));

		com.m_w = 0.0f;
		com = m_globalRotation.RotateVector(com);
		com = com.Scale (m_scale);
		domTranslate* translation = daeSafeCast<domTranslate>(massFrame->createAndPlace(COLLADA_ELEMENT_TRANSLATE)); 
		translation->getValue().append (com.m_x);
		translation->getValue().append (com.m_y);
		translation->getValue().append (com.m_z);

		domRotate* rotation = daeSafeCast<domRotate>(massFrame->createAndPlace(COLLADA_ELEMENT_ROTATE)); 
		rotation->getValue().append (0.0f);
		rotation->getValue().append (0.0f);
		rotation->getValue().append (1.0f);
		rotation->getValue().append (0.0f);

		inertia.m_w = 0.0f;
		inertia = m_globalRotation.RotateVector(inertia);
		inertia = inertia.Scale (m_scale* m_scale);
		domTargetableFloat3* bodyInertia = daeSafeCast<domTargetableFloat3>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_INERTIA));
		bodyInertia->getValue().append(inertia.m_x);
		bodyInertia->getValue().append(inertia.m_y);
		bodyInertia->getValue().append(inertia.m_z);


		// material for this body
//		intanceMaterial = daeSafeCast<domInstance_physics_material>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_INSTANCE_PHYSICS_MATERIAL));
//		_ASSERTE (intanceMaterial);
//		uri.setElement (material);
//		uri.setElement (AddPhysicsMaterialLibrary(document, newtonBody, enumID));
//		uri.resolveURI();
//		intanceMaterial->setUrl(uri);

		// add collision shape for this body
		AddShape (document, techniqueCommon, NewtonBodyGetCollision (newtonBody), shapeFilter);

		domExtra* extra = daeSafeCast<domExtra>(rigidBody->createAndPlace(COLLADA_ELEMENT_EXTRA));
		domTechnique *technique = daeSafeCast<domTechnique>(extra->createAndPlace(COLLADA_ELEMENT_TECHNIQUE));
		technique->setProfile("Newton");

		daeElement* element = (daeElement*)technique->createAndPlace( "BindingUserData" ); 
		domAny *domExtraExtension = (domAny*)element; 
		domExtraExtension->setValue ("default");

		element = (daeElement*)technique->createAndPlace( "BindingSetTransformFunction" ); 
		domExtraExtension = (domAny*)element; 
		domExtraExtension->setValue ("default");

		element = (daeElement*)technique->createAndPlace( "BindingExternalForceFunction" ); 
		domExtraExtension = (domAny*)element; 
		domExtraExtension->setValue ("default");

		element = (daeElement*)technique->createAndPlace( "BindingBodyDestructorCallback" ); 
		domExtraExtension = (domAny*)element; 
		domExtraExtension->setValue ("default");



//		element = (daeElement*)technique->createAndPlace( "AutoSleepMode" ); 
//		domExtraExtension = (domAny*)element; 
//		//autoSleepMode = NewtonBodyGetAutoFreeze (newtonBody);
//		autoSleepMode = false;
//		sprintf (tmpName, "%s", autoSleepMode ? "true" : "false");
//		domExtraExtension->setValue (tmpName);

		char tmpName[256];
		element = (daeElement*)technique->createAndPlace( "InternalLinearDrag" ); 
		domExtraExtension = (domAny*)element; 
		float linearDragValue = NewtonBodyGetLinearDamping (newtonBody);
		sprintf (tmpName, "%f", linearDragValue);
		domExtraExtension->setValue (tmpName);

		float angularDragValue[4];
		element = (daeElement*)technique->createAndPlace( "InternalAngularDrag" ); 
		domExtraExtension = (domAny*)element; 
		NewtonBodyGetAngularDamping (newtonBody, angularDragValue);
		sprintf (tmpName, "%f", angularDragValue[0]);
		domExtraExtension->setValue (tmpName);

//		element = (daeElement*)technique->createAndPlace( "InternalGyroscopicForces" ); 
//		domExtraExtension = (domAny*)element; 
//		//gyroscopyForces = NewtonBodyGetGyroscopicForcesMode (newtonBody);
//		gyroscopyForces = false;
//		sprintf (tmpName, "%s", gyroscopyForces ? "true" : "false");
//		domExtraExtension->setValue (tmpName);

		element = (daeElement*)technique->createAndPlace( "InternalContinueCollision" ); 
		domExtraExtension = (domAny*)element; 
		int continueCollision = NewtonBodyGetContinuousCollisionMode (newtonBody);
//		sprintf (tmpName, "%s", continueCollision ? "true" : "false");
		domExtraExtension->setValue (continueCollision ? "true" : "false");

		element = (daeElement*)technique->createAndPlace( "RecursivelyCollideWithLinkedBodies" ); 
		domExtraExtension = (domAny*)element; 
		int collideWithCollision = NewtonBodyGetJointRecursiveCollision (newtonBody);
//		sprintf (tmpName, "%s", collideWithCollision ? "true" : "false");
		domExtraExtension->setValue (collideWithCollision ? "true" : "false");

		element = (daeElement*)technique->createAndPlace( "UnilateralMaterialID" ); 
		domExtraExtension = (domAny*)element; 
		int materialGroudlID = NewtonBodyGetMaterialGroupID (newtonBody);
		sprintf (tmpName, "%d", materialGroudlID);
		domExtraExtension->setValue (tmpName);

		return rigidBody;
	}


	void AddPhysicsModelLibrary (daeDocument* document, const dList<const NewtonBody*>& bodyList, const char* modelName, 
							     dTree<domGeometry *, const NewtonCollision*>& shapeFilter, dTree<domNode*, dModel*>& nodeMap)
	{
//		int bodyEnumeration; 
//		int jointEnumeration; 
//		void* oldUserData;
//		domCOLLADA *domRoot;
//		domPhysics_model* model;
//		domRigid_body* sentinel;
//		domRigid_body* rigidBody;
//		domRigid_constraint* rigidConstraint;
//		const NewtonBody* body;
//		const NewtonBody* newtonBody;
//		const NewtonJoint* newtonJoint;
//		const NewtonCollision* collision;
//		domLibrary_physics_models* modelLibrary;
//		domLibrary_physics_materials* materialLibrary;
//		NewtonBodyList::dTreeNode* bodyNode;


		// create the image library
//		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot() );
//		modelLibrary = daeSafeCast<domLibrary_physics_models>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_PHYSICS_MODELS));
//		materialLibrary = daeSafeCast<domLibrary_physics_materials>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_PHYSICS_MATERIALS));

		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		if (!domRoot->getLibrary_physics_models_array().getCount()) {
			daeSafeCast<domLibrary_physics_models>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_PHYSICS_MODELS));

//			domLibrary_physics_scenes *library = daeSafeCast<domLibrary_physics_scenes>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_PHYSICS_SCENES));
			char sceneName[256];
//			sprintf (sceneName, "%sphysic", D_ROOT_NODE_NAME);

			domLibrary_physics_scenes *library = daeSafeCast<domLibrary_physics_scenes>(domRoot->createAndPlace(COLLADA_ELEMENT_LIBRARY_PHYSICS_SCENES));
			domPhysics_scene *scene = daeSafeCast<domPhysics_scene>(library->createAndPlace(COLLADA_ELEMENT_PHYSICS_SCENE));
			sprintf (sceneName, "%sphysic", D_ROOT_NODE_NAME);
			scene->setId (sceneName);
			domPhysics_scene::domTechnique_common* technique = daeSafeCast<domPhysics_scene::domTechnique_common>(scene->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));
			domTargetableFloat3* gravity = daeSafeCast<domTargetableFloat3>(technique->createAndPlace(COLLADA_ELEMENT_GRAVITY));
			dVector g (m_globalRotation.RotateVector(dVector (dFloat (0.0f), dFloat (-10.0f), dFloat (0.0f)))); 
			g = g.Scale (m_scale);
			gravity->getValue().append(g.m_x);
			gravity->getValue().append(g.m_y);
			gravity->getValue().append(g.m_z);

			domTargetableFloat* tiemStep = daeSafeCast<domTargetableFloat>(technique->createAndPlace(COLLADA_ELEMENT_TIME_STEP));
			tiemStep->setValue(1.0f / 60.0f);
		}

		domLibrary_physics_models *modelLibrary = domRoot->getLibrary_physics_models_array()[0];
		_ASSERTE (modelLibrary);

		// add the physics models to the scene.
		domPhysics_model* model = daeSafeCast<domPhysics_model>(modelLibrary->createAndPlace(COLLADA_ELEMENT_PHYSICS_MODEL));
		model->setId (modelName);

		domLibrary_physics_scenes *library = domRoot->getLibrary_physics_scenes_array()[0];
		domPhysics_scene *scene = library->getPhysics_scene_array()[0];
		domInstance_physics_model* instanceModel = daeSafeCast<domInstance_physics_model>(scene->createAndPlace(COLLADA_TYPE_INSTANCE_PHYSICS_MODEL));
		daeURI uri (*model);
		uri.set("", "", "", "", model->getId());
		instanceModel->setUrl(uri);

		for (dList<const NewtonBody*>::dListNode* node = bodyList.GetFirst(); node; node = node->GetNext()) {
			const NewtonBody* body = node->GetInfo();
			char name[256];
			sprintf (name, "rigidBody_%s", modelName);
			AddRigidBody (document, model, body, name, shapeFilter);

			domInstance_rigid_body* instanceBody = daeSafeCast<domInstance_rigid_body>(instanceModel->createAndPlace(COLLADA_TYPE_INSTANCE_RIGID_BODY));
			instanceBody->setBody(name);

			dModel* visualModel = (dModel*) NewtonBodyGetUserData(body);
			if (visualModel) {
				_ASSERTE (visualModel->IsType(dModel::GetRttiType()));
				domNode* visualNode = nodeMap.Find (visualModel)->GetInfo();
				_ASSERTE (visualNode);
				daeURI uri (*visualNode);
				uri.set("", "", "", "", visualNode->getID());
				instanceBody->setTarget(uri);
			} else {

			}
			
			domInstance_rigid_body::domTechnique_common* techniqueCommon = daeSafeCast<domInstance_rigid_body::domTechnique_common>(instanceBody->createAndPlace(COLLADA_ELEMENT_TECHNIQUE_COMMON));

			dVector veloc;
			dVector omega;
			NewtonBodyGetOmega(body, &omega[0]);
			NewtonBodyGetVelocity(body, &veloc[0]);
			domInstance_rigid_body::domTechnique_common::domVelocity* initVeloc = daeSafeCast<domInstance_rigid_body::domTechnique_common::domVelocity>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_VELOCITY));
			domInstance_rigid_body::domTechnique_common::domAngular_velocity* initOmega = daeSafeCast<domInstance_rigid_body::domTechnique_common::domAngular_velocity>(techniqueCommon->createAndPlace(COLLADA_ELEMENT_ANGULAR_VELOCITY));

			omega = m_globalRotation.RotateVector(omega);
			veloc = m_globalRotation.RotateVector(veloc.Scale (m_scale));

			initVeloc->getValue().append(veloc[0]);
			initVeloc->getValue().append(veloc[1]);
			initVeloc->getValue().append(veloc[2]);

			initOmega->getValue().append(omega[0]);
			initOmega->getValue().append(omega[1]);
			initOmega->getValue().append(omega[2]);
		}

/*
		// now add all constraints
		NewtonWorldSetUserData(m_world, &m_jointList);
		NewtonWorldForEachJointDo (m_world, NewtonJointList::JointIterator);

		jointEnumeration = 0;
		NewtonJointList::Iterator constIter (m_jointList);
		for (constIter.Begin(); constIter; constIter ++) {
			newtonJoint = constIter.GetNode()->GetKey();
			rigidConstraint = AddRigidConstraint (document, sentinel, model, newtonJoint, jointEnumeration);
			constIter.GetNode()->GetInfo() = rigidConstraint;
			jointEnumeration ++;
		}

		// restore the original user data
		NewtonWorldSetUserData(m_world, oldUserData);

		// destroy the semtinelBody
		NewtonDestroyBody(m_world, body);
*/
	}


	void AddScene (daeDocument* document)
	{
		domCOLLADA *domRoot;
		domInstanceWithExtra *ivs;
		domCOLLADA::domScene *sceneInstance;

		domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		sceneInstance = daeSafeCast<domCOLLADA::domScene>(domRoot->createAndPlace(COLLADA_ELEMENT_SCENE));

		if (domRoot->getLibrary_visual_scenes_array().getCount()) {
			domLibrary_visual_scenes *visualLibrary;
			visualLibrary = domRoot->getLibrary_visual_scenes_array()[0];
			domVisual_scene_Array& visualScenes = visualLibrary->getVisual_scene_array();
//			for (int i = 0; i <  int (visualScenes.getCount()); i ++ ) {
				int i = 0;

				domVisual_scene *visualScene;
				visualScene = visualScenes[i];
				ivs = daeSafeCast<domInstanceWithExtra>(sceneInstance->createAndPlace(COLLADA_ELEMENT_INSTANCE_VISUAL_SCENE));
				daeURI uri (*visualScene);
				uri.set("", "", "", "", visualScene->getId());
				ivs->setUrl (uri);
//				break;
//			}
		}

		if (domRoot->getLibrary_physics_scenes_array().getCount()) {
			domLibrary_physics_scenes *physicsLibrary;
			physicsLibrary = domRoot->getLibrary_physics_scenes_array()[0];
			domPhysics_scene_Array& physicsScenes = physicsLibrary->getPhysics_scene_array();
			for (int i = 0; i <  int (physicsScenes.getCount()); i ++ ) {
				domPhysics_scene *physicsScene;
				physicsScene = physicsScenes[0];
				ivs = daeSafeCast<domInstanceWithExtra>(sceneInstance->createAndPlace(COLLADA_ELEMENT_INSTANCE_PHYSICS_SCENE));
				daeURI uri (*physicsScene);
				uri.set("", "", "", "", physicsScene->getId());
				//uri.setElement (physicsScene);
				//uri.resolveURI();
				ivs->setUrl (uri);
			}
		}
	}


	void LoadVisualScene(daeDocument* document, dModel* model, dLoaderContext* context, CollGeoCache& meshCache,
		ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot );

		domCOLLADA::domScene *scene = domRoot->getScene();
		_ASSERTE (scene);

		// find the visual scene instance that is store in the scene node; 
		domInstanceWithExtra *instanceVisualScene = scene->getInstance_visual_scene();
		if (instanceVisualScene) {

			// if there is a instance to a Scene then Get teh Scene from the uri
			daeURI uri (instanceVisualScene->getUrl());

			daeElement* element = uri.getElement();
			_ASSERTE (element);

			// at this point we know that the collada element is a visual scene, we can cast it;
			//LoadScene (model, visualScene, nodeMap);
			LoadScene (document, model, (domVisual_scene*) element, context, meshCache, modifierVertexMapCache, materialCache, imageCache);
		}
	}



	void LoadVisualScene(daeDocument* document, dSceneModelList& sceneList, dLoaderContext* context, CollGeoCache& meshCache,
						 ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot );

//		domCOLLADA::domScene *scene = domRoot->getScene();
//		_ASSERTE (scene);

		const domLibrary_visual_scenes_Array &libraryArrays = domRoot->getLibrary_visual_scenes_array ();
		for (int j = 0; j < int (libraryArrays.getCount()); j ++) {
			const domVisual_scene_Array& libraryArray = libraryArrays[j]->getVisual_scene_array();
			for (int i = 0; i < int (libraryArray.getCount()); i ++) {
				dModel* model = context->CreateModel();
				domVisual_scene* visualScene = libraryArray[i];
				_ASSERTE (visualScene);
				LoadScene (document, model, visualScene, context, meshCache, modifierVertexMapCache, materialCache, imageCache);
				sceneList.AddModel(model);
				model->Release();
			}
		}
	}


	void LoadPhysicScene(daeDocument* document, NewtonWorld* world, dSceneModelList& sceneList, dLoaderContext* context, CollGeoCache& meshCache,
		ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());
		_ASSERTE (domRoot );

		dTree<dModel*, domNode*> modelCache; 
		const domLibrary_visual_scenes_Array &libraryArrays = domRoot->getLibrary_visual_scenes_array ();
		for (int j = 0; j < int (libraryArrays.getCount()); j ++) {
			const domVisual_scene_Array& libraryArray = libraryArrays[j]->getVisual_scene_array();
			for (int i = 0; i < int (libraryArray.getCount()); i ++) {
				dModel* model = context->CreateModel();
				domVisual_scene* visualScene = libraryArray[i];
				_ASSERTE (visualScene);
				domNode* node = LoadScene (document, model, visualScene, context, meshCache, modifierVertexMapCache, materialCache, imageCache);
				sceneList.AddModel(model);
				model->Release();
				modelCache.Insert(model, node);
			}
		}



		domCOLLADA::domScene *scene = domRoot->getScene();
		_ASSERTE (scene);

		// find the visual scene instance that is store in the scene node; 
		domInstanceWithExtra_Array& physicIntanceArray = scene->getInstance_physics_scene_array();

		for (int i = 0; i < int (physicIntanceArray.getCount()); i ++) {
			domInstanceWithExtra *physicIntanceScene = physicIntanceArray[i];

			// if there is a instance to a Scene then Get the Scene from the uri
			daeURI uri (physicIntanceScene->getUrl());

			daeElement* element = uri.getElement();
			_ASSERTE (element);

			domPhysics_scene* physicScene = (domPhysics_scene*) element;
			domInstance_physics_model_Array& instancePhysicsModelArray = physicScene->getInstance_physics_model_array();
			for (int j = 0; j < int (instancePhysicsModelArray.getCount()); j ++) {
				domInstance_physics_model* instancePhysicsModel = instancePhysicsModelArray[j];

				daeURI bodyUri (instancePhysicsModel->getUrl());
				element = bodyUri.getElement();
				_ASSERTE (element);
				domPhysics_model* physicModel = (domPhysics_model*) element;
				domRigid_body_Array& bodyArray = physicModel->getRigid_body_array();

				domInstance_rigid_body_Array& instanceRigidBodyArray = instancePhysicsModel->getInstance_rigid_body_array();
				for (int k = 0; k < int (instanceRigidBodyArray.getCount()); k ++) {
					domInstance_rigid_body* instanceRigidBody = instanceRigidBodyArray[k];

					domRigid_body* rigidBody = NULL;
					for (int m = 0; m < int (bodyArray.getCount()); m ++) {
						if (!strcmp (instanceRigidBody->getBody(), bodyArray[m]->getSid())) {
							rigidBody = bodyArray[m];
							break;
						}
					}

					daeURI nodeUri (instanceRigidBody->getTarget());
					element = nodeUri.getElement();
					dModel *model = NULL;
					dMatrix matrix (GetIdentityMatrix());
					if (element) {
						domNode* node = (domNode*) element;

						matrix = GetMatrix (node);
						model = modelCache.Find(node)->GetInfo();
						//model = modelCache.Find((domNode*) element)->GetInfo();
					}
				
					NewtonBody* body = LoadRigidBody (world, rigidBody, model, context, meshCache, modifierVertexMapCache, materialCache, imageCache);

					matrix = m_globalRotation.Inverse() * matrix * m_globalRotation;
					matrix.m_posit = matrix.m_posit.Scale (m_scale);
					NewtonBodySetMatrix(body, &matrix[0][0]);

					domInstance_rigid_body::domTechnique_common* technique = instanceRigidBody->getTechnique_common();
					domInstance_rigid_body::domTechnique_common::domVelocity* initVeloc = technique->getVelocity();
					domInstance_rigid_body::domTechnique_common::domAngular_velocity* initOmega = technique->getAngular_velocity();

					dVector omega;
					dVector veloc;

					omega[0] = dFloat(initOmega->getValue()[0]);
					omega[1] = dFloat(initOmega->getValue()[1]);
					omega[2] = dFloat(initOmega->getValue()[2]);

					veloc[0] = dFloat(initVeloc->getValue()[0]);
					veloc[1] = dFloat(initVeloc->getValue()[1]);
					veloc[2] = dFloat(initVeloc->getValue()[2]);

					omega = m_globalRotation.RotateVector(omega);
					veloc = m_globalRotation.RotateVector(veloc.Scale (m_scale));

					NewtonBodySetOmega(body, &omega[0]);
					NewtonBodySetVelocity(body, &veloc[0]);
				}
			}
		}
	}


	struct MaterialTrianglePair
	{
		int m_faceIndex;
		CollMaterial* m_material;
	};

	static int SortMatrialTriangles (const void *A, const void *B) 
	{
		const MaterialTrianglePair* vertexA = (MaterialTrianglePair*) A;
		const MaterialTrianglePair* vertexB = (MaterialTrianglePair*) B;

		if (vertexA[0].m_material < vertexB[0].m_material) {
			return -1;
		} else if (vertexA[0].m_material > vertexB[0].m_material) {
			return 1;
		} else {
			return 0;
		}
	}


	void GetOffssets (const domInputLocalOffset_Array& inputArray, SourceBuffer* sourceBuffers, 
					  SourceBuffer** posSource, int& vertexIndicesOffset, 
					  SourceBuffer** normalSrc, int& normalIndicesOffset, 
					  SourceBuffer** uvSource, int& uvIndicesOffset) 
	{
		int index = 0;
		*uvSource = NULL;
		*posSource = NULL;
		*normalSrc = NULL;
		uvIndicesOffset = 0;
		vertexIndicesOffset = 0;
		normalIndicesOffset = 0;
		for (int k = 0; k < int (inputArray.getCount()); k ++) {

			domInputLocalOffset* offset;
			offset = inputArray[k];

			daeURI uri (offset->getSource());
			daeElement* element = uri.getElement();
			_ASSERTE (element);
			if (!cdom::strcasecmp (offset->getSemantic(), COMMON_PROFILE_INPUT_VERTEX)) {
				vertexIndicesOffset = int (offset->getOffset());

				domVertices* vertices = (domVertices*) element;
				domInputLocal_Array &inputArray = vertices->getInput_array();
				for (int i = 0; i < int (inputArray.getCount()); i ++) {
					domInputLocal* input;
					domInputLocal* offset;
					offset = inputArray[i];
					input = inputArray[i];
					if (!cdom::strcasecmp (offset->getSemantic(), COMMON_PROFILE_INPUT_POSITION)) {
						domAccessor *accessor;
						domFloat_array *floatArray;
						domSource::domTechnique_common *technique;


						daeURI uri1 (input->getSource());
						element = uri1.getElement();
						_ASSERTE (element);
						domSource *source = (domSource *) element;

						floatArray = source->getFloat_array();
						domListOfFloats &srcArray = floatArray->getValue();

						technique = source->getTechnique_common();
						_ASSERTE (technique);

						accessor = technique->getAccessor();
						_ASSERTE (accessor);
						sourceBuffers[index].m_id = source->getId();
						sourceBuffers[index].m_stride = int (accessor->getStride());
						sourceBuffers[index].m_count = int (floatArray->getCount());
						sourceBuffers[index].m_data = &srcArray[0];
						*posSource = &sourceBuffers[index];
						index ++;
						break;
					}
				}

			} else if (!cdom::strcasecmp (offset->getSemantic(), COMMON_PROFILE_INPUT_NORMAL)) {
				normalIndicesOffset = int (offset->getOffset());

				domSource *source = (domSource*) element;

				domFloat_array *floatArray = source->getFloat_array();
				domListOfFloats &srcArray = floatArray->getValue();

				domSource::domTechnique_common *technique = source->getTechnique_common();
				_ASSERTE (technique);

				domAccessor *accessor = technique->getAccessor();
				_ASSERTE (accessor);
				sourceBuffers[index].m_id = source->getId();
				sourceBuffers[index].m_stride = int (accessor->getStride());
				sourceBuffers[index].m_count = int (floatArray->getCount());
				sourceBuffers[index].m_data = &srcArray[0];
				*normalSrc = &sourceBuffers[index];
				index ++;

			} else if (!cdom::strcasecmp (offset->getSemantic(), COMMON_PROFILE_INPUT_TEXCOORD)) {
				uvIndicesOffset = int (offset->getOffset());

				domSource *source = (domSource*) element;
				domFloat_array *floatArray = source->getFloat_array();
				domListOfFloats &srcArray = floatArray->getValue();

				domSource::domTechnique_common *technique = source->getTechnique_common();
				_ASSERTE (technique);

				domAccessor *accessor = technique->getAccessor();
				_ASSERTE (accessor);
				sourceBuffers[index].m_id = source->getId();
				sourceBuffers[index].m_stride = int (accessor->getStride());
				sourceBuffers[index].m_count = int (floatArray->getCount());
				sourceBuffers[index].m_data = &srcArray[0];
				*uvSource = &sourceBuffers[index];
				index ++;
			}
		}
		_ASSERTE (posSource);
	}


	// check image duplicates in the library
	domImage* FindImage (domLibrary_images* library, const char*name) const
	{
		if (name && library) {
			const domImage_Array& array = library->getImage_array();
			for (unsigned i = 0; i < array.getCount(); i ++) {
				domImage* image = array[i];
				if (!strcmp (name, image->getId())) {
					return image;
				}
			}
		}
		return NULL;
	}

	domGeometry* FindGeometry (domLibrary_geometries* library, const char*name) const
	{
		if (name && library) {
			const domGeometry_Array& array = library->getGeometry_array();
			for (unsigned i = 0; i < array.getCount(); i ++) {
				domGeometry* image = array[i];
				if (!strcmp (name, image->getId())) {
					return image;
				}
			}
		}
		return NULL;
	}

	domAnimation* FindAnimation (domLibrary_animations* library, const char*name) const
	{
		if (name && library) {
			const domAnimation_Array& array = library->getAnimation_array();
			for (unsigned i = 0; i < array.getCount(); i ++) {
				domAnimation* image = array[i];
				if (!strcmp (name, image->getId())) {
					return image;
				}
			}
		}
		return NULL;
	}

	domMaterial* FindMaterial (domLibrary_materials* library, const char* name) const
	{
		if (name && library) {
			const domMaterial_Array& array = library->getMaterial_array();
			for (unsigned i = 0; i < array.getCount(); i ++) {
				domMaterial* material = array[i];
				if (!cdom::strcasecmp (name, material->getId())) {
					return material;
				}
			}
		}
		return NULL;
	}


	domTechnique *FindProfileExtra (domExtra_Array& extraArray, const char* keyword)
	{
		// if the geometry have extras, the search the Veter format option 
		for (int j = 0; j < int (extraArray.getCount()); j ++) {
			domExtra* extra = extraArray[j];
			const domTechnique_Array& techniqueArray = extra->getTechnique_array();
			for (int k = 0; k < int (techniqueArray.getCount()); k ++) {
				if (!cdom::strcasecmp (techniqueArray[k]->getProfile(), keyword)) {
					return techniqueArray[k];
				}
			}
		}

		return NULL;
	}




	CollMaterial* GetMaterial (const char* matName, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		daeDatabase* database = m_collada->getDatabase();
		_ASSERTE (database);

		daeDocument *document = database->getDocument(daeUInt (0));
		_ASSERTE (document);

		domCOLLADA *domRoot = daeSafeCast<domCOLLADA>(document->getDomRoot());

		domLibrary_materials* library = NULL;
		if (domRoot->getLibrary_materials_array().getCount()) {
			library = domRoot->getLibrary_materials_array()[0];
		}


		CollMaterial* matId = NULL;
		domMaterial* material = FindMaterial (library, matName);
		if (material) {
			domInstance_effect* instanceEffect;
			instanceEffect = material->getInstance_effect();
			_ASSERTE (instanceEffect);
			if (instanceEffect) {
				daeURI uri (instanceEffect->getUrl());
				daeElement* element = uri.getElement();
				_ASSERTE (element);

	//				effect = FindEffect (effectLibrary, uri.getID());
				domEffect* effect = (domEffect*) element;
				if (effect) {
					matId = materialCache.GetMaterial (effect->getId());
					if (!matId) {
						domLibrary_images* imageLibrary;

						imageLibrary = NULL;
						if (domRoot->getLibrary_images_array().getCount()) {
							imageLibrary = domRoot->getLibrary_images_array()[0];
							_ASSERTE (imageLibrary);
						}

						const domFx_profile_abstract_Array &profileArray = effect->getFx_profile_abstract_array();

						domProfile_COMMON *profile = daeSafeCast<domProfile_COMMON> (profileArray[0]);
						if (profile) {
							// and the diffuse color from the type form the material type
							domProfile_COMMON::domTechnique* technique = profile->getTechnique();
							_ASSERTE (technique);

							domCommon_color_or_texture_type* diffuse = NULL;
							if (technique->getLambert()) {
								domProfile_COMMON::domTechnique::domLambert* parameters;
								parameters = technique->getLambert();
								_ASSERTE (parameters);
								diffuse = parameters->getDiffuse();
							} else if (technique->getPhong()) {
								domProfile_COMMON::domTechnique::domPhong* parameters;
								parameters = technique->getPhong();
								_ASSERTE (parameters);
								diffuse = parameters->getDiffuse();
							} else if (technique->getBlinn()) {
								domProfile_COMMON::domTechnique::domBlinn* parameters;
								parameters = technique->getBlinn();
								_ASSERTE (parameters);
								diffuse = parameters->getDiffuse();
							} else {
								_ASSERTE (0);
							}

							// since this is a prove of concept we only support the diffuse color texture feature
							// more complex material are unsupported at these time
							if (diffuse) {
								domCommon_color_or_texture_type::domTexture *texture;
								texture = diffuse->getTexture();
								if (texture) {
									const char* textName;
									textName = NULL;
									const char* textSample = texture->getTexture();
									domCommon_newparam_type_Array& paramaArray = profile->getNewparam_array();

									// find the texture sample 
									for (int j = 0; !textName && (j < int (paramaArray.getCount())); j ++) {
										const char* name = paramaArray[j]->getSid();
										if (!cdom::strcasecmp (name, textSample)) {
											domFx_sampler2D_common* sampler2d;
											domCommon_newparam_type_complexType* type;
											domFx_sampler2D_common_complexType::domSource* source;

											type = paramaArray[j];
											sampler2d = type->getSampler2D();
											source = sampler2d->getSource();
											const char* textSample2d = source->getValue();

											// find the image name for this diffuse effect
											for (int k = 0; !textName && (k < int (paramaArray.getCount())); k ++) {
												const char* name = paramaArray[k]->getSid(); 
												if (!cdom::strcasecmp (name, textSample2d)) {
													domFx_surface_common* surface;

													type = paramaArray[k];
													surface = type->getSurface();
													//domFx_surface_common::domInit_from_Array& initFromArray = surface->getInit_from_array();

													domFx_surface_init_commonRef surfInit = surface->getFx_surface_init_common();
													domFx_surface_init_from_common_Array initFromArray = surfInit->getInit_from_array();

													// finally get the name of the texture and bail out from form all loops
													for (int m = 0; !textName && (m < int (paramaArray.getCount())); m ++) {
														const xsIDREF& id = initFromArray[m]->getValue();
														textName = id.getID();
													}
												}
											}
										}
									}

									// if we have a texture name save this material as one of the material used by the geometries
									if (textName) {
										domImage* image = FindImage (imageLibrary, textName);
										_ASSERTE (image);

										domImage::domInit_from* initfrom = image->getInit_from();
										_ASSERTE (initfrom);

										if (initfrom->getValue().getOriginalURI()) {
											CollMaterial collMaterial;
											xsAnyURI uri (initfrom->getValue());
											textName = uri.getURI();

											// add the full path texture name to the cache
											imageCache.AddTexture (textName);

											// now get a filtered texture name
											collMaterial.m_texture = imageCache.GetTexture (textName);

											materialCache.AddMaterial(collMaterial, effect->getId());
											matId = materialCache.GetMaterial (effect->getId());
										}
									}

								} else {
									// no technique for this segment only color
									//_ASSERTE (0);
								}
							}
						}

					}
				}
			}
		}


		return matId;
	}


	void LoadTriangles(domTriangles_Array &trianglesArray, CollMaterialCache& materialCache, CollImageCache& imageCache,
					   MeshPoint* points, MaterialTrianglePair* materialTriangle, int& vertexCount)
	{
		// load the triangles
		for (int j = 0; j < int (trianglesArray.getCount()); j ++) {
			domTriangles* triangles = trianglesArray[j];;

			CollMaterial* matId = NULL;
			if (triangles->getMaterial()) {
				matId = GetMaterial (triangles->getMaterial(), materialCache, imageCache);
			}

			int triangleCount = int (triangles->getCount());
			domP *p = triangles->getP();
			domListOfUInts& indices = p->getValue();

			int uvIndicesOffset = 0;
			int vertexIndicesOffset = 0;
			int normalIndicesOffset = 0;
			SourceBuffer *uvSource = NULL;
			SourceBuffer *posSource = NULL;
			SourceBuffer *normalSrc = NULL;
			SourceBuffer sourceBuffers[6];

			GetOffssets (triangles->getInput_array(), sourceBuffers, &posSource, vertexIndicesOffset, &normalSrc, normalIndicesOffset, &uvSource, uvIndicesOffset);

			int index = vertexCount;
			vertexCount += triangleCount * 3;
			int indexCount = int (indices.getCount());
			for (int k = 0; k < indexCount; k += int (triangles->getInput_array().getCount())) {

				int t;
				int m;
				int stride;

				t = index/3;
				materialTriangle[t].m_faceIndex = t;
				materialTriangle[t].m_material = matId;

				//m = int (vertexIndices[k]);
				m = int (indices[k + vertexIndicesOffset]);

				stride = int (posSource->m_stride);
				points[index].m_vertex[0] = dFloat (posSource->m_data[m * stride + 0]);
				points[index].m_vertex[1] = dFloat (posSource->m_data[m * stride + 1]);
				points[index].m_vertex[2] = dFloat (posSource->m_data[m * stride + 2]);
				points[index].m_originalIndex = dFloat(m);

//				if (normalIndices && normalSrc) {
				if (normalSrc) {
//					m = int (indnormalIndices[k]);
					m = int (indices [k + normalIndicesOffset]);
					stride = int (posSource->m_stride);
					points[index].m_normal[0] = dFloat (normalSrc->m_data[m * stride + 0]);
					points[index].m_normal[1] = dFloat (normalSrc->m_data[m * stride + 1]);
					points[index].m_normal[2] = dFloat (normalSrc->m_data[m * stride + 2]);
				} else {
					points[index].m_normal[0] = 0.0f;
					points[index].m_normal[1] = 1.0f;
					points[index].m_normal[2] = 0.0f;
				}


				//				if (uvIndices && uvSource) {
				if (uvSource) {
					//					m = int (uvIndices[k]);
					m = int (indices[k + uvIndicesOffset]);
					stride = int (uvSource->m_stride);
					points[index].m_uv[0] = dFloat (uvSource->m_data[m * stride + 0]);
					points[index].m_uv[1] = dFloat (uvSource->m_data[m * stride + 1]);
				} else {
					points[index].m_uv[0] = 0.0f;
					points[index].m_uv[1] = 0.0f;
				}
				index ++;
			}
		}
	}


	void LoadPolygons(domPolylist_Array &polygonListArray, CollMaterialCache& materialCache, CollImageCache& imageCache, 
					  MeshPoint* points, MaterialTrianglePair* materialTriangle, int& vertexCount)
	{
		// load the polygonList array
		for (int j = 0; j < int (polygonListArray.getCount()); j ++) {

			domPolylist* polygon = polygonListArray[j];
			CollMaterial* matId = NULL;
			if (polygon->getMaterial()) {
				matId = GetMaterial (polygon->getMaterial(), materialCache, imageCache);
			}

			int uvIndicesOffset = 0;
			int vertexIndicesOffset = 0;
			int normalIndicesOffset = 0;
			SourceBuffer *uvSource = NULL;
			SourceBuffer *posSource = NULL;
			SourceBuffer *normalSrc = NULL;
			SourceBuffer sourceBuffers[6];
			GetOffssets (polygon->getInput_array(), sourceBuffers, &posSource, vertexIndicesOffset, &normalSrc, normalIndicesOffset, &uvSource, uvIndicesOffset);

			int stride = int (polygon->getInput_array().getCount());

			domPolylist::domVcount* vcount = polygon->getVcount();
			const domListOfUInts& vIndices = vcount->getValue();

			domPRef elemP = polygon->getP();
			const domListOfUInts& dataIndices = elemP->getValue();
			const domUint* indexP = &dataIndices[0];

			int pointsStride = int (posSource->m_stride);
			int pointcount = int (vIndices.getCount());
			for (int k = 0; k < pointcount; k ++) {
				int count = int (vIndices[k]);
				for (int i = 2; i < count; i ++) {
					int t;
					int m;

					t = vertexCount/3;
					materialTriangle[t].m_faceIndex = t;
					materialTriangle[t].m_material = matId;

					m = int (indexP[0 + vertexIndicesOffset]);
					points[vertexCount].m_vertex[0] = dFloat (posSource->m_data[m * pointsStride + 0]);
					points[vertexCount].m_vertex[1] = dFloat (posSource->m_data[m * pointsStride + 1]);
					points[vertexCount].m_vertex[2] = dFloat (posSource->m_data[m * pointsStride + 2]);
					points[vertexCount].m_originalIndex = dFloat(m);

					if (normalSrc) {
						int normalStride;
						normalStride = int (normalSrc->m_stride);
						m = int (indexP[0 + normalIndicesOffset]);
						normalStride = int (normalSrc->m_stride);
						points[vertexCount].m_normal[0] = dFloat (normalSrc->m_data[m * normalStride + 0]);
						points[vertexCount].m_normal[1] = dFloat (normalSrc->m_data[m * normalStride + 1]);
						points[vertexCount].m_normal[2] = dFloat (normalSrc->m_data[m * normalStride + 2]);
					} else {
						points[vertexCount].m_normal[0] = 0.0f;
						points[vertexCount].m_normal[1] = 1.0f;
						points[vertexCount].m_normal[2] = 0.0f;
					}

					if (uvSource) {
						int uvStride;
						m = int (indexP[0 + uvIndicesOffset]);
						uvStride = int (uvSource->m_stride);
						points[vertexCount].m_uv[0] = dFloat (uvSource->m_data[m * uvStride + 0]);
						points[vertexCount].m_uv[1] = dFloat (uvSource->m_data[m * uvStride + 1]);
					} else {
						points[vertexCount].m_uv[0] = 0.0f;
						points[vertexCount].m_uv[1] = 0.0f;
					}
					vertexCount ++;


					m = int (indexP[(i - 1) * stride + vertexIndicesOffset]);
					points[vertexCount].m_vertex[0] = dFloat (posSource->m_data[m * pointsStride + 0]);
					points[vertexCount].m_vertex[1] = dFloat (posSource->m_data[m * pointsStride + 1]);
					points[vertexCount].m_vertex[2] = dFloat (posSource->m_data[m * pointsStride + 2]);
					points[vertexCount].m_originalIndex = dFloat(m);
					if (normalSrc) {
						int normalStride;
						normalStride = int (normalSrc->m_stride);
						m = int (indexP[(i - 1) * stride + normalIndicesOffset]);
						normalStride = int (normalSrc->m_stride);
						points[vertexCount].m_normal[0] = dFloat (normalSrc->m_data[m * normalStride + 0]);
						points[vertexCount].m_normal[1] = dFloat (normalSrc->m_data[m * normalStride + 1]);
						points[vertexCount].m_normal[2] = dFloat (normalSrc->m_data[m * normalStride + 2]);
					} else {
						points[vertexCount].m_normal[0] = 0.0f;
						points[vertexCount].m_normal[1] = 1.0f;
						points[vertexCount].m_normal[2] = 0.0f;
					}
					if (uvSource) {
						int uvStride;
						m = int (indexP[(i - 1) * stride  + uvIndicesOffset]);
						uvStride = int (uvSource->m_stride);
						points[vertexCount].m_uv[0] = dFloat (uvSource->m_data[m * uvStride + 0]);
						points[vertexCount].m_uv[1] = dFloat (uvSource->m_data[m * uvStride + 1]);
					} else {
						points[vertexCount].m_uv[0] = 0.0f;
						points[vertexCount].m_uv[1] = 0.0f;
					}
					vertexCount ++;


					m = int (indexP[i * stride + vertexIndicesOffset]);
					points[vertexCount].m_vertex[0] = dFloat (posSource->m_data[m * pointsStride + 0]);
					points[vertexCount].m_vertex[1] = dFloat (posSource->m_data[m * pointsStride + 1]);
					points[vertexCount].m_vertex[2] = dFloat (posSource->m_data[m * pointsStride + 2]);
					points[vertexCount].m_originalIndex = dFloat(m);
					if (normalSrc) {
						int normalStride;
						normalStride = int (normalSrc->m_stride);
						m = int (indexP[i * stride + normalIndicesOffset]);
						normalStride = int (normalSrc->m_stride);
						points[vertexCount].m_normal[0] = dFloat (normalSrc->m_data[m * normalStride + 0]);
						points[vertexCount].m_normal[1] = dFloat (normalSrc->m_data[m * normalStride + 1]);
						points[vertexCount].m_normal[2] = dFloat (normalSrc->m_data[m * normalStride + 2]);
					} else {
						points[vertexCount].m_normal[0] = 0.0f;
						points[vertexCount].m_normal[1] = 1.0f;
						points[vertexCount].m_normal[2] = 0.0f;
					}
					if (uvSource) {
						int uvStride;
						m = int (indexP[i * stride + uvIndicesOffset]);
						uvStride = int (uvSource->m_stride);
						points[vertexCount].m_uv[0] = dFloat (uvSource->m_data[m * uvStride + 0]);
						points[vertexCount].m_uv[1] = dFloat (uvSource->m_data[m * uvStride + 1]);
					} else {
						points[vertexCount].m_uv[0] = 0.0f;
						points[vertexCount].m_uv[1] = 0.0f;
					}
					vertexCount ++;
				}
				indexP += count * stride;
			}
		}
	}

	void LoadPolygons(domPolygons_Array &polygonArray, CollMaterialCache& materialCache, CollImageCache& imageCache, 
					  MeshPoint* points, MaterialTrianglePair* materialTriangle, int& vertexCount)
	{
		// load the polygons
		for (int j = 0; j < int (polygonArray.getCount()); j ++) {
			domPolygons* polygons = polygonArray[j];

			CollMaterial* matId = NULL;
			if (polygons->getMaterial()) {
				matId = GetMaterial (polygons->getMaterial(), materialCache, imageCache);
			}

			int polygonCount = int (polygons->getCount());
			int stride = int (polygons->getInput_array().getCount());

			int uvIndicesOffset = 0;
			int vertexIndicesOffset = 0;
			int normalIndicesOffset = 0;
			SourceBuffer *uvSource = NULL;
			SourceBuffer *posSource = NULL;
			SourceBuffer *normalSrc = NULL;
			SourceBuffer sourceBuffers[6];
			GetOffssets (polygons->getInput_array(), sourceBuffers, &posSource, vertexIndicesOffset, &normalSrc, normalIndicesOffset, &uvSource, uvIndicesOffset);

			domP_Array& indexArray = polygons->getP_array();
			_ASSERTE (int (indexArray.getCount()) == polygonCount);
			for (int k = 0; k < polygonCount; k ++) {
				int vCount;
				int pointsStride;

				domPRef pIndices = indexArray[k];
				domListOfUInts& dataIndices = pIndices->getValue();

				vCount = int (dataIndices.getCount() / stride);
				pointsStride = int (posSource->m_stride);

				for (int i = 2; i < vCount; i ++) {
					int t;
					int m;

					t = vertexCount/3;
					materialTriangle[t].m_faceIndex = t;
					materialTriangle[t].m_material = matId;

					m = int (dataIndices[0 + vertexIndicesOffset]);
					points[vertexCount].m_vertex[0] = dFloat (posSource->m_data[m * pointsStride + 0]);
					points[vertexCount].m_vertex[1] = dFloat (posSource->m_data[m * pointsStride + 1]);
					points[vertexCount].m_vertex[2] = dFloat (posSource->m_data[m * pointsStride + 2]);
					points[vertexCount].m_originalIndex = dFloat(m);
					if (normalSrc) {
						int normalStride;
						normalStride = int (normalSrc->m_stride);
						m = int (dataIndices[0 + normalIndicesOffset]);
						normalStride = int (normalSrc->m_stride);
						points[vertexCount].m_normal[0] = dFloat (normalSrc->m_data[m * normalStride + 0]);
						points[vertexCount].m_normal[1] = dFloat (normalSrc->m_data[m * normalStride + 1]);
						points[vertexCount].m_normal[2] = dFloat (normalSrc->m_data[m * normalStride + 2]);
					} else {
						points[vertexCount].m_normal[0] = 0.0f;
						points[vertexCount].m_normal[1] = 1.0f;
						points[vertexCount].m_normal[2] = 0.0f;
					}
					if (uvSource) {
						int uvStride;
						m = int (dataIndices[0 + uvIndicesOffset]);
						uvStride = int (uvSource->m_stride);
						points[vertexCount].m_uv[0] = dFloat (uvSource->m_data[m * uvStride + 0]);
						points[vertexCount].m_uv[1] = dFloat (uvSource->m_data[m * uvStride + 1]);
					} else {
						points[vertexCount].m_uv[0] = 0.0f;
						points[vertexCount].m_uv[1] = 0.0f;
					}
					vertexCount ++;


					m = int (dataIndices[(i - 1) * stride + vertexIndicesOffset]);
					points[vertexCount].m_vertex[0] = dFloat (posSource->m_data[m * pointsStride + 0]);
					points[vertexCount].m_vertex[1] = dFloat (posSource->m_data[m * pointsStride + 1]);
					points[vertexCount].m_vertex[2] = dFloat (posSource->m_data[m * pointsStride + 2]);
					points[vertexCount].m_originalIndex = dFloat(m);
					if (normalSrc) {
						int normalStride;
						normalStride = int (normalSrc->m_stride);
						m = int (dataIndices[(i - 1) * stride + normalIndicesOffset]);
						normalStride = int (normalSrc->m_stride);
						points[vertexCount].m_normal[0] = dFloat (normalSrc->m_data[m * normalStride + 0]);
						points[vertexCount].m_normal[1] = dFloat (normalSrc->m_data[m * normalStride + 1]);
						points[vertexCount].m_normal[2] = dFloat (normalSrc->m_data[m * normalStride + 2]);
					} else {
						points[vertexCount].m_normal[0] = 0.0f;
						points[vertexCount].m_normal[1] = 1.0f;
						points[vertexCount].m_normal[2] = 0.0f;
					}
					if (uvSource) {
						int uvStride;
						m = int (dataIndices[(i - 1) * stride  + uvIndicesOffset]);
						uvStride = int (uvSource->m_stride);
						points[vertexCount].m_uv[0] = dFloat (uvSource->m_data[m * uvStride + 0]);
						points[vertexCount].m_uv[1] = dFloat (uvSource->m_data[m * uvStride + 1]);
					} else {
						points[vertexCount].m_uv[0] = 0.0f;
						points[vertexCount].m_uv[1] = 0.0f;
					}
					vertexCount ++;


					m = int (dataIndices[i * stride + vertexIndicesOffset]);
					points[vertexCount].m_vertex[0] = dFloat (posSource->m_data[m * pointsStride + 0]);
					points[vertexCount].m_vertex[1] = dFloat (posSource->m_data[m * pointsStride + 1]);
					points[vertexCount].m_vertex[2] = dFloat (posSource->m_data[m * pointsStride + 2]);
					points[vertexCount].m_originalIndex = dFloat(m);
					if (normalSrc) {
						int normalStride;
						normalStride = int (normalSrc->m_stride);
						m = int (dataIndices[i * stride + normalIndicesOffset]);
						normalStride = int (normalSrc->m_stride);
						points[vertexCount].m_normal[0] = dFloat (normalSrc->m_data[m * normalStride + 0]);
						points[vertexCount].m_normal[1] = dFloat (normalSrc->m_data[m * normalStride + 1]);
						points[vertexCount].m_normal[2] = dFloat (normalSrc->m_data[m * normalStride + 2]);
					} else {
						points[vertexCount].m_normal[0] = 0.0f;
						points[vertexCount].m_normal[1] = 1.0f;
						points[vertexCount].m_normal[2] = 0.0f;
					}
					if (uvSource) {
						int uvStride;
						m = int (dataIndices[i * stride + uvIndicesOffset]);
						uvStride = int (uvSource->m_stride);
						points[vertexCount].m_uv[0] = dFloat (uvSource->m_data[m * uvStride + 0]);
						points[vertexCount].m_uv[1] = dFloat (uvSource->m_data[m * uvStride + 1]);
					} else {
						points[vertexCount].m_uv[0] = 0.0f;
						points[vertexCount].m_uv[1] = 0.0f;
					}
					vertexCount ++;
				}
			}
		}
	}


	dMesh* LoadMesh (domMesh* colladaMesh, dLoaderContext* context, //domGeometry *colladaGeometry,
					 ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		domGeometry* collGeometry = (domGeometry*) colladaMesh->getParent();
		dMesh* geometry = context->CreateMesh(collGeometry->getId());

		// calculate the total triangle count
		int vertexCount = 0;

		// count polygons in polygons list array
		domPolylist_Array &polygonListArray = colladaMesh->getPolylist_array();
		for (int j = 0; j < int (polygonListArray.getCount()); j ++) {
			domPolylist* polygon;
			domPolylist::domVcount* vcount;

			polygon = polygonListArray[j];
			vcount = polygon->getVcount();
			const domListOfUInts& vIndices = vcount->getValue();
			for (int k = 0; k < int (vIndices.getCount()); k ++) {
				int count = int (vIndices[k]);
				vertexCount += (count - 2) * 3;
			}
		}


		// count polygons
		domPolygons_Array &polygonArray = colladaMesh->getPolygons_array();
		for (int j = 0; j < int (polygonArray.getCount()); j ++) {
			int stride;
			int polygonCount;
			domPolygons* polygons;
			polygons = polygonArray[j];

			polygonCount = int (polygons->getCount());

			stride = int (polygons->getInput_array().getCount());
			domP_Array& indexArray = polygons->getP_array();

			_ASSERTE (int (indexArray.getCount()) == polygonCount);
			for (int k = 0; k < polygonCount; k ++) {
				int vCount;
				domPRef pIndices = indexArray[k];
				domListOfUInts& dataIndices = pIndices->getValue();
				vCount = int (dataIndices.getCount() / stride);
				vertexCount += (vCount - 2) * 3;
			}
		}

		// count triangles
		domTriangles_Array &trianglesArray = colladaMesh->getTriangles_array();
		for (int j = 0; j < int (trianglesArray.getCount()); j ++) {
			domTriangles* triangles;
			triangles = trianglesArray[j];
			vertexCount += int (triangles->getCount()) * 3;
		}

		int totalTriangleCount = vertexCount / 3;
		MaterialTrianglePair* materialTriangle = new MaterialTrianglePair[totalTriangleCount + 1];
		int* indexList = new int[vertexCount];
		MeshPoint* points = new MeshPoint[vertexCount];

		vertexCount = 0;

		LoadTriangles(trianglesArray, materialCache, imageCache, points, materialTriangle, vertexCount);
		LoadPolygons (polygonListArray, materialCache, imageCache, points, materialTriangle, vertexCount);
		LoadPolygons(polygonArray, materialCache, imageCache, points, materialTriangle, vertexCount);


		vertexCount = dModel::PackVertexArray (&points[0].m_vertex[0], 8, sizeof (MeshPoint), vertexCount, indexList);
		// create space to store the vertices, normals and uvs
		geometry->AllocVertexData (vertexCount);
		VerterMap* vertexMap = new VerterMap[vertexCount + 1];

		vertexMap[vertexCount].m_vertexIndexInDMesh = 0x7fffffff;
		vertexMap[vertexCount].m_vertexIndexInColladaMesh = 0x7fffffff;
		modifierVertexMapCache.Insert(vertexMap, geometry);

		for (int j = 0; j < vertexCount; j ++) {
			dVector p(points[j].m_vertex[0], points[j].m_vertex[1], points[j].m_vertex[2], 0.0f);
			geometry->m_vertex[j * 3 + 0] = p.m_x;
			geometry->m_vertex[j * 3 + 1] = p.m_y;
			geometry->m_vertex[j * 3 + 2] = p.m_z;

			dVector n(points[j].m_normal[0], points[j].m_normal[1], points[j].m_normal[2], 0.0f);
			geometry->m_normal[j * 3 + 0] = n.m_x;
			geometry->m_normal[j * 3 + 1] = n.m_y;
			geometry->m_normal[j * 3 + 2] = n.m_z;

			geometry->m_uv[j * 2 + 0] = points[j].m_uv[0];
			geometry->m_uv[j * 2 + 1] = points[j].m_uv[1];

			vertexMap[j].m_vertexIndexInDMesh = j;
			vertexMap[j].m_vertexIndexInColladaMesh = int (points[j].m_originalIndex);
		}


		materialTriangle[totalTriangleCount].m_material = (CollMaterial*) 0x7fffffff;
		qsort(materialTriangle, totalTriangleCount, sizeof (MaterialTrianglePair), SortMatrialTriangles);
		for (int j = 0; j < totalTriangleCount; ) {
			int i ;
			int triangleCount;
			CollMaterial* material;
			i = j;
			material = materialTriangle[i].m_material;
			while (material == materialTriangle[j].m_material) j ++;

			triangleCount = j - i;

			dSubMesh& subMesh = geometry->Append()->GetInfo() ;
			subMesh.AllocIndexData(triangleCount * 3);

			if (material) {
				strcpy (subMesh.m_textureName, material->m_texture.m_textureName);
			}
			for (int k = 0; k < triangleCount; k ++) {
				int index;
				index = materialTriangle[k + i].m_faceIndex;
				subMesh.m_indexes[k * 3 + 0] = indexList[index * 3 + 0];
				subMesh.m_indexes[k * 3 + 1] = indexList[index * 3 + 1];
				subMesh.m_indexes[k * 3 + 2] = indexList[index * 3 + 2];
			}
		}

		delete[] indexList;
		delete[] points;
		delete[] materialTriangle;

		return geometry;
	}


	dMesh* LoadConvexMesh (domConvex_mesh* colladaMesh, dLoaderContext* context, //domGeometry *colladaGeometry,
		ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		domGeometry* collGeometry = (domGeometry*) colladaMesh->getParent();
//		sprintf (geometry->m_name, "%s", collGeometry->getId());

		dMesh* geometry = context->CreateMesh(collGeometry->getId());

		// calculate the total triangle count
		int vertexCount = 0;

		// count polygons in polygons list array
		domPolylist_Array &polygonListArray = colladaMesh->getPolylist_array();
		for (int j = 0; j < int (polygonListArray.getCount()); j ++) {
			domPolylist* polygon;
			domPolylist::domVcount* vcount;

			polygon = polygonListArray[j];
			vcount = polygon->getVcount();
			const domListOfUInts& vIndices = vcount->getValue();
			for (int k = 0; k < int (vIndices.getCount()); k ++) {
				int count = int (vIndices[k]);
				vertexCount += (count - 2) * 3;
			}
		}


		// count polygons
		domPolygons_Array &polygonArray = colladaMesh->getPolygons_array();
		for (int j = 0; j < int (polygonArray.getCount()); j ++) {
			int stride;
			int polygonCount;
			domPolygons* polygons;
			polygons = polygonArray[j];

			polygonCount = int (polygons->getCount());

			stride = int (polygons->getInput_array().getCount());
			domP_Array& indexArray = polygons->getP_array();

			_ASSERTE (int (indexArray.getCount()) == polygonCount);
			for (int k = 0; k < polygonCount; k ++) {
				int vCount;
				domPRef pIndices = indexArray[k];
				domListOfUInts& dataIndices = pIndices->getValue();
				vCount = int (dataIndices.getCount() / stride);
				vertexCount += (vCount - 2) * 3;
			}
		}

		// count triangles
		domTriangles_Array &trianglesArray = colladaMesh->getTriangles_array();
		for (int j = 0; j < int (trianglesArray.getCount()); j ++) {
			domTriangles* triangles;
			triangles = trianglesArray[j];
			vertexCount += int (triangles->getCount()) * 3;
		}

		int totalTriangleCount = vertexCount / 3;
		MaterialTrianglePair* materialTriangle = new MaterialTrianglePair[totalTriangleCount + 1];
		int* indexList = new int[vertexCount];
		MeshPoint* points = new MeshPoint[vertexCount];

		vertexCount = 0;

		LoadTriangles(trianglesArray, materialCache, imageCache, points, materialTriangle, vertexCount);
		LoadPolygons (polygonListArray, materialCache, imageCache, points, materialTriangle, vertexCount);
		LoadPolygons(polygonArray, materialCache, imageCache, points, materialTriangle, vertexCount);


		vertexCount = dModel::PackVertexArray (&points[0].m_vertex[0], 8, sizeof (MeshPoint), vertexCount, indexList);
		// create space to store the vertices, normals and uvs
		geometry->AllocVertexData (vertexCount);
		VerterMap* vertexMap = new VerterMap[vertexCount + 1];

		vertexMap[vertexCount].m_vertexIndexInDMesh = 0x7fffffff;
		vertexMap[vertexCount].m_vertexIndexInColladaMesh = 0x7fffffff;
		modifierVertexMapCache.Insert(vertexMap, geometry);

		for (int j = 0; j < vertexCount; j ++) {
			dVector p(points[j].m_vertex[0], points[j].m_vertex[1], points[j].m_vertex[2], 0.0f);
			geometry->m_vertex[j * 3 + 0] = p.m_x;
			geometry->m_vertex[j * 3 + 1] = p.m_y;
			geometry->m_vertex[j * 3 + 2] = p.m_z;

			dVector n(points[j].m_normal[0], points[j].m_normal[1], points[j].m_normal[2], 0.0f);
			geometry->m_normal[j * 3 + 0] = n.m_x;
			geometry->m_normal[j * 3 + 1] = n.m_y;
			geometry->m_normal[j * 3 + 2] = n.m_z;

			geometry->m_uv[j * 2 + 0] = points[j].m_uv[0];
			geometry->m_uv[j * 2 + 1] = points[j].m_uv[1];

			vertexMap[j].m_vertexIndexInDMesh = j;
			vertexMap[j].m_vertexIndexInColladaMesh = int (points[j].m_originalIndex);
		}


		materialTriangle[totalTriangleCount].m_material = (CollMaterial*) 0x7fffffff;
		qsort(materialTriangle, totalTriangleCount, sizeof (MaterialTrianglePair), SortMatrialTriangles);
		for (int j = 0; j < totalTriangleCount; ) {
			int i ;
			int triangleCount;
			CollMaterial* material;
			i = j;
			material = materialTriangle[i].m_material;
			while (material == materialTriangle[j].m_material) j ++;

			triangleCount = j - i;

			dSubMesh& subMesh = geometry->Append()->GetInfo() ;
			subMesh.AllocIndexData(triangleCount * 3);

			if (material) {
				strcpy (subMesh.m_textureName, material->m_texture.m_textureName);
			}
			for (int k = 0; k < triangleCount; k ++) {
				int index;
				index = materialTriangle[k + i].m_faceIndex;
				subMesh.m_indexes[k * 3 + 0] = indexList[index * 3 + 0];
				subMesh.m_indexes[k * 3 + 1] = indexList[index * 3 + 1];
				subMesh.m_indexes[k * 3 + 2] = indexList[index * 3 + 2];
			}
		}

		delete[] indexList;
		delete[] points;
		delete[] materialTriangle;

		return geometry;
	}

	static int SortVertexMap (const void *A, const void *B) 
	{
		const VerterMap* vertexA = (VerterMap*) A;
		const VerterMap* vertexB = (VerterMap*) B;

		if (vertexA[0].m_vertexIndexInColladaMesh < vertexB[0].m_vertexIndexInColladaMesh) {
			return -1;
		} else if (vertexA[0].m_vertexIndexInColladaMesh > vertexB[0].m_vertexIndexInColladaMesh) {
			return 1;
		} else {
			return 0;
		}
	}


	dSkinModifier* LoadSkinController (daeDocument* document, domSkin* skin, dMesh* mesh, const dModel* model, ModifierVertexCache& modifierVertexMapCache)
	{
		dSkinModifier* skinModifier = new dSkinModifier (mesh);

//		domSkin::domBind_shape_matrix* bindMatrix = skin->getBind_shape_matrix();
//		if (bindMatrix) {
//			domFloat4x4& values = bindMatrix->getValue();
//			dMatrix mat;
//			for (int i = 0; i < 4; i ++) {
//				for (int j = 0; j < 4; j ++) {
//					mat[j][i] = dFloat (values[i * 4 + j]);
//				}
//			}
//			mat = m_globalRotation.Inverse() * mat * m_globalRotation;
//			mat.m_posit = mat.m_posit.Scale (m_scale);
//			mat.TransformTriplex (mesh->m_vertex, 3 * sizeof (dFloat), mesh->m_vertex, 3 * sizeof (dFloat), mesh->m_vertexCount);
//		}

		domSkin::domVertex_weights *vertexWeights = skin->getVertex_weights();
		domInputLocalOffset* weights = vertexWeights->getInput_array()[0];
		domInputLocalOffset* jointInputs = vertexWeights->getInput_array()[1];
		if (strcmp (jointInputs->getSemantic(), COMMON_PROFILE_INPUT_JOINT)) {
			domInputLocalOffset *tmp = weights;
			weights = jointInputs;
			jointInputs = tmp;
		}
		_ASSERTE (!strcmp (weights->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT));
		_ASSERTE (!strcmp (jointInputs->getSemantic(), COMMON_PROFILE_INPUT_JOINT));


		int BoneIndices[1024];
		daeURI uri (jointInputs->getSource());
		const daeElement* element = uri.getElement ();
		domSource *boneSource = (domSource *)element;
		domName_array *boneNames = boneSource->getName_array();
		domListOfNames &boneSrcArray = boneNames->getValue();
		for (int i = 0; i < int (boneSrcArray.getCount()); i ++) {
			dBone* bone;
			bone = model->FindBone(boneSrcArray[i]);
			BoneIndices[i] = bone->GetBoneID();
		}


		daeURI uri1 (weights->getSource());
		element = uri1.getElement ();
		domSource *weightSource = (domSource *)element;
		domFloat_array *weightValue = weightSource->getFloat_array();
		domListOfFloats &weightValueArray = weightValue->getValue();

		dSkinModifier::dBoneVertexWeightData* skinData = new dSkinModifier::dBoneVertexWeightData[mesh->m_vertexCount * 4];
		domSkin::domVertex_weights::domV *v = vertexWeights->getV();
		domSkin::domVertex_weights::domVcount *vCount = vertexWeights->getVcount();

		domListOfInts &vIndices = v->getValue();
		domListOfUInts &vCountIndices = vCount->getValue();
		int jointOffset = int (jointInputs->getOffset());
		int weightOffset = int (weights->getOffset());

		VerterMap* vertexMap = modifierVertexMapCache.Find(mesh)->GetInfo();
		qsort(vertexMap, mesh->m_vertexCount, sizeof (VerterMap), SortVertexMap);


		int vertexIndex = 0;
		int weightsCount = 0;
		int weightStartIndex = 0;
		for (int collVertexIndex = 0; collVertexIndex < (int) vCountIndices.getCount(); collVertexIndex ++) {
			int count = int (vCountIndices[collVertexIndex]);
			for (int j = 0; j < count; j ++) {
				int boneIndex = int (vIndices[weightStartIndex * 2 + jointOffset]);
				int weightIndex = int (vIndices[weightStartIndex * 2 + weightOffset]);
				int boneId = BoneIndices[boneIndex];
				dFloat weightValue = dFloat (weightValueArray[weightIndex]);
				weightStartIndex ++;

				if (weightValue > 1.0e-3f) {
					for (int k = vertexIndex; vertexMap[k].m_vertexIndexInColladaMesh <= collVertexIndex; k ++) {
						skinData[weightsCount].m_boneId = boneId;
						skinData[weightsCount].m_weight = weightValue;
						skinData[weightsCount].m_vertexIndex = vertexMap[k].m_vertexIndexInDMesh;
						weightsCount ++;
					}
				}
			}

			do {
				vertexIndex ++;
			} while (vertexMap[vertexIndex].m_vertexIndexInColladaMesh == collVertexIndex);
		}

		skinModifier->SetBindingPose(mesh, *model, skinData, weightsCount);
		delete[] skinData;

/*
		const dBone* rootBone = NULL;
		for (int i = 0; !rootBone && (i < mesh->m_vertexCount); i ++) {
			for (int j = 0; j < 4; j ++) {
				if (skinModifier->m_vertexWeight[i][j] > 0.0f) {

//					int boneIndex = skinModifier->m_boneWeightIndex[i].m_index[j];
//					for (rootBone = skinModifier->m_skinnedBones[boneIndex]; rootBone->GetParent() && (rootBone->GetParent()->GetType() == dBone::m_bone); rootBone = rootBone->GetParent());
//					skinModifier->SetRootNode(rootBone);

					// remove all of the matrix offset form the skin by baking the transform into the mesh 
					domSkin::domJoints* joints = skin->getJoints();
					domInputLocal *jointName = joints->getInput_array()[0];
					domInputLocal *invBindMatrices = joints->getInput_array()[1];
					if (strcmp (invBindMatrices->getSemantic(), COMMON_PROFILE_INPUT_INV_BIND_MATRIX)) {
						domInputLocal *tmp = jointName;
						jointName = invBindMatrices;
						invBindMatrices = tmp;
					}
					_ASSERTE (!strcmp (jointName->getSemantic(), COMMON_PROFILE_INPUT_JOINT));
					_ASSERTE (!strcmp (invBindMatrices->getSemantic(), COMMON_PROFILE_INPUT_INV_BIND_MATRIX));

					daeURI uri2 (jointName->getSource());
					const daeElement* element = uri2.getElement ();
					domSource *boneSource = (domSource *)element;
					domName_array *boneNames = boneSource->getName_array();
					domListOfNames &boneSrcArray = boneNames->getValue();

					for (int k = 0; k < int (boneSrcArray.getCount()); k ++) {

						//const char* name = boneSrcArray[k];
						if (!strcmp (boneSrcArray[k], rootBone->GetName())) {

							daeURI uri3 (invBindMatrices->getSource());
							const daeElement* element = uri3.getElement ();
							domSource *source = (domSource *)element;
							domFloat_array *invMatricesValue = source->getFloat_array();
							domListOfFloats &values = invMatricesValue->getValue();
							dMatrix mat;
							for (int i = 0; i < 4; i ++) {
								for (int j = 0; j < 4; j ++) {
									mat[j][i] = dFloat (values[i * 4 + j + k * 16]);
								}
							}
							mat = m_globalRotation.Inverse() * mat * m_globalRotation;
							mat.m_posit = mat.m_posit.Scale (m_scale);

							dMatrix skinMatrix (GetIdentityMatrix());
							for (int i = 0; i < skinModifier->m_bonesCount; i ++) {
								if (rootBone == skinModifier->m_skinnedBones[i]) {
									skinMatrix = skinModifier->m_bindingMatrices[i];
									break;
								}
							}

							dMatrix diff (mat * skinMatrix.Inverse());
							diff.TransformTriplex (mesh->m_vertex, 3 * sizeof (dFloat), mesh->m_vertex, 3 * sizeof (dFloat), mesh->m_vertexCount);
							break;
						}
					}
					break;
				}
			}
		}
*/
		

		return skinModifier;
	}


	dMatrix GetOffssetMatrix (const domTranslate_Array &translationArray, const domRotate_Array &rotationArray)
	{
		dMatrix matrix (GetIdentityMatrix());

		for (int i = 0; i < int (translationArray.getCount()); i ++) {
			const domFloat3& data = translationArray[i]->getValue();
			matrix[3][0] += dFloat (data[0]);
			matrix[3][1] += dFloat (data[1]);
			matrix[3][2] += dFloat (data[2]);
		}

		for (int i = 0; i < int (rotationArray.getCount()); i ++) {
			const domFloat4& data = rotationArray[i]->getValue();
			dFloat angle = dFloat (data[3]) * 3.1316f / 180.0f;
			dFloat x = dFloat (data[0]);
			dFloat y = dFloat (data[1]);
			dFloat z = dFloat (data[2]);
			dVector axis (x, y, z, 0.0f);
			axis = axis.Scale (1.0f / sqrtf (axis % axis));
			dQuaternion rot (axis, angle);
			dMatrix colladaMatrix (rot, dVector (0.0f, 0.0f, 0.0f, 1.0f));
			matrix = colladaMatrix * matrix;
		}
		matrix = m_globalRotation.Inverse() * matrix * m_globalRotation;
		matrix.m_posit = matrix.m_posit.Scale(m_scale);
		return matrix;
	}


	NewtonCollision* CreateCollision(NewtonWorld* world, domRigid_body::domTechnique_common::domShape* shape,
									 CollGeoCache& meshCache, ModifierVertexCache& modifierVertexMapCache, 
									 CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		NewtonCollision* collision = NULL;

		int shapeID = 0;

		dMatrix matrix (GetOffssetMatrix (shape->getTranslate_array(), shape->getRotate_array()));
		if (shape->getBox()) {
			domBox* box = shape->getBox(); 
			domBox::domHalf_extents* halfExtend = box->getHalf_extents(); 
			dVector size (dFloat(halfExtend->getValue()[0]), dFloat(halfExtend->getValue()[1]), dFloat(halfExtend->getValue()[2]), 0.0f);
			size = size.Scale (m_scale * 2.0f);
			collision = NewtonCreateBox (world, size.m_x, size.m_y, size.m_z, shapeID, &matrix[0][0]);

		} else if (shape->getSphere()) {
			domSphere* sphere = shape->getSphere(); 

			dFloat radius0 = dFloat (sphere->getRadius()->getValue());
			dFloat radius1 = radius0;
			dFloat radius2 = radius0;
			
			domTechnique* technique = FindProfileExtra (sphere->getExtra_array(), "ellipse");
			if (technique) {
				const daeElementRefArray& array = technique->getContents();
				daeElement* element = array[0];
				domAny *domExtraExtension = (domAny*)element; 
				_ASSERTE (!strcmp (domExtraExtension->getElementName(), "radios"));

				const char* radios = domExtraExtension->getValue();
				sscanf (radios, "%f %f %f", &radius0, &radius1, &radius2);
			}
		
			collision = NewtonCreateSphere (world, radius0 * m_scale, radius1 * m_scale, radius2 * m_scale, shapeID, &matrix[0][0]);

		} else if (shape->getCylinder()) {

			domCylinder* cylinder = shape->getCylinder();
			dFloat height = dFloat (cylinder->getHeight()->getValue()) * m_scale * 2.0f; 
			dFloat radius = dFloat (cylinder->getRadius()->getValue()[0]) * m_scale;

			UnapplyMatrixAligment (matrix);
			domTechnique* technique = FindProfileExtra (cylinder->getExtra_array(), "chamferCylinder");
			if (technique) {
				collision = NewtonCreateChamferCylinder (world, radius, height, shapeID, &matrix[0][0]);
			} else {
				collision = NewtonCreateCylinder (world, radius, height, shapeID, &matrix[0][0]);
			}

		} else if (shape->getCapsule()) {

			domCapsule* capsule = shape->getCapsule(); 
			dFloat radius = dFloat (capsule->getRadius()->getValue()[0]); 
			dFloat height = (dFloat (capsule->getHeight()->getValue()) + radius) * 2.0f;

			radius *= m_scale;
			height *= m_scale;

			UnapplyMatrixAligment (matrix);
			collision = NewtonCreateCapsule (world, radius, height, shapeID, &matrix[0][0]);

		} else if (shape->getTapered_cylinder()) {

			domTapered_cylinder* cone = shape->getTapered_cylinder();
			dFloat height = dFloat (cone->getHeight()->getValue())  * m_scale * 2.0f;
			dFloat radius1 = dFloat (cone->getRadius1()->getValue()[0]) * m_scale;
			dFloat radius2 = dFloat (cone->getRadius2()->getValue()[0]) * m_scale;

			UnapplyMatrixAligment (matrix);
			if (radius1 >= radius2) {
				collision = NewtonCreateCone (world, radius1, height, shapeID, &matrix[0][0]);
			} else {
				matrix = dPitchMatrix (3.141592f) * matrix;
				collision = NewtonCreateCone (world, radius2, height, shapeID, &matrix[0][0]);
			}

		} else if (shape->getInstance_geometry()) {

			domInstance_geometry* instance = shape->getInstance_geometry(); 
			daeURI uri (instance->getUrl());
			const daeElement* element = uri.getElement();
			domGeometry *collGeometry = (domGeometry*) element;

			if (collGeometry->getConvex_mesh()) {
				CollGeoCache::dTreeNode* cacheNode = meshCache.Find(collGeometry);
				if (!cacheNode) {
					dLoaderContext context;
					dMesh* mesh = LoadConvexMesh (collGeometry->getConvex_mesh(), &context, modifierVertexMapCache, materialCache, imageCache);

					mesh->ApplyGlobalScale(m_scale);
					mesh->ApplyGlobalTransform (m_globalRotation);
					cacheNode = meshCache.Insert(mesh, collGeometry);
				}
				dMesh* mesh = cacheNode->GetInfo();
				collision = NewtonCreateConvexHull (world, mesh->m_vertexCount, mesh->m_vertex, 3 * sizeof (dFloat), 0.0f, shapeID, &matrix[0][0]);

			} else {

				CollGeoCache::dTreeNode* cacheNode = meshCache.Find(collGeometry);
				if (!cacheNode) {
					dLoaderContext context;
					dMesh* mesh = LoadMesh (collGeometry->getMesh(), &context, modifierVertexMapCache, materialCache, imageCache);

					mesh->ApplyGlobalScale(m_scale);
					mesh->ApplyGlobalTransform (m_globalRotation);
					cacheNode = meshCache.Insert(mesh, collGeometry);
				}
				dMesh* mesh = cacheNode->GetInfo();

				collision = NewtonCreateTreeCollision (world, NULL);
				NewtonTreeCollisionBeginBuild (collision);

				dFloat* const vertex = mesh->m_vertex;
				for (dMesh::dListNode* node = mesh->GetFirst(); node; node = node->GetNext()) {
					const dSubMesh& segment = node->GetInfo();
					for (int j = 0; j < segment.m_indexCount; j += 3) {
						dVector face[3];

						int index = segment.m_indexes[j + 0] * 3;
						face[0] = dVector (vertex[index + 0], vertex[index + 1], vertex[index + 2], 0.0f);

						index = segment.m_indexes[j + 1] * 3;
						face[1] = dVector (vertex[index + 0], vertex[index + 1], vertex[index + 2], 0.0f);

						index = segment.m_indexes[j + 2] * 3;
						face[2] = dVector (vertex[index + 0], vertex[index + 1], vertex[index + 2], 0.0f);

						NewtonTreeCollisionAddFace (collision, 3, &face[0].m_x, sizeof (dVector), 0);
					}
				}

				NewtonTreeCollisionEndBuild (collision, 1);	

			}

		} else if (shape->getPlane()) {
			_ASSERTE (0);
/*
			domPlane* plane;
			domPlane::domEquation* equation;

			plane = shape->getPlane(); 
			equation = plane->getEquation(); 

			dVector surface (equation->getValue()[0], equation->getValue()[1], equation->getValue()[2], equation->getValue()[2]);
			surface = m_axisRotation.TransformPlane(surface);
			surface = matrix.TransformPlane (surface);
			collision = CreatePlaneCollidion (m_world, surface );
*/
		} else {
			_ASSERTE (0);
		}

		return collision;
	}


	NewtonCollision* CreateCollision(NewtonWorld* world, const domRigid_body::domTechnique_common::domShape_Array& shapeArray, int isDynamics,
									CollGeoCache& meshCache, ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		NewtonCollision* collision = NULL;
		int count = int (shapeArray.getCount());
		if (count == 1)	{
			domRigid_body::domTechnique_common::domShape* shape = shapeArray[0];
			collision = CreateCollision(world, shape, meshCache, modifierVertexMapCache, materialCache, imageCache);
		} else {
			if (isDynamics) {
				NewtonCollision** collsionArray = new NewtonCollision*[count];
				_ASSERTE (count < sizeof (collsionArray) / sizeof (collsionArray[0]));
				for (int i = 0; i < count; i ++) {
					domRigid_body::domTechnique_common::domShape* shape = shapeArray[i];
					collsionArray[i] = CreateCollision(world, shape, meshCache, modifierVertexMapCache, materialCache, imageCache);
				}
				collision = NewtonCreateCompoundCollision (world, count, collsionArray, 0);
				
				for (int i = 0; i < count; i ++) {
					NewtonReleaseCollision (world, collsionArray[i]);
				}

				delete[] collsionArray;
			} else {
				domRigid_body::domTechnique_common::domShape* shape = shapeArray[0];
				collision = CreateCollision(world, shape, meshCache, modifierVertexMapCache, materialCache, imageCache);
			}
		}
		return collision;
	}



	NewtonBody* LoadRigidBody (NewtonWorld* world, domRigid_body* rigidBody, dModel* model, dLoaderContext* context,
							  CollGeoCache& meshCache, ModifierVertexCache& modifierVertexMapCache, 
							  CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
//		int i;
//		int j;
//		int k;
//		int isDynamicsBody;
//		dFloat Ixx;
//		dFloat Iyy;
//		dFloat Izz;
//		dFloat mass;
//		dVector com;
//		domNode* target;
//		daeElement* element;
//		NewtonBody* body;
//		dSceneNode* viualNodePtr;
//		domRigid_body* rigidBody;
//		domTargetableFloat* bodyMass;
//		domTargetableFloat3* bodyInertia;
//		dNodePhysicsRigidBody::dTreeNode* rigidBodyNode;
//		ColladaNodeTodSceneNodeMap::dTreeNode* visualNode;
//		domRigid_body::domTechnique_common::domDynamic* dynamicBody;
//		domRigid_body::domTechnique_common::domMass_frame* massFrame;
//		domInstance_rigid_body* instanceRigidBody

//		element = instanceRigidBody->getTarget().getElement();
//		target = (domNode*) element;
//		visualNode = m_nodeTodNodeMap.Find(target);
//		rigidBodyNode = m_rigidBodyCache.Find (dCRC (instanceRigidBody->getBody()));
//		_ASSERTE (rigidBodyNode);
//		rigidBody = rigidBodyNode->GetInfo();


		domRigid_body::domTechnique_common* techniqueCommon = rigidBody->getTechnique_common();
		_ASSERTE (techniqueCommon);

		int isDynamicsBody = 1;
		if (techniqueCommon->getMass()) {
			if (techniqueCommon->getMass()->getValue() == 0.0f) {
				isDynamicsBody = 0;
			}
		}

		if (isDynamicsBody && techniqueCommon->getDynamic()) {
			if (techniqueCommon->getDynamic()->getValue() == false) {
				isDynamicsBody = 0;
			}
		}

		NewtonCollision* collision = CreateCollision(world, techniqueCommon->getShape_array(), isDynamicsBody,
													 meshCache, modifierVertexMapCache, materialCache, imageCache);


		NewtonBody* body = NewtonCreateBody (world, collision);
		NewtonReleaseCollision (world, collision);

//		m_rigidBodyMap.Insert(body, rigidBody);

		// set user data;
//		NewtonBodySetUserData (body, visualNode ? visualNode->GetInfo() : NULL);
//		NewtonBodySetTransformCallback (body, DefaultColladaPhysicsSetTransform);
//		NewtonBodySetForceAndTorqueCallback (body, DefaultColladaApplyGravityForce);

		// by default disable collision with jointed objects
//		NewtonBodySetJointRecursiveCollision (body, 0);

		// set a destructor for this rigid body
//		NewtonBodySetDestructorCallback (body, PhysicsBodyDestructor);

		// all body have default Material ID		
//		NewtonBodySetMaterialGroupID (body, colladaMaterialIndex);

		dFloat Ixx = 0.0f;
		dFloat Iyy = 0.0f;
		dFloat Izz = 0.0f;
		dFloat mass = 0.0f;
		dVector com (0.0f, 0.0f, 0.0f, 0.0f);
		domTargetableFloat* bodyMass = techniqueCommon->getMass();
		if (bodyMass) {
			domRigid_body::domTechnique_common::domDynamic* dynamicBody = techniqueCommon->getDynamic();
			if (dynamicBody) {
				if (dynamicBody->getValue() == true) {
					mass = dFloat (bodyMass->getValue());
				}
			}
			if (mass > 0.0f) {
				domRigid_body::domTechnique_common::domMass_frame* massFrame = techniqueCommon->getMass_frame();
				domTargetableFloat3* bodyInertia = techniqueCommon->getInertia();
				if (massFrame && bodyInertia) {
					Ixx = dFloat (bodyInertia->getValue()[0]);
					Iyy = dFloat (bodyInertia->getValue()[1]);
					Izz = dFloat (bodyInertia->getValue()[2]);
					if (massFrame->getTranslate_array().getCount()) {
						domTranslate* translation = massFrame->getTranslate_array()[0];
						com.m_x = dFloat (translation->getValue()[0]);
						com.m_y = dFloat (translation->getValue()[1]);
						com.m_z = dFloat (translation->getValue()[2]);
						com = m_globalRotation.RotateVector(com.Scale (m_scale));
					}
				} else {
					dVector inertia;
					NewtonConvexCollisionCalculateInertialMatrix (collision, &inertia[0], &com[0]);	
					Ixx = inertia.m_x * mass;
					Iyy = inertia.m_y * mass;
					Izz = inertia.m_z * mass;
				}
			}
		}

		NewtonBodySetCentreOfMass (body, &com[0]);
		if (mass > 0.0f) {
			NewtonBodySetMassMatrix (body, mass, Ixx, Iyy, Izz);
		}

//		dMatrix matrix (GetIdentityMatrix());
//		if (visualNode) {
//			for (viualNodePtr = visualNode->GetInfo(); viualNodePtr; viualNodePtr = viualNodePtr->GetParent()) {
//				matrix = matrix * viualNodePtr->GetMatrix();
//			}
//			NewtonBodySetMatrix (body, &matrix[0][0]);
//		} else {
//			matrix.m_posit.m_y = - 1000.0f;
//		}


		// add a moronic callada style material;
//		if (visualNode) {
//			ColladaFrictionRestituionMaterial* frictionRestituionMaterial;
//			frictionRestituionMaterial = new ColladaFrictionRestituionMaterial;
//			visualNode->GetInfo()->SetUserData (frictionRestituionMaterial);

			// material for this body
//			domPhysics_material* physicMaterial;
//			domInstance_physics_material* intanceMaterial;
//			intanceMaterial = techniqueCommon->getInstance_physics_material();
//			if (intanceMaterial) {
//				const daeElement* element;
//				domPhysics_material::domTechnique_common* technique;
//				const daeURI& uri = intanceMaterial->getUrl();
//				element = uri.getElement();
//				if (element) {
//					physicMaterial = (domPhysics_material*) element;
//					technique = physicMaterial->getTechnique_common();
//					frictionRestituionMaterial->m_staticFriction = technique->getStatic_friction()->getValue();
//					frictionRestituionMaterial->m_restitution = technique->getRestitution()->getValue();
//					frictionRestituionMaterial->m_dynamicFriction = technique->getDynamic_friction()->getValue();
//				}
//			}
//		}


		domTechnique *technique = FindProfileExtra (rigidBody->getExtra_array(), "Newton");
		if (technique) {
			// it is a newton collada set specific parameters 
			const daeElementRefArray& array = technique->getContents();
			for (int i = 0; i < int (array.getCount()); i ++) {
				daeElement* element = array[i];
				domAny *domExtraExtension = (domAny*)element; 

				if (!cdom::strcasecmp (domExtraExtension->getElementName(), "BindingUserData")) {
					context->SetUserData(body, model, domExtraExtension->getValue());

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "BindingSetTransformFunction")) {
					context->SetTransformCallback(body, domExtraExtension->getValue());

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "BindingExternalForceFunction")) {
					context->SetForceAndTorqueCallback(body, domExtraExtension->getValue());

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "BindingBodyDestructorCallback")) {
					context->SetDestructorCallback(body, domExtraExtension->getValue());

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "AutoSleepMode")) {
					if (!cdom::strcasecmp (domExtraExtension->getValue(), "true")) {
						NewtonBodySetAutoSleep (body, 1);
					} else {
						NewtonBodySetAutoSleep (body, 0);
					}

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "InternalLinearDrag")) {
					dFloat drag;
					sscanf (domExtraExtension->getValue(), "%f", &drag);
					NewtonBodySetLinearDamping(body, drag);

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "InternalAngularDrag")) {
					dFloat drag[4];
					sscanf (domExtraExtension->getValue(), "%f", &drag[0]);
					drag[1] = drag[0];
					drag[2] = drag[0];
					NewtonBodySetAngularDamping (body, &drag[0]);

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "InternalContinueCollision")) {
					if (!cdom::strcasecmp (domExtraExtension->getValue(), "true")) {
						NewtonBodySetContinuousCollisionMode(body, 1);
					} else {
						NewtonBodySetContinuousCollisionMode (body, 0);
					}

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "RecursivelyCollideWithLinkedBodies")) {
					if (!cdom::strcasecmp (domExtraExtension->getValue(), "true")) {
						NewtonBodySetJointRecursiveCollision(body, 1);
					} else {
						NewtonBodySetJointRecursiveCollision (body, 0);
					}

				} else if (!cdom::strcasecmp (domExtraExtension->getElementName(), "UnilateralMaterialID")) {
					int materiaID;
					sscanf (domExtraExtension->getValue(), "%d", &materiaID);

					// for now since collada do not support realistic manifold materials 
					materiaID = 0;
					NewtonBodySetMaterialGroupID (body, materiaID);
				}
			}
		} else {
			// it is not a Newton Collada set the default parameters
			_ASSERTE (0);
			context->SetUserData(body, model, "default");
			context->SetTransformCallback(body, "default");
			context->SetForceAndTorqueCallback(body, "default");
			context->SetDestructorCallback(body, "default");
			NewtonBodySetAutoSleep (body, 1);

			//NewtonBodySetLinearDamping(body, drag);
			//NewtonBodySetAngularDamping (body, &drag[0]);
			//NewtonBodySetContinuousCollisionMode(body, 1);
			//NewtonBodySetContinuousCollisionMode (body, 0);
			//NewtonBodySetJointRecursiveCollision(body, 1);
			//NewtonBodySetJointRecursiveCollision (body, 0);
			//NewtonBodySetMaterialGroupID (body, materiaID);
		}

		return body;
	}




	void LoadNodeData (dModel* model, dBone* bone, domNode* colNode, dLoaderContext* context, CollGeoCache& meshCache, 
					   ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)	
	{
		// get the name ID (note: many exporters do not obey Collada specifications and use the Id instead of the Name) 
		if (colNode->getSid()) {
			bone->SetNameID(colNode->getSid());
		} else if (colNode->getName()) {
			bone->SetNameID(colNode->getName());
		} else {
			bone->SetNameID(colNode->getId());
		}

		dMatrix matrix ( m_globalRotation.Inverse() * GetMatrix (colNode) * m_globalRotation);
		matrix.m_posit = matrix.m_posit.Scale (m_scale);
		bone->SetMatrix(matrix);

		if (colNode->getType() == NODETYPE_JOINT) {
			bone->SetType(dBone::m_bone);
		}


		// instance controller may make reference to nodes that may not being read yet, wee need to read them in a second pass.
		const domInstance_controller_Array& controllerArray = colNode->getInstance_controller_array();
		if (controllerArray.getCount()) {
			domInstance_controller* instance = controllerArray[0];
			daeURI uri (instance->getUrl());
			const daeElement* element = uri.getElement();
			domController* controller = (domController*) element;
			domSkin* skin = controller->getSkin();

			daeURI uriMesh (skin->getSource());
			element = uriMesh.getElement();
			domGeometry* collGeometry = (domGeometry*) element;

			CollGeoCache::dTreeNode* cacheNode = meshCache.Find(collGeometry);
			dMesh* mesh = NULL;
			if (!cacheNode) {
				// Load this Mesh for the firseTime time
				if (collGeometry->getMesh()) {
					mesh = LoadMesh (collGeometry->getMesh(), context, modifierVertexMapCache, materialCache, imageCache);
				} else if (collGeometry->getConvex_mesh()){
					mesh = LoadConvexMesh (collGeometry->getConvex_mesh(), context, modifierVertexMapCache, materialCache, imageCache);
				} else {
					_ASSERTE (0);
					//geometry = new dGeometry;
				}
				mesh->ApplyGlobalScale(m_scale);
				mesh->ApplyGlobalTransform (m_globalRotation);
				cacheNode = meshCache.Insert(mesh, collGeometry);
			}

			_ASSERTE (cacheNode);
			mesh = cacheNode->GetInfo();
			if (!mesh->m_hasBone) {
				// if this mesh is already use by a bone, just add a reference to the mesh 
				mesh->m_hasBone = 1;
				mesh->m_boneID = bone->m_boneID;
			}

			// add a reference to this mesh to this model.
			model->AddMesh(mesh);
			model->m_meshList.GetLast()->GetInfo().m_boneID = bone->m_boneID;
		}


		// read the Mesh instantiated by this node if there are not read yet
		const domInstance_geometry_Array& gemeortyArray = colNode->getInstance_geometry_array();
		if (gemeortyArray.getCount()) {
			// for know we will only allow one mesh per node, as the dModel format does no support array of dMesh per nodes yet
			// it will be in the future
			dMesh* mesh = NULL;
			domInstance_geometry* instance = gemeortyArray[0];

			// get the pointer to the Mesh instance from the uri
			const daeURI& uri = instance->getUrl();
			const daeElement* element = uri.getElement();
			if (element) {
				
				domGeometry* collGeometry = (domGeometry*) element;

				// if the mesh is not in the model, we must load this new mesh instance
				CollGeoCache::dTreeNode* cacheNode = meshCache.Find(collGeometry);
				if (!cacheNode) {
					// Load this Mesh for the firseTime time
					if (collGeometry->getMesh()) {
						mesh = LoadMesh (collGeometry->getMesh(), context, modifierVertexMapCache, materialCache, imageCache);
					} else if (collGeometry->getConvex_mesh()){
						mesh = LoadConvexMesh (collGeometry->getConvex_mesh(), context, modifierVertexMapCache, materialCache, imageCache);
					} else {
						_ASSERTE (0);
		//				geometry = new dGeometry;
					}
					mesh->ApplyGlobalScale(m_scale);
					mesh->ApplyGlobalTransform (m_globalRotation);
					cacheNode = meshCache.Insert(mesh, collGeometry);
				}
				_ASSERTE (cacheNode);
				mesh = cacheNode->GetInfo();
				if (!mesh->m_hasBone) {
					// if this mesh is already use by a bone, just add a reference to the mesh 
					mesh->m_hasBone = 1;
					mesh->m_boneID = bone->m_boneID;
				}
				// add a reference to this mesh to this model.
				model->AddMesh(mesh);
			}

//			for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) { 
//				if (node->GetInfo().m_mesh == mesh) {
//					node->GetInfo().m_boneID = bone->m_boneID;
//				}
//			}

			model->m_meshList.GetLast()->GetInfo().m_boneID = bone->m_boneID;
		}
	}


	domNode* LoadScene (daeDocument* document, dModel* model, domVisual_scene* visualScene, dLoaderContext* context,
						CollGeoCache& meshCache, ModifierVertexCache& modifierVertexMapCache, CollMaterialCache& materialCache, CollImageCache& imageCache)
	{
		int stack;
		int boneId;
		dBone* rootBone;
		domNode* colladaRoot;
		domNode* nodePool[1024];
		dBone* parentBones[1024];
		dTree<dBone*, domNode*> controllersIntances; 

		// create a dummy root bode;
		colladaRoot = NULL;
		rootBone = new dBone (NULL);

		stack = 0;
		const domNode_Array& nodeArray = visualScene->getNode_array();
		for (int i = 0; i < int (nodeArray.getCount()); i ++) {
			parentBones[stack] = rootBone;
			nodePool[stack] = nodeArray[i];
			stack ++;
		}
		_ASSERTE (stack == 1);

		boneId = 0;
		while (stack) {
			dBone* node;
			dBone* parent;
			domNode* colNode;

			stack --;
			colNode = nodePool[stack];
			parent = parentBones[stack]; 

			node = new dBone(parent);

			if (!colladaRoot) {
				colladaRoot = colNode;
			}

			node->m_boneID = boneId;
			boneId ++;

			if (colNode->getInstance_controller_array().getCount()) {
				controllersIntances.Insert(node, colNode);
			}
			LoadNodeData (model, node, colNode, context, meshCache, modifierVertexMapCache, materialCache, imageCache);

			// check if this collada file has Node instances, a feature support by some modelers but not all  
			domInstance_node_Array& instansceNodeArray = colNode->getInstance_node_array();
			for (int i = 0; i < int (instansceNodeArray.getCount()); i ++) {
				daeElement* element;
				domNode* childNode;

				// if there are node instances we will just read them as real nodes copies.
				domInstance_node* instansceNode = instansceNodeArray[0];
				daeURI uri (instansceNode->getUrl());
				element = uri.getElement ();
				childNode = (domNode *)element;

				parentBones[stack] = node;
				nodePool[stack] = childNode;
				stack ++;
			}

			const domNode_Array &nodeArray = colNode->getNode_array();
			for (int i = 0; i < int (nodeArray.getCount()); i ++) {
				parentBones[stack] = node;
				nodePool[stack] = nodeArray[i];
				stack ++;
			}
		}


		// detach all children nodes from the root bone and add them to the Model as root bones.
//		dList<dBone*>& boneList = model->m_skeleton.Append()->GetInfo();
		while (rootBone->GetChild()) {
			dBone *bone;
			bone = rootBone->GetChild();
			bone->Detach();
//			boneList.m_data.Append (bone);
			model->AddSkeleton (bone);
			bone->Release();
		}

		// now load all meshes controllers
		while (controllersIntances.GetCount()) {
			dBone* bone = controllersIntances.GetRoot()->GetInfo();
			domNode* colNode = controllersIntances.GetRoot()->GetKey();
			controllersIntances.Remove(controllersIntances.GetRoot());

			domInstance_controller* instanceController = colNode->getInstance_controller_array()[0];
			daeURI controllerUri (instanceController->getUrl());
			const daeElement* element = controllerUri.getElement();
			domController* controller = (domController*) element;
			_ASSERTE (controller);
			domSkin* skin = controller->getSkin();

			const daeURI& uriMesh = skin->getSource();
			element = uriMesh.getElement();
			domGeometry* collGeometry = (domGeometry*) element;

			_ASSERTE (meshCache.Find(collGeometry));
			dMesh* mesh = meshCache.Find(collGeometry)->GetInfo();

			dSkinModifier* skinModifier = LoadSkinController (document, skin, mesh, model, modifierVertexMapCache);
			for (dList<dMeshInstance>::dListNode* node = model->m_meshList.GetFirst(); node; node = node->GetNext()) {
				dMeshInstance& instance = node->GetInfo();
				if ((instance.m_mesh == mesh) && instance.m_boneID == bone->m_boneID) {
					instance.SetModifier (skinModifier);
					break;
				}
			}
		}

		rootBone->Release();

		return colladaRoot;
	}


	dMatrix m_globalRotation;
	dFloat m_scale;
	int m_nodeIndex;
	DAE* m_collada; 
};


#if 0
static dMatrix GetUpMatrix (int updir)
{
	dMatrix matrix (GetIdentityMatrix());
	if (updir == 0) {
		_ASSERTE (0);

	} else if (updir == 2) {
		matrix[0] = dVector (0.0f, 1.0f, 0.0f, 0.0f);
		matrix[1] = dVector (0.0f, 0.0f, 1.0f, 0.0f);
		matrix[2] = dVector (1.0f, 0.0f, 0.0f, 0.0f);
	}
	return matrix;
}


void dSceneNode::LoadColladaScene (NewtonWorld* newtonWorld, const char *fileName, dLoaderContext& context, int upDir)
{
	DAE* dae;
	daeInt error;

//	dae = new DAE;
	dae = CreateDAE ();
	_ASSERTE (dae);

	error = dae->load(fileName);
	_ASSERTE (error == DAE_OK);
	if (error == DAE_OK) {
		dColladaFileParcel parcel(dae, newtonWorld);
		parcel.ColladatToScene (this, &context, m_fullScene, GetUpMatrix (upDir));
		SetMatrix (GetIdentityMatrix());
	}

	delete dae;
}

void dSceneNode::LoadColladaPhysics(NewtonWorld* newtonWorld, const char *fileName, dLoaderContext& context, int upDir)
{
	DAE* dae;
	daeInt error;

//	dae = new DAE;
	dae = CreateDAE ();
	_ASSERTE (dae);

	error = dae->load(fileName);
	_ASSERTE (error == DAE_OK);
	if (error == DAE_OK) {
		dColladaFileParcel parcel(dae, newtonWorld);
		parcel.ColladatToScene (this, &context, m_physicCollisionAndVisual, GetUpMatrix (upDir));
		SetMatrix (GetIdentityMatrix());
	}

	delete dae;
}
#endif









void ExportColladaScene (const char* fileName, const NewtonWorld* world)
{
	_ASSERTE (0);
/*
	DAE* dae;
	daeInt error;
	daeURI* uriName;
	daeDatabase* database;
	daeDocument* document;

	// create a new collada object
	dae = CreateDAE ();
	_ASSERTE (dae);

	dColladaFileParcel parcel(dae, );
	parcel.SceneToCollada (world, context);

	database = dae->getDatabase();
	if (database) {
		document = database->getDocument(daeUInt (0));
		if (document) {
			uriName = document->getDocumentURI();
			error = dae->saveAs(fileName, uriName->getURI());
			_ASSERTE (error == DAE_OK);
		}
	}

	delete dae;
*/
}






void ExportColladaScene (
	const char* name, 
	const NewtonWorld* world, 
	dColladaSceneExportContext* context, 
	const dMatrix& globalRotation, 
	dFloat scale)
{

}







void dModel::LoadCollada (const char* fileName, dLoaderContext& context, const dMatrix& globalRotation, dFloat scale)
{
	DAE* dae;
	daeInt error;

	//	dae = new DAE;
	dae = new DAE;
	_ASSERTE (dae);

	error = dae->load(fileName);
	_ASSERTE (error == DAE_OK);

	if (error == DAE_OK) {
		dColladaFileParcel parcel(dae, globalRotation, scale);
		parcel.ColladatToScene (this, &context);
	}
	delete dae;
}


void dModel::SaveCollada (const char *fileName, const dMatrix& globalRotation, dFloat scale) const
{
	DAE* dae;
	daeInt error;
	daeURI* uriName;
	daeDatabase* database;
	daeDocument* document;

	// create a new collada object
	dae = new DAE;
	_ASSERTE (dae);

	dColladaFileParcel parcel(dae, globalRotation, scale);
	parcel.SceneToCollada ((dModel*) this);

	database = dae->getDatabase();
	if (database) {
		document = database->getDocument(daeUInt (0));
		if (document) {
			uriName = document->getDocumentURI();
			error = dae->saveAs(fileName, uriName->getURI());
			_ASSERTE (error == DAE_OK);
		}
	}
	delete dae;
}



dSceneModelList::dSceneModelList()
	:dList<dModel*>()
{
}

dSceneModelList::~dSceneModelList()
{
	while (GetFirst()) {
		RemoveModel (GetFirst()->GetInfo());
	}
}

void dSceneModelList::AddModel (dModel* model)
{
	Append (model);
	model->AddRef();
}

void dSceneModelList::RemoveModel (dModel* model)
{
	for (dListNode* node = GetFirst(); node; node = node->GetNext()) {
		if (node->GetInfo() == model) {
			node->GetInfo()->Release();
			Remove (node);
			break;
		}
	}
}


void dSceneModelList::ExportVisualScene (const char* fileName, const dMatrix& globalRotation, dFloat scale)
{
	DAE* dae;
	daeInt error;
	daeURI* uriName;
	daeDatabase* database;
	daeDocument* document;

	// create a new collada object
	dae = new DAE;
	_ASSERTE (dae);

	dColladaFileParcel parcel(dae, globalRotation, scale);
	parcel.SceneToCollada (*this);

	database = dae->getDatabase();
	if (database) {
		document = database->getDocument(daeUInt (0));
		if (document) {
			uriName = document->getDocumentURI();
			error = dae->saveAs(fileName, uriName->getURI());
			_ASSERTE (error == DAE_OK);
		}
	}
	delete dae;
}

void dSceneModelList::ExportPhysicsScene (const char* fileName, NewtonWorld* world, const dMatrix& globalRotation, dFloat scale)
{
	DAE* dae;
	daeInt error;
	daeURI* uriName;
	daeDatabase* database;
	daeDocument* document;

	// create a new collada object
	dae = new DAE;
	_ASSERTE (dae);

	dColladaFileParcel parcel(dae, globalRotation, scale);
	parcel.SceneToCollada (world);

	database = dae->getDatabase();
	if (database) {
		document = database->getDocument(daeUInt (0));
		if (document) {
			uriName = document->getDocumentURI();
			error = dae->saveAs(fileName, uriName->getURI());
			_ASSERTE (error == DAE_OK);
		}
	}
	delete dae;
}


void dSceneModelList::ImportVisualScene  (const char* fileName, dLoaderContext& context, const dMatrix& globalRotation, dFloat scale)
{
	DAE* dae;
	daeInt error;

	dae = new DAE;
	_ASSERTE (dae);

	error = dae->load(fileName);
	_ASSERTE (error == DAE_OK);

	if (error == DAE_OK) {
		dColladaFileParcel parcel(dae, globalRotation, scale);
		parcel.ColladatToScene (*this, &context);
	}
	delete dae;
}



void dSceneModelList::ImportPhysicsScene  (const char* fileName, NewtonWorld* world, dLoaderContext& context, const dMatrix& globalRotation, dFloat scale)
{
	DAE* dae;
	daeInt error;

	dae = new DAE;
	_ASSERTE (dae);

	error = dae->load(fileName);
	_ASSERTE (error == DAE_OK);

	if (error == DAE_OK) {
		dColladaFileParcel parcel(dae, globalRotation, scale);
		parcel.ColladatToScene (*this, world, &context);
	}
	delete dae;
}

