void RenderDevice::Clear(float r, float g, float b, float a, float depth)
{
    const float color[] = {r, g, b, a};

    // Needed for each eye to do its own clear, since ClearRenderTargetView doesn't honor viewport.    
        
    // Save state that is affected by clearing this way
    ID3D11DepthStencilState* oldDepthState = CurDepthState;
    StandardUniformData      clearUniforms;
    
    SetDepthMode(true, true, Compare_Always);
    
    Context->IASetInputLayout(ModelVertexIL);
    Context->GSSetShader(NULL, NULL, 0);
    
    ID3D11ShaderResourceView* sv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
    if (MaxTextureSet[Shader_Fragment])
    {
        Context->PSSetShaderResources(0, MaxTextureSet[Shader_Fragment], sv);
    }
    
    ID3D11Buffer* vertexBuffer = QuadVertexBuffer->GetBuffer();
    UINT vertexStride = sizeof(Vertex);
    UINT vertexOffset = 0;
    Context->IASetVertexBuffers(0, 1, &vertexBuffer, &vertexStride, &vertexOffset);
    
    clearUniforms.View = Matrix4f(2, 0, 0, 0,
                                  0, 2, 0, 0,
                                  0, 0, 0, 0,
                                  -1, -1, depth, 1);
    UniformBuffers[Shader_Vertex]->Data(Buffer_Uniform, &clearUniforms, sizeof(clearUniforms));
    
    ID3D11Buffer* vertexConstants = UniformBuffers[Shader_Vertex]->GetBuffer();
    Context->VSSetConstantBuffers(0, 1, &vertexConstants);
    Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
    VertexShaders[VShader_MV]->Set(Prim_TriangleStrip);
    PixelShaders[FShader_Solid]->Set(Prim_TriangleStrip);
    
    UniformBuffers[Shader_Pixel]->Data(Buffer_Uniform, color, sizeof(color));
    PixelShaders[FShader_Solid]->SetUniformBuffer(UniformBuffers[Shader_Pixel]);
        
    // Clear Viewport   
    Context->OMSetBlendState(NULL, NULL, 0xffffffff);
    Context->Draw(4, 0);
    
    // reset
    CurDepthState = oldDepthState;
    Context->OMSetDepthStencilState(CurDepthState, 0);        
}
// Constructor helper
void  RenderDevice::initShadersAndStates()
{
    CurRenderTarget = NULL;
    for(int i = 0; i < Shader_Count; i++)
    {
        UniformBuffers[i] = *CreateBuffer();
        MaxTextureSet[i] = 0;
    }

    ID3D10Blob* vsData = CompileShader("vs_4_0", DirectVertexShaderSrc);
    VertexShaders[VShader_MV] = *new VertexShader(this, vsData);
    for(int i = 1; i < VShader_Count; i++)
    {
        VertexShaders[i] = *new VertexShader(this, CompileShader("vs_4_0", VShaderSrcs[i]));
    }

    for(int i = 0; i < FShader_Count; i++)
    {
        PixelShaders[i] = *new PixelShader(this, CompileShader("ps_4_0", FShaderSrcs[i]));
    }

    intptr_t            bufferSize = vsData->GetBufferSize();
    const void*         buffer     = vsData->GetBufferPointer();
    ModelVertexIL = NULL;
    ID3D11InputLayout** objRef     = &ModelVertexIL.GetRawRef();

    HRESULT validate = Device->CreateInputLayout(ModelVertexDesc, sizeof(ModelVertexDesc)/sizeof(D3D11_INPUT_ELEMENT_DESC),
        buffer, bufferSize, objRef);
    OVR_UNUSED(validate);

    Ptr<ShaderSet> gouraudShaders = *new ShaderSet();
    gouraudShaders->SetShader(VertexShaders[VShader_MVP]);
    gouraudShaders->SetShader(PixelShaders[FShader_Gouraud]);
    DefaultFill = *new ShaderFill(gouraudShaders);

    D3D11_BLEND_DESC bm;
    memset(&bm, 0, sizeof(bm));
    bm.RenderTarget[0].BlendEnable = true;
    bm.RenderTarget[0].BlendOp     = bm.RenderTarget[0].BlendOpAlpha    = D3D11_BLEND_OP_ADD;
    bm.RenderTarget[0].SrcBlend    = bm.RenderTarget[0].SrcBlendAlpha   = D3D11_BLEND_SRC_ALPHA;
    bm.RenderTarget[0].DestBlend   = bm.RenderTarget[0].DestBlendAlpha  = D3D11_BLEND_INV_SRC_ALPHA;
    bm.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
    BlendState = NULL;
    Device->CreateBlendState(&bm, &BlendState.GetRawRef());

    D3D11_RASTERIZER_DESC rs;
    memset(&rs, 0, sizeof(rs));
    rs.AntialiasedLineEnable = true;
    rs.CullMode              = D3D11_CULL_BACK;    
    rs.DepthClipEnable       = true;
    rs.FillMode              = D3D11_FILL_SOLID;
    Rasterizer = NULL;
    Device->CreateRasterizerState(&rs, &Rasterizer.GetRawRef());

    QuadVertexBuffer = *CreateBuffer();
    const Vertex QuadVertices[] =
    { Vertex(Vector3f(0, 1, 0)), Vertex(Vector3f(1, 1, 0)),
    Vertex(Vector3f(0, 0, 0)), Vertex(Vector3f(1, 0, 0)) };
    QuadVertexBuffer->Data(Buffer_Vertex, QuadVertices, sizeof(QuadVertices));

    SetDepthMode(0, 0);
}
RenderDevice::RenderDevice(const RendererParams& p, HWND window)
{
    RECT rc;
    GetClientRect(window, &rc);
    UINT width   = rc.right - rc.left;
    UINT height  = rc.bottom - rc.top;
    WindowWidth  = width;
    WindowHeight = height;
    Window       = window;
    Params       = p;

	memset(UniformBuffers, 0, sizeof(UniformBuffers));
	memset(CommonUniforms, 0, sizeof(CommonUniforms));
	QuadVertexBuffer = NULL;

    HRESULT hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&DXGIFactory.GetRawRef()));
    if (FAILED(hr))    
        return;

    // Find the adapter & output (monitor) to use for fullscreen, based on the reported name of the HMD's monitor.
    if (Params.MonitorName.GetLength() > 0)
    {
        for(UINT AdapterIndex = 0; ; AdapterIndex++)
        {
            HRESULT hr = DXGIFactory->EnumAdapters(AdapterIndex, &Adapter.GetRawRef());
            if (hr == DXGI_ERROR_NOT_FOUND)
                break;

            DXGI_ADAPTER_DESC Desc;
            Adapter->GetDesc(&Desc);

            UpdateMonitorOutputs();

            if (FullscreenOutput)
                break;
        }

        if (!FullscreenOutput)
            Adapter = NULL;
    }

    if (!Adapter)
    {
        DXGIFactory->EnumAdapters(0, &Adapter.GetRawRef());
    }

    int flags = 0;

    hr = D3D10CreateDevice(Adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D1x_(SDK_VERSION),
                           &Device.GetRawRef());
    Context = Device;
    Context->AddRef();

    if (FAILED(hr))
        return;

    if (!RecreateSwapChain())
        return;

    if (Params.Fullscreen)
        SwapChain->SetFullscreenState(1, FullscreenOutput);

    CurRenderTarget = NULL;
    for(int i = 0; i < Shader_Count; i++)
    {
        UniformBuffers[i] = CreateBuffer();
        MaxTextureSet[i] = 0;
    }

    ID3D10Blob* vsData = CompileShader("vs_4_0", DirectVertexShaderSrc);
    VertexShaders[VShader_MV] = *new VertexShader(this, vsData);
    for(int i = 1; i < VShader_Count; i++)
    {
        VertexShaders[i] = *new VertexShader(this, CompileShader("vs_4_0", VShaderSrcs[i]));
    }

    for(int i = 0; i < FShader_Count; i++)
    {
        PixelShaders[i] = *new PixelShader(this, CompileShader("ps_4_0", FShaderSrcs[i]));
    }

    SPInt               bufferSize = vsData->GetBufferSize();
    const void*         buffer     = vsData->GetBufferPointer();
    ID3D1xInputLayout** objRef     = &ModelVertexIL.GetRawRef();

    HRESULT validate = Device->CreateInputLayout(ModelVertexDesc, sizeof(ModelVertexDesc)/sizeof(D3D1x_(INPUT_ELEMENT_DESC)),
                                                 buffer, bufferSize, objRef);
    OVR_UNUSED(validate);

    Ptr<ShaderSet> gouraudShaders = *new ShaderSet();
    gouraudShaders->SetShader(VertexShaders[VShader_MVP]);
    gouraudShaders->SetShader(PixelShaders[FShader_Gouraud]);
    DefaultFill = *new ShaderFill(gouraudShaders);

    D3D1x_(BLEND_DESC) bm;
    memset(&bm, 0, sizeof(bm));
    bm.BlendEnable[0] = true;
    bm.BlendOp      = bm.BlendOpAlpha   = D3D1x_(BLEND_OP_ADD);
    bm.SrcBlend     = bm.SrcBlendAlpha  = D3D1x_(BLEND_SRC_ALPHA);
    bm.DestBlend    = bm.DestBlendAlpha = D3D1x_(BLEND_INV_SRC_ALPHA);
    bm.RenderTargetWriteMask[0]         = D3D1x_(COLOR_WRITE_ENABLE_ALL);
    Device->CreateBlendState(&bm, &BlendState.GetRawRef());

    D3D1x_(RASTERIZER_DESC) rs;
    memset(&rs, 0, sizeof(rs));
    rs.AntialiasedLineEnable = true;
    rs.CullMode              = D3D1x_(CULL_BACK);    
    rs.DepthClipEnable       = true;
    rs.FillMode              = D3D1x_(FILL_SOLID);
    Device->CreateRasterizerState(&rs, &Rasterizer.GetRawRef());

    QuadVertexBuffer = CreateBuffer();
    const RenderTiny::Vertex QuadVertices[] =
    { Vertex(Vector3f(0, 1, 0)), Vertex(Vector3f(1, 1, 0)),
      Vertex(Vector3f(0, 0, 0)), Vertex(Vector3f(1, 0, 0)) };
    QuadVertexBuffer->Data(Buffer_Vertex, QuadVertices, sizeof(QuadVertices));

    SetDepthMode(0, 0);
}