// 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;
}
// 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;
}