/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#include "Common.h"

namespace glTF
{
    int gltf_get_file_index_by_name(glTFHandle* handle, const char* name)
    {
        if(handle == NULL)
            return -1;
        for(unsigned int i = 0; i < handle->size; i++)
        {
            if( (!strcmp(name, (handle->files[i]->filename))))
            {
                return i;
            }
        }
        return -1;
    }
    glTFFile* gltf_get_json_string(glTFHandle* handle)
    {
        if(handle == NULL)
            return NULL;
        for(unsigned int i = 0; i < handle->size; i++)
        {
            if(handle->files[i]->type == GLTF_JSON)
            {
                return handle->files[i];
            }
        }
        return NULL;
    }
    /* -- Attribute -- */
    Attribute::Attribute()
        : pData(0)
        , count(0)
        , mDataType(DataType_UNKNOW)
    {
    }

    Attribute::~Attribute()
    {
        if (0 != pData)
            delete pData;
    }

    void Attribute::setDataCount(unsigned int count)
    {
        this->count = count;
    }

    unsigned int Attribute::getDataCount() const
    {
        return this->count;
    }

    void Attribute::setByteStride(unsigned int byteStride)
    {
        this->mByteStride = byteStride;
    }

    unsigned int Attribute::getByteStride() const
    {
        return this->mByteStride;
    }

    void Attribute::setDataType(DataType_E type)
    {
        this->mDataType = type;
    }

    DataType_E Attribute::getDataType() const
    {
        return this->mDataType;
    }

    void Attribute::setAttributeData(char* pValue, unsigned int length)
    {
        if (0 == pData)
        {
            pData = new char[length];
        }
        memcpy(this->pData, pValue, length);
    }

    const char* Attribute::getAttributeData() const
    {
        return pData;
    }

    /* -- Light -- */
    Light::Light()
        : mPosition           (sqrt(2.0f)/2, -sqrt(2.0f)/2, 0)
        , mDirection          (sqrt(2.0f)/2, -sqrt(2.0f)/2, 0)
        , mColor              (1.0f, 1.0f, 1.0f)
        , mName("light0Color")
    {
        mColorAmbient = new GLfloat[4];
        mColorDiffuse = new GLfloat[4];
        mColorSpecular = new GLfloat[4];
        mPositions     = new GLfloat[4];
        for(int i=0; i<4; i++)
        {
            mColorAmbient[i]  = 1.0;
            mColorDiffuse[i]  = 1.0;
            mColorSpecular[i] = 1.0;
            mPositions[i]     = 1.0;
        }
    }

    Light::~Light()
    {

    }

    void Light::setName(std::string Name)
    {
        this->mName = Name;
    }

    const std::string& Light::getName()
    {
        return mName;
    }

    void Light::setType(LightSourceType_E Type)
    {
        this->mType = Type;
    }

    const LightSourceType_E& Light::getLightSourceType()
    {
        return mType;
    }

    void Light::setPosition(Vector3D Position)
    {
        this->mPosition = Position;
    }

    const Vector3D& Light::getPosition()
    {
        return mPosition;
    }

    void Light::setDirection(Vector3D Direction)
    {
        this->mDirection = Direction;
    }

    const Vector3D& Light::getDirection()
    {
        return mDirection;
    }

    void Light::setAttenuationConstant(float AttenuationConstant)
    {
        this->mAttenuationConstant = AttenuationConstant;
    }

    const float Light::getAttenuationConstant()
    {
        return mAttenuationConstant;
    }

    void Light::setAttenuationLinear(float AttenuationLinear)
    {
        this->mAttenuationLinear = AttenuationLinear;
    }

    const float Light::getAttenuationLinear()
    {
        return mAttenuationLinear;
    }

    void Light::setAttenuationQuadratic(float AttenuationQuadratic)
    {
        this->mAttenuationQuadratic = AttenuationQuadratic;
    }

    const float Light::getAttenuationQuadratic()
    {
        return mAttenuationQuadratic;
    }

