Add support for loading DDS files that contain raw/uncompressed pixel data. Resolves issue #1097.

This commit is contained in:
Alex Szpakowski
2019-09-17 22:40:11 -03:00
parent a6f8e7dac6
commit d6e37ec4aa
5 changed files with 578 additions and 200 deletions
+171 -44
View File
@@ -20,6 +20,10 @@
#include "ddsHandler.h"
#include "common/Exception.h"
#include "image/ImageData.h"
// dds parser
#include "ddsparse/ddsparse.h"
namespace love
{
@@ -28,6 +32,172 @@ namespace image
namespace magpie
{
static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB)
{
using namespace dds::dxinfo;
sRGB = false;
switch (dxformat)
{
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
case DXGI_FORMAT_R32G32B32A32_FLOAT:
return PIXELFORMAT_RGBA32F;
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
return PIXELFORMAT_RGBA16F;
case DXGI_FORMAT_R16G16B16A16_UNORM:
return PIXELFORMAT_RGBA16;
case DXGI_FORMAT_R32G32_TYPELESS:
case DXGI_FORMAT_R32G32_FLOAT:
return PIXELFORMAT_RG32F;
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
case DXGI_FORMAT_R10G10B10A2_UNORM:
return PIXELFORMAT_RGB10A2;
case DXGI_FORMAT_R11G11B10_FLOAT:
return PIXELFORMAT_RG11B10F;
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
sRGB = (dxformat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
return PIXELFORMAT_RGBA8;
case DXGI_FORMAT_R16G16_TYPELESS:
case DXGI_FORMAT_R16G16_FLOAT:
return PIXELFORMAT_RG16F;
case DXGI_FORMAT_R16G16_UNORM:
return PIXELFORMAT_RG16;
case DXGI_FORMAT_R32_TYPELESS:
case DXGI_FORMAT_R32_FLOAT:
return PIXELFORMAT_R32F;
case DXGI_FORMAT_R8G8_TYPELESS:
case DXGI_FORMAT_R8G8_UNORM:
return PIXELFORMAT_RG8;
case DXGI_FORMAT_R16_TYPELESS:
case DXGI_FORMAT_R16_FLOAT:
return PIXELFORMAT_R16F;
case DXGI_FORMAT_R16_UNORM:
return PIXELFORMAT_R16;
case DXGI_FORMAT_R8_TYPELESS:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_A8_UNORM:
return PIXELFORMAT_R8;
case DXGI_FORMAT_BC1_TYPELESS:
case DXGI_FORMAT_BC1_UNORM:
case DXGI_FORMAT_BC1_UNORM_SRGB:
sRGB = (dxformat == DXGI_FORMAT_BC1_UNORM_SRGB);
return PIXELFORMAT_DXT1;
case DXGI_FORMAT_BC2_TYPELESS:
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC2_UNORM_SRGB:
sRGB = (dxformat == DXGI_FORMAT_BC2_UNORM_SRGB);
return PIXELFORMAT_DXT3;
case DXGI_FORMAT_BC3_TYPELESS:
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC3_UNORM_SRGB:
sRGB = (dxformat == DXGI_FORMAT_BC3_UNORM_SRGB);
return PIXELFORMAT_DXT5;
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
return PIXELFORMAT_BC4;
case DXGI_FORMAT_BC4_SNORM:
return PIXELFORMAT_BC4s;
case DXGI_FORMAT_BC5_TYPELESS:
case DXGI_FORMAT_BC5_UNORM:
return PIXELFORMAT_BC5;
case DXGI_FORMAT_BC5_SNORM:
return PIXELFORMAT_BC5s;
case DXGI_FORMAT_B5G6R5_UNORM:
return PIXELFORMAT_RGB565;
case DXGI_FORMAT_B5G5R5A1_UNORM:
return PIXELFORMAT_RGB5A1;
case DXGI_FORMAT_BC6H_TYPELESS:
case DXGI_FORMAT_BC6H_UF16:
return PIXELFORMAT_BC6H;
case DXGI_FORMAT_BC6H_SF16:
return PIXELFORMAT_BC6Hs;
case DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT_BC7_UNORM_SRGB:
sRGB = (dxformat == DXGI_FORMAT_BC7_UNORM_SRGB);
return PIXELFORMAT_BC7;
default:
return PIXELFORMAT_UNKNOWN;
}
}
bool DDSHandler::canDecode(Data *data)
{
using namespace dds::dxinfo;
DXGIFormat dxformat = dds::getDDSPixelFormat(data->getData(), data->getSize());
bool isSRGB = false;
PixelFormat format = convertFormat(dxformat, isSRGB);
return ImageData::validPixelFormat(format);
}
FormatHandler::DecodedImage DDSHandler::decode(Data *data)
{
DecodedImage img;
dds::Parser parser(data->getData(), data->getSize());
bool isSRGB = false;
img.format = convertFormat(parser.getFormat(), isSRGB);
if (!ImageData::validPixelFormat(img.format))
throw love::Exception("Could not parse DDS pixel data: Unsupported format.");
if (parser.getMipmapCount() == 0)
throw love::Exception("Could not parse DDS pixel data: No readable texture data.");
// We only support the top mip level through this codepath.
const dds::Image *ddsimg = parser.getImageData(0);
try
{
img.data = new uint8[ddsimg->dataSize];
}
catch (std::exception &)
{
throw love::Exception("Out of memory.");
}
memcpy(img.data, ddsimg->data, ddsimg->dataSize);
img.size = ddsimg->dataSize;
img.width = ddsimg->width;
img.height = ddsimg->height;
return img;
}
bool DDSHandler::canParseCompressed(Data *data)
{
return dds::isCompressedDDS(data->getData(), data->getSize());
@@ -35,7 +205,7 @@ bool DDSHandler::canParseCompressed(Data *data)
StrongRef<CompressedMemory> DDSHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format, bool &sRGB)
{
if (!dds::isDDS(filedata->getData(), filedata->getSize()))
if (!dds::isCompressedDDS(filedata->getData(), filedata->getSize()))
throw love::Exception("Could not decode compressed data (not a DDS file?)");
PixelFormat texformat = PIXELFORMAT_UNKNOWN;
@@ -88,49 +258,6 @@ StrongRef<CompressedMemory> DDSHandler::parseCompressed(Data *filedata, std::vec
return memory;
}
PixelFormat DDSHandler::convertFormat(dds::Format ddsformat, bool &sRGB)
{
sRGB = false;
switch (ddsformat)
{
case dds::FORMAT_DXT1:
return PIXELFORMAT_DXT1;
case dds::FORMAT_DXT1srgb:
sRGB = true;
return PIXELFORMAT_DXT1;
case dds::FORMAT_DXT3:
return PIXELFORMAT_DXT3;
case dds::FORMAT_DXT3srgb:
sRGB = true;
return PIXELFORMAT_DXT3;
case dds::FORMAT_DXT5:
return PIXELFORMAT_DXT5;
case dds::FORMAT_DXT5srgb:
sRGB = true;
return PIXELFORMAT_DXT5;
case dds::FORMAT_BC4:
return PIXELFORMAT_BC4;
case dds::FORMAT_BC4s:
return PIXELFORMAT_BC4s;
case dds::FORMAT_BC5:
return PIXELFORMAT_BC5;
case dds::FORMAT_BC5s:
return PIXELFORMAT_BC5s;
case dds::FORMAT_BC6H:
return PIXELFORMAT_BC6H;
case dds::FORMAT_BC6Hs:
return PIXELFORMAT_BC6Hs;
case dds::FORMAT_BC7:
return PIXELFORMAT_BC7;
case dds::FORMAT_BC7srgb:
sRGB = true;
return PIXELFORMAT_BC7;
default:
return PIXELFORMAT_UNKNOWN;
}
}
} // magpie
} // image
} // love
+2 -8
View File
@@ -23,9 +23,6 @@
// LOVE
#include "image/FormatHandler.h"
// dds parser
#include "ddsparse/ddsparse.h"
// STL
#include <string>
@@ -46,16 +43,13 @@ public:
virtual ~DDSHandler() {}
// Implements FormatHandler.
bool canDecode(Data *data) override;
DecodedImage decode(Data *data) override;
bool canParseCompressed(Data *data) override;
StrongRef<CompressedMemory> parseCompressed(Data *filedata,
std::vector<StrongRef<CompressedSlice>> &images,
PixelFormat &format, bool &sRGB) override;
private:
static PixelFormat convertFormat(dds::Format ddsformat, bool &sRGB);
}; // DDSHandler
} // magpie