Files
bluflame/aiwaz/Aiwaz/Resources/RenderTarget/RenderTargetBase.cpp
2026-04-18 22:31:51 +02:00

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