mirror of
https://github.com/microsoft/DirectXTex
synced 2024-11-09 22:40:06 +00:00
Portable PixMap reader/writers for texconv (#180)
This commit is contained in:
parent
09fc5fe957
commit
0539287324
@ -101,7 +101,10 @@ add_executable(texassemble Texassemble/texassemble.cpp)
|
||||
target_link_libraries(texassemble ${PROJECT_NAME})
|
||||
source_group(texassemble REGULAR_EXPRESSION Texassemble/*.*)
|
||||
|
||||
add_executable(texconv Texconv/texconv.cpp)
|
||||
add_executable(texconv
|
||||
Texconv/texconv.cpp
|
||||
Texconv/ExtendedBMP.cpp
|
||||
Texconv/PortablePixMap.cpp)
|
||||
target_link_libraries(texconv ${PROJECT_NAME})
|
||||
source_group(texconv REGULAR_EXPRESSION Texconv/*.*)
|
||||
|
||||
|
@ -296,9 +296,9 @@ const SValue g_pExtFileTypes[] =
|
||||
|
||||
namespace
|
||||
{
|
||||
inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
struct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
|
||||
using ScopedFindHandle = std::unique_ptr<void, find_closer>;
|
||||
|
||||
@ -543,6 +543,7 @@ namespace
|
||||
PrintList(13, g_pFilters);
|
||||
}
|
||||
|
||||
|
||||
HRESULT SaveImageFile(const Image& img, DWORD fileType, const wchar_t* szOutputFile)
|
||||
{
|
||||
switch (fileType)
|
||||
@ -566,6 +567,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
DM_UNDEFINED = 0,
|
||||
@ -574,6 +576,7 @@ namespace
|
||||
DM_PREVIOUS = 3
|
||||
};
|
||||
|
||||
|
||||
void FillRectangle(const Image& img, const RECT& destRect, uint32_t color)
|
||||
{
|
||||
RECT clipped =
|
||||
@ -598,6 +601,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BlendRectangle(const Image& composed, const Image& raw, const RECT& destRect)
|
||||
{
|
||||
using namespace DirectX::PackedVector;
|
||||
@ -636,6 +640,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT LoadAnimatedGif(const wchar_t* szFile, std::vector<std::unique_ptr<ScratchImage>>& loadedImages, bool usebgcolor)
|
||||
{
|
||||
// https://code.msdn.microsoft.com/windowsapps/Windows-Imaging-Component-65abbc6a/
|
||||
|
193
Texconv/ExtendedBMP.cpp
Normal file
193
Texconv/ExtendedBMP.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: ExtendedBMP.cpp
|
||||
//
|
||||
// Utilities for reading BMP files including the DXTn unofficial "FS70"
|
||||
// extension created for Microsoft flight simulators.
|
||||
//
|
||||
// http://www.mwgfx.co.uk/programs/dxtbmp.htm
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248926
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#define NODRAWTEXT
|
||||
#define NOMCX
|
||||
#define NOSERVICE
|
||||
#define NOHELP
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "DirectXTex.h"
|
||||
|
||||
using namespace DirectX;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };
|
||||
|
||||
using ScopedHandle = std::unique_ptr<void, handle_closer>;
|
||||
|
||||
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
HRESULT ReadData(_In_z_ const wchar_t* szFile, std::unique_ptr<uint8_t[]>& blob, size_t& blobSize)
|
||||
{
|
||||
blob.reset();
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));
|
||||
#else
|
||||
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
blobSize = 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, size_t(header->biWidth), size_t(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;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT __cdecl LoadFromBMPEx(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_In_ WIC_FLAGS flags,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image) noexcept
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> bmpData;
|
||||
size_t bmpSize;
|
||||
HRESULT hr = ReadData(szFile, bmpData, bmpSize);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = LoadFromWICMemory(bmpData.get(), bmpSize, flags, metadata, image);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = LoadFromExtendedBMPMemory(bmpData.get(), bmpSize, metadata, image);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
return S_OK;
|
||||
}
|
594
Texconv/PortablePixMap.cpp
Normal file
594
Texconv/PortablePixMap.cpp
Normal file
@ -0,0 +1,594 @@
|
||||
//--------------------------------------------------------------------------------------
|
||||
// File: PortablePixMap.cpp
|
||||
//
|
||||
// Utilities for reading & writing Portable PixMap files (PPM/PFM)
|
||||
//
|
||||
// http://paulbourke.net/dataformats/ppm/
|
||||
// http://paulbourke.net/dataformats/pbmhdr/
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkId=248926
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#define NODRAWTEXT
|
||||
#define NOMCX
|
||||
#define NOSERVICE
|
||||
#define NOHELP
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "DirectXTex.h"
|
||||
|
||||
using namespace DirectX;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } };
|
||||
|
||||
using ScopedHandle = std::unique_ptr<void, handle_closer>;
|
||||
|
||||
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
class auto_delete_file
|
||||
{
|
||||
public:
|
||||
auto_delete_file(HANDLE hFile) noexcept : m_handle(hFile) {}
|
||||
|
||||
auto_delete_file(const auto_delete_file&) = delete;
|
||||
auto_delete_file& operator=(const auto_delete_file&) = delete;
|
||||
|
||||
~auto_delete_file()
|
||||
{
|
||||
if (m_handle)
|
||||
{
|
||||
FILE_DISPOSITION_INFO info = {};
|
||||
info.DeleteFile = TRUE;
|
||||
(void)SetFileInformationByHandle(m_handle, FileDispositionInfo, &info, sizeof(info));
|
||||
}
|
||||
}
|
||||
|
||||
void clear() noexcept { m_handle = nullptr; }
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
};
|
||||
|
||||
inline size_t FindEOL(_In_z_ const char* pString, size_t max)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
||||
//find endl
|
||||
while (pos < max)
|
||||
{
|
||||
if (pString[pos] == '\n')
|
||||
return pos;
|
||||
pos++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRESULT ReadData(_In_z_ const wchar_t* szFile, std::unique_ptr<uint8_t[]>& blob, size_t& blobSize)
|
||||
{
|
||||
blob.reset();
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr)));
|
||||
#else
|
||||
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN, nullptr)));
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
blobSize = fileInfo.EndOfFile.LowPart;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
// PPM
|
||||
//============================================================================
|
||||
|
||||
HRESULT __cdecl LoadFromPortablePixMap(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image) noexcept
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> ppmData;
|
||||
size_t ppmSize;
|
||||
HRESULT hr = ReadData(szFile, ppmData, ppmSize);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (ppmSize < 3)
|
||||
return E_FAIL;
|
||||
|
||||
if (ppmData[0] != 'P' || (ppmData[1] != '3' && ppmData[1] != '6'))
|
||||
return E_FAIL;
|
||||
|
||||
bool ascii = ppmData[1] == '3';
|
||||
|
||||
enum
|
||||
{
|
||||
PPM_WIDTH, PPM_HEIGHT, PPM_MAX, PPM_DATA_R, PPM_DATA_G, PPM_DATA_B
|
||||
};
|
||||
|
||||
int mode = PPM_WIDTH;
|
||||
|
||||
auto pData = ppmData.get() + 2;
|
||||
ppmSize -= 2;
|
||||
|
||||
size_t width = 0;
|
||||
uint32_t max = 255;
|
||||
uint32_t *pixels = nullptr;
|
||||
uint32_t *pixelEnd = nullptr;
|
||||
|
||||
while (ppmSize > 0)
|
||||
{
|
||||
if (!ascii && mode == PPM_DATA_R)
|
||||
{
|
||||
// Binary data
|
||||
if (max > 255 || !pixels || !pixelEnd)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
if (ppmSize > 1 && '\r' == *pData)
|
||||
{
|
||||
pData++;
|
||||
ppmSize--;
|
||||
}
|
||||
|
||||
if (*pData != '\n')
|
||||
return E_FAIL;
|
||||
|
||||
pData++;
|
||||
ppmSize--;
|
||||
|
||||
while (ppmSize > 0 && (pixels < pixelEnd))
|
||||
{
|
||||
*pixels++ = (255 * pData[0] / max)
|
||||
| ((255 * pData[1] / max) << 8)
|
||||
| ((255 * pData[2] / max) << 16)
|
||||
| 0xff000000;
|
||||
|
||||
pData += 3;
|
||||
ppmSize -= 3;
|
||||
}
|
||||
|
||||
return (pixels != pixelEnd) ? E_FAIL : S_OK;
|
||||
}
|
||||
|
||||
if (isspace(*pData))
|
||||
{
|
||||
// Whitespace
|
||||
pData++;
|
||||
ppmSize--;
|
||||
}
|
||||
else if (*pData == '#')
|
||||
{
|
||||
// Comment
|
||||
while (ppmSize > 0 && *pData != '\n')
|
||||
{
|
||||
pData++;
|
||||
ppmSize--;
|
||||
}
|
||||
|
||||
if (ppmSize > 0)
|
||||
{
|
||||
pData++;
|
||||
ppmSize--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASCII number
|
||||
uint32_t u = 0;
|
||||
|
||||
while (ppmSize > 0 && !isspace(*pData))
|
||||
{
|
||||
if (!isdigit(*pData))
|
||||
return E_FAIL;
|
||||
|
||||
u = u * 10 + (*pData - '0');
|
||||
|
||||
pData++;
|
||||
ppmSize--;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case PPM_WIDTH:
|
||||
if (u == 0)
|
||||
return E_FAIL;
|
||||
|
||||
width = u;
|
||||
break;
|
||||
|
||||
case PPM_HEIGHT:
|
||||
{
|
||||
if (u == 0)
|
||||
return E_FAIL;
|
||||
|
||||
if (metadata)
|
||||
{
|
||||
*metadata = {};
|
||||
metadata->width = width;
|
||||
metadata->height = u;
|
||||
metadata->depth = metadata->arraySize = metadata->mipLevels = 1;
|
||||
metadata->format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
metadata->dimension = TEX_DIMENSION_TEXTURE2D;
|
||||
}
|
||||
|
||||
hr = image.Initialize2D(DXGI_FORMAT_R8G8B8A8_UNORM, width, u, 1, 1);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
auto img = image.GetImage(0, 0, 0);
|
||||
|
||||
pixels = reinterpret_cast<uint32_t*>(img->pixels);
|
||||
pixelEnd = pixels + width * u;
|
||||
}
|
||||
break;
|
||||
|
||||
case PPM_MAX:
|
||||
if (u == 0)
|
||||
return E_FAIL;
|
||||
|
||||
max = u;
|
||||
break;
|
||||
|
||||
case PPM_DATA_R:
|
||||
if (pixels >= pixelEnd)
|
||||
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
|
||||
|
||||
*pixels = ((u * 255) / max) | 0xff000000;
|
||||
break;
|
||||
|
||||
case PPM_DATA_G:
|
||||
if (pixels >= pixelEnd)
|
||||
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
|
||||
|
||||
*pixels |= ((u * 255) / max) << 8;
|
||||
break;
|
||||
|
||||
case PPM_DATA_B:
|
||||
if (pixels >= pixelEnd)
|
||||
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
|
||||
|
||||
*pixels |= ((u * 255) / max) << 16;
|
||||
|
||||
if (++pixels == pixelEnd)
|
||||
return S_OK;
|
||||
|
||||
mode = PPM_DATA_R - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
mode++;
|
||||
}
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT __cdecl SaveToPortablePixMap(
|
||||
_In_ const Image& image,
|
||||
_In_z_ const wchar_t* szFile) noexcept
|
||||
{
|
||||
switch (image.format)
|
||||
{
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
||||
break;
|
||||
|
||||
default:
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
char header[256] = {};
|
||||
int len = sprintf_s(header, "P6\n%zu %zu\n255\n", image.width, image.height);
|
||||
if (len == -1)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
ScratchImage tmpImage;
|
||||
if (image.format == DXGI_FORMAT_R8G8B8A8_UNORM || image.format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)
|
||||
{
|
||||
tmpImage.InitializeFromImage(image);
|
||||
}
|
||||
else
|
||||
{
|
||||
HRESULT hr = Convert(image,
|
||||
IsSRGB(image.format) ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
TEX_FILTER_DEFAULT, 0.f, tmpImage);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
|
||||
ScratchImage data;
|
||||
data.Initialize2D(DXGI_FORMAT_R8G8B8A8_UNORM, image.width, image.height, 1, 1, CP_FLAGS_24BPP);
|
||||
|
||||
const auto& img = tmpImage.GetImage(0, 0, 0);
|
||||
auto dptr = data.GetPixels();
|
||||
for (size_t y = 0; y < image.height; ++y)
|
||||
{
|
||||
auto sptr = img->pixels + y * image.rowPitch;
|
||||
|
||||
for (size_t x = 0; x < image.width; ++x)
|
||||
{
|
||||
*(dptr++) = sptr[0];
|
||||
*(dptr++) = sptr[1];
|
||||
*(dptr++) = sptr[2];
|
||||
sptr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr)));
|
||||
#else
|
||||
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr)));
|
||||
#endif
|
||||
if (!hFile)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
auto_delete_file delonfail(hFile.get());
|
||||
|
||||
DWORD bytesWritten;
|
||||
if (!WriteFile(hFile.get(), header, static_cast<DWORD>(len), &bytesWritten, nullptr))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
if (!WriteFile(hFile.get(), data.GetPixels(), static_cast<DWORD>(data.GetPixelsSize()), &bytesWritten, nullptr))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
delonfail.clear();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
// PFM
|
||||
//============================================================================
|
||||
|
||||
HRESULT __cdecl LoadFromPortablePixMapHDR(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image) noexcept
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> pfmData;
|
||||
size_t pfmSize;
|
||||
HRESULT hr = ReadData(szFile, pfmData, pfmSize);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (pfmSize < 3)
|
||||
return E_FAIL;
|
||||
|
||||
if (pfmData[0] != 'P' || (pfmData[1] != 'f' && pfmData[1] != 'F') || pfmData[2] != '\n')
|
||||
return E_FAIL;
|
||||
|
||||
bool monochrome = pfmData[1] == 'f';
|
||||
|
||||
auto pData = reinterpret_cast<const char*>(pfmData.get()) + 3;
|
||||
pfmSize -= 3;
|
||||
|
||||
size_t len = FindEOL(pData, 256);
|
||||
if (!len)
|
||||
return E_FAIL;
|
||||
|
||||
char dataStr[256] = {};
|
||||
char junkStr[256] = {};
|
||||
strncpy_s(dataStr, pData, len + 1);
|
||||
|
||||
size_t width = 0, height = 0;
|
||||
if (sscanf_s(dataStr, "%zu %zu%s", &width, &height, junkStr, 256) != 2)
|
||||
return E_FAIL;
|
||||
|
||||
pData += len + 1;
|
||||
pfmSize -= len + 1;
|
||||
if (!pfmSize)
|
||||
return E_FAIL;
|
||||
|
||||
len = FindEOL(pData, 256);
|
||||
if (!len)
|
||||
return E_FAIL;
|
||||
|
||||
strncpy_s(dataStr, pData, len + 1);
|
||||
|
||||
float aspectRatio = 0.f;
|
||||
if (sscanf_s(dataStr, "%f%s", &aspectRatio, junkStr, 256) != 1)
|
||||
return E_FAIL;
|
||||
|
||||
bool bigendian = (aspectRatio >= 0);
|
||||
|
||||
pData += len + 1;
|
||||
pfmSize -= len + 1;
|
||||
if (!pfmSize)
|
||||
return E_FAIL;
|
||||
|
||||
size_t scanline = width * sizeof(float) * (monochrome ? 1 : 3);
|
||||
if (pfmSize < scanline * height)
|
||||
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
|
||||
|
||||
if (metadata)
|
||||
{
|
||||
*metadata = {};
|
||||
metadata->width = width;
|
||||
metadata->height = height;
|
||||
metadata->depth = metadata->arraySize = metadata->mipLevels = 1;
|
||||
metadata->format = monochrome ? DXGI_FORMAT_R32_FLOAT : DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
metadata->dimension = TEX_DIMENSION_TEXTURE2D;
|
||||
}
|
||||
|
||||
hr = image.Initialize2D(monochrome ? DXGI_FORMAT_R32_FLOAT : DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
width, height, 1, 1);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
auto img = image.GetImage(0, 0, 0);
|
||||
|
||||
auto sptr = reinterpret_cast<const uint32_t*>(pData);
|
||||
|
||||
if (monochrome)
|
||||
{
|
||||
for (size_t y = 0; y < height; ++y)
|
||||
{
|
||||
auto dptr = reinterpret_cast<uint32_t*>(img->pixels + (height - y - 1) * img->rowPitch);
|
||||
|
||||
for (size_t x = 0; x < width; ++x)
|
||||
{
|
||||
*dptr++ = (bigendian) ? _byteswap_ulong(*sptr++) : *sptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t y = 0; y < height; ++y)
|
||||
{
|
||||
auto dptr = reinterpret_cast<uint32_t*>(img->pixels + (height - y - 1) * img->rowPitch);
|
||||
|
||||
for (size_t x = 0; x < width; ++x)
|
||||
{
|
||||
if (bigendian)
|
||||
{
|
||||
dptr[0] = _byteswap_ulong(sptr[0]);
|
||||
dptr[1] = _byteswap_ulong(sptr[1]);
|
||||
dptr[2] = _byteswap_ulong(sptr[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
dptr[0] = sptr[0];
|
||||
dptr[1] = sptr[1];
|
||||
dptr[2] = sptr[2];
|
||||
}
|
||||
|
||||
dptr[3] = 0x3f800000; // 1.f
|
||||
sptr += 3;
|
||||
dptr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT __cdecl SaveToPortablePixMapHDR(
|
||||
_In_ const Image& image,
|
||||
_In_z_ const wchar_t* szFile) noexcept
|
||||
{
|
||||
switch (image.format)
|
||||
{
|
||||
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
||||
case DXGI_FORMAT_R32G32B32_FLOAT:
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
case DXGI_FORMAT_R32_FLOAT:
|
||||
break;
|
||||
|
||||
default:
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
char header[256] = {};
|
||||
int len = sprintf_s(header, "P%c\n%zu %zu\n-1.000000\n",
|
||||
(image.format == DXGI_FORMAT_R32_FLOAT) ? 'f' : 'F',
|
||||
image.width, image.height);
|
||||
|
||||
if (len == -1)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
ScratchImage tmpImage;
|
||||
if (image.format == DXGI_FORMAT_R32_FLOAT || image.format == DXGI_FORMAT_R32G32B32_FLOAT)
|
||||
{
|
||||
tmpImage.InitializeFromImage(image);
|
||||
}
|
||||
else
|
||||
{
|
||||
HRESULT hr = Convert(image, DXGI_FORMAT_R32G32B32_FLOAT, TEX_FILTER_DEFAULT, 0.f, tmpImage);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
|
||||
ScratchImage flipImage;
|
||||
HRESULT hr = FlipRotate(*tmpImage.GetImage(0, 0, 0), TEX_FR_FLIP_VERTICAL, flipImage);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
tmpImage.Release();
|
||||
|
||||
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
|
||||
ScopedHandle hFile(safe_handle(CreateFile2(szFile, GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr)));
|
||||
#else
|
||||
ScopedHandle hFile(safe_handle(CreateFileW(szFile, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr)));
|
||||
#endif
|
||||
if (!hFile)
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
auto_delete_file delonfail(hFile.get());
|
||||
|
||||
DWORD bytesWritten;
|
||||
if (!WriteFile(hFile.get(), header, static_cast<DWORD>(len), &bytesWritten, nullptr))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
if (!WriteFile(hFile.get(), flipImage.GetPixels(), static_cast<DWORD>(flipImage.GetPixelsSize()), &bytesWritten, nullptr))
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
|
||||
delonfail.clear();
|
||||
|
||||
return S_OK;
|
||||
}
|
@ -322,6 +322,8 @@
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ExtendedBMP.cpp" />
|
||||
<ClCompile Include="PortablePixMap.cpp" />
|
||||
<ClCompile Include="Texconv.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -8,6 +8,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Texconv.cpp" />
|
||||
<ClCompile Include="PortablePixMap.cpp" />
|
||||
<ClCompile Include="ExtendedBMP.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Texconv.rc">
|
||||
|
@ -328,6 +328,8 @@
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ExtendedBMP.cpp" />
|
||||
<ClCompile Include="PortablePixMap.cpp" />
|
||||
<ClCompile Include="Texconv.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -8,6 +8,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Texconv.cpp" />
|
||||
<ClCompile Include="PortablePixMap.cpp" />
|
||||
<ClCompile Include="ExtendedBMP.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Texconv.rc">
|
||||
|
@ -53,8 +53,10 @@ using namespace DirectX;
|
||||
using namespace DirectX::PackedVector;
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
enum OPTIONS
|
||||
namespace
|
||||
{
|
||||
enum OPTIONS
|
||||
{
|
||||
OPT_RECURSIVE = 1,
|
||||
OPT_FILELIST,
|
||||
OPT_WIDTH,
|
||||
@ -111,38 +113,34 @@ enum OPTIONS
|
||||
OPT_PAPER_WHITE_NITS,
|
||||
OPT_BCNONMULT4FIX,
|
||||
OPT_MAX
|
||||
};
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum
|
||||
{
|
||||
ROTATE_709_TO_HDR10 = 1,
|
||||
ROTATE_HDR10_TO_709,
|
||||
ROTATE_709_TO_2020,
|
||||
ROTATE_2020_TO_709,
|
||||
ROTATE_P3_TO_HDR10,
|
||||
ROTATE_P3_TO_2020,
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(OPT_MAX <= 64, "dwOptions is a DWORD64 bitfield");
|
||||
static_assert(OPT_MAX <= 64, "dwOptions is a DWORD64 bitfield");
|
||||
|
||||
struct SConversion
|
||||
{
|
||||
struct SConversion
|
||||
{
|
||||
wchar_t szSrc[MAX_PATH];
|
||||
wchar_t szDest[MAX_PATH];
|
||||
};
|
||||
};
|
||||
|
||||
struct SValue
|
||||
{
|
||||
struct SValue
|
||||
{
|
||||
LPCWSTR pName;
|
||||
DWORD dwValue;
|
||||
};
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const SValue g_pOptions[] =
|
||||
{
|
||||
const SValue g_pOptions[] =
|
||||
{
|
||||
{ L"r", OPT_RECURSIVE },
|
||||
{ L"flist", OPT_FILELIST },
|
||||
{ L"w", OPT_WIDTH },
|
||||
@ -199,12 +197,12 @@ const SValue g_pOptions[] =
|
||||
{ L"nits", OPT_PAPER_WHITE_NITS },
|
||||
{ L"fixbc4x4", OPT_BCNONMULT4FIX},
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
};
|
||||
|
||||
#define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }
|
||||
|
||||
const SValue g_pFormats[] =
|
||||
{
|
||||
const SValue g_pFormats[] =
|
||||
{
|
||||
// List does not include _TYPELESS or depth/stencil formats
|
||||
DEFFMT(R32G32B32A32_FLOAT),
|
||||
DEFFMT(R32G32B32A32_UINT),
|
||||
@ -288,10 +286,10 @@ const SValue g_pFormats[] =
|
||||
DEFFMT(B4G4R4A4_UNORM),
|
||||
|
||||
{ nullptr, DXGI_FORMAT_UNKNOWN }
|
||||
};
|
||||
};
|
||||
|
||||
const SValue g_pFormatAliases[] =
|
||||
{
|
||||
const SValue g_pFormatAliases[] =
|
||||
{
|
||||
{ L"DXT1", DXGI_FORMAT_BC1_UNORM },
|
||||
{ L"DXT2", DXGI_FORMAT_BC2_UNORM },
|
||||
{ L"DXT3", DXGI_FORMAT_BC2_UNORM },
|
||||
@ -308,10 +306,10 @@ const SValue g_pFormatAliases[] =
|
||||
{ L"BPTC_FLOAT", DXGI_FORMAT_BC6H_UF16 },
|
||||
|
||||
{ nullptr, DXGI_FORMAT_UNKNOWN }
|
||||
};
|
||||
};
|
||||
|
||||
const SValue g_pReadOnlyFormats[] =
|
||||
{
|
||||
const SValue g_pReadOnlyFormats[] =
|
||||
{
|
||||
DEFFMT(R32G32B32A32_TYPELESS),
|
||||
DEFFMT(R32G32B32_TYPELESS),
|
||||
DEFFMT(R16G16B16A16_TYPELESS),
|
||||
@ -357,10 +355,10 @@ const SValue g_pReadOnlyFormats[] =
|
||||
{ L"V408", DXGI_FORMAT(132) },
|
||||
|
||||
{ nullptr, DXGI_FORMAT_UNKNOWN }
|
||||
};
|
||||
};
|
||||
|
||||
const SValue g_pFilters[] =
|
||||
{
|
||||
const SValue g_pFilters[] =
|
||||
{
|
||||
{ L"POINT", TEX_FILTER_POINT },
|
||||
{ L"LINEAR", TEX_FILTER_LINEAR },
|
||||
{ L"CUBIC", TEX_FILTER_CUBIC },
|
||||
@ -380,10 +378,10 @@ const SValue g_pFilters[] =
|
||||
{ L"BOX_DITHER_DIFFUSION", TEX_FILTER_BOX | TEX_FILTER_DITHER_DIFFUSION },
|
||||
{ L"TRIANGLE_DITHER_DIFFUSION", TEX_FILTER_TRIANGLE | TEX_FILTER_DITHER_DIFFUSION },
|
||||
{ nullptr, TEX_FILTER_DEFAULT }
|
||||
};
|
||||
};
|
||||
|
||||
const SValue g_pRotateColor[] =
|
||||
{
|
||||
const SValue g_pRotateColor[] =
|
||||
{
|
||||
{ L"709to2020", ROTATE_709_TO_2020 },
|
||||
{ L"2020to709", ROTATE_2020_TO_709 },
|
||||
{ L"709toHDR10", ROTATE_709_TO_HDR10 },
|
||||
@ -391,20 +389,22 @@ const SValue g_pRotateColor[] =
|
||||
{ L"P3to2020", ROTATE_P3_TO_2020 },
|
||||
{ L"P3toHDR10", ROTATE_P3_TO_HDR10 },
|
||||
{ nullptr, 0 },
|
||||
};
|
||||
};
|
||||
|
||||
#define CODEC_DDS 0xFFFF0001
|
||||
#define CODEC_TGA 0xFFFF0002
|
||||
#define CODEC_HDP 0xFFFF0003
|
||||
#define CODEC_JXR 0xFFFF0004
|
||||
#define CODEC_HDR 0xFFFF0005
|
||||
#define CODEC_PPM 0xFFFF0006
|
||||
#define CODEC_PFM 0xFFFF0007
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
#define CODEC_EXR 0xFFFF0006
|
||||
#define CODEC_EXR 0xFFFF0008
|
||||
#endif
|
||||
|
||||
const SValue g_pSaveFileTypes[] = // valid formats to write to
|
||||
{
|
||||
const SValue g_pSaveFileTypes[] = // valid formats to write to
|
||||
{
|
||||
{ L"BMP", WIC_CODEC_BMP },
|
||||
{ L"JPG", WIC_CODEC_JPEG },
|
||||
{ L"JPEG", WIC_CODEC_JPEG },
|
||||
@ -417,14 +417,16 @@ const SValue g_pSaveFileTypes[] = // valid formats to write to
|
||||
{ L"WDP", WIC_CODEC_WMP },
|
||||
{ L"HDP", CODEC_HDP },
|
||||
{ L"JXR", CODEC_JXR },
|
||||
#ifdef USE_OPENEXR
|
||||
{ L"PPM", CODEC_PPM },
|
||||
{ L"PFM", CODEC_PFM },
|
||||
#ifdef USE_OPENEXR
|
||||
{ L"EXR", CODEC_EXR },
|
||||
#endif
|
||||
#endif
|
||||
{ nullptr, CODEC_DDS }
|
||||
};
|
||||
};
|
||||
|
||||
const SValue g_pFeatureLevels[] = // valid feature levels for -fl for maximimum size
|
||||
{
|
||||
const SValue g_pFeatureLevels[] = // valid feature levels for -fl for maximimum size
|
||||
{
|
||||
{ L"9.1", 2048 },
|
||||
{ L"9.2", 2048 },
|
||||
{ L"9.3", 4096 },
|
||||
@ -435,7 +437,36 @@ const SValue g_pFeatureLevels[] = // valid feature levels for -fl for maximimu
|
||||
{ L"12.0", 16384 },
|
||||
{ L"12.1", 16384 },
|
||||
{ nullptr, 0 },
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HRESULT __cdecl LoadFromBMPEx(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_In_ WIC_FLAGS flags,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image) noexcept;
|
||||
|
||||
HRESULT __cdecl LoadFromPortablePixMap(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image) noexcept;
|
||||
|
||||
HRESULT __cdecl SaveToPortablePixMap(
|
||||
_In_ const Image& image,
|
||||
_In_z_ const wchar_t* szFile) noexcept;
|
||||
|
||||
HRESULT __cdecl LoadFromPortablePixMapHDR(
|
||||
_In_z_ const wchar_t* szFile,
|
||||
_Out_opt_ TexMetadata* metadata,
|
||||
_Out_ ScratchImage& image) noexcept;
|
||||
|
||||
HRESULT __cdecl SaveToPortablePixMapHDR(
|
||||
_In_ const Image& image,
|
||||
_In_z_ const wchar_t* szFile) noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -445,13 +476,9 @@ const SValue g_pFeatureLevels[] = // valid feature levels for -fl for maximimu
|
||||
|
||||
namespace
|
||||
{
|
||||
inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
struct handle_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) CloseHandle(h); } };
|
||||
|
||||
using ScopedHandle = std::unique_ptr<void, handle_closer>;
|
||||
|
||||
struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
struct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
|
||||
using ScopedFindHandle = std::unique_ptr<void, find_closer>;
|
||||
|
||||
@ -984,127 +1011,6 @@ 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);
|
||||
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, size_t(header->biWidth), size_t(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;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
@ -1803,20 +1709,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
}
|
||||
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, WIC_FLAGS_NONE | dwFilter, &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (SUCCEEDED(LoadFromExtendedBMPMemory(bmpData.get(), bmpSize, &info, *image)))
|
||||
{
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
hr = LoadFromBMPEx(pConv->szSrc, WIC_FLAGS_NONE | dwFilter, &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L" FAILED (%x)\n", static_cast<unsigned int>(hr));
|
||||
@ -1841,6 +1734,24 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (_wcsicmp(ext, L".ppm") == 0)
|
||||
{
|
||||
hr = LoadFromPortablePixMap(pConv->szSrc, &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L" FAILED (%x)\n", static_cast<unsigned int>(hr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (_wcsicmp(ext, L".pfm") == 0)
|
||||
{
|
||||
hr = LoadFromPortablePixMapHDR(pConv->szSrc, &info, *image);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
wprintf(L" FAILED (%x)\n", static_cast<unsigned int>(hr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifdef USE_OPENEXR
|
||||
else if (_wcsicmp(ext, L".exr") == 0)
|
||||
{
|
||||
@ -3146,6 +3057,14 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
||||
hr = SaveToHDRFile(img[0], pConv->szDest);
|
||||
break;
|
||||
|
||||
case CODEC_PPM:
|
||||
hr = SaveToPortablePixMap(img[0], pConv->szDest);
|
||||
break;
|
||||
|
||||
case CODEC_PFM:
|
||||
hr = SaveToPortablePixMapHDR(img[0], pConv->szDest);
|
||||
break;
|
||||
|
||||
#ifdef USE_OPENEXR
|
||||
case CODEC_EXR:
|
||||
hr = SaveToEXRFile(img[0], pConv->szDest);
|
||||
|
@ -361,9 +361,9 @@ const SValue g_pExtFileTypes[] =
|
||||
|
||||
namespace
|
||||
{
|
||||
inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
struct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
|
||||
using ScopedFindHandle = std::unique_ptr<void, find_closer>;
|
||||
|
||||
@ -573,7 +573,12 @@ namespace
|
||||
PrintList(15, g_pDumpFileTypes);
|
||||
}
|
||||
|
||||
HRESULT LoadImage(const wchar_t *fileName, DWORD dwOptions, TEX_FILTER_FLAGS dwFilter, TexMetadata& info, std::unique_ptr<ScratchImage>& image)
|
||||
HRESULT LoadImage(
|
||||
const wchar_t *fileName,
|
||||
DWORD dwOptions,
|
||||
TEX_FILTER_FLAGS dwFilter,
|
||||
TexMetadata& info,
|
||||
std::unique_ptr<ScratchImage>& image)
|
||||
{
|
||||
if (!fileName)
|
||||
return E_INVALIDARG;
|
||||
@ -1233,7 +1238,12 @@ namespace
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
HRESULT Difference(const Image& image1, const Image& image2, TEX_FILTER_FLAGS dwFilter, DXGI_FORMAT format, ScratchImage& result)
|
||||
HRESULT Difference(
|
||||
const Image& image1,
|
||||
const Image& image2,
|
||||
TEX_FILTER_FLAGS dwFilter,
|
||||
DXGI_FORMAT format,
|
||||
ScratchImage& result)
|
||||
{
|
||||
if (!image1.pixels || !image2.pixels)
|
||||
return E_POINTER;
|
||||
@ -1370,7 +1380,10 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
inline static bool IsFixUpOffset(_In_range_(0, 2) size_t uPartitions, _In_range_(0, 63) uint64_t uShape, _In_range_(0, 15) size_t uOffset)
|
||||
inline static bool IsFixUpOffset(
|
||||
_In_range_(0, 2) size_t uPartitions,
|
||||
_In_range_(0, 63) uint64_t uShape,
|
||||
_In_range_(0, 15) size_t uOffset)
|
||||
{
|
||||
for (size_t p = 0; p <= uPartitions; p++)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user