    void Light::setColor(Vector3D Color)
    {
        this->mColor = Color;
    }

    const Vector3D Light::getColor()
    {
        return this->mColor;
    }

    void Light::setColorDiffuse(GLfloat* ColorDiffuse)
    {
        for (int i=0; i<3; i++)
        {
            mColorDiffuse[i] =  *ColorDiffuse;
        }
    }

    const GLfloat* Light::getColorDiffuse()
    {
        return mColorDiffuse;
    }

    void Light::setColorSpecular(GLfloat* ColorSpecular)
    {
        for (int i=0; i<3; i++)
        {
            mColorSpecular[i] = *ColorSpecular;
        }
    }

    const GLfloat* Light::getColorSpecular()
    {
        return mColorSpecular;
    }

    void Light::setColorAmbient(GLfloat* ColorAmbient)
    {
        for (int i=0; i<3; i++)
        {
            mColorAmbient[i] = *ColorAmbient;
        }
    }

    const GLfloat* Light::getColorAmbient()
    {
        return mColorAmbient;
    }

    void Light::setPositions(GLfloat *position)
    {
        memcpy(mPositions, position, sizeof(mPositions)*4);
    }
    const GLfloat* Light::getPositions()
    {
        return mPositions;
    }

    /* -- Camera -- */
    Camera::Camera()
        : mPosition (0.0f, 5.0f, 10.0f)
        , mUp		(0.f,1.f,0.f)
        , mLookAt	(0.f,0.f,1.f)
        , mXFov	    (1.0f)
        , mYFov	    (1.2f)
        , mNear  	(0.1f)
        , mFar		(1000.f)
        , mAspectRatio (0.f)
    {
    }

    Camera::~Camera()
    {
    }

    void Camera::setXFov(float xFov)
    {
        this->mXFov = xFov;
    }

    float Camera::getXFov()
    {
        return this->mXFov;
    }

    void Camera::setYFov(float yFov)
    {
        this->mYFov = yFov;
    }

    float Camera::getYFov()
    {
        return this->mYFov;
    }

    void Camera::setFar(float far)
    {
        this->mFar = far;
    }

    float Camera::getFar()
    {
        return this->mFar;
    }

    void Camera::setNear(float near)
    {
        this->mNear = near;
    }

    float Camera::getNear()
    {
        return this->mNear;
    }

    void Camera::setAspectRatio(float aspectRatio)
    {
        this->mAspectRatio = aspectRatio;
    }

    float Camera::getAspectRatio()
    {
        return this->mAspectRatio;
    }

    void Camera::setPosition(Vector3D& vPosition)
    {
        this->mPosition = vPosition;
    }

    Vector3D& Camera::getPosition()
    {
        return this->mPosition;
    }

    void Camera::setLookAt(Vector3D& vLookAt)
    {
        this->mLookAt = vLookAt;
    }

    Vector3D& Camera::getLookAt()
    {
        return this->mLookAt;
    }

    void Camera::setUp(Vector3D& vUp)
    {
        this->mUp = vUp;
    }

    Vector3D& Camera::getUp()
    {
        return this->mUp;
    }

    /* -- TechAttribute -- */
    TechAttribute::TechAttribute()
    {
    }

    TechAttribute::~TechAttribute()
    {
    }

    void TechAttribute::setAttributeName(std::string name)
    {
        this->mAttributeName = name;
    }

    const std::string TechAttribute::getAttributeName()
    {
        return this->mAttributeName;
    }

    void TechAttribute::setAttributeIndex(std::string index)
    {
        this->mAttributeIndex = index;
    }

    const std::string TechAttribute::getAttributeIndex()
    {
        return this->mAttributeIndex;
    }

    /* -- TechUniform -- */
    TechUniform::TechUniform()
    {
    }

    TechUniform::~TechUniform()
    {
    }

    void TechUniform::setUniformName(std::string name)
    {
        this->mUniformName = name;
    }

