// Retrieve specified domain shader //----------------------------------------------------------------------------- CPUTResult CPUTAssetLibraryDX11::GetDomainShader( const cString &name, ID3D11Device *pD3dDevice, const cString &shaderMain, const cString &shaderProfile, CPUTDomainShaderDX11 **ppDomainShader, bool nameIsFullPathAndFilename ) { CPUTResult result = CPUT_SUCCESS; cString finalName; if( name.at(0) == '$' ) { finalName = name; } else { // Resolve name to absolute path CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); pServices->ResolveAbsolutePathAndFilename( nameIsFullPathAndFilename? name : (mShaderDirectoryName + name), &finalName); } // see if the shader is already in the library void *pShader = FindDomainShader(finalName + shaderMain + shaderProfile, true); if(NULL!=pShader) { *ppDomainShader = (CPUTDomainShaderDX11*) pShader; (*ppDomainShader)->AddRef(); return result; } *ppDomainShader = CPUTDomainShaderDX11::CreateDomainShader( finalName, pD3dDevice, shaderMain, shaderProfile ); return result; }
// sets the resource directory to use when loading GUI resources //----------------------------------------------------------------------------- CPUTResult CPUTGuiController::SetResourceDirectory(const cString ResourceDirectory) { // check to see if the specified directory is valid CPUTResult result = CPUT_SUCCESS; // resolve the directory to a full path cString FullPath; CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); result = pServices->ResolveAbsolutePathAndFilename(ResourceDirectory, &FullPath); if(CPUTFAILED(result)) { return result; } // check existence of directory result = pServices->DoesDirectoryExist(FullPath); if(CPUTFAILED(result)) { return result; } // set the resource directory (absolute path) mResourceDirectory = FullPath; return result; }
//----------------------------------------------------------------------------- CPUTFont *CPUTAssetLibrary::GetFont(const cString &name ) { // Resolve name to absolute path CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); cString absolutePathAndFilename; pServices->ResolveAbsolutePathAndFilename( (mFontDirectoryName + name), &absolutePathAndFilename); // If we already have one by this name, then return it CPUTFont *pFont = FindFont(absolutePathAndFilename, true); if(NULL==pFont) { return CPUTFont::CreateFont( name, absolutePathAndFilename); } pFont->AddRef(); return pFont; }
// Retrieve specified pixel shader // TODO: Delegate creation to asset (AssetLibrary shouldn't know the nitty-gritty details of how to create an asset) //----------------------------------------------------------------------------- CPUTResult CPUTAssetLibraryOGLES::GetPixelShader( const cString &name, const cString &shaderMain, const cString &shaderProfile, CPUTPixelShaderOGLES **ppPixelShader, bool nameIsFullPathAndFilename ) { CPUTResult result = CPUT_SUCCESS; // Resolve name to absolute path before searching cString absolutePathAndFilename; CPUTOSServices* pServices = CPUTOSServices::GetOSServices(); pServices->ResolveAbsolutePathAndFilename( nameIsFullPathAndFilename? name : (m_ShaderDirectoryName + name), &absolutePathAndFilename); // see if the shader is already in the library void *pShader = FindPixelShader(absolutePathAndFilename); if(NULL!=pShader) { *ppPixelShader = (CPUTPixelShaderOGLES*) pShader; (*ppPixelShader)->AddRef(); return result; } // load the pixel shader as null-terminated char* string void* pShaderString=NULL; result = LoadShaderFileString(absolutePathAndFilename, &pShaderString); ASSERT( CPUTSUCCESS(result), _L("Error loading pixel shader: ")+name ); // compile the pixel/fragment shader GLuint NewPixelShaderID = CompileShader(GL_FRAGMENT_SHADER, pShaderString); ASSERT( (0!=NewPixelShaderID), _L("Error compiling pixel shader: "+name) ); // delete the shader's string now that it's no longer needed delete [] pShaderString; // store this new shader CPUTPixelShaderOGLES *pNewCPUTPixelShader = new CPUTPixelShaderOGLES( NewPixelShaderID ); // add shader to library AddPixelShader(absolutePathAndFilename, pNewCPUTPixelShader); // return the shader *ppPixelShader = pNewCPUTPixelShader; return result; }
//----------------------------------------------------------------------------- CPUTAssetSet *CPUTAssetLibrary::GetAssetSet( const cString &name, bool nameIsFullPathAndFilename ) { // Resolve the absolute path cString absolutePathAndFilename; CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); pServices->ResolveAbsolutePathAndFilename( nameIsFullPathAndFilename ? name : (mAssetSetDirectoryName + name + _L(".set")), &absolutePathAndFilename ); absolutePathAndFilename = nameIsFullPathAndFilename ? name : absolutePathAndFilename; CPUTAssetSet *pAssetSet = FindAssetSet(absolutePathAndFilename, true); if(NULL == pAssetSet) { return CPUTAssetSet::CreateAssetSet( name, absolutePathAndFilename ); } pAssetSet->AddRef(); return pAssetSet; }
// Find an asset in a specific library // ** Does not Addref() returned items ** // Asset library doesn't care if we're using absolute paths for names or not, it // just adds/finds/deletes the matching string literal. //----------------------------------------------------------------------------- void *CPUTAssetLibrary::FindAsset(const cString &name, CPUTAssetListEntry *pList, bool nameIsFullPathAndFilename) { cString absolutePathAndFilename; CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); pServices->ResolveAbsolutePathAndFilename( nameIsFullPathAndFilename ? name : (mAssetSetDirectoryName + name), &absolutePathAndFilename); absolutePathAndFilename = nameIsFullPathAndFilename ? name : absolutePathAndFilename; UINT hash = CPUTComputeHash( absolutePathAndFilename ); while(NULL!=pList) { if( hash == pList->hash && (0 == _wcsicmp( absolutePathAndFilename.data(), pList->name.data() )) ) { return (void*)pList->pData; } pList = pList->pNext; } return NULL; }
// // FUNCTION: InitInstance(HINSTANCE, int) // PURPOSE: Saves instance handle and creates main window // COMMENTS: // In this function, we save the instance handle in a global variable and // create and display the main program window. //----------------------------------------------------------------------------- BOOL WindowWinCPRTViewer::InitInstance(HINSTANCE hInstance, int nCmdShow, int windowWidth, int windowHeight) { m_hInst = hInstance; // Store instance handle in our global variable LPCSTR lpTitle = m_AppTitle; if( (0==windowWidth) || (0==windowHeight) ) { // zero sized windows means - you choose the size. :) CPUTOSServices* pServices = CPUTOSServices::GetOSServices(); pServices->GetDesktopDimensions(windowWidth, windowHeight); // default window size will be 1/3 of the screen size windowWidth/=3; windowHeight/=3; } m_hWnd = CreateWindow("CPRTChildWindowClass", lpTitle, //APPTITLE, APPTITLE, //szWindowClass, szTitle, WS_CHILDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, parentHWnd, NULL, (HINSTANCE)GetWindowLongPtr(parentHWnd, GWLP_HINSTANCE), NULL); if (!m_hWnd) { return FALSE; } ShowWindow(m_hWnd, nCmdShow); UpdateWindow(m_hWnd); CPUTOSServices* pServices = CPUTOSServices::GetOSServices(); pServices->SethWnd(m_hWnd); return TRUE; }
//----------------------------------------------------------------------------- CPUTTexture *CPUTAssetLibrary::GetTexture(const cString &name, bool nameIsFullPathAndFilename, bool loadAsSRGB ) { cString finalName; if( name.at(0) == '$' ) { finalName = name; } else { // Resolve name to absolute path CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); pServices->ResolveAbsolutePathAndFilename( nameIsFullPathAndFilename? name : (mTextureDirectoryName + name), &finalName); } // If we already have one by this name, then return it CPUTTexture *pTexture = FindTexture(finalName, true); if(NULL==pTexture) { return CPUTTexture::CreateTexture( name, finalName, loadAsSRGB); } pTexture->AddRef(); return pTexture; }
//----------------------------------------------------------------------------- CPUTRenderStateBlock *CPUTAssetLibrary::GetRenderStateBlock(const cString &name, bool nameIsFullPathAndFilename ) { // Resolve name to absolute path before searching cString finalName; if( name.at(0) == '$' ) { finalName = name; } else { // Resolve name to absolute path CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); pServices->ResolveAbsolutePathAndFilename( nameIsFullPathAndFilename? name : (mShaderDirectoryName + name), &finalName); } // see if the render state block is already in the library CPUTRenderStateBlock *pRenderStateBlock = FindRenderStateBlock(finalName, true); if(NULL==pRenderStateBlock) { return CPUTRenderStateBlock::CreateRenderStateBlock( name, finalName ); } pRenderStateBlock->AddRef(); return pRenderStateBlock; }
// 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(); }
// InitInstance // Saves the windows instance handle, creates, and displays the main program // window //----------------------------------------------------------------------------- BOOL CPUTWindowWin::InitInstance(int nCmdShow, int windowWidth, int windowHeight, int windowX, int windowY) { // assure we have a valid hInstance ASSERT(NULL!=mhInst, _L("")); // zero sized windows means - you choose the size. :) if( (0==windowWidth) || (0==windowHeight) ) { CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); pServices->GetDesktopDimensions(&windowWidth, &windowHeight); // default window size 1280x720 // but if screen is smaller than 1280x720, then pick 1/3 the screen size // so that it doesn't appear off the edges if(1280>windowWidth) { windowWidth = (2*windowWidth)/3; windowHeight = (2*windowHeight)/3; } else { windowWidth=1280; windowHeight=720; } } // set up size structure RECT rc = { 0, 0, windowWidth, windowHeight }; AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE ); // if x = -1, then let windows decide where to put it if(-1==windowX) { windowX = CW_USEDEFAULT; } // create the window mhWnd = CreateWindow(mAppTitle.c_str(), mAppTitle.c_str(), WS_OVERLAPPEDWINDOW, windowX, //CW_USEDEFAULT, windowY, //CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, mhInst, NULL); if (!mhWnd) { return FALSE; } ShowWindow(mhWnd, nCmdShow); UpdateWindow(mhWnd); // initialize the OS services with the hWND so you can make // reference to this object CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); pServices->SethWnd(mhWnd); return TRUE; }
// 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; }
//----------------------------------------------- HRESULT CPUTRenderTargetColor::CreateRenderTarget( cString textureName, UINT width, UINT height, DXGI_FORMAT colorFormat, UINT multiSampleCount, bool createUAV, bool recreate ) { HRESULT result; mName = textureName; mWidth = width; mHeight = height; mColorFormat = colorFormat; mMultiSampleCount = multiSampleCount; CPUTAssetLibrary *pAssetLibrary = CPUTAssetLibrary::GetAssetLibrary(); CPUTOSServices *pServices = CPUTOSServices::GetOSServices(); // Create the color texture int createFlags = createUAV ? D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS : D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; mColorDesc = CD3D11_TEXTURE2D_DESC( colorFormat, width, height, 1, // Array Size 1, // MIP Levels createFlags, D3D11_USAGE_DEFAULT, 0, mMultiSampleCount, 0 ); ID3D11Device *pD3dDevice = CPUT_DX11::GetDevice(); // If MSAA enabled, then create MSAA texture if( mMultiSampleCount>1 ) { result = pD3dDevice->CreateTexture2D( &mColorDesc, NULL, &mpColorTextureDXMSAA ); ASSERT( SUCCEEDED(result), _L("Failed creating MSAA render target texture") ); D3D11_SHADER_RESOURCE_VIEW_DESC srDesc = { colorFormat, D3D11_SRV_DIMENSION_TEXTURE2DMS, 0 }; srDesc.Texture2D.MipLevels = 1; result = pD3dDevice->CreateShaderResourceView( mpColorTextureDXMSAA, &srDesc, &mpColorSRVMSAA ); ASSERT( SUCCEEDED(result), _L("Failed creating MSAA render target shader resource view") ); CPUTSetDebugName( mpColorSRVMSAA, textureName + _L(" ColorMSAA") ); if( !recreate ) { cString msaaName = mName + _L("_MSAA"); mpColorTextureMSAA = new CPUTTextureDX11( msaaName ); // If the name starts with a '$', then its an internal texture (has no filesystem path). // Otherwise, its a file, so prepend filesystem path CPUTAssetLibrary *pAssetLibrary = CPUTAssetLibrary::GetAssetLibrary(); cString finalName; if( mName.at(0) == '$' ) { finalName = msaaName; }else { pServices->ResolveAbsolutePathAndFilename( (pAssetLibrary->GetTextureDirectory() + msaaName), &finalName); } pAssetLibrary->AddTexture( finalName, mpColorTextureMSAA ); } ((CPUTTextureDX11*)mpColorTextureMSAA)->SetTextureAndShaderResourceView( mpColorTextureDXMSAA, mpColorSRVMSAA ); } // Create non-MSAA texture. If we're MSAA, then we'll resolve into this. If not, then we'll render directly to this one. mColorDesc.SampleDesc.Count = 1; result = pD3dDevice->CreateTexture2D( &mColorDesc, NULL, &mpColorTextureDX ); ASSERT( SUCCEEDED(result), _L("Failed creating render target texture") ); // Create the shader-resource view from the non-MSAA texture D3D11_SHADER_RESOURCE_VIEW_DESC srDesc = { colorFormat, D3D11_SRV_DIMENSION_TEXTURE2D, 0 }; srDesc.Texture2D.MipLevels = 1; result = pD3dDevice->CreateShaderResourceView( mpColorTextureDX, &srDesc, &mpColorSRV ); ASSERT( SUCCEEDED(result), _L("Failed creating render target shader resource view") ); CPUTSetDebugName( mpColorSRV, textureName + _L(" Color") ); mHasUav = createUAV; // Remember, so we know to recreate it (or not) on RecreateRenderTarget() if( createUAV ) { // D3D11_SHADER_RESOURCE_VIEW_DESC srDesc = { colorFormat, D3D_SRV_DIMENSION_BUFFER, 0 }; D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; memset( &uavDesc, 0, sizeof(uavDesc) ); uavDesc.Format = colorFormat; uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; uavDesc.Texture2D.MipSlice = 0; result = pD3dDevice->CreateUnorderedAccessView( mpColorTextureDX, &uavDesc, &mpColorUAV ); ASSERT( SUCCEEDED(result), _L("Failed creating render target buffer shader resource view") ); CPUTSetDebugName( mpColorUAV, textureName + _L(" Color Buffer") ); } if( !recreate ) { mpColorTexture = new CPUTTextureDX11(mName); pAssetLibrary->AddTexture( mName, mpColorTexture ); mpColorBuffer = new CPUTBufferDX11(mName, NULL, mpColorUAV); // We don't have an ID3D11Buffer, but we want to track this UAV as if the texture was a buffer. pAssetLibrary->AddBuffer( mName, mpColorBuffer ); } ((CPUTTextureDX11*)mpColorTexture)->SetTextureAndShaderResourceView( mpColorTextureDX, mpColorSRV); // Choose our render target. If MSAA, then use the MSAA texture, and use resolve to fill the non-MSAA texture. ID3D11Texture2D *pColorTexture = (mMultiSampleCount>1) ? mpColorTextureDXMSAA : mpColorTextureDX; result = pD3dDevice->CreateRenderTargetView( pColorTexture, NULL, &mpColorRenderTargetView ); ASSERT( SUCCEEDED(result), _L("Failed creating render target view") ); CPUTSetDebugName( mpColorRenderTargetView, mName ); return S_OK; }
// Load and register all the resources needed by the GUI system //----------------------------------------------------------------------------- CPUTResult CPUTGuiControllerDX11::RegisterGUIResources(ID3D11DeviceContext *pImmediateContext, cString VertexShaderFilename, cString PixelShaderFilename, cString RenderStateFile, cString DefaultFontFilename, cString ControlAtlasTexture) { if(NULL==pImmediateContext) { return CPUT_ERROR_INVALID_PARAMETER; } CPUTResult result; HRESULT hr; ID3D11Device *pD3dDevice = NULL; CPUTOSServices *pServices = NULL; CPUTAssetLibraryDX11 *pAssetLibrary = NULL; cString ErrorMessage; // Get the services/resource pointers we need pServices = CPUTOSServices::GetOSServices(); pImmediateContext->GetDevice(&pD3dDevice); pAssetLibrary = (CPUTAssetLibraryDX11*)CPUTAssetLibraryDX11::GetAssetLibrary(); // Get the resource directory cString ResourceDirectory; CPUTGuiControllerDX11::GetController()->GetResourceDirectory(ResourceDirectory); // 1. Load the renderstate configuration for the GUI system mpGUIRenderStateBlock = (CPUTRenderStateBlockDX11*) pAssetLibrary->GetRenderStateBlock(ResourceDirectory+RenderStateFile); ASSERT(mpGUIRenderStateBlock, _L("Error loading the render state file (.rs) needed for the CPUT GUI system")); // 2. Store the shader path from AssetLibrary, change it to OUR resource directory cString OriginalAssetLibraryDirectory = pAssetLibrary->GetShaderDirectory(); pAssetLibrary->SetShaderDirectoryName(ResourceDirectory); // 3. load the shaders for gui drawing // Load the GUI Vertex Shader cString FullPath, FinalPath; FullPath = mResourceDirectory + VertexShaderFilename; pServices->ResolveAbsolutePathAndFilename(FullPath, &FinalPath); result = pAssetLibrary->GetVertexShader(FinalPath, pD3dDevice, _L("VS"), _L("vs_4_0"), &mpGUIVertexShader, true); CPUTSetDebugName( mpGUIVertexShader->GetNativeVertexShader(), _L("GUIVertexShader")); if(CPUTFAILED(result)) { ASSERT(CPUTSUCCESS(result), _L("Error loading the vertex shader needed for the CPUT GUI system.")); } ID3DBlob *pVertexShaderBlob = mpGUIVertexShader->GetBlob(); // Load the GUI Pixel Shader FullPath = mResourceDirectory + PixelShaderFilename; pServices->ResolveAbsolutePathAndFilename(FullPath, &FinalPath); result = pAssetLibrary->GetPixelShader(FinalPath, pD3dDevice, _L("PS"), _L("ps_4_0"), &mpGUIPixelShader, true); CPUTSetDebugName( mpGUIPixelShader->GetNativePixelShader(), _L("GUIPixelShader")); if(CPUTFAILED(result)) { ASSERT(CPUTSUCCESS(result), _L("Error loading the pixel shader needed for the CPUT GUI system.")); } // Restore the previous shader directory pAssetLibrary->SetShaderDirectoryName(OriginalAssetLibraryDirectory); // 4. Create the vertex layout description for all the GUI controls we'll draw // set vertex shader as active so we can configure it ID3D11VertexShader *pVertexShader = mpGUIVertexShader->GetNativeVertexShader(); pImmediateContext->VSSetShader( pVertexShader, NULL, 0 ); D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = ARRAYSIZE( layout ); // Create the input layout hr = pD3dDevice->CreateInputLayout( layout, numElements, pVertexShaderBlob->GetBufferPointer(), pVertexShaderBlob->GetBufferSize(), &mpVertexLayout ); ASSERT( SUCCEEDED(hr), _L("Error creating CPUT GUI system input layout" )); CPUTSetDebugName( mpVertexLayout, _L("CPUT GUI InputLayout object")); // 5. create the vertex shader constant buffer pointers D3D11_BUFFER_DESC bd; ZeroMemory( &bd, sizeof(bd) ); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(GUIConstantBufferVS); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = 0; hr = pD3dDevice->CreateBuffer( &bd, NULL, &mpConstantBufferVS ); ASSERT( SUCCEEDED(hr), _L("Error creating constant buffer VS" )); CPUTSetDebugName( mpConstantBufferVS, _L("GUI ConstantBuffer")); // Set the texture directory for loading the control texture atlas pAssetLibrary->SetTextureDirectoryName(ResourceDirectory); // load the control atlas mpControlTextureAtlas = (CPUTTextureDX11*) pAssetLibrary->GetTexture(ControlAtlasTexture); if(NULL==mpControlTextureAtlas) { return CPUT_TEXTURE_LOAD_ERROR; } mpControlTextureAtlasView = mpControlTextureAtlas->GetShaderResourceView(); mpControlTextureAtlasView->AddRef(); // restore the asset library's texture directory pAssetLibrary->SetTextureDirectoryName(OriginalAssetLibraryDirectory); // 6. Load the font atlas // store the existing asset library font directory OriginalAssetLibraryDirectory = pAssetLibrary->GetFontDirectory(); // set font directory to the resource directory pAssetLibrary->SetFontDirectoryName(ResourceDirectory); mpFont = (CPUTFontDX11*) pAssetLibrary->GetFont(DefaultFontFilename); if(NULL==mpFont) { return CPUT_TEXTURE_LOAD_ERROR; } mpTextTextureAtlas = mpFont->GetAtlasTexture(); mpTextTextureAtlas->AddRef(); mpTextTextureAtlasView = mpFont->GetAtlasTextureResourceView(); mpTextTextureAtlasView->AddRef(); // restore the asset library's font directory pAssetLibrary->SetTextureDirectoryName(OriginalAssetLibraryDirectory); // 7. Set up the DirectX uber-buffers that the controls draw into int maxSize = max(CPUT_GUI_BUFFER_STRING_SIZE, CPUT_GUI_BUFFER_SIZE); maxSize = max(maxSize, CPUT_GUI_VERTEX_BUFFER_SIZE); maxSize *= sizeof( CPUTGUIVertex ); char *pZeroedBuffer= new char[maxSize]; memset(pZeroedBuffer, 0, maxSize); // set up buffer description ZeroMemory( &bd, sizeof(bd) ); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof( CPUTGUIVertex ) * CPUT_GUI_VERTEX_BUFFER_SIZE; //mUberBufferIndex; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; // initialization data (all 0's for now) D3D11_SUBRESOURCE_DATA InitData; ZeroMemory( &InitData, sizeof(InitData) ); InitData.pSysMem = mpMirrorBuffer; // mpUberBuffer SAFE_RELEASE(mpUberBuffer); hr = pD3dDevice->CreateBuffer( &bd, &InitData, &mpUberBuffer ); ASSERT( !FAILED( hr ), _L("CPUT GUI FPS counter buffer creation failure")); CPUTSetDebugName(mpUberBuffer, _L("CPUT GUI: Control's main vertex buffer")); // mpTextUberBuffer bd.ByteWidth = sizeof( CPUTGUIVertex ) * CPUT_GUI_BUFFER_STRING_SIZE; hr = pD3dDevice->CreateBuffer( &bd, &InitData, &mpTextUberBuffer ); ASSERT( !FAILED( hr ), _L("CPUT GUI FPS counter buffer creation failure")); CPUTSetDebugName(mpTextUberBuffer, _L("CPUT GUI: control text vertex buffer")); // mpFocusedControlBuffer bd.ByteWidth = sizeof( CPUTGUIVertex ) * CPUT_GUI_VERTEX_BUFFER_SIZE; hr = pD3dDevice->CreateBuffer( &bd, &InitData, &mpFocusedControlBuffer ); ASSERT( !FAILED( hr ), _L("CPUT GUI FPS counter buffer creation failure")); CPUTSetDebugName(mpFocusedControlBuffer, _L("CPUT GUI: focused control images vertex buffer")); // mpFocusedControlTextBuffer bd.ByteWidth = sizeof( CPUTGUIVertex ) * CPUT_GUI_BUFFER_STRING_SIZE; //mFocusedControlTextBufferIndex; hr = pD3dDevice->CreateBuffer( &bd, &InitData, &mpFocusedControlTextBuffer ); ASSERT( !FAILED( hr ), _L("CPUT GUI FPS counter buffer creation failure")); CPUTSetDebugName(mpFocusedControlTextBuffer, _L("CPUT GUI: focused control text vertex buffer")); // mpFPSDirectXBuffer bd.ByteWidth = sizeof( CPUTGUIVertex ) * CPUT_GUI_BUFFER_STRING_SIZE; hr = pD3dDevice->CreateBuffer( &bd, &InitData, &mpFPSDirectXBuffer ); ASSERT( !FAILED( hr ), _L("CPUT GUI FPS counter buffer creation failure")); CPUTSetDebugName(mpFPSDirectXBuffer, _L("CPUT GUI: FPS display text")); // no longer need the device - release it. SAFE_RELEASE(pD3dDevice); SAFE_DELETE_ARRAY(pZeroedBuffer); // 8. Register all GUI sub-resources // 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; } // create the FPS CPUTText object for drawing FPS mpFPSCounter = new CPUTText(_L("FPS:"), ID_CPUT_GUI_FPS_COUNTER, mpFont); mpFPSCounter->SetAutoArranged(false); mpFPSCounter->SetPosition(0,0); // start the timer mpFPSTimer->StartTimer(); // done return CPUT_SUCCESS; }
// 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; }