// Load and register all the resources needed by the GUI system
//-----------------------------------------------------------------------------
CPUTResult CPUTGuiControllerOGL::Initialize(const std::string& materialName, const std::string& fontName)
{
    CPUTResult result = CPUT_SUCCESS;

	std::string name = "$cbGUIValues";
    CPUTBufferDesc desc;
    desc.cpuAccess = BUFFER_CPU_WRITE;
    desc.memory = BUFFER_DYNAMIC;
    desc.target = BUFFER_UNIFORM;
    desc.pData = NULL;
    desc.sizeBytes = sizeof(GUIConstantBufferVS);
    mpConstantBufferVS = CPUTBuffer::Create(name, &desc);
   
    CPUTAssetLibraryOGL *pAssetLibrary = NULL;
    pAssetLibrary = (CPUTAssetLibraryOGL*)CPUTAssetLibraryOGL::GetAssetLibrary();
    pAssetLibrary->AddConstantBuffer("", name, "", mpConstantBufferVS);

    mpMaterial = pAssetLibrary->GetMaterial(materialName);
    mpFont = pAssetLibrary->GetFont(fontName);

    CPUTBufferElementInfo pGUIVertex[3] = {
        { "POSITION", 0, 0, CPUT_F32, 3, 3*sizeof(float), 0 },            
        { "TEXCOORD", 0, 1, CPUT_F32, 2, 2*sizeof(float), 3*sizeof(float)},
        { "COLOR",    0, 2, CPUT_F32, 4, 4*sizeof(float), 5*sizeof(float)},
    };

    mpUberBuffer = CPUTMeshOGL::Create();
    mpUberBuffer->CreateNativeResources(NULL, 0, 3, pGUIVertex, mBufferSize, mpMirrorBuffer, NULL, 0, NULL);

    return CPUT_SUCCESS;
}
//-----------------------------------------------------------------------------
void CPUTMaterialEffectOGL::BindConstantBuffers( CPUTShaderParameters &params, const CPUTModel *pModel, int meshIndex )
{
    CPUTAssetLibraryOGL *pAssetLibrary = (CPUTAssetLibraryOGL*)CPUTAssetLibrary::GetAssetLibrary();
    
    for(params.mConstantBufferCount=0; params.mConstantBufferCount < params.mConstantBufferParameterCount; params.mConstantBufferCount++)
    {
        cString constantBufferName;
        UINT constantBufferCount = params.mConstantBufferCount;

// Dirty fix - you should work on std::string in all OS'es ! Why WSTRING ? Whyyyyyyy
#ifndef CPUT_OS_WINDOWS
        cString tagName = params.mConstantBufferParameterNames[constantBufferCount];
#else
        cString tagName = s2ws(params.mConstantBufferParameterNames[constantBufferCount].c_str());
#endif


        CPUTConfigEntry *pValue = mConfigBlock.GetValueByName(tagName);
        if( !pValue->IsValid() )
        {
            // We didn't find our property in the file.  Is it in the global config block?
            pValue = CPUTMaterial::mGlobalProperties.GetValueByName(tagName);
        }
		ASSERT( pValue->IsValid(), L"Can't find constant buffer '" + tagName + L"'." ); //  TODO: fix message
        
        constantBufferName = pValue->ValueAsString();
     
        UINT bindPoint = params.mConstantBufferBindPoints[constantBufferCount];
        ASSERT( bindPoint < CPUT_MATERIAL_MAX_CONSTANT_BUFFER_SLOTS, _L("Constant buffer bind point out of range.") );

        params.mBindConstantBufferMin = std::min( params.mBindConstantBufferMin, bindPoint );
        params.mBindConstantBufferMax = std::max( params.mBindConstantBufferMax, bindPoint );

        if( constantBufferName[0] == '@' )
        {
            constantBufferName += ptoc(pModel) + itoc(meshIndex);
        }
        else if( constantBufferName[0] == '#' )
        {
            constantBufferName += ptoc(pModel);
        }
        if( !params.mpConstantBuffer[constantBufferCount] )
        {
            params.mpConstantBuffer[constantBufferCount] = pAssetLibrary->GetConstantBuffer( constantBufferName );
            ASSERT( params.mpConstantBuffer[constantBufferCount], _L("Failed getting constant buffer ") + constantBufferName);
        }

#ifndef CPUT_FOR_OGLES2
        ES3_COMPAT(glUniformBlockBinding(mShaderProgram, bindPoint, bindPoint)); // just use the index as the binding point
#else
#warning "Need to do something with uniform buffers here"
#endif
        // If has constant buffer, then add to mppBindConstantBuffer
//        params.mppBindConstantBuffers[bindPoint]   = ((CPUTBufferOGL*)mpConstantBuffer[constantBufferCount])->GetNativeBuffer();
//        if( params.mppBindConstantBuffers[bindPoint] ) {
//            params.mppBindConstantBuffers[bindPoint]->AddRef();
//        }
    }
	  DEBUG_PRINT(_L("Exit BindConstantBuffers"));

}
void CPUTMaterialEffectOGL::BindUAVs( CPUTShaderParameters &params, const CPUTModel *pModel, int meshIndex )
{
#ifdef CPUT_SUPPORT_IMAGE_STORE

    CPUTAssetLibraryOGL *pAssetLibrary = (CPUTAssetLibraryOGL*)CPUTAssetLibrary::GetAssetLibrary();

    for(params.mUAVCount=0; params.mUAVCount < params.mUAVParameterCount; params.mUAVCount++)
    {
        cString UAVName;
        unsigned int UAVCount = params.mUAVCount;

// Dirty fix
#ifndef CPUT_OS_WINDOWS
        cString tagName = params.mpUAVParameterNames[UAVCount];
#else
        cString tagName = s2ws(params.mpUAVParameterNames[UAVCount].c_str());
#endif

        CPUTConfigEntry *pValue = mConfigBlock.GetValueByName(tagName);
        if( !pValue->IsValid() )
        {
            // We didn't find our property in the file.  Is it in the global config block?
            pValue = CPUTMaterial::mGlobalProperties.GetValueByName(tagName);
        }
        ASSERT( pValue->IsValid(), L"Can't find UAV '" + tagName + L"'." ); //  TODO: fix message
        UAVName = pValue->ValueAsString();
        // If the UAV name not specified.  Load default.dds instead
        if( 0 == UAVName.length() ) 
        { 
            UAVName = _L("default.dds"); 
        }

        UINT bindPoint = params.mUAVCount;//params.mpUAVParameterBindPoints[UAVCount];
        params.mpUAVParameterBindPoints.push_back(bindPoint);
//        UINT bindPoint = params.mpUAVParameterBindPoint[UAVCount]; mpUAVParameterBindPoints
        ASSERT( bindPoint < CPUT_MATERIAL_MAX_UAV_SLOTS, _L("UAV bind point out of range.") );

        params.mBindViewMin = std::min( params.mBindViewMin, bindPoint );
        params.mBindViewMax = std::max( params.mBindViewMax, bindPoint );

        if( UAVName[0] == '@' )
        {
            // This is a per-mesh value.  Add to per-mesh list.
            UAVName += ptoc(pModel) + itoc(meshIndex);
        } else if( UAVName[0] == '#' )
        {
            // This is a per-mesh value.  Add to per-mesh list.
            UAVName += ptoc(pModel);
        }

        // Get the sRGB flag (default to true)
//#ifndef CPUT_OS_WINDOWS
        cString SRGBName = tagName + _L("sRGB");
//#else
//        cString SRGBName = tagName + L"sRGB";
//#endif
        CPUTConfigEntry *pSRGBValue = mConfigBlock.GetValueByName(SRGBName);
        bool loadAsSRGB = pSRGBValue->IsValid() ?  loadAsSRGB = pSRGBValue->ValueAsBool() : true;

        if( !params.mpUAV[UAVCount] )
        {
            params.mpUAV[UAVCount] = pAssetLibrary->GetTexture( UAVName, false, loadAsSRGB );
            ASSERT( params.mpUAV[UAVCount], _L("Failed getting UAV ") + UAVName);
        }

        cString ReadName = tagName + _L("READ");
        CPUTConfigEntry *pRead = mConfigBlock.GetValueByName(ReadName);
        bool read = pRead->IsValid() ? pRead->ValueAsBool() : true;
        cString WriteName = tagName + _L("WRITE");
        CPUTConfigEntry *pWrite = mConfigBlock.GetValueByName(WriteName);
        bool write = pWrite->IsValid() ? pWrite  ->ValueAsBool() : true;
        if(write && read)
            params.mpUAVMode[UAVCount] = GL_READ_WRITE;
        else if(read)
            params.mpUAVMode[UAVCount] = GL_READ_ONLY;
        else
            params.mpUAVMode[UAVCount] = GL_WRITE_ONLY;

        // The shader file (e.g. .fx) can specify the UAV bind point (e.g., t0).  Those specifications 
        // might not be contiguous, and there might be gaps (bind points without assigned UAVs)
        // TODO: Warn about missing bind points?
//        params.mppBindViews[bindPoint] = ((CPUTTextureOGL*)mpTexture[textureCount])->GetShaderResourceView();
//        params.mppBindViews[bindPoint]->AddRef();

        //
        // Match up the UAV name in any UAV samplers given in the renderstate file. If there wasn't
        // one specified for a particular UAV then it just uses the default sampler.
        //
        CPUTRenderStateOGL *pRenderState;
        pRenderState = ((CPUTRenderStateBlockOGL*)mpRenderStateBlock)->GetState();
        
        mSamplerIDs[UAVCount] = pRenderState->DefaultSamplerID;
        for (int renderStateIDX = 0; renderStateIDX < NUM_SAMPLERS_PER_RENDERSTATE; renderStateIDX++) {
			if(renderStateIDX<((CPUTRenderStateBlockOGL*)mpRenderStateBlock)->GetNumSamplers())
            {
                mSamplerIDs[UAVCount] = pRenderState->SamplerIDs[renderStateIDX];
            }
        }
    }
#endif

}
CPUTResult CPUTMaterialEffectOGL::LoadMaterialEffect(
    const cString   &fileName,
    const CPUTModel *pModel,
          int        meshIndex,
    const char     **pShaderMacros,
          int        externalCount,
          cString   *pExternalName,
          float4    *pExternals,
          int       *pExternalOffset,
          int       *pExternalSize
){
    CPUTResult result = CPUT_SUCCESS;
	CPUTConfigEntry *pValue;

    mMaterialName = fileName;
    mMaterialNameHash = CPUTComputeHash( mMaterialName );

    // Open/parse the file
    CPUTConfigFile file;
    result = file.LoadFile(fileName);
    if(CPUTFAILED(result))
    {
        return result;
    }

    // Make a local copy of all the parameters
    CPUTConfigBlock *pBlock = file.GetBlock(0);
    ASSERT( pBlock, _L("Error getting parameter block") );
    if( !pBlock )
    {
        return CPUT_ERROR_PARAMETER_BLOCK_NOT_FOUND;
    }
    mConfigBlock = *pBlock;

    // get necessary device and AssetLibrary pointers
    //ID3D11Device *pD3dDevice = CPUT_DX11::GetDevice();
    CPUTAssetLibraryOGL *pAssetLibrary = (CPUTAssetLibraryOGL*)CPUTAssetLibrary::GetAssetLibrary();

   {
        CPUTConfigEntry *pEntryPointName, *pProfileName;
        int numFiles = 0;
        cString pBase = _L("VertexShaderFileOGL_");
        cString pName = pBase + to_cString(numFiles+1);
        std::vector<cString> filenames;
        while (mConfigBlock.GetValueByName(pName)->IsValid())
        {
            filenames.push_back(mConfigBlock.GetValueByName(pName)->ValueAsString());
            numFiles++;
            pName = pBase + to_cString(numFiles+1);
        }
        if(numFiles > 0)
        {
            pEntryPointName = mConfigBlock.GetValueByName(_L("VertexShaderMain"));
            pProfileName    = mConfigBlock.GetValueByName(_L("VertexShaderProfile"));
            pAssetLibrary->GetVertexShader(
                filenames,
                /*pD3dDevice,*/
                _L("VertexShaderMain"),
                pProfileName->ValueAsString(),
                &mpVertexShader,
                false,
                (CPUT_SHADER_MACRO*)pShaderMacros
            );
        }
    }

#ifdef CPUT_SUPPORT_TESSELLATION
    {
        int numFiles = 0;
        cString pBase = _L("ControlShaderFileOGL_");
        cString pName = pBase + to_cString(numFiles+1);
        std::vector<cString> filenames;
        while (mConfigBlock.GetValueByName(pName)->IsValid())
        {
            filenames.push_back(mConfigBlock.GetValueByName(pName)->ValueAsString());
            numFiles++;
            pName = pBase + to_cString(numFiles+1);
        }
        if(numFiles > 0) 
        {
			pAssetLibrary->GetHullShader(
                filenames,
                /* pD3dDevice,*/
                _L("ControlShaderMain"), 
                _L(""),
                &mpControlShader,
                false,
                (CPUT_SHADER_MACRO*)pShaderMacros
            );
        }
    }
    {
        int numFiles = 0;
        cString pBase = _L("EvaluationShaderFileOGL_");
        cString pName = pBase + to_cString(numFiles+1);
        std::vector<cString> filenames;
        while (mConfigBlock.GetValueByName(pName)->IsValid())
        {
            filenames.push_back(mConfigBlock.GetValueByName(pName)->ValueAsString());
            numFiles++;
            pName = pBase + to_cString(numFiles+1);
        }
        if(numFiles > 0) 
        {
			pAssetLibrary->GetDomainShader(
                filenames,
                /* pD3dDevice,*/
                _L("EvaluationShaderMain"), 
                _L(""),
                &mpEvaluationShader,
                false,
                (CPUT_SHADER_MACRO*)pShaderMacros
            );
        }
    }
#endif
    {
        int numFiles = 0;
        cString pBase = _L("GeometryShaderFileOGL_");
        cString pName = pBase + to_cString(numFiles+1);
        std::vector<cString> filenames;
        while (mConfigBlock.GetValueByName(pName)->IsValid())
        {
            filenames.push_back(mConfigBlock.GetValueByName(pName)->ValueAsString());
            numFiles++;
            pName = pBase + to_cString(numFiles+1);
        }
        if(numFiles > 0) 
        {
			pAssetLibrary->GetGeometryShader(
                filenames,
                /* pD3dDevice,*/
                _L("GeometryShaderMain"), 
                _L(""),
                &mpGeometryShader,
                false,
                (CPUT_SHADER_MACRO*)pShaderMacros
            );
        }
    }

    // load and store the pixel shader if it was specified
    {
        int numFiles = 0;
        cString pBase = _L("FragmentShaderFileOGL_");
        cString pName = pBase + to_cString(numFiles+1);
        std::vector<cString> filenames;
        while (mConfigBlock.GetValueByName(pName)->IsValid())
        {
            filenames.push_back(mConfigBlock.GetValueByName(pName)->ValueAsString());
            numFiles++;
            pName = pBase + to_cString(numFiles+1);
        }
        if(numFiles > 0) 
        {
            pAssetLibrary->GetPixelShader(
                filenames,
                /* pD3dDevice,*/
                _L("FragmentShaderMain"), //mConfigBlock.GetValueByName(_L("FragmentShaderMain"))->ValueAsString(),
                mConfigBlock.GetValueByName(_L("FragmentShaderProfile"))->ValueAsString(),
                &mpFragmentShader,
                false,
                (CPUT_SHADER_MACRO*)pShaderMacros
            );
        }
    }

    // load and store the render state file if it was specified
    pValue = mConfigBlock.GetValueByName(_L("RenderStateFile"));
    if( pValue->IsValid() )
    {
        mpRenderStateBlock = pAssetLibrary->GetRenderStateBlock(pValue->ValueAsString());
    }


    int IsLinked;
    char *shaderProgramInfoLog;
    int maxLength;
    
     mShaderProgram = glCreateProgram();
 
    // Attach our shaders to our program
    // Attach our shaders to our program
    if (mpVertexShader) {
        GL_CHECK(glAttachShader(mShaderProgram, mpVertexShader->GetShaderID()));
    }
    if (mpFragmentShader) {
        GL_CHECK(glAttachShader(mShaderProgram, mpFragmentShader->GetShaderID()));
    }
    if (mpControlShader) {
        GL_CHECK(glAttachShader(mShaderProgram, mpControlShader->GetShaderID()));
    }
    if (mpEvaluationShader) {
        GL_CHECK(glAttachShader(mShaderProgram, mpEvaluationShader->GetShaderID()));
    }
	if (mpGeometryShader) {
		GL_CHECK(glAttachShader(mShaderProgram, mpGeometryShader->GetShaderID()));
	}
    /*
    GL_CHECK(glBindAttribLocation(mShaderProgram, 0, "in_Position"));
    GL_CHECK(glBindAttribLocation(mShaderProgram, 1, "inNormal"));
    GL_CHECK(glBindAttribLocation(mShaderProgram, 2, "inBinormal"));
    GL_CHECK(glBindAttribLocation(mShaderProgram, 3, "inTangent"));
    GL_CHECK(glBindAttribLocation(mShaderProgram, 4, "inTex"));
      */          
    
    // Link our program
    // At this stage, the vertex and fragment programs are inspected, optimized and a binary code is generated for the shader.
    // The binary code is uploaded to the GPU, if there is no error.
    GL_CHECK(glLinkProgram(mShaderProgram));
 
    // Again, we must check and make sure that it linked. If it fails, it would mean either there is a mismatch between the vertex
    // and fragment shaders. It might be that you have surpassed your GPU's abilities. Perhaps too many ALU operations or
    // too many texel fetch instructions or too many interpolators or dynamic loops.
 
    GL_CHECK(glGetProgramiv(mShaderProgram, GL_LINK_STATUS, (int *)&IsLinked));
    if(IsLinked == false)
    {
        // Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv.
        glGetProgramiv(mShaderProgram, GL_INFO_LOG_LENGTH, &maxLength);
 
        // The maxLength includes the NULL character
        shaderProgramInfoLog = (char *)malloc(maxLength);
 
        // Notice that glGetProgramInfoLog, not glGetShaderInfoLog.
        glGetProgramInfoLog(mShaderProgram, maxLength, &maxLength, shaderProgramInfoLog);
        DEBUG_PRINT_ALWAYS((_L("Failed to link shader program:\n%s\n"), shaderProgramInfoLog));
        ASSERT(false, _L("glLinkProgram failed"));

        // Handle the error in an appropriate way such as displaying a message or writing to a log file.
        // In this simple program, we'll just leave
        //DEBUG_PRINT_ALWAYS(("Failed to link shader program:\n%s\n", shaderProgramInfoLog));
        free(shaderProgramInfoLog);
    }
    
    // Shader must be successfully linked before we can query uniform locations
    ReadShaderSamplersAndTextures( mShaderProgram, &mVertexShaderParameters );
    glUseProgram(0);
// For each of the shader stages, bind shaders and buffers
//    for( CPUTShaderParameters **pCur = mpShaderParametersList; *pCur; pCur++ ) // Bind textures and buffersfor each shader stage
    {
        BindTextures(        mVertexShaderParameters, pModel, meshIndex );
        //BindTextures(        **pCur, pModel, meshIndex );
        //BindBuffers(         **pCur, pModel, meshIndex );
        BindUAVs(            mVertexShaderParameters, pModel, meshIndex );
        BindConstantBuffers( mVertexShaderParameters, pModel, meshIndex );
    }
    
    return result;
}
// Load and register all the resources needed by the GUI system
//-----------------------------------------------------------------------------
CPUTResult CPUTGuiControllerOGL::RegisterGUIResources()
{
    CPUTResult result = CPUT_SUCCESS;

	cString name = _L("$cbGUIValues");
    mpConstantBufferVS = new CPUTBufferOGL(name);
    GLuint id = mpConstantBufferVS->GetBufferID();
    GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, mpConstantBufferVS->GetBufferID()));
    GL_CHECK(glBufferData(GL_UNIFORM_BUFFER, sizeof(GUIConstantBufferVS), NULL, GL_DYNAMIC_DRAW)); // NULL to just init buffer size
    GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
    DEBUG_PRINT(_L("bind gui constant buffers: %d\n"), id);
