mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
cppkore uses string/wstring as StringBase while we use std::string/std::wstring as string/wstring. Changed all types in cppkore to String/WString instead.
702 lines
21 KiB
C++
702 lines
21 KiB
C++
#include "stdafx.h"
|
|
#include "Texture.h"
|
|
#include "DDS.h"
|
|
#include "MathHelper.h"
|
|
#include <wincodec.h>
|
|
|
|
#include "..\cppkore_incl\DirectXTex\DirectXTex.h"
|
|
|
|
#if _WIN64
|
|
#if _DEBUG
|
|
#pragma comment(lib, "..\\cppkore_libs\\DirectXTex\\DirectXTex_x64d.lib")
|
|
#else
|
|
#pragma comment(lib, "..\\cppkore_libs\\DirectXTex\\DirectXTex_x64r.lib")
|
|
#endif
|
|
#else
|
|
#error DirectXTex doesn't support non x64 builds yet
|
|
#endif
|
|
|
|
#define InternalScratchImage ((DirectX::ScratchImage*)this->DirectXImage)
|
|
|
|
namespace Assets
|
|
{
|
|
Texture::Texture(void* ScratchImage)
|
|
: DirectXImage(ScratchImage)
|
|
{
|
|
}
|
|
|
|
Texture::Texture(uint32_t Width, uint32_t Height)
|
|
: Texture(Width, Height, DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM)
|
|
{
|
|
}
|
|
|
|
Texture::Texture(uint32_t Width, uint32_t Height, DXGI_FORMAT Format)
|
|
: DirectXImage(nullptr)
|
|
{
|
|
this->DirectXImage = new DirectX::ScratchImage();
|
|
|
|
DirectX::TexMetadata Data{};
|
|
Data.width = Width;
|
|
Data.height = Height;
|
|
Data.depth = 1;
|
|
Data.arraySize = 1;
|
|
Data.mipLevels = 1;
|
|
Data.dimension = DirectX::TEX_DIMENSION::TEX_DIMENSION_TEXTURE2D;
|
|
Data.format = Format;
|
|
InternalScratchImage->Initialize(Data);
|
|
}
|
|
|
|
Texture::~Texture()
|
|
{
|
|
if (DirectXImage)
|
|
delete InternalScratchImage;
|
|
DirectXImage = nullptr;
|
|
}
|
|
|
|
Texture::Texture(Texture&& Rhs) noexcept
|
|
{
|
|
this->DirectXImage = Rhs.DirectXImage;
|
|
Rhs.DirectXImage = nullptr;
|
|
}
|
|
|
|
const uint32_t Texture::Width() const
|
|
{
|
|
return (uint32_t)InternalScratchImage->GetMetadata().width;
|
|
}
|
|
|
|
const uint32_t Texture::Height() const
|
|
{
|
|
return (uint32_t)InternalScratchImage->GetMetadata().height;
|
|
}
|
|
|
|
const uint32_t Texture::Pitch() const
|
|
{
|
|
return (uint32_t)InternalScratchImage->GetImages()->rowPitch;
|
|
}
|
|
|
|
const uint32_t Texture::MipCount() const
|
|
{
|
|
return (uint32_t)InternalScratchImage->GetMetadata().mipLevels;
|
|
}
|
|
|
|
const uint32_t Texture::BlockSize() const
|
|
{
|
|
return (uint32_t)InternalScratchImage->GetPixelsSize();
|
|
}
|
|
|
|
uint8_t* Texture::GetPixels()
|
|
{
|
|
return InternalScratchImage->GetImages()->pixels;
|
|
}
|
|
|
|
const uint8_t* Texture::GetPixels() const
|
|
{
|
|
return InternalScratchImage->GetImages()->pixels;
|
|
}
|
|
|
|
const DXGI_FORMAT Texture::Format() const
|
|
{
|
|
return InternalScratchImage->GetMetadata().format;
|
|
}
|
|
|
|
const uint8_t Texture::GetBpp() const
|
|
{
|
|
DXGI_FORMAT format = this->Format();
|
|
return DirectX::BitsPerPixel(format);
|
|
}
|
|
|
|
const uint8_t Texture::Pixbl() const
|
|
{
|
|
uint32_t format = this->Format();
|
|
|
|
if ((format >= 70 && format <= 84) || format >= 94 && format <= 99)
|
|
return 4;
|
|
return 1;
|
|
}
|
|
|
|
// this function assumes that both of the textures are in the same format
|
|
void Texture::CopyTextureSlice(std::unique_ptr<Texture>& SourceTexture, DirectX::Rect srcRect, uint32_t x, uint32_t y)
|
|
{
|
|
DirectX::CopyRectangle(*((DirectX::ScratchImage*)SourceTexture->DirectXImage)->GetImage(0, 0, 0), srcRect, *InternalScratchImage->GetImage(0, 0, 0), DirectX::TEX_FILTER_DEFAULT, x, y);
|
|
}
|
|
|
|
void Texture::ConvertToFormat(DXGI_FORMAT Format)
|
|
{
|
|
if (InternalScratchImage->GetMetadata().format == Format)
|
|
return;
|
|
|
|
// If we need to decompress, and our target is not compressed, we can skip a loop here by directly going to the target
|
|
DXGI_FORMAT DecompressFmt = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
|
|
if (!DirectX::IsCompressed(Format))
|
|
DecompressFmt = Format;
|
|
|
|
// First, check if we are currently compressed...
|
|
if (DirectX::IsCompressed(InternalScratchImage->GetMetadata().format))
|
|
{
|
|
auto TemporaryImage = std::make_unique<DirectX::ScratchImage>();
|
|
auto Result = DirectX::Decompress(InternalScratchImage->GetImages(), InternalScratchImage->GetImageCount(), InternalScratchImage->GetMetadata(), DecompressFmt, *TemporaryImage);
|
|
|
|
if (SUCCEEDED(Result))
|
|
{
|
|
delete InternalScratchImage;
|
|
DirectXImage = TemporaryImage.release();
|
|
}
|
|
else
|
|
{
|
|
throw std::exception("Failed to decompress the image format");
|
|
}
|
|
}
|
|
|
|
// If the target is compressed, compress the new data
|
|
if (DirectX::IsCompressed(Format))
|
|
{
|
|
auto TemporaryImage = std::make_unique<DirectX::ScratchImage>();
|
|
auto Result = DirectX::Compress(InternalScratchImage->GetImages(), InternalScratchImage->GetImageCount(), InternalScratchImage->GetMetadata(), Format, DirectX::TEX_COMPRESS_FLAGS::TEX_COMPRESS_DEFAULT, DirectX::TEX_THRESHOLD_DEFAULT, *TemporaryImage);
|
|
|
|
if (SUCCEEDED(Result))
|
|
{
|
|
delete InternalScratchImage;
|
|
DirectXImage = TemporaryImage.release();
|
|
}
|
|
else
|
|
{
|
|
throw std::exception("Failed to compress the image format");
|
|
}
|
|
}
|
|
else if (InternalScratchImage->GetMetadata().format != Format)
|
|
{
|
|
auto TemporaryImage = std::make_unique<DirectX::ScratchImage>();
|
|
auto Result = DirectX::Convert(InternalScratchImage->GetImages(), InternalScratchImage->GetImageCount(), InternalScratchImage->GetMetadata(), Format, DirectX::TEX_FILTER_FLAGS::TEX_FILTER_DEFAULT, DirectX::TEX_THRESHOLD_DEFAULT, *TemporaryImage);
|
|
|
|
if (SUCCEEDED(Result))
|
|
{
|
|
delete InternalScratchImage;
|
|
DirectXImage = TemporaryImage.release();
|
|
}
|
|
else
|
|
{
|
|
throw std::exception("Failed to convert the image format");
|
|
}
|
|
}
|
|
}
|
|
|
|
void Texture::Transcode(TranscodeType Type)
|
|
{
|
|
// Depending on the transcode type, we need to ensure a format...
|
|
switch (Type)
|
|
{
|
|
case TranscodeType::NormalMapBC5:
|
|
this->Transcoder_NormalMapBC5();
|
|
break;
|
|
case TranscodeType::NormalMapBC5OpenGl:
|
|
this->Transcoder_NormalMapBC5OpenGl();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Texture::Save(const String& File)
|
|
{
|
|
if (File.EndsWith(".dds"))
|
|
this->Save(File, SaveFileType::Dds);
|
|
else if (File.EndsWith(".tga"))
|
|
this->Save(File, SaveFileType::Tga);
|
|
else if (File.EndsWith(".tiff"))
|
|
this->Save(File, SaveFileType::Tiff);
|
|
else if (File.EndsWith(".hdr"))
|
|
this->Save(File, SaveFileType::Hdr);
|
|
else if (File.EndsWith(".png"))
|
|
this->Save(File, SaveFileType::Png);
|
|
else if (File.EndsWith(".bmp"))
|
|
this->Save(File, SaveFileType::Bmp);
|
|
else if (File.EndsWith(".jpg"))
|
|
this->Save(File, SaveFileType::Jpeg);
|
|
else if (File.EndsWith(".jxr"))
|
|
this->Save(File, SaveFileType::Jxr);
|
|
else if (File.EndsWith(".gif"))
|
|
this->Save(File, SaveFileType::Gif);
|
|
else
|
|
throw std::exception("Unknown image file extension");
|
|
}
|
|
|
|
void Texture::Save(const String& File, SaveFileType Type)
|
|
{
|
|
this->EnsureFormatForType(Type);
|
|
HRESULT SaveResult = 0;
|
|
|
|
auto OutputWide = File.ToWString();
|
|
|
|
switch (Type)
|
|
{
|
|
case SaveFileType::Dds:
|
|
SaveResult = DirectX::SaveToDDSFile(InternalScratchImage->GetImages(), InternalScratchImage->GetImageCount(), InternalScratchImage->GetMetadata(), DirectX::DDS_FLAGS::DDS_FLAGS_NONE, (const wchar_t*)OutputWide);
|
|
break;
|
|
case SaveFileType::Tga:
|
|
SaveResult = DirectX::SaveToTGAFile(*InternalScratchImage->GetImages(), (const wchar_t*)OutputWide);
|
|
break;
|
|
case SaveFileType::Hdr:
|
|
SaveResult = DirectX::SaveToHDRFile(*InternalScratchImage->GetImages(), (const wchar_t*)OutputWide);
|
|
break;
|
|
default:
|
|
{
|
|
// This handles all WIC-Codec based formats
|
|
auto Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_BMP);
|
|
std::function<void __cdecl(IPropertyBag2*)> PropertyWriter = nullptr;
|
|
|
|
switch (Type)
|
|
{
|
|
case SaveFileType::Gif:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_GIF);
|
|
break;
|
|
case SaveFileType::Jpeg:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_JPEG);
|
|
PropertyWriter = [](IPropertyBag2* props)
|
|
{
|
|
PROPBAG2 options{};
|
|
VARIANT varValues{};
|
|
options.pstrName = (LPOLESTR)L"ImageQuality";
|
|
varValues.vt = VT_R4;
|
|
varValues.fltVal = 1.f;
|
|
|
|
(void)props->Write(1, &options, &varValues);
|
|
};
|
|
break;
|
|
case SaveFileType::Jxr:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_WMP);
|
|
break;
|
|
case SaveFileType::Png:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_PNG);
|
|
break;
|
|
case SaveFileType::Tiff:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_TIFF);
|
|
PropertyWriter = [](IPropertyBag2* props)
|
|
{
|
|
PROPBAG2 options{};
|
|
VARIANT varValues{};
|
|
options.pstrName = (LPOLESTR)L"TiffCompressionMethod";
|
|
varValues.vt = VT_UI1;
|
|
varValues.bVal = WICTiffCompressionOption::WICTiffCompressionDontCare;
|
|
|
|
(void)props->Write(1, &options, &varValues);
|
|
};
|
|
break;
|
|
}
|
|
|
|
SaveResult = DirectX::SaveToWICFile(*InternalScratchImage->GetImages(), DirectX::WIC_FLAGS::WIC_FLAGS_FORCE_SRGB, Wc, (const wchar_t*)OutputWide, nullptr, PropertyWriter);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (FAILED(SaveResult))
|
|
throw std::exception("An error occured while saving the image");
|
|
}
|
|
|
|
void Texture::Save(IO::Stream& Stream, SaveFileType Type)
|
|
{
|
|
this->EnsureFormatForType(Type);
|
|
DirectX::Blob TemporaryBuffer;
|
|
|
|
SaveToMemoryBlob(&TemporaryBuffer, Type);
|
|
|
|
Stream.Write((uint8_t*)TemporaryBuffer.GetBufferPointer(), 0, (uint64_t)TemporaryBuffer.GetBufferSize());
|
|
}
|
|
|
|
void Texture::Save(uint8_t* Buffer, uint64_t BufferLength, SaveFileType Type)
|
|
{
|
|
this->EnsureFormatForType(Type);
|
|
DirectX::Blob TemporaryBuffer;
|
|
|
|
SaveToMemoryBlob(&TemporaryBuffer, Type);
|
|
|
|
std::memcpy(Buffer, TemporaryBuffer.GetBufferPointer(), min(TemporaryBuffer.GetBufferSize(), BufferLength));
|
|
}
|
|
|
|
Texture Texture::FromFile(const String& File)
|
|
{
|
|
Texture Result;
|
|
DirectX::TexMetadata MetaData;
|
|
HRESULT LoadResult = 0;
|
|
|
|
Result.DirectXImage = new DirectX::ScratchImage();
|
|
|
|
auto WidePath = File.ToWString();
|
|
if (File.EndsWith(".dds"))
|
|
LoadResult = DirectX::LoadFromDDSFile((const wchar_t*)WidePath, DirectX::DDS_FLAGS::DDS_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
else if (File.EndsWith(".tga"))
|
|
LoadResult = DirectX::LoadFromTGAFile((const wchar_t*)WidePath, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
else if (File.EndsWith(".hdr"))
|
|
LoadResult = DirectX::LoadFromHDRFile((const wchar_t*)WidePath, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
else
|
|
LoadResult = DirectX::LoadFromWICFile((const wchar_t*)WidePath, DirectX::WIC_FLAGS::WIC_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
|
|
if (FAILED(LoadResult))
|
|
{
|
|
delete (DirectX::ScratchImage*)Result.DirectXImage;
|
|
Result.DirectXImage = nullptr;
|
|
|
|
throw std::exception("An error occured loading the image");
|
|
}
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
Texture Texture::FromFile(const String& File, TextureType Type)
|
|
{
|
|
Texture Result;
|
|
DirectX::TexMetadata MetaData;
|
|
HRESULT LoadResult = 0;
|
|
|
|
Result.DirectXImage = new DirectX::ScratchImage();
|
|
|
|
auto WidePath = File.ToWString();
|
|
switch (Type)
|
|
{
|
|
case TextureType::DDS:
|
|
LoadResult = DirectX::LoadFromDDSFile((const wchar_t*)WidePath, DirectX::DDS_FLAGS::DDS_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::TGA:
|
|
LoadResult = DirectX::LoadFromTGAFile((const wchar_t*)WidePath, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::HDR:
|
|
LoadResult = DirectX::LoadFromHDRFile((const wchar_t*)WidePath, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::WIC:
|
|
LoadResult = DirectX::LoadFromWICFile((const wchar_t*)WidePath, DirectX::WIC_FLAGS::WIC_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
}
|
|
|
|
if (FAILED(LoadResult))
|
|
{
|
|
delete (DirectX::ScratchImage*)Result.DirectXImage;
|
|
Result.DirectXImage = nullptr;
|
|
|
|
throw std::exception("An error occured loading the image");
|
|
}
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
Texture Texture::FromStream(IO::Stream& Stream, TextureType Type)
|
|
{
|
|
Texture Result;
|
|
DirectX::TexMetadata MetaData;
|
|
HRESULT LoadResult = 0;
|
|
|
|
Result.DirectXImage = new DirectX::ScratchImage();
|
|
|
|
auto ScratchBuffer = std::make_unique<uint8_t[]>(Stream.GetLength());
|
|
Stream.Read(ScratchBuffer.get(), 0, Stream.GetLength());
|
|
|
|
switch (Type)
|
|
{
|
|
case TextureType::DDS:
|
|
LoadResult = DirectX::LoadFromDDSMemory(ScratchBuffer.get(), Stream.GetLength(), DirectX::DDS_FLAGS::DDS_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::TGA:
|
|
LoadResult = DirectX::LoadFromTGAMemory(ScratchBuffer.get(), Stream.GetLength(), &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::HDR:
|
|
LoadResult = DirectX::LoadFromHDRMemory(ScratchBuffer.get(), Stream.GetLength(), &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::WIC:
|
|
LoadResult = DirectX::LoadFromWICMemory(ScratchBuffer.get(), Stream.GetLength(), DirectX::WIC_FLAGS::WIC_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
}
|
|
|
|
if (FAILED(LoadResult))
|
|
{
|
|
delete (DirectX::ScratchImage*)Result.DirectXImage;
|
|
Result.DirectXImage = nullptr;
|
|
|
|
throw std::exception("An error occured loading the image");
|
|
}
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
Texture Texture::FromBuffer(uint8_t* Buffer, uint64_t BufferLength, TextureType Type)
|
|
{
|
|
Texture Result;
|
|
DirectX::TexMetadata MetaData;
|
|
HRESULT LoadResult = 0;
|
|
|
|
Result.DirectXImage = new DirectX::ScratchImage();
|
|
|
|
switch (Type)
|
|
{
|
|
case TextureType::DDS:
|
|
LoadResult = DirectX::LoadFromDDSMemory(Buffer, BufferLength, DirectX::DDS_FLAGS::DDS_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::TGA:
|
|
LoadResult = DirectX::LoadFromTGAMemory(Buffer, BufferLength, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::HDR:
|
|
LoadResult = DirectX::LoadFromHDRMemory(Buffer, BufferLength, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
case TextureType::WIC:
|
|
LoadResult = DirectX::LoadFromWICMemory(Buffer, BufferLength, DirectX::WIC_FLAGS::WIC_FLAGS_NONE, &MetaData, *(DirectX::ScratchImage*)Result.DirectXImage);
|
|
break;
|
|
}
|
|
|
|
if (FAILED(LoadResult))
|
|
{
|
|
delete (DirectX::ScratchImage*)Result.DirectXImage;
|
|
Result.DirectXImage = nullptr;
|
|
|
|
throw std::exception("An error occured loading the image");
|
|
}
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
Texture Texture::FromRawBlock(uint8_t* Buffer, uint64_t BufferLength, uint32_t Width, uint32_t Height, DXGI_FORMAT Format)
|
|
{
|
|
DDSFormat BlockFormat{};
|
|
BlockFormat.Format = Format;
|
|
|
|
auto ExpectedBlockSize = Assets::DDS::CalculateBlockSize(Width, Height, BlockFormat);
|
|
|
|
if (BufferLength < ExpectedBlockSize)
|
|
throw std::exception("Invalid buffer length specified");
|
|
|
|
auto Result = Texture(Width, Height, Format);
|
|
|
|
std::memcpy(((DirectX::ScratchImage*)Result.DirectXImage)->GetImages()->pixels, Buffer, ExpectedBlockSize);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
int Texture::Morton(uint32_t i, uint32_t sx, uint32_t sy)
|
|
{
|
|
int v0 = 1;
|
|
int v1 = 1;
|
|
int v2 = i;
|
|
int v3 = sx;
|
|
int v4 = sy;
|
|
int v5 = 0;
|
|
int v6 = 0;
|
|
while (v3 > 1 || v4 > 1)
|
|
{
|
|
if (v3 > 1)
|
|
{
|
|
v5 += v1 * (v2 & 1);
|
|
v2 >>= 1;
|
|
v1 *= 2;
|
|
v3 >>= 1;
|
|
}
|
|
if (v4 > 1)
|
|
{
|
|
v6 += v0 * (v2 & 1);
|
|
v2 >>= 1;
|
|
v0 *= 2;
|
|
v4 >>= 1;
|
|
}
|
|
}
|
|
return v6 * sx + v5;
|
|
}
|
|
|
|
|
|
Texture::Texture()
|
|
: DirectXImage(nullptr)
|
|
{
|
|
}
|
|
|
|
void Texture::EnsureFormatForType(SaveFileType Type)
|
|
{
|
|
switch (Type)
|
|
{
|
|
// These formats require a 32bpp, so B8G8R8A8_UNORM - like format to encode (Only transcode if not 32bpp)
|
|
case SaveFileType::Png:
|
|
case SaveFileType::Bmp:
|
|
case SaveFileType::Jpeg:
|
|
case SaveFileType::Tiff:
|
|
case SaveFileType::Gif:
|
|
case SaveFileType::Jxr:
|
|
case SaveFileType::Tga:
|
|
if (!IsValid32bppFormat(InternalScratchImage->GetMetadata().format))
|
|
this->ConvertToFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM);
|
|
break;
|
|
// This format requires either R32G32B32A32_FLOAT or R32G32B32_FLOAT
|
|
case SaveFileType::Hdr:
|
|
this->ConvertToFormat(DXGI_FORMAT::DXGI_FORMAT_R32G32B32A32_FLOAT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Texture::SaveToMemoryBlob(void* Blob, SaveFileType Type)
|
|
{
|
|
HRESULT SaveResult = 0;
|
|
|
|
switch (Type)
|
|
{
|
|
case SaveFileType::Dds:
|
|
SaveResult = DirectX::SaveToDDSMemory(InternalScratchImage->GetImages(), InternalScratchImage->GetImageCount(), InternalScratchImage->GetMetadata(), DirectX::DDS_FLAGS::DDS_FLAGS_NONE, *(DirectX::Blob*)Blob);
|
|
break;
|
|
case SaveFileType::Tga:
|
|
SaveResult = DirectX::SaveToTGAMemory(*InternalScratchImage->GetImages(), *(DirectX::Blob*)Blob);
|
|
break;
|
|
case SaveFileType::Hdr:
|
|
SaveResult = DirectX::SaveToHDRMemory(*InternalScratchImage->GetImages(), *(DirectX::Blob*)Blob);
|
|
break;
|
|
default:
|
|
{
|
|
// This handles all WIC-Codec based formats
|
|
auto Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_BMP);
|
|
std::function<void __cdecl(IPropertyBag2*)> PropertyWriter = nullptr;
|
|
|
|
switch (Type)
|
|
{
|
|
case SaveFileType::Gif:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_GIF);
|
|
break;
|
|
case SaveFileType::Jpeg:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_JPEG);
|
|
PropertyWriter = [](IPropertyBag2 * props)
|
|
{
|
|
PROPBAG2 options{};
|
|
VARIANT varValues{};
|
|
options.pstrName = (LPOLESTR)L"ImageQuality";
|
|
varValues.vt = VT_R4;
|
|
varValues.fltVal = 1.f;
|
|
|
|
(void)props->Write(1, &options, &varValues);
|
|
};
|
|
break;
|
|
case SaveFileType::Jxr:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_WMP);
|
|
break;
|
|
case SaveFileType::Png:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_PNG);
|
|
break;
|
|
case SaveFileType::Tiff:
|
|
Wc = DirectX::GetWICCodec(DirectX::WICCodecs::WIC_CODEC_TIFF);
|
|
PropertyWriter = [](IPropertyBag2 * props)
|
|
{
|
|
PROPBAG2 options{};
|
|
VARIANT varValues{};
|
|
options.pstrName = (LPOLESTR)L"TiffCompressionMethod";
|
|
varValues.vt = VT_UI1;
|
|
varValues.bVal = WICTiffCompressionOption::WICTiffCompressionDontCare;
|
|
|
|
(void)props->Write(1, &options, &varValues);
|
|
};
|
|
break;
|
|
}
|
|
|
|
SaveResult = DirectX::SaveToWICMemory(*InternalScratchImage->GetImages(), DirectX::WIC_FLAGS::WIC_FLAGS_NONE, Wc, *(DirectX::Blob*)Blob, nullptr, PropertyWriter);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (FAILED(SaveResult))
|
|
throw std::exception("An error occured while saving the image");
|
|
}
|
|
|
|
void Texture::Transcoder_NormalMapBC5()
|
|
{
|
|
// Ensure R8G8B8A8 value and ordering...
|
|
if (this->Format() != DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM)
|
|
this->ConvertToFormat(DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM);
|
|
|
|
// Create a temporary image
|
|
auto TemporaryResult = std::make_unique<DirectX::ScratchImage>();
|
|
auto CurrentResult = (DirectX::ScratchImage*)this->DirectXImage;
|
|
|
|
auto TranscodeResult = DirectX::TransformImage(CurrentResult->GetImages(), CurrentResult->GetImageCount(), CurrentResult->GetMetadata(),
|
|
[](DirectX::XMVECTOR* OutPixels, const DirectX::XMVECTOR* InPixels, size_t Width, size_t Slice)
|
|
{
|
|
for (size_t i = 0; i < Width; i++)
|
|
{
|
|
auto Scanline = InPixels[i];
|
|
|
|
auto Red = DirectX::XMVectorGetX(Scanline);
|
|
auto Green = DirectX::XMVectorGetY(Scanline);
|
|
|
|
// Calculate the blue channel
|
|
float NormalX = 2 * Red - 1;
|
|
float NormalY = 2 * Green - 1;
|
|
float NormalZ = 0.0f;
|
|
|
|
// Check if we can average it
|
|
if (1 - NormalX * NormalX - NormalY * NormalY > 0)
|
|
{
|
|
NormalZ = std::sqrtf(1 - NormalX * NormalX - NormalY * NormalY);
|
|
}
|
|
|
|
// Calculate the final blue value and clamp it between 0 and 1
|
|
float ResultBlueVal = Math::MathHelper::Clamp<float>(((NormalZ + 1) / 2.0f), 0, 1.0);
|
|
|
|
OutPixels[i] = DirectX::XMVectorSetZ(Scanline, ResultBlueVal);
|
|
}
|
|
}, *TemporaryResult);
|
|
|
|
// If it succeeds, we must then
|
|
if (SUCCEEDED(TranscodeResult))
|
|
{
|
|
delete (DirectX::ScratchImage*)this->DirectXImage;
|
|
this->DirectXImage = TemporaryResult.release();
|
|
}
|
|
}
|
|
|
|
void Texture::Transcoder_NormalMapBC5OpenGl()
|
|
{
|
|
// Ensure R8G8B8A8 value and ordering...
|
|
if (this->Format() != DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM)
|
|
this->ConvertToFormat(DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM);
|
|
|
|
// Create a temporary image
|
|
auto TemporaryResult = std::make_unique<DirectX::ScratchImage>();
|
|
auto CurrentResult = (DirectX::ScratchImage*)this->DirectXImage;
|
|
|
|
auto TranscodeResult = DirectX::TransformImage(CurrentResult->GetImages(), CurrentResult->GetImageCount(), CurrentResult->GetMetadata(),
|
|
[](DirectX::XMVECTOR* OutPixels, const DirectX::XMVECTOR* InPixels, size_t Width, size_t Slice)
|
|
{
|
|
for (size_t i = 0; i < Width; i++)
|
|
{
|
|
auto Scanline = InPixels[i];
|
|
|
|
auto Red = DirectX::XMVectorGetX(Scanline);
|
|
auto Green = DirectX::XMVectorGetY(Scanline);
|
|
|
|
// Invert G (Y) to match DirectX
|
|
Green = 1.0f - Green;
|
|
Scanline = DirectX::XMVectorSetY(Scanline, Green);
|
|
|
|
// Calculate the blue channel
|
|
float NormalX = 2 * Red - 1;
|
|
float NormalY = 2 * Green - 1;
|
|
float NormalZ = 0.0f;
|
|
|
|
// Check if we can average it
|
|
if (1 - NormalX * NormalX - NormalY * NormalY > 0)
|
|
{
|
|
NormalZ = std::sqrtf(1 - NormalX * NormalX - NormalY * NormalY);
|
|
}
|
|
|
|
// Calculate the final blue value and clamp it between 0 and 1
|
|
float ResultBlueVal = Math::MathHelper::Clamp<float>(((NormalZ + 1) / 2.0f), 0, 1.0);
|
|
|
|
OutPixels[i] = DirectX::XMVectorSetZ(Scanline, ResultBlueVal);
|
|
}
|
|
}, *TemporaryResult);
|
|
|
|
// If it succeeds, we must then
|
|
if (SUCCEEDED(TranscodeResult))
|
|
{
|
|
delete (DirectX::ScratchImage*)this->DirectXImage;
|
|
this->DirectXImage = TemporaryResult.release();
|
|
}
|
|
}
|
|
|
|
bool Texture::IsValid32bppFormat(DXGI_FORMAT Format)
|
|
{
|
|
switch (Format)
|
|
{
|
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
} |