#include "stdafx.h" #include "IEngine.h" #include "IResourceFactory.h" #include "Texture.h" #include 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(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(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(argHeight, argWidth); tmp > 1; tmp /= 2, ++mipMapLevels); mipMapLevels = std::max(1, std::min(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(1, argElements) * mipMapLevels]; uint32 maxI = std::max(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(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()); }