    const std::string& TechUniform::getUniformName()
    {
        return this->mUniformName;
    }

    void TechUniform::setUniformIndex(std::string index)
    {
        this->mUniformIndex = index;
    }

    const std::string& TechUniform::getUniformIndex()
    {
        return this->mUniformIndex;
    }

    /* -- Technique -- */
    Technique::Technique()
        : mProgramId (0)
        , mTechniqueState (false)
    {
        pState = new TechniqueState();
    }

    Technique::~Technique()
    {
        std::vector<class TechUniform*>::iterator vit;
        for (vit = mTechUnifVec.begin(); vit != mTechUnifVec.end(); ++vit)
        {
            if (0 != *vit)
                delete (*vit);
        }

        std::map<std::string, class TechAttribute*>::iterator mit;
        for (mit = mTechAttrMap.begin(); mit != mTechAttrMap.end(); ++mit)	
        {
            delete mit->second;
        }
        mTechAttrMap.clear();
        freeTechnique();
        delete pState;
    }

    void Technique::setProgramState(bool flag)
    {
        this->mTechniqueState = flag;
    }

    bool Technique::getProgramState() const
    {
        return this->mTechniqueState;
    }

    void Technique::setProgramId(unsigned int id)
    {
        this->mProgramId = id;
    }

    unsigned int Technique::getProgramId() const
    {
        return this->mProgramId;
    }

    void Technique::setVertexShader(std::string shaderName)
    {
        this->mVertexShaderName = shaderName;
    }

    const std::string Technique::getVertexShader()
    {
        return this->mVertexShaderName;
    }

    void Technique::setFragmentShader(std::string shaderName)
    {
        this->mFragmentShaderName = shaderName;
    }

    const std::string Technique::getFragmentShader()
    {
        return this->mFragmentShaderName;
    }

    void Technique::insertTechAttribute(std::string key, class TechAttribute* pTechAttr)
    {
        this->mTechAttrMap.insert(
            std::map<std::string, class TechAttribute*>::value_type(key, pTechAttr));
    }

    class TechAttribute* Technique::getTechAttribute(const std::string& key)
    {
        std::map<std::string, class TechAttribute*>::const_iterator it;
        it = mTechAttrMap.find(key);
        if (it != mTechAttrMap.end())
        {
            return it->second;
        }

        return 0;
    }

    unsigned int Technique::getTechAttributeSize() const
    {
        return this->mTechAttrMap.size();
    }

    void Technique::setTechUniform(class TechUniform* pUniform)
    {
        (this->mTechUnifVec).push_back(pUniform);
    }

    class TechUniform* Technique::getTechUniform(unsigned int index)
    {
        if (this->mTechUnifVec.size() <= index)
            return 0;
        return this->mTechUnifVec[index];
    }

    unsigned int Technique::getTechUniformSize() const
    {
        return this->mTechUnifVec.size();
    }

    TechniqueState* Technique::getTechState()
    {
        return pState;
    }

    void Technique::initTechnique(glTFHandle* pGltfHandle)
    {
        int vShaderIdx = gltf_get_file_index_by_name(pGltfHandle, mVertexShaderName.c_str());
        int fShaderIdx = gltf_get_file_index_by_name(pGltfHandle, mFragmentShaderName.c_str());
        if(vShaderIdx >= 0 && fShaderIdx >= 0)
        {
            const char* pvShader = pGltfHandle->files[vShaderIdx]->buffer;
            const char* pfShader = pGltfHandle->files[fShaderIdx]->buffer;
            mProgramId = mShaderProg.createProgram(pvShader, pfShader);
        }
        if (0 != mProgramId)
        {
            this->setProgramState(true);
        }
    }

    void Technique::useTechnique()
    {
        mShaderProg.useProgram(0);
        mShaderProg.useProgram(mProgramId);
    }
    
    void Technique::freeTechnique()
    {
        mShaderProg.deleteProgram(mProgramId);
        this->setProgramState(false);
    }