//    GL_CHECK(glBindBufferBase(GL_UNIFORM_BUFFER, mpConstantBufferVS->GetBufferID(), mpConstantBufferVS->GetBufferID()));
    DEBUG_PRINT(_L("completed bind gui constant buffers\n"));
    CPUTAssetLibrary::GetAssetLibrary()->AddConstantBuffer(_L(""), name, _L(""), mpConstantBufferVS);

    CPUTAssetLibraryOGL *pAssetLibrary = NULL;
    pAssetLibrary = (CPUTAssetLibraryOGL*)CPUTAssetLibraryOGL::GetAssetLibrary();

    // Get the resource directory
    cString mediaDirectory;
    mediaDirectory = pAssetLibrary->GetMediaDirectoryName();

    mpTextMaterial = pAssetLibrary->GetMaterial(_L("guimaterial_text"));
    mpControlMaterial = pAssetLibrary->GetMaterial(_L("guimaterial_control"));

    CPUTBufferElementInfo pGUIVertex[3] = {
        { "POSITION", 0, 0, CPUT_F32, 3, 3*sizeof(float), 0 },            
        { "TEXCOORD", 0, 1, CPUT_F32, 2, 2*sizeof(float), 3*sizeof(float)},
        { "COLOR",    0, 2, CPUT_F32, 4, 4*sizeof(float), 5*sizeof(float)},
    };

    unsigned int maxSize = std::max(CPUT_GUI_BUFFER_STRING_SIZE, CPUT_GUI_BUFFER_SIZE);
    maxSize = std::max(maxSize, CPUT_GUI_VERTEX_BUFFER_SIZE);    
    maxSize *= sizeof( CPUTGUIVertex );

    mpUberBuffer = new CPUTMeshOGL();
    mpUberBuffer->CreateNativeResources(NULL, 0, 3, pGUIVertex, CPUT_GUI_VERTEX_BUFFER_SIZE, mpMirrorBuffer, NULL, 0, NULL);

    mpTextUberBuffer = new CPUTMeshOGL();
    mpTextUberBuffer->CreateNativeResources(NULL, 0, 3, pGUIVertex, CPUT_GUI_VERTEX_BUFFER_SIZE, NULL, NULL, 0, NULL);

    mpFocusedControlBuffer = new CPUTMeshOGL();
	mpFocusedControlBuffer->CreateNativeResources(NULL, 0, 3, pGUIVertex, CPUT_GUI_VERTEX_BUFFER_SIZE, mpFocusedControlMirrorBuffer, NULL, 0, NULL);

    mpFocusedControlTextBuffer = new CPUTMeshOGL();
	mpFocusedControlTextBuffer->CreateNativeResources(NULL, 0, 3, pGUIVertex, CPUT_GUI_VERTEX_BUFFER_SIZE, mpFocusedControlTextMirrorBuffer, NULL, 0, NULL);

    // Walk all the controls/fonts and have them register all their required static resources
    // Returning errors if you couldn't find your resources
    result = CPUTText::RegisterStaticResources();
    if(CPUTFAILED(result))
    {
        return result;
    }
    result = CPUTButton::RegisterStaticResources();
    if(CPUTFAILED(result))
    {
        return result;
    }
    result = CPUTCheckbox::RegisterStaticResources();
    if(CPUTFAILED(result))
    {
        return result;
    }
    result = CPUTSlider::RegisterStaticResources();
    if(CPUTFAILED(result))
    {
        return result;
    }
    result = CPUTDropdown::RegisterStaticResources();
    if(CPUTFAILED(result))
    {
        return result;
    }
    DEBUG_PRINT(_L("Exit RegisterGUIResources()\n"));
    return CPUT_SUCCESS;
}
// Load the set file definition of this object
// 1. Parse the block of name/parent/transform info for model block
// 2. Load the model's binary payload (i.e., the meshes)
// 3. Assert the # of meshes matches # of materials
// 4. Load each mesh's material
//-----------------------------------------------------------------------------
CPUTResult CPUTModelOGL::LoadModel(CPUTConfigBlock *pBlock, int *pParentID, CPUTModel *pMasterModel, int numSystemMaterials, cString *pSystemMaterialNames)
{
    CPUTResult result = CPUT_SUCCESS;
    CPUTAssetLibraryOGL *pAssetLibrary = (CPUTAssetLibraryOGL*)CPUTAssetLibrary::GetAssetLibrary();

    cString modelSuffix = ptoc(this);

    // set the model's name
    mName = pBlock->GetValueByName(_L("name"))->ValueAsString();
    mName = mName + _L(".mdl");

    // resolve the full path name
    cString modelLocation;
    cString resolvedPathAndFile;
    modelLocation = ((CPUTAssetLibraryOGL*)CPUTAssetLibrary::GetAssetLibrary())->GetModelDirectoryName();
    modelLocation = modelLocation+mName;

    CPUTFileSystem::ResolveAbsolutePathAndFilename(modelLocation, &resolvedPathAndFile);

    // Get the parent ID.  Note: the caller will use this to set the parent.
    *pParentID = pBlock->GetValueByName(_L("parent"))->ValueAsInt();

    LoadParentMatrixFromParameterBlock( pBlock );

    // Get the bounding box information
    float3 center(0.0f), half(0.0f);
    pBlock->GetValueByName(_L("BoundingBoxCenter"))->ValueAsFloatArray(center.f, 3);
    pBlock->GetValueByName(_L("BoundingBoxHalf"))->ValueAsFloatArray(half.f, 3);
    mBoundingBoxCenterObjectSpace = center;
    mBoundingBoxHalfObjectSpace   = half;

    mMeshCount = pBlock->GetValueByName(_L("meshcount"))->ValueAsInt();
    mpMesh     = new CPUTMesh*[mMeshCount];
    mpLayoutCount = new UINT[mMeshCount];
    mpRootMaterial = new CPUTMaterial*[mMeshCount];
    memset( mpRootMaterial, 0, mMeshCount * sizeof(CPUTMaterial*) );
    mpMaterialEffect = new CPUTMaterialEffect**[mMeshCount];
    memset( mpMaterialEffect, 0, mMeshCount * sizeof(CPUTMaterialEffect*) );
       
    // get the material names, load them, and match them up with each mesh
    cString materialName,shadowMaterialName;
    char pNumber[4];
    cString materialValueName;

    CPUTModelOGL *pMasterModelDX = (CPUTModelOGL*)pMasterModel;

    for(UINT ii=0; ii<mMeshCount; ii++)
    {
        if(pMasterModelDX)
        {
            // Reference the master model's mesh.  Don't create a new one.
            mpMesh[ii] = pMasterModelDX->mpMesh[ii];
            mpMesh[ii]->AddRef();
        }
        else
        {
            mpMesh[ii] = new CPUTMeshOGL();
        }
    }
    if( !pMasterModelDX )
    {
        // Not a clone/instance.  So, load the model's binary payload (i.e., vertex and index buffers)
        // TODO: Change to use GetModel()
        result = LoadModelPayload(resolvedPathAndFile);
        ASSERT( CPUTSUCCESS(result), _L("Failed loading model") );
    }

    for(UINT ii=0; ii<mMeshCount; ii++)
    {
        // get the right material number ('material0', 'material1', 'material2', etc)
        materialValueName = _L("material");
        snprintf(pNumber, 4, "%d", ii);
//        _itoa(ii, pNumber, 4, 10);
        materialValueName.append(s2ws(pNumber));
        materialName = pBlock->GetValueByName(materialValueName)->ValueAsString();
        shadowMaterialName = pBlock->GetValueByName(_L("shadowCast") + materialValueName)->ValueAsString();
        bool isSkinned = pBlock->GetValueByName(_L("skeleton")) != &CPUTConfigEntry::sNullConfigValue;
        if( shadowMaterialName.length() == 0 )
        {
            if(!isSkinned)
            {
                shadowMaterialName = _L("%shadowCast");
            }
            else
            {
                shadowMaterialName = _L("%shadowCastSkinned");
            }
        }

        // Get/load material for this mesh
        UINT totalNameCount = numSystemMaterials + NUM_GLOBAL_SYSTEM_MATERIALS;
        cString *pFinalSystemNames = new cString[totalNameCount];

        // Copy "global" system materials to caller-supplied list
        for( int jj=0; jj<numSystemMaterials; jj++ )
        {
            pFinalSystemNames[jj] = pSystemMaterialNames[jj];
        }
        pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_SHADOW_CAST]                =  shadowMaterialName;
//        pFinalSystemNames[totalNameCount + CPUT_MATERIAL_INDEX_BOUNDING_BOX]                = _L("%BoundingBox");
        int finalNumSystemMaterials = numSystemMaterials + NUM_GLOBAL_SYSTEM_MATERIALS;
        CPUTMaterial *pMaterial = pAssetLibrary->GetMaterial(materialName, false, this, ii, NULL, finalNumSystemMaterials, pFinalSystemNames);
        ASSERT( pMaterial, _L("Couldn't find material.") );

        delete []pFinalSystemNames;

        mpLayoutCount[ii] = pMaterial->GetMaterialEffectCount();
        SetMaterial(ii, pMaterial);

        // Release the extra refcount we're holding from the GetMaterial operation earlier
        // now the asset library, and this model have the only refcounts on that material
        pMaterial->Release();

        // Create two ID3D11InputLayout objects, one for each material.
     //   mpMesh[ii]->BindVertexShaderLayout( mpMaterial[ii], mpShadowCastMaterial);
        // mpShadowCastMaterial->Release()
    }


    return result;
}