// Re-calculates all the positions of the controls based on their sizes
// to have a 'pretty' layout
//--------------------------------------------------------------------------------
void CPUTGuiController::RecalculateLayout()
{
    // if we have no valid panel, just return
    if(CPUT_CONTROL_ID_INVALID == mActiveControlPanelSlotID)
    {
        return;
    }

    // if we don't want the auto-layout feature, just return
    if(false == mbAutoLayout)
    {
        return;
    }

    // get window size
    CPUT_RECT windowRect;
    CPUTOSServices *pServices = CPUTOSServices::GetOSServices();
    pServices->GetClientDimensions(&windowRect.x, &windowRect.y, &windowRect.width, &windowRect.height);

    // Build columns of controls right to left
    int x,y;
    x=0; y=0;

    // walk list of controls, counting up their *heights*, until the
    // column is full.  While counting, keep track of the *widest*
    int width, height;
    const int GUI_WINDOW_PADDING = 5;

    int numberOfControls = (int) mControlPanelIDList[mActiveControlPanelSlotID]->mControlList.size();
    int indexStart=0;
    int indexEnd=0;
    int columnX = 0;
    int columnNumber = 1;
    while(indexEnd < numberOfControls)
    {
        int columnWidth=0;
        y=0;
        // figure out which controls belong in this column + column width
        while( indexEnd < numberOfControls )
        {
            if(mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[indexEnd]->IsVisible() &&
                mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[indexEnd]->IsAutoArranged())
            {
                mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[indexEnd]->GetDimensions(width, height);
                if( y + height + GUI_WINDOW_PADDING < (windowRect.height-2*GUI_WINDOW_PADDING))
                {
                    y = y + height + GUI_WINDOW_PADDING;
                    if(columnWidth < width)
                    {
                        columnWidth = width;
                    }
                    indexEnd++;
                }
                else
                {
                    // if the window is now so small it won't fit a whole control, just
                    // draw one anyway and it'll just have to be clipped
                    if(indexEnd == indexStart)
                    {
                        columnWidth = width;
                        indexEnd++;
                    }
                    break;
                }
            }
            else
            {
                indexEnd++;
            }
        }
        

        // ok, now re-position each control with x at widest, and y at proper height
        y=GUI_WINDOW_PADDING;
        for(int i=indexStart; i<indexEnd; i++)
        {
            if(mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[i]->IsVisible() &&
                mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[i]->IsAutoArranged())
            {
                mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[i]->GetDimensions(width, height);
                x = windowRect.width - columnX - columnWidth - (columnNumber*GUI_WINDOW_PADDING);
                mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[i]->SetPosition(x,y);

                y = y + height + GUI_WINDOW_PADDING;
            }
        }
        indexStart = indexEnd;
        columnX+=columnWidth;
        columnNumber++;
    }
        
    mRecalculateLayout = false;
}
Пример #2
0
// incoming resize event to be handled and translated
//-----------------------------------------------------------------------------
void CPUT_DX11::ResizeWindow(UINT width, UINT height)
{
    HRESULT hr;
    CPUTResult result;
    CPUTAssetLibraryDX11 *pAssetLibrary = (CPUTAssetLibraryDX11*)CPUTAssetLibraryDX11::GetAssetLibrary();

    // TODO: Making the back and depth buffers into CPUTRenderTargets should simplify this (CPUTRenderTarget* manages RTV, SRV, UAV, etc.)
    if( mpBackBuffer )         ((CPUTBufferDX11*)mpBackBuffer)->ReleaseBuffer();
    if( mpDepthBuffer )        ((CPUTBufferDX11*)mpDepthBuffer)->ReleaseBuffer();
    if( mpBackBufferTexture )  ((CPUTTextureDX11*)mpBackBufferTexture)->ReleaseTexture();
    if( mpDepthBufferTexture ) ((CPUTTextureDX11*)mpDepthBufferTexture)->ReleaseTexture();

    // Make sure we don't have any buffers bound.
    mpContext->ClearState();
    Present();
    mpContext->Flush();

    SAFE_RELEASE(mpBackBufferRTV);
    SAFE_RELEASE(mpBackBufferSRV);
    SAFE_RELEASE(mpBackBufferUAV);
    SAFE_RELEASE(mpDepthStencilSRV);

    CPUT::ResizeWindow( width, height );

    // Call the sample's clean up code if present.
    ReleaseSwapChain();

    // handle the internals of a resize
    int windowWidth, windowHeight;
    CPUTOSServices *pServices = CPUTOSServices::GetOSServices();
    pServices->GetClientDimensions( &windowWidth, &windowHeight);

    // resize the swap chain
    hr = mpSwapChain->ResizeBuffers(mSwapChainBufferCount, windowWidth, windowHeight, mSwapChainFormat, 0);
    ASSERT( SUCCEEDED(hr), _L("Error resizing swap chain") );

    // re-create the render-target view
    ID3D11Texture2D *pSwapChainBuffer = NULL;
    hr = mpSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D), (LPVOID*) (&pSwapChainBuffer));
    ASSERT(SUCCEEDED(hr), _L(""));
    hr = mpD3dDevice->CreateRenderTargetView( pSwapChainBuffer, NULL, &mpBackBufferRTV);
    ASSERT(SUCCEEDED(hr), _L(""));
    hr = mpD3dDevice->CreateShaderResourceView( pSwapChainBuffer, NULL, &mpBackBufferSRV);
    ASSERT(SUCCEEDED(hr), _L(""));
