//------------------------------
    bool LibraryEffectsLoader::fillSamplerArray ()
    {
        COLLADAFW::EffectCommon& commonEffect =  *mCurrentEffect->getCommonEffects().back();
        COLLADAFW::SamplerPointerArray& samplerArray = commonEffect.getSamplerPointerArray();

        // Iterate over the list of used samplers in the current effect profile 
        // and push them in the sampler array.
		size_t samplerCount = mEffectProfileSamplersMap.size();
		samplerArray.reallocMemory(samplerCount);
		samplerArray.setCount(samplerCount);
        StringIndexMap::const_iterator it = mEffectProfileSamplersMap.begin ();
        while ( it != mEffectProfileSamplersMap.end () )
        {
            String samplerSid = it->first;
			size_t samplerIndex = it->second;

            bool validSampler =  false;
            SidSamplerInfoMap::iterator samplerIt = mEffectProfileSidSamplerInfoMap.find ( samplerSid );
            
            if ( samplerIt == mEffectProfileSidSamplerInfoMap.end () )
            {
                samplerIt = mEffectSidSamplerInfoMap.find ( samplerSid );
                if ( samplerIt != mEffectSidSamplerInfoMap.end () ) validSampler = true;
            }
            else validSampler = true;
            
            if ( validSampler )
            {
                SamplerInfo& samplerInfo = samplerIt->second;
                samplerInfo.id = samplerArray.getCount();
                COLLADAFW::Sampler* sampler = samplerInfo.sampler;
                sampler->setSid(samplerSid);
                if ( !sampler->getSourceImage().isValid() )
                {
                    bool validSurface = false;
                    SidSurfaceMap::const_iterator surfaceIt = mEffectProfileSidSurfaceMap.find( samplerInfo.surfaceSid );
                    if ( surfaceIt == mEffectProfileSidSurfaceMap.end() )
                    {
                        surfaceIt = mEffectSidSurfaceMap.find( samplerInfo.surfaceSid );
                        if ( surfaceIt != mEffectSidSurfaceMap.end() ) validSurface = true;
                    }
                    else validSurface = true;
                    if ( validSurface )
                    {
                        const Surface& surface = surfaceIt->second;
                        sampler->setSource(surface.imageUniqueId);

                        // copy sampler into common effect
                        samplerArray[samplerIndex] = sampler->clone();
                    }
                }
                else
                {
					samplerArray[samplerIndex] = sampler->clone();
                }
            }
            else
			{
				// we a null sampler here, to ensure the index of all of the following sampler remain correct
				samplerArray[samplerIndex] = 0;

				if ( !handleFWLError ( SaxFWLError::ERROR_UNRESOLVED_REFERENCE, "No sampler for texture \"" + samplerSid + "\" defined!" ))
					return false;
			}
            ++it;
        }

		return true;
    }
	//------------------------------
	bool LibraryEffectsLoader::handleExtraEffectTextures( const COLLADAFW::PointerArray<COLLADAFW::TextureAttributes>& effectTextures )
	{
		bool success = true;

		size_t countExtraTextures = effectTextures.getCount();
		if( countExtraTextures == 0 )
			return success;

// 		switch ( mCurrentProfile )
// 		{
// 		case PROFILE_COMMON:
//			{

		for( size_t iTexture = 0; iTexture < countExtraTextures; ++iTexture )
		{
			COLLADAFW::TextureAttributes* textureAttributes = effectTextures[iTexture];
			if( textureAttributes == 0 )
				continue;

			// Check if the texture is referenced.
			const String& textureSid = textureAttributes->textureSampler;
			SidSamplerInfoMap::const_iterator it = mEffectProfileSidSamplerInfoMap.find(textureSid);
			if ( it == mEffectProfileSidSamplerInfoMap.end() )
			{
				it = mEffectSidSamplerInfoMap.find( textureSid );
				if ( it == mEffectSidSamplerInfoMap.end() )
				{
					String msg("Texture with sid \"" + textureSid + "\" not found");
					if ( mCurrentEffect )
					{
						msg += " in effect with id \"" + mCurrentEffect->getOriginalId() + "\"";
					}
					msg += ".";
					success = handleFWLError ( SaxFWLError::ERROR_UNRESOLVED_REFERENCE, msg );
					continue;;
				}
			}

			// Push the texture sid of the current sampler in the list of used samplers
			// of the current effect profile. 
			size_t samplerIndex = 0;
			StringIndexMap::const_iterator samplerIt = mEffectProfileSamplersMap.find(textureSid);
			if ( samplerIt == mEffectProfileSamplersMap.end() )
			{
				// This sid has not been used before. Add to map with next index
				samplerIndex = mNextSamplerIndex;
				mEffectProfileSamplersMap.insert(std::make_pair(textureSid, mNextSamplerIndex++));
			}
			else
			{
				// This sid is already in the map. Use its index
				samplerIndex = samplerIt->second;
			}

			// Initialize the texture element.
			//bumpMap.setUniqueId ( createUniqueId(COLLADAFW::Texture::ID()) ); //texture id?
			textureAttributes->samplerId = samplerIndex;
			if ( !(textureAttributes->texCoord.empty()) )
				textureAttributes->textureMapId = getTextureMapIdBySematic( textureAttributes->texCoord );
		}

//				break;
//			}
//		}
		return success;
	}