    /* -- MaterialProperty -- */
    MaterialProperty::MaterialProperty()
        : mTextureType(TextureType_NONE)
        , mDataType(DataType_UNKNOW)
        , mDataLength(0)
        , pData(0)
    {
    }

    MaterialProperty::~MaterialProperty()
    {
        delete pData;
    }

    void MaterialProperty::setPropertyName(std::string name)
    {
        this->mPropertyName = name;
    }

    const std::string& MaterialProperty::getPropertyName() const
    {
        return this->mPropertyName;
    }

    void MaterialProperty::setImagePath(std::string index)
    {
        this->mImagePath = index;
    }

    const std::string& MaterialProperty::getImagePath() const
    {
        return this->mImagePath;
    }

    void MaterialProperty::setDataLength(unsigned int length)
    {
        this->mDataLength = length;
    }

    unsigned int MaterialProperty::getDataLength()
    {
        return this->mDataLength;
    }

    void MaterialProperty::setDataType(DataType_E type)
    {
        this->mDataType = type;
    }

    DataType_E MaterialProperty::getDataType() const
    {
        return this->mDataType;
    }

    void MaterialProperty::setPropertyData(char* pValue)
    {
        this->pData = pValue;
    }

    const char* MaterialProperty::getPropertyData() const
    {
        return pData;
    }

    /* -- Material -- */
    Material::Material()
    {
    }

    Material::~Material()
    {
        std::vector<class MaterialProperty*>::iterator it;
        for (it = mPropertyVec.begin(); it != mPropertyVec.end(); ++it)
        {
            if (0 != *it)
                delete (*it);
        }
        mPropertyVec.clear();
    }

    void Material::pushMaterialProper(class MaterialProperty* pProperty)
    {
        this->mPropertyVec.push_back(pProperty);
    }

    const class MaterialProperty* Material::getMaterialProper(unsigned int index)
    {
        if (this->mPropertyVec.size() <= index)
            return 0;
        return this->mPropertyVec[index];
    }

    unsigned int Material::getMaterialProperSize()
    {
        return this->mPropertyVec.size();
    }

    void Material::setTechniqueId(std::string techniqueId)
    {
        this->mTechniqueId = techniqueId;
    }

    const std::string& Material::getTechniqueId() const
    {
        return this->mTechniqueId;
    }

    /* -- Primitives -- */
    Primitives::Primitives()
    {
    };

    Primitives::~Primitives()
    {
        mAttributeMap.clear();
    };

    void Primitives::setMaterialIndex(std::string materialIndex)
    {
        this->mMaterialIndex = materialIndex;
    }

    const std::string Primitives::getMaterialIndex() const
    {
        return this->mMaterialIndex;
    }

    void Primitives::setIndicesIndex(std::string indicesIndex)
    {
        this->mIndicesIndex = indicesIndex;
    }

    const std::string Primitives::getIndicesIndex() const
    {
        return this->mIndicesIndex;
    }

    void Primitives::insertAttribute(std::string key, std::string value)
    {
        mAttributeMap.insert(
            std::map<std::string, std::string>::value_type(key, value));
    }

    const std::string Primitives::getAttributeIndex(const std::string& key) const
    {
        std::map<std::string, std::string>::const_iterator it;
        it = mAttributeMap.find(key);
        if (it != mAttributeMap.end())
        {
            return it->second;
        }

        return "";
    }

    unsigned int Primitives::getAttributeSize() const
    {
        return this->mAttributeMap.size();
    }

    /* -- Mesh -- */
    Mesh::Mesh()
    {
    }

    Mesh::~Mesh()
    {
        std::vector<class Primitives*>::iterator it;
        for (it = mPrimitiveVec.begin(); it != mPrimitiveVec.end(); ++it)
        {
            if (0 != *it)
                delete (*it);
        }
        mPrimitiveVec.clear();
    }

    void Mesh::setMeshName(std::string mName)
    {
        this->mName = mName;
    }

    const std::string Mesh::getMeshName()
    {
        return this->mName;
    }

