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