Reputation: 31
I want to create a function to convert the input dds file to another format (also DDS) function signature will be like this
std::vector<byte> ConvertDDS(const byte* src, const size_t src_len, const DXGI_FORMAT format)
in here src
will be a pointer to the dds file content (full dds), and format
will be the format that we want to convert the src
into, the function return a vector of bytes that hold the converted dds.
as I said before the input DDS can be any format (I mean not any, but we better guess that it will be any) it can be compressed or uncompressed so we need to handle these two cases as well
What would be the right and correct way to write this function?
Currently I have this code, it will convert the dds, but the result aren't what I except them to be:
Here is a working example of my current code
#include <iostream>
#include <fstream>
#include <vector>
#include <DirectXTex.h>
void throw_error(std::string err, HRESULT hr)
{
LPWSTR errorText = nullptr;
DWORD messageLength = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, hr & 0x0000FFFF, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&errorText, 0, nullptr);
if (messageLength > 0)
{
std::wstring wErrorText(errorText);
std::string errorString(wErrorText.begin(), wErrorText.end());
LocalFree(errorText);
throw std::invalid_argument(err + ": " + errorString);
}
}
std::vector<byte> ConvertDDS(const byte* src, const size_t src_len, const DXGI_FORMAT format)
{
DirectX::TEX_FILTER_FLAGS dwFilter = DirectX::TEX_FILTER_DEFAULT;
DirectX::TEX_FILTER_FLAGS dwSRGB = DirectX::TEX_FILTER_DEFAULT;
DirectX::TEX_FILTER_FLAGS dwConvert = DirectX::TEX_FILTER_DEFAULT;
DirectX::TEX_FILTER_FLAGS dwFilterOpts = DirectX::TEX_FILTER_DEFAULT;
DirectX::TexMetadata meta;
// Initialize COM (needed for WIC)
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
throw_error("Failed to initialize COM", hr);
std::unique_ptr<DirectX::ScratchImage> image(new (std::nothrow) DirectX::ScratchImage);
// load texture from memory, supported types are DDS, PNG and TGA
hr = DirectX::LoadFromDDSMemory(src, src_len, DirectX::DDS_FLAGS_ALLOW_LARGE_FILES, &meta, *image);
if (FAILED(hr))
throw_error("Can't load texture from memory", hr);
// If format doesn't match convert it
if (meta.format != format)
{
// --- Planar ------------------------------------------------------------------
if (DirectX::IsPlanar(meta.format))
{
auto img = image->GetImage(0, 0, 0);
assert(img);
const size_t nimg = image->GetImageCount();
std::unique_ptr<DirectX::ScratchImage> timage(new (std::nothrow) DirectX::ScratchImage);
hr = ConvertToSinglePlane(img, nimg, meta, *timage);
if (FAILED(hr))
throw_error(" FAILED [converttosingleplane]", hr);
auto& tinfo = timage->GetMetadata();
meta.format = tinfo.format;
assert(meta.width == tinfo.width);
assert(meta.height == tinfo.height);
assert(meta.depth == tinfo.depth);
assert(meta.arraySize == tinfo.arraySize);
assert(meta.mipLevels == tinfo.mipLevels);
assert(meta.miscFlags == tinfo.miscFlags);
assert(meta.dimension == tinfo.dimension);
image.swap(timage);
}
// --- Decompress --------------------------------------------------------------
if (DirectX::IsCompressed(meta.format))
{
std::unique_ptr<DirectX::ScratchImage> nimage(new (std::nothrow) DirectX::ScratchImage);
hr = DirectX::Decompress(
image->GetImages(),
image->GetImageCount(),
meta,
DXGI_FORMAT_UNKNOWN,
*nimage
);
if (FAILED(hr))
throw_error("Can't decompress dds texture", hr); // decompress new texture failed
meta.format = nimage->GetMetadata().format;
image.swap(nimage);
}
if (meta.format != format)
{
// If the original file is compressed we compress the src
// Else we just convert it
if (DirectX::IsCompressed(format))
{
std::unique_ptr<DirectX::ScratchImage> nimage(new (std::nothrow) DirectX::ScratchImage);
hr = DirectX::Compress(
image->GetImages(),
image->GetImageCount(),
meta,
format,
DirectX::TEX_COMPRESS_FLAGS::TEX_COMPRESS_DEFAULT,
DirectX::TEX_THRESHOLD_DEFAULT,
*nimage
);
if (FAILED(hr))
throw_error("Can't compress dds texture", hr); // convert new texture failed
image.swap(nimage);
}
else
{
std::unique_ptr<DirectX::ScratchImage> nimage(new (std::nothrow) DirectX::ScratchImage);
hr = DirectX::Convert(
image->GetImages(),
image->GetImageCount(),
meta,
format,
dwFilter | dwFilterOpts | dwSRGB | dwConvert,
DirectX::TEX_THRESHOLD_DEFAULT,
*nimage
);
if (FAILED(hr))
throw_error("Can't convert dds texture", hr); // convert new texture failed
image.swap(nimage);
}
meta.format = image->GetMetadata().format;
}
}
std::unique_ptr<DirectX::Blob> blob(new (std::nothrow) DirectX::Blob);
DirectX::SaveToDDSMemory(
image->GetImages(),
image->GetImageCount(),
image->GetMetadata(),
DirectX::DDS_FLAGS_NONE,
*blob.get()
);
std::vector<byte> result(blob->GetBufferSize());
std::memcpy(result.data(), blob->GetBufferPointer(), blob->GetBufferSize());
return result;
}
this code does seem to be working, but output as I said dont have the transparent background and overall looks wrong... what should I do? I'm not very familer with DirectXTex API so I will be happy if someone can help me.
I tried to convert a DDS texture with format DXGI_FORMAT_B8G8R8A8_UNORM
to DXGI_FORMAT_R8_UNORM
but failed.
input had transparency but output only had a white background
the content of the texture also were wrong after conversation.
Upvotes: 2
Views: 641
Reputation: 41022
What behavior do you want for going from DXGI_FORMAT_B8G8R8A8_UNORM
to DXGI_FORMAT_R8_UNORM
?
The default behavior for an RGB to R conversion is to use luminance to convert the RGB to a greyscale and store that in the RED channel. There's no place to put a transparency channel in the target.
Are you expecting the alpha channel to 'mask' the image here? If so, what's the 'background color'?
If you want to keep the alpha channel you'd need to use DXGI_FORMAT_R8A8_UNORM
.
DirectXTex does support other ways of mapping the channels. You can do channel swizzles, or you can use flags like
TEX_FILTER_RGB_COPY_RED
,TEX_FILTER_RGB_COPY_GREEN
, orTEX_FILTER_RGB_COPY_BLUE
. See Filter flags.
For examples of doing arbitrary channel swizzles, see texconv.
Upvotes: 4