Add support for reading non-standard BMP files with DXTn data
This commit is contained in:
parent
2b2f90259a
commit
06816df22c
@ -13,8 +13,6 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#define NODRAWTEXT
|
#define NODRAWTEXT
|
||||||
#define NOGDI
|
|
||||||
#define NOBITMAP
|
|
||||||
#define NOMCX
|
#define NOMCX
|
||||||
#define NOSERVICE
|
#define NOSERVICE
|
||||||
#define NOHELP
|
#define NOHELP
|
||||||
@ -428,6 +426,10 @@ namespace
|
|||||||
{
|
{
|
||||||
inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? 0 : h; }
|
inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? 0 : h; }
|
||||||
|
|
||||||
|
struct handle_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) CloseHandle(h); } };
|
||||||
|
|
||||||
|
typedef std::unique_ptr<void, handle_closer> ScopedHandle;
|
||||||
|
|
||||||
struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||||
|
|
||||||
typedef public std::unique_ptr<void, find_closer> ScopedFindHandle;
|
typedef public std::unique_ptr<void, find_closer> ScopedFindHandle;
|
||||||
@ -952,6 +954,128 @@ namespace
|
|||||||
float normalizedLinear = pow(std::max(pow(abs(ST2084), 1.0f / 78.84375f) - 0.8359375f, 0.0f) / (18.8515625f - 18.6875f * pow(abs(ST2084), 1.0f / 78.84375f)), 1.0f / 0.1593017578f);
|
float normalizedLinear = pow(std::max(pow(abs(ST2084), 1.0f / 78.84375f) - 0.8359375f, 0.0f) / (18.8515625f - 18.6875f * pow(abs(ST2084), 1.0f / 78.84375f)), 1.0f / 0.1593017578f);
|
||||||
return normalizedLinear;
|
return normalizedLinear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT ReadData(_In_z_ const wchar_t* szFile, std::unique_ptr<uint8_t []>& blob, size_t& bmpSize)
|
||||||
|
{
|
||||||
|
blob.reset();
|
||||||
|
|
||||||
|
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||||
|
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
|
||||||
|
if (!hFile)
|
||||||
|
{
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the file size
|
||||||
|
FILE_STANDARD_INFO fileInfo;
|
||||||
|
if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
|
||||||
|
{
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough)
|
||||||
|
if (fileInfo.EndOfFile.HighPart > 0)
|
||||||
|
{
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero-sized files assumed to be invalid
|
||||||
|
if (fileInfo.EndOfFile.LowPart < 1)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file
|
||||||
|
blob.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]);
|
||||||
|
if (!blob)
|
||||||
|
{
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
if (!ReadFile(hFile.get(), blob.get(), fileInfo.EndOfFile.LowPart, &bytesRead, nullptr))
|
||||||
|
{
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesRead != fileInfo.EndOfFile.LowPart)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bmpSize = fileInfo.EndOfFile.LowPart;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT LoadFromExtendedBMPMemory(_In_reads_bytes_(size) const void* pSource, _In_ size_t size, _Out_opt_ TexMetadata* metadata, _Out_ ScratchImage& image)
|
||||||
|
{
|
||||||
|
// This loads from non-standard BMP files that are not supported by WIC
|
||||||
|
image.Release();
|
||||||
|
|
||||||
|
if (size < (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
// Valid BMP files always start with 'BM' at the top
|
||||||
|
auto filehdr = reinterpret_cast<const BITMAPFILEHEADER*>(pSource);
|
||||||
|
if (filehdr->bfType != 0x4D42)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
if (size < filehdr->bfOffBits)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
auto header = reinterpret_cast<const BITMAPINFOHEADER*>(reinterpret_cast<const uint8_t*>(pSource) + sizeof(BITMAPFILEHEADER));
|
||||||
|
if (header->biSize != sizeof(BITMAPINFOHEADER))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
if (header->biWidth < 1 || header->biHeight < 1 || header->biPlanes != 1 || header->biBitCount != 16)
|
||||||
|
{
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
switch (header->biCompression)
|
||||||
|
{
|
||||||
|
case 0x31545844: // FourCC "DXT1"
|
||||||
|
format = DXGI_FORMAT_BC1_UNORM;
|
||||||
|
break;
|
||||||
|
case 0x33545844: // FourCC "DXT3"
|
||||||
|
format = DXGI_FORMAT_BC2_UNORM;
|
||||||
|
break;
|
||||||
|
case 0x35545844: // FourCC "DXT5"
|
||||||
|
format = DXGI_FORMAT_BC3_UNORM;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hr = image.Initialize2D(format, header->biWidth, header->biHeight, 1, 1);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (header->biSizeImage != image.GetPixelsSize())
|
||||||
|
return E_UNEXPECTED;
|
||||||
|
|
||||||
|
size_t remaining = size - filehdr->bfOffBits;
|
||||||
|
if (!remaining)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
if (remaining < image.GetPixelsSize())
|
||||||
|
return E_UNEXPECTED;
|
||||||
|
|
||||||
|
auto pixels = reinterpret_cast<const uint8_t*>(pSource) + filehdr->bfOffBits;
|
||||||
|
|
||||||
|
memcpy(image.GetPixels(), pixels, image.GetPixelsSize());
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
*metadata = image.GetMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1578,6 +1702,28 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
|||||||
image->OverrideFormat(info.format);
|
image->OverrideFormat(info.format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (_wcsicmp(ext, L".bmp") == 0)
|
||||||
|
{
|
||||||
|
std::unique_ptr<uint8_t []> bmpData;
|
||||||
|
size_t bmpSize;
|
||||||
|
hr = ReadData(pConv->szSrc, bmpData, bmpSize);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = LoadFromWICMemory(bmpData.get(), bmpSize, dwFilter, &info, *image);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(LoadFromExtendedBMPMemory(bmpData.get(), bmpSize, &info, *image)))
|
||||||
|
{
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
wprintf(L" FAILED (%x)\n", hr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (_wcsicmp(ext, L".tga") == 0)
|
else if (_wcsicmp(ext, L".tga") == 0)
|
||||||
{
|
{
|
||||||
hr = LoadFromTGAFile(pConv->szSrc, &info, *image);
|
hr = LoadFromTGAFile(pConv->szSrc, &info, *image);
|
||||||
|
Loading…
Reference in New Issue
Block a user