#include "stdafx.h" #include #include "RenderTargetBase.h" RenderTargetBase::RenderTargetBase(IEngine& argEngine) : m_Engine(argEngine) , m_ClearDepthStencilBufferDepth(1.0f) // 1.0f is the maximum depth , m_ClearDepthStencilBufferStencil(0) // clear the full stencil buffer , m_ClearColorBufferColor(D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f)) // good old black opaque , m_RenderTargetView(NULL) , m_DepthStencilView(NULL) , m_DepthStencilTexture(NULL) , m_RenderingTargets(NULL) , m_D3D10Viewports(NULL) , m_MultiSampleCount(1) , m_MultiSampleQuality(0) , m_LastBindFlags(BindFlags::Default) , m_ActiveRenderTargetCount(0) { this->set_ViewPort(this->get_ViewPort()); // force d3d10 viewport generation m_Commands.push_back(new Command(this, CommandFlags::EndChain | CommandFlags::FlushChain, SetRenderTargetCommandType, 0)); memset(m_EmptyShaderResView, 0, sizeof(m_EmptyShaderResView)); } RenderTargetBase::~RenderTargetBase() { this->Uninitialize(); } void RenderTargetBase::Uninitialize() { if (m_Engine.get_EngineStates().LastRenderTarget == this) m_Engine.get_EngineStates().LastRenderTarget = NULL; // clear used states ID3D10Device& device = m_Engine.get_DX10Device(); ID3D10RenderTargetView* activeRenderTargetViews[D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT]; ID3D10DepthStencilView* activeDepthStencilView; device.OMGetRenderTargets(D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT, activeRenderTargetViews, &activeDepthStencilView); bool clearRenderTargets = false; if (activeDepthStencilView == m_DepthStencilView && m_DepthStencilView != NULL) clearRenderTargets = true; for (uint32 i = 0; i < D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) { if (activeRenderTargetViews[i] != NULL) { for (uint32 k = 0; k < m_AdditionalRenderingTargets.size() + 1; ++k) { if (m_RenderingTargets != NULL && m_RenderingTargets[k] == activeRenderTargetViews[i]) clearRenderTargets = true; } activeRenderTargetViews[i]->Release(); } else break; } if (clearRenderTargets) device.OMSetRenderTargets(0, NULL, NULL); if (m_RenderTargetView != NULL) m_RenderTargetView->Release(); m_RenderTargetView = NULL; if (m_DepthStencilView != NULL) m_DepthStencilView->Release(); m_DepthStencilView = NULL; if (m_DepthStencilTexture != NULL) m_DepthStencilTexture->Release(); m_DepthStencilTexture = NULL; this->KillViewPortAndRenderTargetData(); } void RenderTargetBase::set_ViewPort(const ViewPort& argViewPort) { m_ViewPort = argViewPort; this->KillViewPortAndRenderTargetData(); this->BuildViewPortAndRenderTargetData(); } void RenderTargetBase::set_HasDepthStencilBuffer(bool argState) { if (m_RenderTargetView == NULL) { throw L"RenderTarget: Access forbidden until resource has been initialized."; } m_Engine.get_DX10Device().ClearState(); if (m_DepthStencilView != NULL) m_DepthStencilView->Release(); m_DepthStencilView = NULL; if (m_DepthStencilTexture != NULL) m_DepthStencilTexture->Release(); m_DepthStencilTexture = NULL; if (!argState) return; // no further effort needed here ID3D10Device& device = m_Engine.get_DX10Device(); D3D10_TEXTURE2D_DESC depthTextureDesc; D3D10_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc; ZeroMemory(&depthTextureDesc,sizeof(depthTextureDesc)); depthTextureDesc.Width = this->get_RenderTargetWidth(); depthTextureDesc.Height = this->get_RenderTargetHeight(); depthTextureDesc.MipLevels = 1; depthTextureDesc.ArraySize = 1; depthTextureDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthTextureDesc.SampleDesc.Count = m_MultiSampleCount == 0 ? 1 : m_MultiSampleCount; depthTextureDesc.SampleDesc.Quality = m_MultiSampleQuality; depthTextureDesc.Usage = D3D10_USAGE_DEFAULT; depthTextureDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL; depthTextureDesc.CPUAccessFlags = 0; depthTextureDesc.MiscFlags = 0; if(device.CreateTexture2D(&depthTextureDesc, 0, &m_DepthStencilTexture) != S_OK) { throw L"RenderTarget: Unable to create depthstencil texture."; } ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc)); depthStencilViewDesc.Format = depthTextureDesc.Format; depthStencilViewDesc.ViewDimension = m_MultiSampleCount >= 1 ? D3D10_DSV_DIMENSION_TEXTURE2DMS : D3D10_DSV_DIMENSION_TEXTURE2D; depthStencilViewDesc.Texture2D.MipSlice = 0; if(device.CreateDepthStencilView(m_DepthStencilTexture, &depthStencilViewDesc, &m_DepthStencilView) != S_OK) { if (m_DepthStencilTexture != NULL) m_DepthStencilTexture->Release(); m_DepthStencilTexture = NULL; throw L"RenderTarget: Unable to create depth stencil view."; } } void RenderTargetBase::AddAdditionalRenderTarget(IRenderTargetBase& argTarget) { this->RemoveAdditionalRenderTarget(argTarget); if (m_AdditionalRenderingTargets.size() + 1 == D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT) { throw L"RenderTarget: Unable to add an additional rendering target, list is full."; } if (argTarget.get_DX10RenderTargetView() == NULL) { throw L"RenderingResource: Unable to add an additional rendering target, new target is not initialized."; } m_AdditionalRenderingTargets.push_back(&argTarget); this->KillViewPortAndRenderTargetData(); this->BuildViewPortAndRenderTargetData(); } void RenderTargetBase::RemoveAdditionalRenderTarget(IRenderTargetBase& argTarget) { std::vector::iterator found = std::find(m_AdditionalRenderingTargets.begin(), m_AdditionalRenderingTargets.end(), &argTarget); if (found != m_AdditionalRenderingTargets.end()) m_AdditionalRenderingTargets.erase(found); this->KillViewPortAndRenderTargetData(); this->BuildViewPortAndRenderTargetData(); } void RenderTargetBase::BuildViewPortAndRenderTargetData() { // Rebuild rendertargets if (m_RenderingTargets == NULL) { if ((m_LastBindFlags & BindFlags::BindAllTextures) == BindFlags::BindAllTextures) { m_ActiveRenderTargetCount = 1 + m_AdditionalRenderingTargets.size(); m_RenderingTargets = new ID3D10RenderTargetView*[m_ActiveRenderTargetCount]; m_RenderingTargets[0] = m_RenderTargetView; for (uint32 i = 0; i < m_AdditionalRenderingTargets.size(); ++i) m_RenderingTargets[i + 1] = m_AdditionalRenderingTargets[i]->get_DX10RenderTargetView(); } else if (m_LastBindFlags & BindFlags::BindAllTextures) { m_ActiveRenderTargetCount = 0; if (m_LastBindFlags & BindFlags::BindBaseTexture) ++m_ActiveRenderTargetCount; if (m_LastBindFlags & BindFlags::BindAdditionalTexture0) ++m_ActiveRenderTargetCount; if (m_LastBindFlags & BindFlags::BindAdditionalTexture1) ++m_ActiveRenderTargetCount; if (m_LastBindFlags & BindFlags::BindAdditionalTexture2) ++m_ActiveRenderTargetCount; if (m_LastBindFlags & BindFlags::BindAdditionalTexture3) ++m_ActiveRenderTargetCount; m_RenderingTargets = new ID3D10RenderTargetView*[m_ActiveRenderTargetCount]; int bufferIndex = 0; if (m_LastBindFlags & BindFlags::BindBaseTexture) m_RenderingTargets[bufferIndex++] = m_RenderTargetView; if (m_LastBindFlags & BindFlags::BindAdditionalTexture0) m_RenderingTargets[bufferIndex++] = m_AdditionalRenderingTargets[0]->get_DX10RenderTargetView(); if (m_LastBindFlags & BindFlags::BindAdditionalTexture1) m_RenderingTargets[bufferIndex++] = m_AdditionalRenderingTargets[1]->get_DX10RenderTargetView(); if (m_LastBindFlags & BindFlags::BindAdditionalTexture2) m_RenderingTargets[bufferIndex++] = m_AdditionalRenderingTargets[2]->get_DX10RenderTargetView(); if (m_LastBindFlags & BindFlags::BindAdditionalTexture3) m_RenderingTargets[bufferIndex++] = m_AdditionalRenderingTargets[3]->get_DX10RenderTargetView(); } else throw L"No render target bindable."; } // Rebuild viewports if (m_D3D10Viewports == NULL) { m_D3D10Viewports = new D3D10_VIEWPORT[m_ActiveRenderTargetCount]; m_D3D10Viewports[0].Height = m_ViewPort.m_Height; m_D3D10Viewports[0].Width = m_ViewPort.m_Width; m_D3D10Viewports[0].MinDepth = m_ViewPort.m_MinDepth; m_D3D10Viewports[0].MaxDepth = m_ViewPort.m_MaxDepth; m_D3D10Viewports[0].TopLeftX = m_ViewPort.m_TopLeftX; m_D3D10Viewports[0].TopLeftY = m_ViewPort.m_TopLeftY; for (uint32 i = 0; i < m_ActiveRenderTargetCount - 1; ++i) { ViewPort viewPort = m_AdditionalRenderingTargets[i]->get_ViewPort(); m_D3D10Viewports[i + 1].Height = viewPort.m_Height; m_D3D10Viewports[i + 1].Width = viewPort.m_Width; m_D3D10Viewports[i + 1].MinDepth = viewPort.m_MinDepth; m_D3D10Viewports[i + 1].MaxDepth = viewPort.m_MaxDepth; m_D3D10Viewports[i + 1].TopLeftX = viewPort.m_TopLeftX; m_D3D10Viewports[i + 1].TopLeftY = viewPort.m_TopLeftY; } } } void RenderTargetBase::KillViewPortAndRenderTargetData() { if (m_RenderingTargets != NULL) delete [] m_RenderingTargets; m_RenderingTargets = NULL; if (m_D3D10Viewports != NULL) delete [] m_D3D10Viewports; m_D3D10Viewports = NULL; m_ActiveRenderTargetCount = 0; } void RenderTargetBase::Bind(DWORD argBindFlags) { if ((argBindFlags & ~ BindFlags::ClearAll) != (m_LastBindFlags & ~ BindFlags::ClearAll)) { m_LastBindFlags = argBindFlags; this->KillViewPortAndRenderTargetData(); this->BuildViewPortAndRenderTargetData(); } m_LastBindFlags = argBindFlags; ID3D10Device& device = m_Engine.get_DX10Device(); this->Clear(argBindFlags); device.PSSetShaderResources(0, 128, m_EmptyShaderResView); device.OMSetRenderTargets(m_ActiveRenderTargetCount, m_RenderingTargets, m_DepthStencilView); device.RSSetViewports(m_ActiveRenderTargetCount, m_D3D10Viewports); m_Engine.get_EngineStates().LastRenderTarget = this; } void RenderTargetBase::UnbindAllRenderTargets() { m_Engine.get_DX10Device().OMSetRenderTargets(0, NULL, NULL); m_Engine.get_DX10Device().RSSetViewports(0, NULL); m_Engine.get_EngineStates().LastRenderTarget = NULL; } CommandExecuteResult::Enumeration RenderTargetBase::ExecuteCommand(unsigned char argCommandType, ICommandBuffer& argCurrentBuffer, uint32 argCurrentPositon) { if (argCommandType == RenderTargetBase::SetRenderTargetCommandType) { if (m_Engine.get_EngineStates().LastRenderTarget != this) { this->UnbindAllRenderTargets(); this->Bind(); } else this->Clear(); } return CommandExecuteResult::None; } void RenderTargetBase::Clear(DWORD argBindFlags) { ID3D10Device& device = m_Engine.get_DX10Device(); if (argBindFlags & BindFlags::ClearColor) device.ClearRenderTargetView(m_RenderTargetView, (FLOAT*)m_ClearColorBufferColor); if ((argBindFlags & BindFlags::ClearDepthStencil) && m_DepthStencilView != NULL) device.ClearDepthStencilView(m_DepthStencilView, 0x01L | 0x02L, m_ClearDepthStencilBufferDepth, m_ClearDepthStencilBufferStencil); }