    void Mesh::setPrimitiveVec(class Primitives* pPrim)
    {
        (this->mPrimitiveVec).push_back(pPrim);
    }

    const class Primitives* Mesh::getPrimitiveVec(unsigned int index) const
    {
        if (this->mPrimitiveVec.size() <= index)
            return 0;
        return this->mPrimitiveVec[index];
    }

    unsigned int Mesh::getPrimitiveVecSize() const
    {
        return this->mPrimitiveVec.size();
    }

    /* -- Node -- */
    Node::Node()
        : mNodeType(NodeType_Init)
        , pParent(0)
        , pMatrix(0)
        , LightFlag(1)
        , bFlagCamera(false)
    {
    }

    Node::~Node()
    {
        std::vector<class Node*>::iterator it;
        for (it = mChildrenVec.begin(); it != mChildrenVec.end(); ++it)
        {
            if (0 != *it)
                delete (*it);
        }
        mChildrenVec.clear();
        delete pMatrix;
    }

    void Node::setMatrix(glm::mat4* matrix)
    {
        this->pMatrix = matrix;
    }

    glm::mat4* Node::getMatrix() const
    {
        return this->pMatrix;
    }

    void Node::setNodeType(NodeType_E _type)
    {
        this->mNodeType = _type;
    }

    NodeType_E Node::getNodeType() const
    {
        return this->mNodeType;
    }

    void Node::setNodeName(std::string name)
    {
        this->mName = name;
    }

    const std::string Node::getNodeName() const
    {
        return this->mName;
    }

    void Node::setLightIndex(std::string lightIndex)
    {
        this->mLightIndex = lightIndex;
    }

    const std::string Node::getLightIndex() const
    {
        return this->mLightIndex;
    }

    void Node::setCameraIndex(std::string cameraIndex)
    {
        this->mCameraIndex = cameraIndex;
    }

    const std::string Node::getCameraIndex()
    {
        return this->mCameraIndex;
    }

    void Node::pushMeshIndex(std::string& _index)
    {
        (this->mMesheIndexVec).push_back(_index);
    }

    const std::string Node::getMeshIndex(unsigned int index) const
    {
        if (this->mMesheIndexVec.size() <= index)
            return NULL;
        return this->mMesheIndexVec[index];
    }

    unsigned int Node::getMeshIndexSize() const
    {
        return this->mMesheIndexVec.size();
    }

    void Node::pushChildNode(class Node* pNode)
    {
        (this->mChildrenVec).push_back(pNode);
    }

    const class Node* Node::getChildNode(unsigned int index) const
    {
        if (this->mChildrenVec.size() <= index)
            return 0;
        return this->mChildrenVec[index];
    }

    class Node* Node::getChildrenNode(unsigned int index)
    {
        if (this->mChildrenVec.size() <= index)
            return 0;
        return this->mChildrenVec[index];
    }

    unsigned int Node::getChildNodeSize() const
    {
        return this->mChildrenVec.size();
    }

    void Node::setParentNode(class Node* pParentNode)
    {
        this->pParent = pParentNode;
    }

    const class Node* Node::getParentNode()
    {
        return this->pParent;
    }
    const int Node::getLightFlag()
    {
        return this->LightFlag;
    }
    void Node::setLightFlag()
    {
        this->LightFlag = 0;
    }

    /* -- Scene -- */
    Scene::Scene()
        : pRootNode(0)
        , pBuffer(0)
        , pGltfHandle(0)
        , mVertexMin(1e10f, 1e10f, 1e10f)
        , mVertexMax(-1e10f, -1e10f, -1e10f)
    {
    }

    Scene::~Scene()
    {
        freeMap(mMeshMap);
        freeMap(mMaterialMap);
        freeMap(mLightMap);
        freeMap(mCameraMap);
        freeMap(mAttributeMap);
        freeMap(mTechniqueMap);
        freeTexture();
        delete pRootNode;  
        delete pBuffer;
        mNodeVec.clear();
    }