#ifdef CREATE_SWAP_CHAIN_UAV
    // Not every DXGI format supports UAV.  So, create UAV only if sample chooses to do so.
    hr = mpD3dDevice->CreateUnorderedAccessView( pSwapChainBuffer, NULL, &mpBackBufferUAV);
    ASSERT(SUCCEEDED(hr), _L(""));
#endif
    // Add the back buffer to the asset library.  Create CPUTBuffer and a CPUTTexture forms and add them.
    if( mpBackBuffer )
    {
        ((CPUTBufferDX11*)mpBackBuffer)->SetBufferAndViews( NULL, mpBackBufferSRV, mpBackBufferUAV );
    }
    else
    {
        cString backBufferName = _L("$BackBuffer"); 
        mpBackBuffer  = new CPUTBufferDX11( backBufferName,  NULL, mpBackBufferUAV );
        pAssetLibrary->AddBuffer( backBufferName, mpBackBuffer );
    }
    if( mpBackBufferTexture )
    {
        ((CPUTTextureDX11*)mpBackBufferTexture)->SetTextureAndShaderResourceView( NULL, mpBackBufferSRV );
    }
    else
    {
        cString backBufferName = _L("$BackBuffer"); 
        mpBackBufferTexture  = new CPUTTextureDX11( backBufferName, NULL, mpBackBufferSRV );
        pAssetLibrary->AddTexture( backBufferName, mpBackBufferTexture );
    }

    // release the old depth buffer objects
    // release the temporary swap chain buffer
    SAFE_RELEASE(pSwapChainBuffer);
    SAFE_RELEASE(mpDepthStencilBuffer);
    SAFE_RELEASE(mpDepthStencilState);
    SAFE_RELEASE(mpDepthStencilView);

    result = CreateAndBindDepthBuffer(windowWidth, windowHeight);
    if(CPUTFAILED(result))
    {
        // depth buffer creation error
        ASSERT(0,_L(""));
    }

    if( mpDepthBuffer )
    {
        ((CPUTBufferDX11*)mpDepthBuffer)->SetBufferAndViews( NULL, mpDepthStencilSRV, NULL );
    }
    else
    {
        cString depthBufferName = _L("$DepthBuffer"); 
        mpDepthBuffer  = new CPUTBufferDX11( depthBufferName, NULL, mpDepthStencilSRV );
        pAssetLibrary->AddBuffer( depthBufferName, mpDepthBuffer );
    }
    if( mpDepthBufferTexture )
    {
        ((CPUTTextureDX11*)mpDepthBufferTexture)->SetTextureAndShaderResourceView( NULL, mpDepthStencilSRV );
    }
    else
    {
        cString DepthBufferName = _L("$DepthBuffer"); 
        mpDepthBufferTexture  = new CPUTTextureDX11( DepthBufferName, NULL, mpDepthStencilSRV );
        pAssetLibrary->AddTexture( DepthBufferName, mpDepthBufferTexture );
    }

    // Release our extra reference to each view.
    // if(mpBackBufferSRV)   mpBackBufferSRV->Release();
    // if(mpBackBufferUAV)   mpBackBufferUAV->Release();
    // if(mpDepthStencilSRV) mpDepthStencilSRV->Release();;

    // set the viewport
    D3D11_VIEWPORT vp;
    vp.Width = (FLOAT) windowWidth;
    vp.Height = (FLOAT)windowHeight;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    mpContext->RSSetViewports( 1, &vp );

    // trigger the GUI manager to resize
    CPUTGuiControllerDX11::GetController()->Resize();
}
// Draw - must be positioned after all the controls are defined
//--------------------------------------------------------------------------------
void CPUTGuiControllerDX11::Draw(ID3D11DeviceContext *pImmediateContext)
{
    HEAPCHECK;

    if( 0 != GetNumberOfControlsInPanel())
    {
        SetGUIDrawingState(pImmediateContext);
    }
    else
    {
        return;
    }

    ID3D11VertexShader *pVertexShader = mpGUIVertexShader->GetNativeVertexShader();
    ID3D11PixelShader  *pPixelShader  = mpGUIPixelShader->GetNativePixelShader();

    // if any of the controls have announced they are dirty, then rebuild the mirror buffer and rebind
    if(mUberBufferDirty)
    {
        
        // if a resize was flagged, do it now.  
        if(mRecalculateLayout)
        {
            RecalculateLayout();
        }


        // 'clear' the buffer by resetting the pointer to the head
        mUberBufferIndex = 0;
        mTextUberBufferIndex = 0;
        mFocusedControlBufferIndex = 0;
        mFocusedControlTextBufferIndex = 0;

        int ii=0;
        while(ii<GetNumberOfControlsInPanel())
        {
            CPUTControl *pControl = mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[ii];

            // don't draw the focus control - draw it last so it stays on 'top'
            if(mpFocusControl != pControl)
            {
                switch(pControl->GetType())
                {
                case CPUT_BUTTON:
                    ((CPUTButton*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);                    
                    break;
                case CPUT_CHECKBOX:
                    ((CPUTCheckbox*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                case CPUT_SLIDER:
                    ((CPUTSlider*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                case CPUT_DROPDOWN:
                    ((CPUTDropdown*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;

                case CPUT_STATIC:
                    ((CPUTText*)pControl)->DrawIntoBuffer(mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                }
            }
            ii++;
            HEAPCHECK
        }

        // do the 'focused' control last so it stays on top (i.e. dropdowns)
        if(mpFocusControl)
        {
            switch(mpFocusControl->GetType())
            {
            case CPUT_BUTTON:
                ((CPUTButton*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);                    
                break;
            case CPUT_CHECKBOX:
                ((CPUTCheckbox*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_SLIDER:
                ((CPUTSlider*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_DROPDOWN:
                ((CPUTDropdown*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_STATIC:
                ((CPUTText*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            }
        }
        
                
        // update the uber-buffers with the control graphics
        UpdateUberBuffers(pImmediateContext);

        // Clear dirty flag on uberbuffer
        mUberBufferDirty = false;

    }
    HEAPCHECK



    // calculate the fps
    double elapsed = mpFPSTimer->GetElapsedTime();
    double fps = 1.0 / elapsed;
    mLastFPS = (float) fps;

	mFPSAvg[mFPSInst] = (float) fps;
	mFPSInst++;
	if(mFPSInst == AVG_FRAMES)
		mFPSInst = 0;

	float total = 0.0f;
	for(int i = 0; i < AVG_FRAMES; i++)
	{
		total += mFPSAvg[i];
	}

    int windowWidth, windowHeight;
    CPUTOSServices *pServices = CPUTOSServices::GetOSServices( );
    pServices->GetClientDimensions( &windowWidth, &windowHeight );

    // if we're drawing the FPS counter - update that
    // We do this independently of uber-buffer updates since we'll have FPS updates every frame,
    // but likely not have control updates every frame
    if(mbDrawFPS)
    {
        // calculate the time elapsed since last frame
        bool UberBufferWasDirty = mUberBufferDirty;

        cString Data;
        {
            wchar_t wcstring[CPUT_MAX_STRING_LENGTH];
            float avgFps = total/(float)AVG_FRAMES;
            swprintf_s(&wcstring[0], CPUT_MAX_STRING_LENGTH, _L("Window res: %d x %d, AVG FPS:%.2f \t(FPS:%.2f)  "), windowWidth, windowHeight, avgFps, fps);
            Data=wcstring;
        }
		// build the FPS string
        cString FPS = Data;
        mpFPSCounter->SetText(FPS); 

        // 'draw' the string into the buffer
        mFPSBufferIndex = 0;
        mpFPSCounter->DrawIntoBuffer(mpFPSMirrorBuffer, &mFPSBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);

        // update the DirectX vertex buffer
        ASSERT(CPUT_GUI_BUFFER_STRING_SIZE > mFocusedControlTextBufferIndex, _L("CPUT GUI: Too many strings for default-sized uber-buffer.  Increase CPUT_GUI_BUFFER_STRING_SIZE"));
        pImmediateContext->UpdateSubresource(mpFPSDirectXBuffer, 0, NULL, mpFPSMirrorBuffer, mFPSBufferIndex*sizeof(CPUTGUIVertex), 0);
        
        // start next frame timer
        mpFPSTimer->StartTimer();
        if(false == UberBufferWasDirty)
        {
            mUberBufferDirty = false;
        }
    }


    // set up orthographic display
    GUIConstantBufferVS ConstantBufferMatrices;
    float znear = 0.1f;
    float zfar = 100.0f;
	DirectX::XMMATRIX m;

    m = DirectX::XMMatrixOrthographicOffCenterLH(0, (float)windowWidth, (float)windowHeight, 0, znear, zfar);
    ConstantBufferMatrices.Projection = XMMatrixTranspose( m );

    // set the vertex shader
    pImmediateContext->VSSetShader( pVertexShader, NULL, 0 );
    UINT VertexStride = sizeof(CPUTGUIVertex);
    UINT VertexOffset = 0;
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpUberBuffer, &VertexStride, &VertexOffset );

    m = DirectX::XMMatrixIdentity();
    ConstantBufferMatrices.Model = XMMatrixTranspose( m );
    pImmediateContext->UpdateSubresource( mpConstantBufferVS, 0, NULL, &ConstantBufferMatrices, 0, 0 );
    pImmediateContext->VSSetConstantBuffers( 0, 1, &mpConstantBufferVS );

    // -- draw the normal controls --    
    // draw the control graphics
    pImmediateContext->PSSetShader( pPixelShader, NULL, 0 );
    pImmediateContext->PSSetShaderResources( 0, 1, &mpControlTextureAtlasView );    
    pImmediateContext->Draw(mUberBufferIndex,0);

    // draw the control's text
    pImmediateContext->PSSetShaderResources( 0, 1, &mpTextTextureAtlasView );
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpTextUberBuffer, &VertexStride, &VertexOffset );
    // draw the text uber-buffer
    pImmediateContext->Draw(mTextUberBufferIndex,0);

    // draw the FPS counter
    if(mbDrawFPS)
    {
        pImmediateContext->IASetVertexBuffers( 0, 1, &mpFPSDirectXBuffer, &VertexStride, &VertexOffset );
        pImmediateContext->Draw(mFPSBufferIndex, 0);
    }
    
    // -- draw the focused control --
    // Draw the focused control's graphics
    pImmediateContext->PSSetShader( pPixelShader, NULL, 0 );
    pImmediateContext->PSSetShaderResources( 0, 1, &mpControlTextureAtlasView );
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpFocusedControlBuffer, &VertexStride, &VertexOffset );
    // draw the uber-buffer
    pImmediateContext->Draw(mFocusedControlBufferIndex,0);


    // Draw the focused control's text
    pImmediateContext->PSSetShaderResources( 0, 1, &mpTextTextureAtlasView );
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpFocusedControlTextBuffer, &VertexStride, &VertexOffset );
    // draw the text uber-buffer
    pImmediateContext->Draw(mFocusedControlTextBufferIndex,0);


    // restore the drawing state
    ClearGUIDrawingState(pImmediateContext);
    HEAPCHECK;
}