329 lines
10 KiB
C++
329 lines
10 KiB
C++
#include "stdafx.h"
|
|
#include "IEngine.h"
|
|
#include "IResourceFactory.h"
|
|
#include "Texture.h"
|
|
#include <algorithm>
|
|
|
|
|
|
Texture::Texture(IEngine& argEngine)
|
|
: ShaderParameterCollection(argEngine, 3)
|
|
, m_ShaderResourceView(NULL)
|
|
, m_TextureResource(NULL)
|
|
, m_TextureBuffer(NULL)
|
|
, m_Texture(NULL)
|
|
, m_TextureWidth(0)
|
|
, m_TextureHeight(0)
|
|
, m_TextureFormat(DataFormat::Unknown)
|
|
, m_LockedTexture(false)
|
|
, m_LockedArrayElement(0)
|
|
, m_TextureBindingName("Diffuse")
|
|
, m_TextureArraySize(0)
|
|
{
|
|
}
|
|
|
|
|
|
Texture::~Texture()
|
|
{
|
|
this->Uninitialize();
|
|
m_Engine.get_ResourceFactory().DeleteTexture(*const_cast<Texture*>(this), true);
|
|
}
|
|
|
|
|
|
void Texture::Uninitialize()
|
|
{
|
|
m_FileName = L"";
|
|
m_LockedTexture = false;
|
|
m_TextureWidth = 0;
|
|
m_TextureHeight = 0;
|
|
m_TextureArraySize = 0;
|
|
m_TextureFormat = DataFormat::Unknown;
|
|
|
|
if (m_ShaderResourceView != NULL)
|
|
m_ShaderResourceView->Release();
|
|
m_ShaderResourceView = NULL;
|
|
|
|
if (m_Texture != NULL)
|
|
m_Texture->Release();
|
|
m_Texture = NULL;
|
|
m_TextureResource = NULL;
|
|
|
|
if (m_TextureBuffer != NULL)
|
|
m_TextureBuffer->Release();
|
|
m_TextureBuffer = NULL;
|
|
}
|
|
|
|
|
|
void Texture::set_BindingName(const string8& argName)
|
|
{
|
|
if (!m_TextureBindingName.empty())
|
|
this->RemoveParameter(m_TextureBindingName);
|
|
|
|
m_TextureBindingName = argName;
|
|
|
|
if (m_ShaderResourceView == NULL)
|
|
return;
|
|
|
|
if (!m_TextureBindingName.empty() && m_ShaderResourceView != NULL)
|
|
this->SetParameter(argName, *const_cast<Texture*>(this));
|
|
}
|
|
|
|
void Texture::LoadFromFile(const string16& argFileName, DataAccessType::Enumeration argAccessType)
|
|
{
|
|
this->Uninitialize();
|
|
|
|
D3DX10_IMAGE_LOAD_INFO loadInfo;
|
|
loadInfo.Width = D3DX10_DEFAULT;
|
|
loadInfo.Height = D3DX10_DEFAULT;
|
|
loadInfo.Depth = D3DX10_DEFAULT;
|
|
loadInfo.FirstMipLevel = D3DX10_DEFAULT;
|
|
loadInfo.MipLevels = D3DX10_DEFAULT;
|
|
loadInfo.BindFlags = D3DX10_DEFAULT;
|
|
loadInfo.MiscFlags = D3DX10_DEFAULT;
|
|
loadInfo.Format = DXGI_FORMAT(D3DX10_DEFAULT);
|
|
loadInfo.Filter = D3DX10_DEFAULT;
|
|
loadInfo.MipFilter = D3DX10_DEFAULT;
|
|
loadInfo.pSrcInfo = NULL;
|
|
|
|
if (argAccessType == DataAccessType::Static)
|
|
{
|
|
loadInfo.Usage = D3D10_USAGE(D3DX10_DEFAULT);
|
|
loadInfo.CpuAccessFlags = D3DX10_DEFAULT;
|
|
}
|
|
else if (argAccessType == DataAccessType::CpuReadOnly)
|
|
{
|
|
loadInfo.BindFlags = 0;
|
|
loadInfo.Usage = D3D10_USAGE_STAGING;
|
|
loadInfo.CpuAccessFlags = D3D10_CPU_ACCESS_WRITE | D3D10_CPU_ACCESS_READ;
|
|
}
|
|
else if (argAccessType == DataAccessType::Dynamic)
|
|
{
|
|
loadInfo.Usage = D3D10_USAGE_DYNAMIC;
|
|
loadInfo.CpuAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
|
}
|
|
|
|
IFile* textureFile = m_Engine.get_FileSystem().Open(argFileName);
|
|
if (textureFile == NULL)
|
|
throw L"Unable to open texture file.";
|
|
|
|
|
|
ID3D10Device& device = m_Engine.get_DX10Device();
|
|
if (S_OK != ::D3DX10CreateTextureFromMemory(&device,
|
|
textureFile->get_Buffer(),
|
|
textureFile->get_BufferLength(),
|
|
&loadInfo,
|
|
NULL,
|
|
&m_TextureResource,
|
|
NULL
|
|
))
|
|
{
|
|
this->Uninitialize();
|
|
throw L"Texture: Unable to load texture.";
|
|
}
|
|
|
|
D3DX10_IMAGE_INFO loadedImageInfo;
|
|
D3DX10GetImageInfoFromMemory(textureFile->get_Buffer(), textureFile->get_BufferLength(), NULL, &loadedImageInfo, NULL);
|
|
|
|
delete textureFile;
|
|
|
|
if (argAccessType != DataAccessType::CpuReadOnly)
|
|
{
|
|
D3D10_SHADER_RESOURCE_VIEW_DESC texViewDesc;
|
|
ZeroMemory(&texViewDesc, sizeof(texViewDesc));
|
|
texViewDesc.Format = loadedImageInfo.Format;
|
|
texViewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
|
texViewDesc.Texture2DArray.MostDetailedMip = 0;
|
|
texViewDesc.Texture2DArray.MipLevels = loadedImageInfo.MipLevels;
|
|
|
|
if (S_OK != device.CreateShaderResourceView(m_TextureResource, &texViewDesc, &m_ShaderResourceView))
|
|
{
|
|
this->Uninitialize();
|
|
throw L"Texture: Unable to create resource view.";
|
|
}
|
|
}
|
|
|
|
m_Texture = (ID3D10Texture2D*)m_TextureResource;
|
|
m_FileName = argFileName;
|
|
m_TextureWidth = loadedImageInfo.Width;
|
|
m_TextureHeight = loadedImageInfo.Height;
|
|
m_TextureFormat = (DataFormat::Enumeration)loadedImageInfo.Format;
|
|
m_TextureArraySize = 0;
|
|
|
|
this->set_BindingName(this->get_BindingName());
|
|
}
|
|
|
|
|
|
void Texture::CreateTexture(const CreateTextureDescriptor& argDesc)
|
|
{
|
|
this->CreateTexture(argDesc.Width, argDesc.Height, argDesc.MipLevels, argDesc.Elements, argDesc.Format, argDesc.InitialData_, argDesc.AccessType, false, 1, 0);
|
|
}
|
|
|
|
|
|
LockedTextureData Texture::LockTextureBuffer(DataAccessMode::Enumeration argAccessMode, uint32 argArrayElement)
|
|
{
|
|
LockedTextureData outData = { NULL, 0 };
|
|
if (m_Texture == NULL)
|
|
throw L"Texture: Access forbidden until resource has been initialized.";
|
|
|
|
if (m_LockedTexture)
|
|
throw L"Texture: Only one access to the texture buffer at one time possible.";
|
|
|
|
if (argArrayElement >= m_TextureArraySize && m_TextureArraySize != 0 && argArrayElement != 0)
|
|
throw L"Texture: Access element index out of range.";
|
|
|
|
D3D10_MAPPED_TEXTURE2D mapped;
|
|
if (S_OK != m_Texture->Map(D3D10CalcSubresource(0, argArrayElement, 1), (D3D10_MAP)argAccessMode, 0, &mapped))
|
|
throw L"TextureResource: Access to the texture buffer was not successfull.";
|
|
|
|
outData.Data = mapped.pData;
|
|
outData.RowPitch = mapped.RowPitch;
|
|
|
|
m_LockedTexture = true;
|
|
m_LockedArrayElement = argArrayElement;
|
|
|
|
return outData;
|
|
}
|
|
|
|
|
|
void Texture::UnlockTextureBuffer()
|
|
{
|
|
if (m_Texture == NULL)
|
|
throw L"Texture: Access forbidden until resource has been initialized.";
|
|
|
|
if (!m_LockedTexture)
|
|
throw L"Texture: No access was done ending the access to the texture buffer is not possible.";
|
|
|
|
m_Texture->Unmap(D3D10CalcSubresource(0, m_LockedArrayElement, 1));
|
|
|
|
m_LockedTexture = false;
|
|
}
|
|
|
|
|
|
void Texture::CreateRenderTargetTexture(uint32 argWidth, uint32 argHeight, DataFormat::Enumeration argFormat, uint32 argMultiSampleCount, uint32 argMultiSampleQuality)
|
|
{
|
|
this->CreateTexture(argWidth, argHeight, 1, 0, argFormat, NULL, DataAccessType::Static, true, argMultiSampleCount, argMultiSampleQuality);
|
|
}
|
|
|
|
|
|
void Texture::CreateTexture(uint32 argWidth, uint32 argHeight, uint32 argMipLevels, uint32 argElements, DataFormat::Enumeration argFormat, TextureInitialData* ar_InitialData_, DataAccessType::Enumeration argAccessType, bool argRenderTarget, uint32 argMultiSampleCount, uint32 argMultiSampleQuality)
|
|
{
|
|
this->Uninitialize();
|
|
|
|
ID3D10Device& device = m_Engine.get_DX10Device();
|
|
|
|
if (argElements > 512)
|
|
throw L"Texture: TextureArrays must not exceed the maximum element count of 512.";
|
|
|
|
if (argElements > 0 && ar_InitialData_ == NULL)
|
|
throw L"TextureResource: TextureArrays must provide a initial data set.";
|
|
|
|
// calculate the needed amount of mipmap levels
|
|
uint32 mipMapLevels = 1;
|
|
for (uint32 tmp = std::min<uint32>(argHeight, argWidth); tmp > 1; tmp /= 2, ++mipMapLevels);
|
|
mipMapLevels = std::max<uint32>(1, std::min<uint32>(mipMapLevels, argMipLevels == 0 ? mipMapLevels : argMipLevels));
|
|
|
|
// initialize the initiate data (this includes fake mipmap levels)
|
|
D3D10_SUBRESOURCE_DATA* subResourceData = NULL;
|
|
if (ar_InitialData_ != NULL)
|
|
{
|
|
subResourceData = new D3D10_SUBRESOURCE_DATA[std::max<uint32>(1, argElements) * mipMapLevels];
|
|
uint32 maxI = std::max<uint32>(1, argElements);
|
|
|
|
for (uint32 i = 0; i < maxI; ++i)
|
|
for (uint32 k = 0; k < mipMapLevels; ++k)
|
|
{
|
|
subResourceData[i * mipMapLevels + k].pSysMem = ar_InitialData_[i].Data;
|
|
subResourceData[i * mipMapLevels + k].SysMemSlicePitch = 0;
|
|
|
|
// use fake mipmap sizes when we are processing mipmaps, so we do not allocate unnecessary memory
|
|
// due the post calculation step for the mipmaps
|
|
if (k > 0)
|
|
subResourceData[i * mipMapLevels + k].SysMemPitch = 1;
|
|
else
|
|
subResourceData[i * mipMapLevels + k].SysMemPitch = ar_InitialData_[i].Pitch;
|
|
}
|
|
}
|
|
|
|
// create the resource
|
|
D3D10_TEXTURE2D_DESC texDesc;
|
|
ZeroMemory(&texDesc, sizeof(texDesc));
|
|
texDesc.Width = argWidth;
|
|
texDesc.Height = argHeight;
|
|
texDesc.MipLevels = mipMapLevels;
|
|
texDesc.ArraySize = std::max<uint32>(1, argElements);
|
|
texDesc.Format = (DXGI_FORMAT)argFormat;
|
|
texDesc.SampleDesc.Count = argMultiSampleCount;
|
|
texDesc.SampleDesc.Quality = argMultiSampleQuality;
|
|
|
|
if (argAccessType == DataAccessType::Static)
|
|
{
|
|
texDesc.Usage = D3D10_USAGE_DEFAULT;
|
|
texDesc.CPUAccessFlags = 0;
|
|
}
|
|
else if (argAccessType == DataAccessType::Dynamic)
|
|
{
|
|
texDesc.Usage = D3D10_USAGE_DYNAMIC;
|
|
texDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
|
}
|
|
|
|
if (argAccessType != DataAccessType::CpuReadOnly)
|
|
texDesc.BindFlags = ((mipMapLevels > 1 || argRenderTarget) ? D3D10_BIND_RENDER_TARGET : 0) | D3D10_BIND_SHADER_RESOURCE;
|
|
if (mipMapLevels > 1)
|
|
texDesc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS;
|
|
|
|
if (S_OK != device.CreateTexture2D(&texDesc, subResourceData, &m_Texture))
|
|
{
|
|
if (subResourceData != NULL)
|
|
delete subResourceData;
|
|
|
|
this->Uninitialize();
|
|
throw L"Texture: Unable to create plain texture.";
|
|
return;
|
|
}
|
|
|
|
if (subResourceData != NULL)
|
|
delete [] subResourceData;
|
|
|
|
m_TextureResource = m_Texture;
|
|
|
|
// update the mipmapchain
|
|
if (mipMapLevels > 1)
|
|
{
|
|
if (S_OK != ::D3DX10FilterTexture(m_Texture, 0, D3DX10_DEFAULT))
|
|
throw L"Texture: Unable to filter texture (mipmaps).";
|
|
else
|
|
m_Texture->GetDesc(&texDesc);
|
|
}
|
|
|
|
// create the resource view when possible
|
|
if (argAccessType != DataAccessType::CpuReadOnly)
|
|
{
|
|
D3D10_SHADER_RESOURCE_VIEW_DESC texViewDesc;
|
|
ZeroMemory(&texViewDesc, sizeof(texViewDesc));
|
|
texViewDesc.Format = texDesc.Format;
|
|
texViewDesc.Buffer.ElementWidth = argElements;
|
|
|
|
if (argElements > 0)
|
|
texViewDesc.ViewDimension = argMultiSampleCount == 1 ? D3D10_SRV_DIMENSION_TEXTURE2DARRAY : D3D10_SRV_DIMENSION_TEXTURE2DMSARRAY;
|
|
else
|
|
texViewDesc.ViewDimension = argMultiSampleCount == 1 ? D3D10_SRV_DIMENSION_TEXTURE2D : D3D10_SRV_DIMENSION_TEXTURE2DMS;
|
|
|
|
texViewDesc.Texture2DArray.MostDetailedMip = 0;
|
|
texViewDesc.Texture2DArray.MipLevels = texDesc.MipLevels;
|
|
texViewDesc.Texture2DArray.ArraySize = argElements;
|
|
|
|
if (S_OK != device.CreateShaderResourceView(m_TextureResource, &texViewDesc, &m_ShaderResourceView))
|
|
{
|
|
this->Uninitialize();
|
|
throw L"TextureResource: Unable to create resource view.";
|
|
}
|
|
}
|
|
|
|
// finalize
|
|
m_TextureWidth = argWidth;
|
|
m_TextureHeight = argHeight;
|
|
m_TextureFormat = argFormat;
|
|
m_TextureArraySize = argElements;
|
|
|
|
this->set_BindingName(this->get_BindingName());
|
|
}
|