    void Scene::freeTexture()
    {
        std::map<std::string, class Texture*>::iterator it_2;
        for (it_2 = mTexturesMap.begin();it_2!=mTexturesMap.end();++it_2)
        {
            if(NULL !=it_2->second)
            {
                it_2->second->deleteTexture();
            }
        }
    }

    template<typename M> void Scene::freeMap(M& aMap)
    {
        for (typename M::iterator it = aMap.begin(); it != aMap.end(); ++it)
        {
            delete it->second;
        }
        aMap.clear();
    }

    class Mesh* Scene::findMesh(const std::string& key)
    {
        std::map<std::string, class Mesh*>::iterator it;
        it = mMeshMap.find(key);
        if (it != mMeshMap.end())
        {
            return it->second;
        }

        return 0;
    }

    class Material* Scene::findMaterial(const std::string& key)
    {
        std::map<std::string, class Material*>::iterator it;
        it = mMaterialMap.find(key);
        if (it != mMaterialMap.end())
        {
            return it->second;
        }
        return 0;
    }

    std::string Scene::GetLightIndex()
    {
        for (unsigned int i=0; i<pRootNode->getChildNodeSize(); i++)
        {
            const class Node *pNode = pRootNode->getChildNode(i);
            if ( pNode->getLightIndex() != "")
                return pNode->getLightIndex();
        }
        return "";
    }

    int Scene::getLight()
    {
        return pRootNode->getLightFlag();
    }

    class Camera* Scene::findCamera(const std::string& key)
    {
        std::map<std::string, class Camera*>::iterator it;
        it = mCameraMap.find(key);
        if (it != mCameraMap.end())
        {
            return it->second;
        }
        return 0;
    }

    const std::string Scene::getCameraIndex() const
    {
        return this->pRootNode->getChildrenNode(1)->getCameraIndex();
    }

    const glm::mat4* Scene::getCameraMatrix() const
    {
        return this->pRootNode->getChildrenNode(1)->getMatrix();
    }

    class Light* Scene::findLight(const std::string& key)
    {
        std::map<std::string, class Light*>::iterator it;
        it = mLightMap.find(key);
        if( it != mLightMap.end())
        {
            return it->second;
        }
        return 0;
    }

    const class Attribute* Scene::findAttribute(const std::string& key)
    {
        std::map<std::string, class Attribute*>::iterator it;
        it = mAttributeMap.find(key);
        if (it != mAttributeMap.end())
        {
            return it->second;
        }
        return 0;
    }

    class Technique* Scene::findTechnique(const std::string& key)
    {
        std::map<std::string, class Technique*>::iterator it;
        it = mTechniqueMap.find(key);
        if (it != mTechniqueMap.end())
        {
            return it->second;
        }
        return 0;
    }

    glm::mat4* Scene::findLightTransformation()
    {
        for (unsigned int i=0; i<pRootNode->getChildNodeSize(); i++)
        {
            const class Node *pNode = pRootNode->getChildNode(i);
            if ( pNode->getLightIndex() != "")
                return pNode->getMatrix();
        }
        return new glm::mat4(1.0f);
    }

    const class Node* Scene::getRootNode() const
    {
        return this->pRootNode;
    }

    void Scene::setRootNode(class Node* pNode)
    {
        this->pRootNode = pNode;
    }

    void Scene::pushNode(class Node* pNode)
    {
        this->mNodeVec.push_back(pNode);
    }

    const class Node* Scene::getNode(unsigned int index)
    {
        if (this->mNodeVec.size() <= index)
            return 0;
        return this->mNodeVec[index];
    }

    unsigned int Scene::getNodeSize()
    {
        return this->mNodeVec.size();
    }

    char* Scene::getBuffer(unsigned int length)
    {
        if (0 == this->pBuffer && 0 != length)
        {
            this->pBuffer = new char[length];
        }
        return this->pBuffer;
    }
    