//-----------------------------
bool DocumentProcessor::createAndWriteSkinController( const Loader::InstanceControllerData& instanceControllerData,
        const COLLADAFW::UniqueId& controllerDataUniqueId,
        const COLLADAFW::UniqueId& sourceUniqueId,
        const StringList& sidsOrIds,
        bool resolveIds)
{
    if ( !controllerDataUniqueId.isValid() )
        return false;

    const URIList& skeletonRoots = instanceControllerData.skeletonRoots;

    NodeList joints;

    for ( StringList::const_iterator it = sidsOrIds.begin(); it != sidsOrIds.end(); ++it)
    {
        const String sidOrId = *it;

        bool jointFound = false;

        if ( resolveIds )
        {
            const SidTreeNode* joint = resolveSid( sidOrId );
            if ( joint )
            {
                // the joint could be found
                if ( joint->getTargetType() == SidTreeNode::TARGETTYPECLASS_OBJECT )
                {
                    const COLLADAFW::Object* object = joint->getObjectTarget();

                    if ( object->getClassId() == COLLADAFW::Node::ID() )
                    {
                        joints.push_back( (COLLADAFW::Node*)object );

                        jointFound = true;
                        //search for the next joint
                    }
                    else
                    {
                        // we could resolve the sid, but is not a joint/node
                    }
                }
                else
                {
                    // we could resolve the sid, but is not a joint/node
                }
            }
        }
        else
        {
            for ( URIList::const_iterator skeletonIt = skeletonRoots.begin(); skeletonIt != skeletonRoots.end(); ++skeletonIt)
            {
                const COLLADABU::URI& skeletonUri = *skeletonIt;

                SidAddress sidAddress( skeletonUri, sidOrId );
                const SidTreeNode* joint = resolveSid( sidAddress );
                if ( joint )
                {
                    // the joint could be found
                    if ( joint->getTargetType() != SidTreeNode::TARGETTYPECLASS_OBJECT )
                    {
                        // we could resolve the sid, but is not a joint/node
                        break;
                    }

                    const COLLADAFW::Object* object = joint->getObjectTarget();

                    if ( object->getClassId() != COLLADAFW::Node::ID() )
                    {
                        // we could resolve the sid, but is not a joint/node
                        break;
                    }

                    joints.push_back( (COLLADAFW::Node*)object );

                    jointFound = true;
                    //search for the next joint
                    break;
                }
            }
        }


        if ( !jointFound )
        {
            std::stringstream msg;
            msg << "Could not resolve " << (resolveIds ? "id" : "sid") << " \"";
            msg << sidOrId << "\" referenced in skin controller.";
            if ( handleFWLError( SaxFWLError::ERROR_UNRESOLVED_REFERENCE, msg.str() ))
            {
                return false;
            }
        }
    }

    COLLADAFW::SkinController skinController( createUniqueId(COLLADAFW::SkinController::ID()));

    COLLADAFW::UniqueIdArray &jointsUniqueIds = skinController.getJoints();
    jointsUniqueIds.allocMemory( joints.size() );
    jointsUniqueIds.setCount(joints.size());

    size_t i = 0;
    NodeList::const_iterator it = joints.begin();
    for ( ; it != joints.end(); ++it, ++i )
    {
        const COLLADAFW::Node* node = *it;
        jointsUniqueIds[i] = node->getUniqueId();
    }

    skinController.setSkinControllerData(controllerDataUniqueId);
    skinController.setSource(sourceUniqueId);

    bool success = true;
    // Check if we have already wrote a skin controller that describes the same controller, i.e. has same
    // source, skin data and joints. If so, do not write it again and reference the previously used in the
    // scene graph
    const COLLADAFW::SkinController* skinControllerToWrite = 0;
    Loader::SkinControllerSet::const_iterator skinControllerIt = mSkinControllerSet.find( skinController );
    if ( skinControllerIt == mSkinControllerSet.end() )
    {
        skinControllerToWrite = &skinController;
        success = writer()->writeController(skinControllerToWrite);
        mSkinControllerSet.insert( skinController );
    }
    else
    {
        skinControllerToWrite = &(*skinControllerIt);
    }

    instanceControllerData.instanceController->setInstanciatedObjectId( skinControllerToWrite->getUniqueId() );

    return success;
}
	//------------------------------
	bool LibraryEffectsLoader::handleTexture( const texture__AttributeData& attributeData )
	{
		bool success = true;
		switch ( mCurrentProfile )
		{
		case PROFILE_COMMON:
			{
                // Get the current color or texture element.
				COLLADAFW::ColorOrTexture* colorOrTexture = getCurrentColorOrTexture ( true );

                // Check if the texture is referenced.
                String textureSid = (const char *)attributeData.texture;
				SidSamplerInfoMap::const_iterator it = mEffectProfileSidSamplerInfoMap.find(textureSid);
				if ( it == mEffectProfileSidSamplerInfoMap.end() )
                {
                    it = mEffectSidSamplerInfoMap.find((const char*)attributeData.texture);
                    if ( it == mEffectSidSamplerInfoMap.end() )
                    {
						String msg("Texture with sid \"" + textureSid + "\" not found");
						if ( mCurrentEffect )
						{
							msg += " in effect with id \"" + mCurrentEffect->getOriginalId() + "\"";
						}
						msg += ".";
                        success = handleFWLError ( SaxFWLError::ERROR_UNRESOLVED_REFERENCE, msg );
                        break;
                    }
                }

				// Push the texture sid of the current sampler in the list of used samplers
				// of the current effect profile. 
				size_t samplerIndex = 0;
				StringIndexMap::const_iterator samplerIt = mEffectProfileSamplersMap.find(textureSid);
				if ( samplerIt == mEffectProfileSamplersMap.end() )
				{
					// This sid has not been used before. Add to map with next index
					samplerIndex = mNextSamplerIndex;
					mEffectProfileSamplersMap.insert(std::make_pair(textureSid, mNextSamplerIndex++));
				}
				else
				{
					// This sid is already in the map. Use its index
					samplerIndex = samplerIt->second;
				}

				// Initialize the texture element.
				/* const SamplerInfo& samplerInfo = it->second; */ /* UNUSED */
				colorOrTexture->setType(COLLADAFW::ColorOrTexture::TEXTURE);
				COLLADAFW::Texture& texture = colorOrTexture->getTexture();
                texture.setUniqueId ( createUniqueId(COLLADAFW::Texture::ID()) );
				texture.setSamplerId( samplerIndex );
				if ( attributeData.texcoord )
				{
					texture.setTextureMapId( getTextureMapIdBySematic( attributeData.texcoord) );
                    texture.setTexcoord(attributeData.texcoord);
                }

				break;
			}
            /*
                PROFILE_BRIDGE,
                PROFILE_CG,
                PROFILE_GLES,
                PROFILE_GLES2,
                PROFILE_GLSL,
                PROFILE_COMMON,
                PROFILE_NONE
              */
            default:
                break;
		}
		return success;

	}
	//------------------------------
	bool LibraryControllersLoader::begin__input____InputLocal( const input____InputLocal__AttributeData& attributeData )
	{
		// we ignore inputs that don't have semantics or source
		if ( !attributeData.semantic || !attributeData.source  )
		{
			return true;
		}

		ControllerInputSemantics semantic = getControllerInputSemanticsBySemanticStr( attributeData.semantic );
		if ( semantic == SEMANTIC_UNKNOWN )
		{
			return true;
		}

		switch ( mCurrentControllerType )
		{
		case SKIN_CONTROLLER:
			{
				switch ( semantic )
				{
				case SEMANTIC_JOINT:
					{
						if ( !mCurrentSkinControllerData )
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);

						const StringList* nodeSidsOrIds = 0;
						bool isIdArray = false;
						StringListMap::const_iterator itSid = mJointSidsMap.find(sourceId);
						// check if the node sid array could be found
						if ( itSid != mJointSidsMap.end() )
						{
							nodeSidsOrIds = &itSid->second;
							isIdArray = false;
						}
						else
						{
							// check if it is an id_array
							StringListMap::const_iterator itId = mJointIdsMap.find(sourceId);
							if ( itId != mJointIdsMap.end() )
							{
								nodeSidsOrIds = &itId->second;
								isIdArray = true;
							}
							else
							{
								if ( !handleFWLError ( SaxFWLError::ERROR_SOURCE_NOT_FOUND, "Source with id \"" + sourceId + "\" in skin controller with  id \"" + mOriginalId + "\" used in input with semantic SEMANTIC_JOINT could not be found!" ))
									return false;
								break;
							}
						}

						const COLLADAFW::UniqueId& controllerUniqueId = mCurrentSkinControllerData->getUniqueId();
						addSkinDataJointSidsPair( controllerUniqueId, *nodeSidsOrIds, isIdArray);

						// try to write the SkinController here
						if ( ((getObjectFlags() & Loader::CONTROLLER_FLAG) != 0) && (mCurrentControllerSourceUniqueId.isValid()) )
						{
							Loader::InstanceControllerDataList& instanceControllerDataList = getInstanceControllerDataListByControllerUniqueId(controllerUniqueId);
							Loader::InstanceControllerDataList::iterator listIt = instanceControllerDataList.begin();

							while ( listIt != instanceControllerDataList.end() )
							{
								const Loader::InstanceControllerData& instanceControllerData = *listIt;
								bool success = getFileLoader()->createAndWriteSkinController( instanceControllerData, 
																					   		  controllerUniqueId, 
									                                                          mCurrentControllerSourceUniqueId,
									                                                          *nodeSidsOrIds,
																							  isIdArray);
								//on success we need to remove this controller instance
								if ( success )
								{
									listIt = instanceControllerDataList.erase( listIt );
								}
								else
								{
									listIt++;
								}
							}
						}
						mCurrentSkinControllerData->setJointsCount(nodeSidsOrIds->size());
					}
					break;
				case SEMANTIC_INV_BIND_MATRIX:
					{
						if ( !mCurrentSkinControllerData)
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);
						SourceBase* sourceBase = getSourceById ( sourceId );

						if ( !sourceBase || (sourceBase->getDataType() != SourceBase::DATA_TYPE_REAL) )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "SourceBase of skin controller with semantic SEMANTIC_INV_BIND_MATRIX not valid!" );
							break;
						}

						if ( sourceBase->getStride() != 16 )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "Stride of sourceBase of skin controller with semantic SEMANTIC_INV_BIND_MATRIX not valid!" );
							break;
						}

						const RealSource *inverseBindMatricesSource = (const RealSource *)sourceBase;
						const RealArrayElement& inverseBindMatricesElement = inverseBindMatricesSource->getArrayElement();

						const RealArray& inverseBindMatricesArray = inverseBindMatricesElement.getValues();

						size_t matrixElementsCount = inverseBindMatricesArray.getCount();

						size_t matrixCount = matrixElementsCount / 16;


						COLLADAFW::Matrix4Array& inverseBindMatrices = mCurrentSkinControllerData->getInverseBindMatrices();
						inverseBindMatrices.allocMemory( matrixCount );
						inverseBindMatrices.setCount( matrixCount );

						size_t index = 0;
						for ( size_t i = 0; i < matrixCount; ++i)
						{
							// fill the matrix
							COLLADABU::Math::Matrix4 matrix;
							for ( size_t j = 0; j < 16; ++j,++index)
							{
								matrix.setElement( j, inverseBindMatricesArray[index]);
							}
							inverseBindMatrices[i] = matrix;
						}
					}
					break;
				}
			}
			break;
		case MORPH_CONTROLLER:
			{
				switch ( semantic )
				{
				case SEMANTIC_MORPH_TARGET:
					{
						if ( !mCurrentMorphController )
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);
						StringListMap::const_iterator it = mJointIdsMap.find(sourceId);

						// check if the node sid array could be found
						if ( it == mJointIdsMap.end() )
						{
							if ( !handleFWLError ( SaxFWLError::ERROR_SOURCE_NOT_FOUND, "Source with id \"" + sourceId + "\" in morph controller with  id \"" + mOriginalId + "\" used in input with semantic SEMANTIC_MORPH_TARGET could not be found!" ))
								return false;
							break;
						}

						const StringList& meshIds = it->second;
						size_t meshIdCount = meshIds.size();

						COLLADAFW::UniqueIdArray& morphTargets = mCurrentMorphController->getMorphTargets();
						morphTargets.allocMemory(meshIdCount);
						morphTargets.setCount(meshIdCount);
						StringList::const_iterator itTarget = meshIds.begin();
						for ( size_t i = 0 ; itTarget != meshIds.end(); ++itTarget, ++i)
						{
							morphTargets[i] = createUniqueIdFromId( itTarget->c_str(), COLLADAFW::Geometry::ID());
						}

					}
					break;
				case SEMANTIC_MORPH_WEIGHT:
					{
						if ( !mCurrentMorphController)
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);
						SourceBase* sourceBase = getSourceById( sourceId );

						if ( !sourceBase || (sourceBase->getDataType() != SourceBase::DATA_TYPE_REAL) )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "SourceBase of skin controller with semantic SEMANTIC_MORPH_WEIGHT not valid!" );
							break;
						}


						unsigned long long stride = sourceBase->getStride();
						if( stride == 0 )
						{
							handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "Stride of sourceBase of skin controller with semantic SEMANTIC_MORPH_WEIGHT not found! Assuming stride 1!" );
							stride = 1;
						}
						if ( stride != 1 )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "Stride of sourceBase of skin controller with semantic SEMANTIC_MORPH_WEIGHT not valid!" );
							break;
						}
						const RealSource *weightSource = (const RealSource *)sourceBase;
						COLLADAFW::FloatOrDoubleArray& morphWeights = mCurrentMorphController->getMorphWeights();
						addToSidTree( sourceId.c_str(), 0, &morphWeights );
						moveUpInSidTree();

						setRealValues( morphWeights, weightSource );
					}
					break;
				}
			}
			break;
		}

		return true;
	}