308 lines
10 KiB
C++
308 lines
10 KiB
C++
#include "stdafx.h"
|
|
#include <algorithm>
|
|
#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<IRenderTargetBase*>::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);
|
|
} |