    bool Scene::setBuffer(const std::string& binName, unsigned int length)
    {
        int idx = gltf_get_file_index_by_name(pGltfHandle, binName.c_str());
        if(idx >= 0)
        {
            memcpy(pBuffer, pGltfHandle->files[idx]->buffer, length);
            return true;
        }
        return false;
    }

    void Scene::setVertexMax(float x, float y, float z)
    {
        mVertexMax.x = std::max(x, mVertexMax.x);
        mVertexMax.y = std::max(y, mVertexMax.y);
        mVertexMax.z = std::max(z, mVertexMax.z);
    }

    glm::vec3& Scene::getVertexMax()
    {
        return mVertexMax;
    }

    void Scene::setVertexMin(float x, float y, float z)
    {
        mVertexMin.x = std::min(x, mVertexMin.x);
        mVertexMin.y = std::min(y, mVertexMin.y);
        mVertexMin.z = std::min(z, mVertexMin.z);
    }

    glm::vec3& Scene::getVertexMin()
    {
        return mVertexMin;
    }

    void Scene::insertMeshMap(std::string key, class Mesh* pMesh)
    {
        this->mMeshMap.insert(
            std::map<std::string, class Mesh*>::value_type(key, pMesh));
    }

    void Scene::insertMaterialMap(std::string key, class Material* pMaterial)
    {
        this->mMaterialMap.insert(
            std::map<std::string, class Material*>::value_type(key, pMaterial));
    }

    void Scene::insertCameraMap(std::string key, class Camera* pCamera)
    {
        this->mCameraMap.insert(
            std::map<std::string, class Camera*>::value_type(key, pCamera));
    }

    void Scene::insertLightMap(std::string key, class Light* pLight)
    {
        this->mLightMap.insert(
            std::map<std::string, class Light*>::value_type(key, pLight));
    }

    void Scene::insertAttributeMap(std::string key, class Attribute* pAttribute)
    {
        this->mAttributeMap.insert(
            std::map<std::string, class Attribute*>::value_type(key, pAttribute));
    }

    void Scene::insertTechniqueMap(std::string key, class Technique* pTechnique)
    {
        this->mTechniqueMap.insert(
            std::map<std::string, class Technique*>::value_type(key, pTechnique));
    }
  
    bool Scene::loadTexture(std::string imagePath)
    {
        if (findTexture(imagePath) == NULL)
        {
            Texture* oneTexture = new Texture();

            glTFFile* pglTFFile = getGltfFileByFileName(imagePath);
            oneTexture->loadTexture2DFromBuffer((unsigned char*)(pglTFFile->buffer),pglTFFile->imagewidth, pglTFFile->imageheight);

            
            oneTexture->setFiltering(TEXTURE_FILTER_MAG_NEAREST, TEXTURE_FILTER_MIN_NEAREST);
            insertTextureMap(imagePath,oneTexture);
        }
        return true;
    }

    Texture* Scene::findTexture(const std::string& key)
    {
        std::map<std::string, class Texture*>::iterator it;
        it = mTexturesMap.find(key);
        if (it != mTexturesMap.end())
        {
            return it->second;
        }
        return NULL;
    }

    void Scene::insertTextureMap(std::string key, class Texture* pTexture)
    {
        this->mTexturesMap.insert(
            std::map<std::string, class Texture*>::value_type(key, pTexture));
    }

    void Scene::setGltfHandle(glTFHandle* handle)
    {
        if(handle != NULL)
            this->pGltfHandle = handle;
    }

    glTFHandle* Scene::getGltfHandle()
    {
        return this->pGltfHandle;
    }

    glTFFile* Scene::getGltfFileByFileName(std::string fileName)
    {
        if (pGltfHandle == NULL)
        {
            return NULL;
        }
        for (unsigned int i = 0;i< pGltfHandle->size;i++)
        {
            if (!strcmp(pGltfHandle->files[i]->filename, fileName.c_str()))
            {
                return pGltfHandle->files[i];
            }
        }
        return NULL;
    }
}
