void TextureUploaderGL::AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)
    {
        *ppBuffer = nullptr;
        RefCntAutoPtr<UploadBufferGL> pUploadBuffer;

        {
            std::lock_guard<std::mutex> CacheLock(m_pInternalData->m_UploadBuffCacheMtx);
            auto &Cache = m_pInternalData->m_UploadBufferCache;
            if (!Cache.empty())
            {
                auto DequeIt = Cache.find(Desc);
                if (DequeIt != Cache.end())
                {
                    auto &Deque = DequeIt->second;
                    if (!Deque.empty())
                    {
                        pUploadBuffer.Attach(Deque.front().Detach());
                        Deque.pop_front();
                    }
                }
            }
        }

        if( !pUploadBuffer )
        {
            pUploadBuffer = MakeNewRCObj<UploadBufferGL>()(Desc);
            LOG_INFO_MESSAGE("TextureUploaderGL: created upload buffer for ", Desc.Width, 'x', Desc.Height, 'x', Desc.Depth, ' ', m_pDevice->GetTextureFormatInfo(Desc.Format).Name, " texture" )
        }
ShaderD3DBase::ShaderD3DBase(const ShaderCreationAttribs &CreationAttribs)
{
    std::string strShaderProfile;
    switch(CreationAttribs.Desc.ShaderType)
    {
        case SHADER_TYPE_VERTEX:  strShaderProfile="vs"; break;
        case SHADER_TYPE_PIXEL:   strShaderProfile="ps"; break;
        case SHADER_TYPE_GEOMETRY:strShaderProfile="gs"; break;
        case SHADER_TYPE_HULL:    strShaderProfile="hs"; break;
        case SHADER_TYPE_DOMAIN:  strShaderProfile="ds"; break;
        case SHADER_TYPE_COMPUTE: strShaderProfile="cs"; break;

        default: UNEXPECTED( "Unknown shader type" );
    }
    strShaderProfile += "_";
    auto *pProfileSuffix = DXShaderProfileToString(CreationAttribs.Desc.TargetProfile);
    strShaderProfile += pProfileSuffix;

    String ShaderSource(g_HLSLDefinitions);
    if( CreationAttribs.Source )
        ShaderSource.append( CreationAttribs.Source );
    else
    {
        VERIFY(CreationAttribs.pShaderSourceStreamFactory, "Input stream factory is null");
        VERIFY(CreationAttribs.FilePath, "File path is null. Either shader source or source file path must be specified.");
        RefCntAutoPtr<IFileStream> pSourceStream;
        CreationAttribs.pShaderSourceStreamFactory->CreateInputStream( CreationAttribs.FilePath, &pSourceStream );
        RefCntAutoPtr<Diligent::IDataBlob> pFileData( new Diligent::DataBlobImpl );
        pSourceStream->Read( pFileData );
        // Null terminator is not read from the stream!
        auto* FileDataPtr = reinterpret_cast<Char*>( pFileData->GetDataPtr() );
        auto Size = pFileData->GetSize();
        ShaderSource.append( FileDataPtr, FileDataPtr + Size/sizeof(*FileDataPtr) );
    }

    const D3D_SHADER_MACRO *pDefines = nullptr;
    std::vector<D3D_SHADER_MACRO> D3DMacros;
    if( CreationAttribs.Macros )
    {
        for( auto* pCurrMacro = CreationAttribs.Macros; pCurrMacro->Name && pCurrMacro->Definition; ++pCurrMacro )
        {
            D3DMacros.push_back( {pCurrMacro->Name, pCurrMacro->Definition} );
        }
        D3DMacros.push_back( {nullptr, nullptr} );
        pDefines = D3DMacros.data();
    }

    CHECK_D3D_RESULT_THROW( CompileShader( ShaderSource.c_str(), CreationAttribs.EntryPoint, pDefines, CreationAttribs.pShaderSourceStreamFactory, strShaderProfile.c_str(), &m_pShaderByteCode ),
                            "Failed to compile the shader");
}
/**
* Just the current frame in the display.
*/
void Engine::DrawFrame()
{
    float fFPS;
    if( monitor_.Update( fFPS ) )
    {
        UpdateFPS( fFPS );
    }
    //renderer_.Update( monitor_.GetCurrentTime() );

    static Timer Timer;
    static double PrevTime = Timer.GetElapsedTime();
    auto CurrTime = Timer.GetElapsedTime();
    auto ElapsedTime = CurrTime - PrevTime;
    PrevTime = CurrTime;
    sample_->Update(CurrTime, ElapsedTime);

    //renderer_.Render();
    sample_->Render();

    // Draw tweak bars
    TwDraw();

    // Swap
    pSwapChain_->Present();
    //if( EGL_SUCCESS != pRenderDevice_->Present() )
    //{
    //    UnloadResources();
    //    LoadResources();
    //}
}
    STDMETHOD( Open )(THIS_ D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes)
    {
        RefCntAutoPtr<IFileStream> pSourceStream;
        m_pStreamFactory->CreateInputStream( pFileName, &pSourceStream );
        if( pSourceStream == nullptr )
        {
            LOG_ERROR( "Failed to open shader include file ", pFileName, ". Check that the file exists" );
            return E_FAIL;
        }

        RefCntAutoPtr<Diligent::IDataBlob> pFileData( new Diligent::DataBlobImpl );
        pSourceStream->Read( pFileData );
        *ppData = pFileData->GetDataPtr();
        *pBytes = static_cast<UINT>( pFileData->GetSize() );

        m_DataBlobs.insert( std::make_pair(*ppData, pFileData) );

        return S_OK;
    }
void EarthHemsiphere::Create( class ElevationDataSource *pDataSource,
                               const RenderingParams &Params,
                               IRenderDevice* pDevice,
                               IDeviceContext* pContext,
                               const Char* MaterialMaskPath,
							   const Char* TileTexturePath[],
                               const Char* TileNormalMapPath[],
                               IBuffer *pcbCameraAttribs,
                               IBuffer *pcbLightAttribs,
                               IBuffer *pcMediaScatteringParams)
{
    m_Params = Params;
    m_pDevice = pDevice;

    const Uint16 *pHeightMap;
    size_t HeightMapPitch;
    pDataSource->GetDataPtr(pHeightMap, HeightMapPitch);
    Uint32 iHeightMapDim = pDataSource->GetNumCols();
    VERIFY_EXPR(iHeightMapDim == pDataSource->GetNumRows() );

    TextureDesc NormalMapDesc;
    NormalMapDesc.Name = "Normal map texture";
    NormalMapDesc.Type = RESOURCE_DIM_TEX_2D;
    NormalMapDesc.Width = iHeightMapDim;
    NormalMapDesc.Height = iHeightMapDim;
    NormalMapDesc.Format = TEX_FORMAT_RG8_UNORM;
    NormalMapDesc.Usage = USAGE_DEFAULT;
    NormalMapDesc.BindFlags = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET;
    NormalMapDesc.MipLevels = 0;
  
    RefCntAutoPtr<ITexture>  ptex2DNormalMap;
    pDevice->CreateTexture(NormalMapDesc, TextureData(), &ptex2DNormalMap);
    m_ptex2DNormalMapSRV = ptex2DNormalMap->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);

    CreateUniformBuffer( pDevice, sizeof( TerrainAttribs ), "Terrain Attribs CB", &m_pcbTerrainAttribs );

    RefCntAutoPtr<IResourceMapping> pResMapping;
    ResourceMappingDesc ResMappingDesc;
    ResourceMappingEntry pEntries[] = 
    { 
        { "cbCameraAttribs", pcbCameraAttribs }, 
        { "cbTerrainAttribs", m_pcbTerrainAttribs}, 
        { "cbLightAttribs", pcbLightAttribs}, 
        { "g_tex2DNormalMap", ptex2DNormalMap->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE) }, 
        { "cbParticipatingMediaScatteringParams", pcMediaScatteringParams },
        {} 
    };
    ResMappingDesc.pEntries = pEntries;
    pDevice->CreateResourceMapping( ResMappingDesc, &pResMapping );

    RefCntAutoPtr<ITexture> ptex2DMtrlMask;
    CreateTextureFromFile(MaterialMaskPath, TextureLoadInfo(), pDevice, &ptex2DMtrlMask);
    auto ptex2DMtrlMaskSRV = ptex2DMtrlMask->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
    pResMapping->AddResource("g_tex2DMtrlMap", ptex2DMtrlMaskSRV, true);

    // Load tiles
    IDeviceObject* ptex2DTileDiffuseSRV[NUM_TILE_TEXTURES] = {};
    RefCntAutoPtr<ITexture> ptex2DTileDiffuse[NUM_TILE_TEXTURES];
    IDeviceObject* ptex2DTileNMSRV[NUM_TILE_TEXTURES] = {};
    RefCntAutoPtr<ITexture> ptex2DTileNM[NUM_TILE_TEXTURES];
	for(int iTileTex = 0; iTileTex < (int)NUM_TILE_TEXTURES; iTileTex++)
    {
        {
            TextureLoadInfo DiffMapLoadInfo;
            DiffMapLoadInfo.IsSRGB = false;
            CreateTextureFromFile(TileTexturePath[iTileTex], DiffMapLoadInfo, pDevice, &ptex2DTileDiffuse[iTileTex]);
            ptex2DTileDiffuseSRV[iTileTex] = ptex2DTileDiffuse[iTileTex]->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
        }
        
        {
            
            CreateTextureFromFile(TileNormalMapPath[iTileTex], TextureLoadInfo(), pDevice, &ptex2DTileNM[iTileTex]);
            ptex2DTileNMSRV[iTileTex] = ptex2DTileNM[iTileTex]->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
        }
	}
    pResMapping->AddResourceArray("g_tex2DTileDiffuse", 0,  ptex2DTileDiffuseSRV, NUM_TILE_TEXTURES, true);
    pResMapping->AddResourceArray("g_tex2DTileNM", 0, ptex2DTileNMSRV, NUM_TILE_TEXTURES, true);


    m_pTerrainScript = CreateRenderScriptFromFile( "shaders\\Terrain.lua", pDevice, pContext, [&]( ScriptParser *pScriptParser )
    {
        pScriptParser->SetGlobalVariable( "extResourceMapping", pResMapping );
    } );

    m_pTerrainScript->GetSamplerByName( "ComparisonSampler", &m_pComparisonSampler );

    RenderNormalMap( pDevice, pContext, pHeightMap, HeightMapPitch, iHeightMapDim, ptex2DNormalMap, pResMapping );

    m_pTerrainScript->Run( pContext, "CreateHemisphereShaders" );

    std::vector<HemisphereVertex> VB;
    std::vector<Uint32> StitchIB;
    GenerateSphereGeometry(pDevice, AirScatteringAttribs().fEarthRadius, m_Params.m_iRingDimension, m_Params.m_iNumRings, pDataSource, m_Params.m_TerrainAttribs.m_fElevationSamplingInterval, m_Params.m_TerrainAttribs.m_fElevationScale, VB, StitchIB, m_SphereMeshes);

    BufferDesc VBDesc;
    VBDesc.Name = "Hemisphere vertex buffer";
    VBDesc.uiSizeInBytes = (Uint32)(VB.size() * sizeof( VB[0] ));
    VBDesc.Usage = USAGE_STATIC;
    VBDesc.BindFlags = BIND_VERTEX_BUFFER;
    BufferData VBInitData;
    VBInitData.pData = VB.data();
    VBInitData.DataSize = VBDesc.uiSizeInBytes;
    pDevice->CreateBuffer( VBDesc, VBInitData, &m_pVertBuff );
    VERIFY( m_pVertBuff, "Failed to create VB" );

    m_uiNumStitchIndices = (Uint32)StitchIB.size();
    BufferDesc StitchIndexBufferDesc;
    StitchIndexBufferDesc.uiSizeInBytes = (Uint32)(m_uiNumStitchIndices * sizeof( StitchIB[0] ));
    StitchIndexBufferDesc.Usage = USAGE_STATIC;
    StitchIndexBufferDesc.BindFlags = BIND_INDEX_BUFFER;
    BufferData IBInitData;
    IBInitData.pData = StitchIB.data();
    IBInitData.DataSize = StitchIndexBufferDesc.uiSizeInBytes;
    // Create the buffer
    pDevice->CreateBuffer( StitchIndexBufferDesc, IBInitData, &m_pStitchIndBuff);
    VERIFY( m_pStitchIndBuff, "Failed to create stitch IB" );
}
void Engine::TrimMemory()
{
    LOGI( "Trimming memory" );
    pRenderDevice_->Invalidate();
}
/**
* Tear down the EGL context currently associated with the display.
*/
void Engine::TermDisplay()
{
    pRenderDevice_->Suspend();

}
/**
* Initialize an EGL context for the current display.
*/
int Engine::InitDisplay()
{
    if( !initialized_resources_ )
    {
        EngineCreationAttribs EngineCreationAttribs;
        EngineCreationAttribs.strShaderCachePath = "/tmp/ShaderCache";
        RefCntAutoPtr<Diligent::IRenderDevice> pRenderDevice;
        SwapChainDesc SwapChainDesc;
        CreateDeviceAndSwapChainGL( EngineCreationAttribs, &pRenderDevice, &pDeviceContext_, SwapChainDesc, app_->window, &pSwapChain_ );

        Diligent::IRenderDeviceGLES *pRenderDeviceOpenGLES;
        pRenderDevice->QueryInterface( Diligent::IID_RenderDeviceGLES, reinterpret_cast<IObject**>(&pRenderDeviceOpenGLES) );
        pRenderDevice_.Attach( pRenderDeviceOpenGLES );

        LoadResources();
        initialized_resources_ = true;

        // Set font scaling
        TwDefine(" GLOBAL fontscaling=3");

        // TW_OPENGL and TW_OPENGL_CORE were designed to select rendering with 
        // very old GL specification. Using these modes results in applying some 
        // odd offsets which distorts everything
        // Latest OpenGL works very much like Direct3D11, and 
        // Tweak Bar will never know if D3D or OpenGL is actually used
        if (!TwInit(TW_DIRECT3D11, pRenderDevice_.RawPtr(), pDeviceContext_.RawPtr(), SwapChainDesc.ColorBufferFormat))
        {
            LOGE( "Failed to Init Ant tweak bar" );
            return 0;
        }

        sample_.reset( CreateSample(pRenderDevice, pDeviceContext_, pSwapChain_) );
    }
    else
    {
        // initialize OpenGL ES and EGL
        if( EGL_SUCCESS != pRenderDevice_->Resume( app_->window ) )
        {
            UnloadResources();
            LoadResources();
        }
    }

    ShowUI();

    auto width = pSwapChain_->GetDesc().Width;
    auto height = pSwapChain_->GetDesc().Height;

    //Note that screen size might have been changed
    pDeviceContext_->SetViewports( 1, nullptr, width, height );
    //renderer_.UpdateViewport();
    
    sample_->WindowResize(width, height);

    // Send the new window size to AntTweakBar
    TwWindowSize(width, height);


    //tap_camera_.SetFlip( 1.f, -1.f, -1.f );
    //tap_camera_.SetPinchTransformFactor( 2.f, 2.f, 8.f );

    return 0;
}
void Tutorial08_Tessellation::Initialize(IRenderDevice *pDevice, IDeviceContext **ppContexts, Uint32 NumDeferredCtx, ISwapChain *pSwapChain)
{
    const auto& deviceCaps = pDevice->GetDeviceCaps();
    if(!deviceCaps.bTessellationSupported)
    {
        throw std::runtime_error("Hardware tessellation is not supported");
    }

    SampleBase::Initialize(pDevice, ppContexts, NumDeferredCtx, pSwapChain);

    ShaderMacroHelper MacroHelper;
    
    {
        // Pipeline state object encompasses configuration of all GPU stages

        PipelineStateDesc PSODesc;
        // Pipeline state name is used by the engine to report issues
        // It is always a good idea to give objects descriptive names
        PSODesc.Name = "Terrain PSO"; 

        // This is a graphics pipeline
        PSODesc.IsComputePipeline = false; 

        // This tutorial will render to a single render target
        PSODesc.GraphicsPipeline.NumRenderTargets = 1;
        // Set render target format which is the format of the swap chain's color buffer
        PSODesc.GraphicsPipeline.RTVFormats[0] = pSwapChain->GetDesc().ColorBufferFormat;
        // Set depth buffer format which is the format of the swap chain's back buffer
        PSODesc.GraphicsPipeline.DSVFormat = pSwapChain->GetDesc().DepthBufferFormat;
        // Primitive topology type defines what kind of primitives will be rendered by this pipeline state
        PSODesc.GraphicsPipeline.PrimitiveTopologyType = PRIMITIVE_TOPOLOGY_TYPE_PATCH;
        // Cull back faces
        PSODesc.GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_BACK;
        // Enable depth testing
        PSODesc.GraphicsPipeline.DepthStencilDesc.DepthEnable = True;

        // Create dynamic uniform buffer that will store shader constants
        CreateUniformBuffer(pDevice, sizeof(GlobalConstants), "Global shader constants CB", &m_ShaderConstants);

        ShaderCreationAttribs CreationAttribs;
        // Tell the system that the shader source code is in HLSL.
        // For OpenGL, the engine will convert this into GLSL behind the scene
        CreationAttribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;

        // In this tutorial, we will load shaders from file. To be able to do that,
        // we need to create a shader source stream factory
        BasicShaderSourceStreamFactory BasicSSSFactory;
        CreationAttribs.pShaderSourceStreamFactory = &BasicSSSFactory;
        // Define variable type that will be used by default
        CreationAttribs.Desc.DefaultVariableType = SHADER_VARIABLE_TYPE_STATIC;
        // Create vertex shader
        RefCntAutoPtr<IShader> pVS;
        {
            CreationAttribs.Desc.ShaderType = SHADER_TYPE_VERTEX;
            CreationAttribs.EntryPoint = "TerrainVS";
            CreationAttribs.Desc.Name = "Terrain VS";
            CreationAttribs.FilePath = "terrain.vsh";
            pDevice->CreateShader(CreationAttribs, &pVS);
            pVS->GetShaderVariable("VSConstants")->Set(m_ShaderConstants);
        }

        // Create geometry shader
        RefCntAutoPtr<IShader> pGS;
        {
            CreationAttribs.Desc.ShaderType = SHADER_TYPE_GEOMETRY;
            CreationAttribs.EntryPoint = "TerrainGS";
            CreationAttribs.Desc.Name = "Terrain GS";
            CreationAttribs.FilePath = "terrain.gsh";
            pDevice->CreateShader(CreationAttribs, &pGS);
            pGS->GetShaderVariable("GSConstants")->Set(m_ShaderConstants);
        }

        // Create hull shader
        RefCntAutoPtr<IShader> pHS;
        {
            CreationAttribs.Desc.ShaderType = SHADER_TYPE_HULL;
            CreationAttribs.EntryPoint = "TerrainHS";
            CreationAttribs.Desc.Name = "Terrain HS";
            CreationAttribs.FilePath = "terrain.hsh";

            ShaderVariableDesc Vars[] = 
            {
                {"g_HeightMap", SHADER_VARIABLE_TYPE_MUTABLE}
            };
            CreationAttribs.Desc.VariableDesc = Vars;
            CreationAttribs.Desc.NumVariables = _countof(Vars);

            // Define static sampler for g_Texture. Static samplers should be used whenever possible
            SamplerDesc SamLinearClampDesc( FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, 
                TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP);
            StaticSamplerDesc StaticSamplers[] = 
            {
                {"g_HeightMap", SamLinearClampDesc}
            };
            CreationAttribs.Desc.StaticSamplers = StaticSamplers;
            CreationAttribs.Desc.NumStaticSamplers = _countof(StaticSamplers);

            MacroHelper.AddShaderMacro("BLOCK_SIZE", m_BlockSize);
            CreationAttribs.Macros = MacroHelper;

            pDevice->CreateShader(CreationAttribs, &pHS);
            pHS->GetShaderVariable("HSConstants")->Set(m_ShaderConstants);
        }

        // Create domain shader
        RefCntAutoPtr<IShader> pDS;
        {
            CreationAttribs.Desc.ShaderType = SHADER_TYPE_DOMAIN;
            CreationAttribs.EntryPoint = "TerrainDS";
            CreationAttribs.Desc.Name = "Terrain DS";
            CreationAttribs.FilePath = "terrain.dsh";
            CreationAttribs.Macros = nullptr;
            
            pDevice->CreateShader(CreationAttribs, &pDS);
            pDS->GetShaderVariable("DSConstants")->Set(m_ShaderConstants);
        }

        // Create pixel shader
        RefCntAutoPtr<IShader> pPS, pWirePS;
        {
            CreationAttribs.Desc.ShaderType = SHADER_TYPE_PIXEL;
            CreationAttribs.EntryPoint = "TerrainPS";
            CreationAttribs.Desc.Name = "Terrain PS";
            CreationAttribs.FilePath = "terrain.psh";
            // Shader variables should typically be mutable, which means they are expected
            // to change on a per-instance basis
            ShaderVariableDesc Vars[] = 
            {
                {"g_Texture", SHADER_VARIABLE_TYPE_MUTABLE}
            };
            CreationAttribs.Desc.VariableDesc = Vars;
            CreationAttribs.Desc.NumVariables = _countof(Vars);

            // Define static sampler for g_Texture. Static samplers should be used whenever possible
            SamplerDesc SamLinearClampDesc( FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, 
                                            TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP);
            StaticSamplerDesc StaticSamplers[] = 
            {
                {"g_Texture", SamLinearClampDesc}
            };
            CreationAttribs.Desc.StaticSamplers = StaticSamplers;
            CreationAttribs.Desc.NumStaticSamplers = _countof(StaticSamplers);

            pDevice->CreateShader(CreationAttribs, &pPS);

            CreationAttribs.EntryPoint = "WireTerrainPS";
            CreationAttribs.Desc.Name = "Wireframe Terrain PS";
            CreationAttribs.FilePath = "terrain_wire.psh";
            pDevice->CreateShader(CreationAttribs, &pWirePS);

            pWirePS->GetShaderVariable("PSConstants")->Set(m_ShaderConstants);
        }

        PSODesc.GraphicsPipeline.pVS = pVS;
        PSODesc.GraphicsPipeline.pHS = pHS;
        PSODesc.GraphicsPipeline.pDS = pDS;
        PSODesc.GraphicsPipeline.pPS = pPS;

        pDevice->CreatePipelineState(PSODesc, &m_pPSO[0]);

        PSODesc.GraphicsPipeline.pGS = pGS;
        PSODesc.GraphicsPipeline.pPS = pWirePS;
        pDevice->CreatePipelineState(PSODesc, &m_pPSO[1]);
    }

    {
        // Load texture
        TextureLoadInfo loadInfo;
        loadInfo.IsSRGB = false;
        loadInfo.Name = "Terrain height map";
        RefCntAutoPtr<ITexture> HeightMap;
        CreateTextureFromFile("ps_height_1k.png", loadInfo, m_pDevice, &HeightMap);
        const auto HMDesc = HeightMap->GetDesc();
        m_HeightMapWidth = HMDesc.Width;
        m_HeightMapHeight = HMDesc.Height;
        // Get shader resource view from the texture
        m_HeightMapSRV = HeightMap->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
    }

    {
        TextureLoadInfo loadInfo;
        loadInfo.IsSRGB = true;
        loadInfo.Name = "Terrain color map";
        RefCntAutoPtr<ITexture> ColorMap;
        CreateTextureFromFile("ps_texture_2k.png", loadInfo, m_pDevice, &ColorMap);
        // Get shader resource view from the texture
        m_ColorMapSRV = ColorMap->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
    }

    // Since we are using mutable variable, we must create shader resource binding object
    // http://diligentgraphics.com/2016/03/23/resource-binding-model-in-diligent-engine-2-0/
    for(size_t i=0; i < _countof(m_pPSO); ++i)
    {
        m_pPSO[i]->CreateShaderResourceBinding(&m_SRB[i]);
        // Set texture SRV in the SRB
        m_SRB[i]->GetVariable(SHADER_TYPE_PIXEL, "g_Texture")->Set(m_ColorMapSRV);
        m_SRB[i]->GetVariable(SHADER_TYPE_DOMAIN, "g_HeightMap")->Set(m_HeightMapSRV);
        m_SRB[i]->GetVariable(SHADER_TYPE_HULL, "g_HeightMap")->Set(m_HeightMapSRV);
    }

    // Create a tweak bar
    TwBar *bar = TwNewBar("Settings");
    int barSize[2] = {224 * m_UIScale, 120 * m_UIScale};
    TwSetParam(bar, NULL, "size", TW_PARAM_INT32, 2, barSize);

    // Add grid size control
    TwAddVarRW(bar, "Animate", TW_TYPE_BOOLCPP, &m_Animate, "");
    TwAddVarRW(bar, "Adaptive tessellation", TW_TYPE_BOOLCPP, &m_AdaptiveTessellation, "");
    TwAddVarRW(bar, "Wireframe", TW_TYPE_BOOLCPP, &m_Wireframe, "");
    TwAddVarRW(bar, "Tess density", TW_TYPE_FLOAT, &m_TessDensity, "min=1 max=32 step=0.1");
    TwAddVarRW(bar, "Distance", TW_TYPE_FLOAT, &m_Distance, "min=1 max=20 step=0.1");
}