From 685cc02fc77d8fc0f178a7d0e43d7d30a216bad9 Mon Sep 17 00:00:00 2001 From: d1str4ught <> Date: Wed, 27 Aug 2025 16:23:19 +0200 Subject: [PATCH] image loading reworked --- src/EterImageLib/DDSTextureLoader9.cpp | 1573 ++++++++++++++++++ src/EterImageLib/DDSTextureLoader9.h | 145 ++ src/EterImageLib/DXTCImage.cpp | 1604 ------------------- src/EterImageLib/DXTCImage.h | 143 -- src/EterImageLib/STBImageImplementation.cpp | 7 + src/EterLib/GrpImageTexture.cpp | 259 +-- src/EterLib/GrpImageTexture.h | 4 +- src/UserInterface/MarkImage.cpp | 6 +- 8 files changed, 1815 insertions(+), 1926 deletions(-) create mode 100644 src/EterImageLib/DDSTextureLoader9.cpp create mode 100644 src/EterImageLib/DDSTextureLoader9.h delete mode 100644 src/EterImageLib/DXTCImage.cpp delete mode 100644 src/EterImageLib/DXTCImage.h create mode 100644 src/EterImageLib/STBImageImplementation.cpp diff --git a/src/EterImageLib/DDSTextureLoader9.cpp b/src/EterImageLib/DDSTextureLoader9.cpp new file mode 100644 index 0000000..0275dfb --- /dev/null +++ b/src/EterImageLib/DDSTextureLoader9.cpp @@ -0,0 +1,1573 @@ +//-------------------------------------------------------------------------------------- +// File: DDSTextureLoader9.cpp +// +// Functions for loading a DDS texture and creating a Direct3D runtime resource for it +// +// Note these functions are useful as a light-weight runtime loader for DDS files. For +// a full-featured DDS file reader, writer, and texture processing pipeline see +// the 'Texconv' sample and the 'DirectXTex' library. +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + +#include "StdAfx.h" +#include "DDSTextureLoader9.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef _MSC_VER +// Off by default warnings +#pragma warning(disable : 4619 4616 4623 4626 5027) +// C4619/4616 #pragma warning warnings +// C4623 default constructor was implicitly defined as deleted +// C4626 assignment operator was implicitly defined as deleted +// C5027 move assignment operator was implicitly defined as deleted +#endif + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wcovered-switch-default" +#pragma clang diagnostic ignored "-Wswitch-enum" +#endif + +using namespace DirectX; +using Microsoft::WRL::ComPtr; + +//-------------------------------------------------------------------------------------- +// Macros +//-------------------------------------------------------------------------------------- +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \ + ((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 )) +#endif /* defined(MAKEFOURCC) */ + +//-------------------------------------------------------------------------------------- +// DDS file structure definitions +// +// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library +//-------------------------------------------------------------------------------------- +#pragma pack(push,1) + +constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS " + +struct DDS_PIXELFORMAT +{ + uint32_t size; + uint32_t flags; + uint32_t fourCC; + uint32_t RGBBitCount; + uint32_t RBitMask; + uint32_t GBitMask; + uint32_t BBitMask; + uint32_t ABitMask; +}; + +#define DDS_FOURCC 0x00000004 // DDPF_FOURCC +#define DDS_RGB 0x00000040 // DDPF_RGB +#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE +#define DDS_ALPHA 0x00000002 // DDPF_ALPHA +#define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV +#define DDS_BUMPLUMINANCE 0x00040000 // DDPF_BUMPLUMINANCE + +#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH + +#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX +#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX +#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY +#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY +#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ +#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ + +#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\ + DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\ + DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ ) + +#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP + +struct DDS_HEADER +{ + uint32_t size; + uint32_t flags; + uint32_t height; + uint32_t width; + uint32_t pitchOrLinearSize; + uint32_t depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags + uint32_t mipMapCount; + uint32_t reserved1[11]; + DDS_PIXELFORMAT ddspf; + uint32_t caps; + uint32_t caps2; + uint32_t caps3; + uint32_t caps4; + uint32_t reserved2; +}; + +#pragma pack(pop) + +//-------------------------------------------------------------------------------------- +namespace +{ + struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } }; + + using ScopedHandle = std::unique_ptr; + + inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; } + + //-------------------------------------------------------------------------------------- + HRESULT LoadTextureDataFromMemory( + _In_reads_(ddsDataSize) const uint8_t* ddsData, + size_t ddsDataSize, + const DDS_HEADER** header, + const uint8_t** bitData, + size_t* bitSize) noexcept + { + if (!header || !bitData || !bitSize) + { + return E_POINTER; + } + + *bitSize = 0; + + if (ddsDataSize > UINT32_MAX) + { + return E_FAIL; + } + + if (ddsDataSize < (sizeof(uint32_t) + sizeof(DDS_HEADER))) + { + return E_FAIL; + } + + // DDS files always start with the same magic number ("DDS ") + auto const dwMagicNumber = *reinterpret_cast(ddsData); + if (dwMagicNumber != DDS_MAGIC) + { + return E_FAIL; + } + + auto hdr = reinterpret_cast(ddsData + sizeof(uint32_t)); + + // Verify header to validate DDS file + if (hdr->size != sizeof(DDS_HEADER) || + hdr->ddspf.size != sizeof(DDS_PIXELFORMAT)) + { + return E_FAIL; + } + + // Check for DX10 extension + if ((hdr->ddspf.flags & DDS_FOURCC) && + (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC)) + { + // We don't support the new DX10 header for Direct3D 9 + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // setup the pointers in the process request + *header = hdr; + auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER); + *bitData = ddsData + offset; + *bitSize = ddsDataSize - offset; + + return S_OK; + } + + + //-------------------------------------------------------------------------------------- + HRESULT LoadTextureDataFromFile( + _In_z_ const wchar_t* fileName, + std::unique_ptr& ddsData, + const DDS_HEADER** header, + const uint8_t** bitData, + size_t* bitSize) noexcept + { + if (!header || !bitData || !bitSize) + { + return E_POINTER; + } + + *bitSize = 0; + + // open the file + #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + ScopedHandle hFile(safe_handle(CreateFile2(fileName, + GENERIC_READ, + FILE_SHARE_READ, + OPEN_EXISTING, + nullptr))); + #else + ScopedHandle hFile(safe_handle(CreateFileW(fileName, + GENERIC_READ, + FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 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 + if (fileInfo.EndOfFile.HighPart > 0) + { + return E_FAIL; + } + + // Need at least enough data to fill the header and magic number to be a valid DDS + if (fileInfo.EndOfFile.LowPart < (sizeof(uint32_t) + sizeof(DDS_HEADER))) + { + return E_FAIL; + } + + // create enough space for the file data + ddsData.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]); + if (!ddsData) + { + return E_OUTOFMEMORY; + } + + // read the data in + DWORD bytesRead = 0; + if (!ReadFile(hFile.get(), + ddsData.get(), + fileInfo.EndOfFile.LowPart, + &bytesRead, + nullptr + )) + { + ddsData.reset(); + return HRESULT_FROM_WIN32(GetLastError()); + } + + if (bytesRead < fileInfo.EndOfFile.LowPart) + { + ddsData.reset(); + return E_FAIL; + } + + // DDS files always start with the same magic number ("DDS ") + auto const dwMagicNumber = *reinterpret_cast(ddsData.get()); + if (dwMagicNumber != DDS_MAGIC) + { + ddsData.reset(); + return E_FAIL; + } + + auto hdr = reinterpret_cast(ddsData.get() + sizeof(uint32_t)); + + // Verify header to validate DDS file + if (hdr->size != sizeof(DDS_HEADER) || + hdr->ddspf.size != sizeof(DDS_PIXELFORMAT)) + { + ddsData.reset(); + return E_FAIL; + } + + // Check for DX10 extension + if ((hdr->ddspf.flags & DDS_FOURCC) && + (MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC)) + { + // We don't support the new DX10 header for Direct3D 9 + ddsData.reset(); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // setup the pointers in the process request + *header = hdr; + auto offset = sizeof(uint32_t) + sizeof(DDS_HEADER); + *bitData = ddsData.get() + offset; + *bitSize = fileInfo.EndOfFile.LowPart - offset; + + return S_OK; + } + + + //-------------------------------------------------------------------------------------- + // Return the BPP for a particular format + //-------------------------------------------------------------------------------------- + size_t BitsPerPixel(_In_ D3DFORMAT fmt) noexcept + { + switch (static_cast(fmt)) + { + case D3DFMT_A32B32G32R32F: + return 128; + + case D3DFMT_A16B16G16R16: + case D3DFMT_Q16W16V16U16: + case D3DFMT_A16B16G16R16F: + case D3DFMT_G32R32F: + return 64; + + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A2B10G10R10: + case D3DFMT_A8B8G8R8: + case D3DFMT_X8B8G8R8: + case D3DFMT_G16R16: + case D3DFMT_A2R10G10B10: + case D3DFMT_Q8W8V8U8: + case D3DFMT_V16U16: + case D3DFMT_X8L8V8U8: + case D3DFMT_A2W10V10U10: + case D3DFMT_D32: + case D3DFMT_D24S8: + case D3DFMT_D24X8: + case D3DFMT_D24X4S4: + case D3DFMT_D32F_LOCKABLE: + case D3DFMT_D24FS8: + case D3DFMT_INDEX32: + case D3DFMT_G16R16F: + case D3DFMT_R32F: + #if !defined(D3D_DISABLE_9EX) + case D3DFMT_D32_LOCKABLE: + #endif + return 32; + + case D3DFMT_R8G8B8: + return 24; + + case D3DFMT_A4R4G4B4: + case D3DFMT_X4R4G4B4: + case D3DFMT_R5G6B5: + case D3DFMT_L16: + case D3DFMT_A8L8: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A8R3G3B2: + case D3DFMT_V8U8: + case D3DFMT_CxV8U8: + case D3DFMT_L6V5U5: + case D3DFMT_G8R8_G8B8: + case D3DFMT_R8G8_B8G8: + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D15S1: + case D3DFMT_D16: + case D3DFMT_INDEX16: + case D3DFMT_R16F: + case D3DFMT_YUY2: + // From DX docs, reference/d3d/enums/d3dformat.asp + // (note how it says that D3DFMT_R8G8_B8G8 is "A 16-bit packed RGB format analogous to UYVY (U0Y0, V0Y1, U2Y2, and so on)") + case D3DFMT_UYVY: + return 16; + + case D3DFMT_R3G3B2: + case D3DFMT_A8: + case D3DFMT_A8P8: + case D3DFMT_P8: + case D3DFMT_L8: + case D3DFMT_A4L4: + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/directxvideoaccelerationdxvavideosubtypes.asp + case MAKEFOURCC('A', 'I', '4', '4'): + case MAKEFOURCC('I', 'A', '4', '4'): + #if !defined(D3D_DISABLE_9EX) + case D3DFMT_S8_LOCKABLE: + #endif + return 8; + + case D3DFMT_DXT1: + return 4; + + case MAKEFOURCC('Y', 'V', '1', '2'): + return 12; + + #if !defined(D3D_DISABLE_9EX) + case D3DFMT_A1: + return 1; + #endif + + default: + return 0; + } + } + + + //-------------------------------------------------------------------------------------- + // Get surface information for a particular format + //-------------------------------------------------------------------------------------- + HRESULT GetSurfaceInfo( + _In_ size_t width, + _In_ size_t height, + _In_ D3DFORMAT fmt, + size_t* outNumBytes, + _Out_opt_ size_t* outRowBytes, + _Out_opt_ size_t* outNumRows) noexcept + { + uint64_t numBytes = 0; + uint64_t rowBytes = 0; + uint64_t numRows = 0; + + bool bc = false; + bool packed = false; + size_t bpe = 0; + switch (static_cast(fmt)) + { + case D3DFMT_DXT1: + bc = true; + bpe = 8; + break; + + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + bc = true; + bpe = 16; + break; + + case D3DFMT_R8G8_B8G8: + case D3DFMT_G8R8_G8B8: + case D3DFMT_UYVY: + case D3DFMT_YUY2: + packed = true; + bpe = 4; + break; + + default: + break; + } + + if (bc) + { + uint64_t numBlocksWide = 0; + if (width > 0) + { + numBlocksWide = std::max(1u, (uint64_t(width) + 3u) / 4u); + } + uint64_t numBlocksHigh = 0; + if (height > 0) + { + numBlocksHigh = std::max(1u, (uint64_t(height) + 3u) / 4u); + } + rowBytes = numBlocksWide * bpe; + numRows = numBlocksHigh; + numBytes = rowBytes * numBlocksHigh; + } + else if (packed) + { + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numRows = uint64_t(height); + numBytes = rowBytes * height; + } + else + { + const size_t bpp = BitsPerPixel(fmt); + if (!bpp) + return E_INVALIDARG; + + rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte + numRows = uint64_t(height); + numBytes = rowBytes * height; + } + + #if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + #else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); + #endif + + if (outNumBytes) + { + *outNumBytes = static_cast(numBytes); + } + if (outRowBytes) + { + *outRowBytes = static_cast(rowBytes); + } + if (outNumRows) + { + *outNumRows = static_cast(numRows); + } + + return S_OK; + } + + + //-------------------------------------------------------------------------------------- +#define ISBITMASK( r,g,b,a ) ( ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a ) + + D3DFORMAT GetD3D9Format(const DDS_PIXELFORMAT& ddpf) noexcept + { + if (ddpf.flags & DDS_RGB) + { + switch (ddpf.RGBBitCount) + { + case 32: + if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000)) + { + return D3DFMT_A8R8G8B8; + } + if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0)) + { + return D3DFMT_X8R8G8B8; + } + if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)) + { + return D3DFMT_A8B8G8R8; + } + if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0)) + { + return D3DFMT_X8B8G8R8; + } + + // Note that many common DDS reader/writers (including D3DX) swap the + // the RED/BLUE masks for 10:10:10:2 formats. We assume + // below that the 'backwards' header mask is being used since it is most + // likely written by D3DX. + + // For 'correct' writers this should be 0x3ff00000,0x000ffc00,0x000003ff for BGR data + if (ISBITMASK(0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000)) + { + return D3DFMT_A2R10G10B10; + } + + // For 'correct' writers this should be 0x000003ff,0x000ffc00,0x3ff00000 for RGB data + if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)) + { + return D3DFMT_A2B10G10R10; + } + + if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000)) + { + return D3DFMT_G16R16; + } + if (ISBITMASK(0xffffffff, 0x00000000, 0x00000000, 0x00000000)) + { + return D3DFMT_R32F; // D3DX writes this out as a FourCC of 114 + } + break; + + case 24: + if (ISBITMASK(0xff0000, 0x00ff00, 0x0000ff, 0)) + { + return D3DFMT_R8G8B8; + } + break; + + case 16: + if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0x0000)) + { + return D3DFMT_R5G6B5; + } + if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000)) + { + return D3DFMT_A1R5G5B5; + } + if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0)) + { + return D3DFMT_X1R5G5B5; + } + if (ISBITMASK(0x0f00, 0x00f0, 0x000f, 0xf000)) + { + return D3DFMT_A4R4G4B4; + } + if (ISBITMASK(0x0f00, 0x00f0, 0x000f, 0)) + { + return D3DFMT_X4R4G4B4; + } + if (ISBITMASK(0x00e0, 0x001c, 0x0003, 0xff00)) + { + return D3DFMT_A8R3G3B2; + } + + // NVTT versions 1.x wrote these as RGB instead of LUMINANCE + if (ISBITMASK(0xffff, 0, 0, 0)) + { + return D3DFMT_L16; + } + if (ISBITMASK(0x00ff, 0, 0, 0xff00)) + { + return D3DFMT_A8L8; + } + break; + + case 8: + if (ISBITMASK(0xe0, 0x1c, 0x03, 0)) + { + return D3DFMT_R3G3B2; + } + + // NVTT versions 1.x wrote these as RGB instead of LUMINANCE + if (ISBITMASK(0xff, 0, 0, 0)) + { + return D3DFMT_L8; + } + + // Paletted texture formats are typically not supported on modern video cards aka D3DFMT_P8, D3DFMT_A8P8 + break; + } + } + else if (ddpf.flags & DDS_LUMINANCE) + { + switch (ddpf.RGBBitCount) + { + case 16: + if (ISBITMASK(0xffff, 0, 0, 0)) + { + return D3DFMT_L16; + } + if (ISBITMASK(0x00ff, 0, 0, 0xff00)) + { + return D3DFMT_A8L8; + } + break; + + case 8: + if (ISBITMASK(0x0f, 0, 0, 0xf0)) + { + return D3DFMT_A4L4; + } + if (ISBITMASK(0xff, 0, 0, 0)) + { + return D3DFMT_L8; + } + if (ISBITMASK(0x00ff, 0, 0, 0xff00)) + { + return D3DFMT_A8L8; // Some DDS writers assume the bitcount should be 8 instead of 16 + } + break; + } + } + else if (ddpf.flags & DDS_ALPHA) + { + if (8 == ddpf.RGBBitCount) + { + return D3DFMT_A8; + } + } + else if (ddpf.flags & DDS_BUMPDUDV) + { + switch (ddpf.RGBBitCount) + { + case 32: + if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)) + { + return D3DFMT_Q8W8V8U8; + } + if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000)) + { + return D3DFMT_V16U16; + } + if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)) + { + return D3DFMT_A2W10V10U10; + } + break; + + case 16: + if (ISBITMASK(0x00ff, 0xff00, 0, 0)) + { + return D3DFMT_V8U8; + } + break; + } + } + else if (ddpf.flags & DDS_BUMPLUMINANCE) + { + switch (ddpf.RGBBitCount) + { + case 32: + if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0)) + { + return D3DFMT_X8L8V8U8; + } + break; + + case 16: + if (ISBITMASK(0x001f, 0x03e0, 0xfc00, 0)) + { + return D3DFMT_L6V5U5; + } + break; + } + } + else if (ddpf.flags & DDS_FOURCC) + { + if (MAKEFOURCC('D', 'X', 'T', '1') == ddpf.fourCC) + { + return D3DFMT_DXT1; + } + if (MAKEFOURCC('D', 'X', 'T', '2') == ddpf.fourCC) + { + return D3DFMT_DXT2; + } + if (MAKEFOURCC('D', 'X', 'T', '3') == ddpf.fourCC) + { + return D3DFMT_DXT3; + } + if (MAKEFOURCC('D', 'X', 'T', '4') == ddpf.fourCC) + { + return D3DFMT_DXT4; + } + if (MAKEFOURCC('D', 'X', 'T', '5') == ddpf.fourCC) + { + return D3DFMT_DXT5; + } + + if (MAKEFOURCC('R', 'G', 'B', 'G') == ddpf.fourCC) + { + return D3DFMT_R8G8_B8G8; + } + if (MAKEFOURCC('G', 'R', 'G', 'B') == ddpf.fourCC) + { + return D3DFMT_G8R8_G8B8; + } + + if (MAKEFOURCC('U', 'Y', 'V', 'Y') == ddpf.fourCC) + { + return D3DFMT_UYVY; + } + if (MAKEFOURCC('Y', 'U', 'Y', '2') == ddpf.fourCC) + { + return D3DFMT_YUY2; + } + + // Check for D3DFORMAT enums being set here + switch (ddpf.fourCC) + { + case D3DFMT_A16B16G16R16: + case D3DFMT_Q16W16V16U16: + case D3DFMT_R16F: + case D3DFMT_G16R16F: + case D3DFMT_A16B16G16R16F: + case D3DFMT_R32F: + case D3DFMT_G32R32F: + case D3DFMT_A32B32G32R32F: + case D3DFMT_CxV8U8: + return static_cast(ddpf.fourCC); + } + } + + return D3DFMT_UNKNOWN; + } + +#undef ISBITMASK + + +//-------------------------------------------------------------------------------------- + HRESULT CreateTextureFromDDS( + _In_ LPDIRECT3DDEVICE9 device, + _In_ const DDS_HEADER* header, + _In_reads_bytes_(bitSize) const uint8_t* bitData, + _In_ size_t bitSize, + _In_ DWORD usage, + _In_ D3DPOOL pool, + _Outptr_ LPDIRECT3DBASETEXTURE9* texture, + bool generateMipsIfMissing) noexcept + { + HRESULT hr = S_OK; + + UINT iWidth = header->width; + UINT iHeight = header->height; + + UINT iMipCount = header->mipMapCount; + if (0 == iMipCount) + { + iMipCount = 1; + } + + // Bound sizes (for security purposes we don't trust DDS file metadata larger than the D3D 10 hardware requirements) + if (iMipCount > 14u /*D3D10_REQ_MIP_LEVELS*/) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // We could support a subset of 'DX10' extended header DDS files, but we'll assume here we are only + // supporting legacy DDS files for a Direct3D9 device + + const D3DFORMAT fmt = GetD3D9Format(header->ddspf); + if (fmt == D3DFMT_UNKNOWN || BitsPerPixel(fmt) == 0) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + if (header->flags & DDS_HEADER_FLAGS_VOLUME) + { + UINT iDepth = header->depth; + + if ((iWidth > 2048u /*D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/) + || (iHeight > 2048u /*D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/) + || (iDepth > 2048u /*D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION*/)) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // Create the volume texture (let the runtime do the validation) + ComPtr pTexture; + hr = device->CreateVolumeTexture(iWidth, iHeight, iDepth, iMipCount, + usage, fmt, pool, pTexture.GetAddressOf(), nullptr); + if (FAILED(hr)) + return hr; + + ComPtr pStagingTexture; + if (pool == D3DPOOL_DEFAULT) + { + hr = device->CreateVolumeTexture(iWidth, iHeight, iDepth, iMipCount, + 0u, fmt, D3DPOOL_SYSTEMMEM, pStagingTexture.GetAddressOf(), nullptr); + if (FAILED(hr)) + return hr; + } + else + { + pStagingTexture = pTexture; + } + + // Lock, fill, unlock + size_t NumBytes = 0; + size_t RowBytes = 0; + size_t NumRows = 0; + const uint8_t* pSrcBits = bitData; + const uint8_t* pEndBits = bitData + bitSize; + D3DLOCKED_BOX LockedBox = {}; + + for (UINT i = 0; i < iMipCount; ++i) + { + GetSurfaceInfo(iWidth, iHeight, fmt, &NumBytes, &RowBytes, &NumRows); + + if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + if ((pSrcBits + (NumBytes * iDepth)) > pEndBits) + { + return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); + } + + if (SUCCEEDED(pStagingTexture->LockBox(i, &LockedBox, nullptr, 0))) + { + auto pDestBits = static_cast(LockedBox.pBits); + + for (UINT j = 0; j < iDepth; ++j) + { + uint8_t* dptr = pDestBits; + const uint8_t* sptr = pSrcBits; + + // Copy stride line by line + for (size_t h = 0; h < NumRows; h++) + { + memcpy_s(dptr, static_cast(LockedBox.RowPitch), sptr, RowBytes); + dptr += LockedBox.RowPitch; + sptr += RowBytes; + } + + pDestBits += LockedBox.SlicePitch; + pSrcBits += NumBytes; + } + + pStagingTexture->UnlockBox(i); + } + + iWidth = iWidth >> 1; + iHeight = iHeight >> 1; + iDepth = iDepth >> 1; + if (iWidth == 0) + iWidth = 1; + if (iHeight == 0) + iHeight = 1; + if (iDepth == 0) + iDepth = 1; + } + + if (pool == D3DPOOL_DEFAULT) + { + hr = device->UpdateTexture(pStagingTexture.Get(), pTexture.Get()); + if (FAILED(hr)) + return hr; + } + + *texture = pTexture.Detach(); + } + else if (header->caps2 & DDS_CUBEMAP) + { + if ((iWidth > 8192u /*D3D10_REQ_TEXTURECUBE_DIMENSION*/) + || (iHeight > 8192u /*D3D10_REQ_TEXTURECUBE_DIMENSION*/)) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // We require at least one face to be defined, and the faces must be square + if ((header->caps2 & DDS_CUBEMAP_ALLFACES) == 0 || iHeight != iWidth) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // Create the cubemap (let the runtime do the validation) + ComPtr pTexture; + hr = device->CreateCubeTexture(iWidth, iMipCount, + usage, fmt, pool, pTexture.GetAddressOf(), nullptr); + if (FAILED(hr)) + return hr; + + ComPtr pStagingTexture; + if (pool == D3DPOOL_DEFAULT) + { + hr = device->CreateCubeTexture(iWidth, iMipCount, + 0u, fmt, D3DPOOL_SYSTEMMEM, pStagingTexture.GetAddressOf(), nullptr); + if (FAILED(hr)) + return hr; + } + else + { + pStagingTexture = pTexture; + } + + // Lock, fill, unlock + size_t NumBytes = 0; + size_t RowBytes = 0; + size_t NumRows = 0; + const uint8_t* pSrcBits = bitData; + const uint8_t* pEndBits = bitData + bitSize; + D3DLOCKED_RECT LockedRect = {}; + + UINT mask = DDS_CUBEMAP_POSITIVEX & ~DDS_CUBEMAP; + for (UINT f = 0; f < 6; ++f, mask <<= 1) + { + if (!(header->caps2 & mask)) + continue; + + UINT w = iWidth; + UINT h = iHeight; + for (UINT i = 0; i < iMipCount; ++i) + { + GetSurfaceInfo(w, h, fmt, &NumBytes, &RowBytes, &NumRows); + + if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + if ((pSrcBits + NumBytes) > pEndBits) + { + return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); + } + + if (SUCCEEDED(pStagingTexture->LockRect(static_cast(f), i, &LockedRect, nullptr, 0))) + { + auto pDestBits = static_cast(LockedRect.pBits); + + // Copy stride line by line + for (size_t r = 0; r < NumRows; r++) + { + memcpy_s(pDestBits, static_cast(LockedRect.Pitch), pSrcBits, RowBytes); + pDestBits += LockedRect.Pitch; + pSrcBits += RowBytes; + } + + pStagingTexture->UnlockRect(static_cast(f), i); + } + + w = w >> 1; + h = h >> 1; + if (w == 0) + w = 1; + if (h == 0) + h = 1; + } + } + + if (pool == D3DPOOL_DEFAULT) + { + hr = device->UpdateTexture(pStagingTexture.Get(), pTexture.Get()); + if (FAILED(hr)) + return hr; + } + + *texture = pTexture.Detach(); + } + else + { + if ((iWidth > 8192u /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/) + || (iHeight > 8192u /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/)) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + // Create the texture (let the runtime do the validation) + if (generateMipsIfMissing && iMipCount <= 1) + usage |= D3DUSAGE_AUTOGENMIPMAP; + + ComPtr pTexture; + hr = device->CreateTexture(iWidth, iHeight, iMipCount, + usage, fmt, pool, + pTexture.GetAddressOf(), nullptr); + if (FAILED(hr)) + return hr; + + ComPtr pStagingTexture; + if (pool == D3DPOOL_DEFAULT) + { + hr = device->CreateTexture(iWidth, iHeight, iMipCount, + 0u, fmt, D3DPOOL_SYSTEMMEM, pStagingTexture.GetAddressOf(), nullptr); + if (FAILED(hr)) + return hr; + } + else + { + pStagingTexture = pTexture; + } + + // Lock, fill, unlock + size_t NumBytes = 0; + size_t RowBytes = 0; + size_t NumRows = 0; + const uint8_t* pSrcBits = bitData; + const uint8_t* pEndBits = bitData + bitSize; + D3DLOCKED_RECT LockedRect = {}; + + for (UINT i = 0; i < iMipCount; ++i) + { + GetSurfaceInfo(iWidth, iHeight, fmt, &NumBytes, &RowBytes, &NumRows); + + if (NumBytes > UINT32_MAX || RowBytes > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + if ((pSrcBits + NumBytes) > pEndBits) + { + return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); + } + + if (SUCCEEDED(pStagingTexture->LockRect(i, &LockedRect, nullptr, 0))) + { + auto pDestBits = static_cast(LockedRect.pBits); + + // Copy stride line by line + for (UINT h = 0; h < NumRows; h++) + { + memcpy_s(pDestBits, static_cast(LockedRect.Pitch), pSrcBits, RowBytes); + pDestBits += LockedRect.Pitch; + pSrcBits += RowBytes; + } + + pStagingTexture->UnlockRect(i); + } + + iWidth = iWidth >> 1; + iHeight = iHeight >> 1; + if (iWidth == 0) + iWidth = 1; + if (iHeight == 0) + iHeight = 1; + } + + if (pool == D3DPOOL_DEFAULT) + { + hr = device->UpdateTexture(pStagingTexture.Get(), pTexture.Get()); + if (FAILED(hr)) + return hr; + } + + *texture = pTexture.Detach(); + } + + return hr; + } +} // anonymous namespace + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemory( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + LPDIRECT3DBASETEXTURE9* texture, + bool generateMipsIfMissing) noexcept +{ + return CreateDDSTextureFromMemoryEx(d3dDevice, ddsData, ddsDataSize, 0u, D3DPOOL_DEFAULT, generateMipsIfMissing, texture); +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemoryEx( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + _In_ DWORD usage, + _In_ D3DPOOL pool, + bool generateMipsIfMissing, + LPDIRECT3DBASETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !ddsData || !texture) + { + return E_INVALIDARG; + } + + // Validate DDS file in memory + const DDS_HEADER* header = nullptr; + const uint8_t* bitData = nullptr; + size_t bitSize = 0; + + HRESULT hr = LoadTextureDataFromMemory(ddsData, ddsDataSize, + &header, + &bitData, + &bitSize + ); + if (FAILED(hr)) + return hr; + + return CreateTextureFromDDS( + d3dDevice, + header, + bitData, + bitSize, + usage, + pool, + texture, + generateMipsIfMissing); +} + +// Type-specific standard versions +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemory( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + LPDIRECT3DTEXTURE9* texture, + bool generateMipsIfMissing) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !ddsData || !ddsDataSize || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromMemoryEx(d3dDevice, ddsData, ddsDataSize, 0u, D3DPOOL_DEFAULT, generateMipsIfMissing, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_TEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemory( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + LPDIRECT3DCUBETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !ddsData || !ddsDataSize || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromMemoryEx(d3dDevice, ddsData, ddsDataSize, 0u, D3DPOOL_DEFAULT, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_CUBETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemory( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + LPDIRECT3DVOLUMETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !ddsData || !ddsDataSize || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromMemoryEx(d3dDevice, ddsData, ddsDataSize, 0u, D3DPOOL_DEFAULT, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_VOLUMETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +// Type-specific extended versions +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemoryEx( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + DWORD usage, + D3DPOOL pool, + bool generateMipsIfMissing, + LPDIRECT3DTEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !ddsData || !ddsDataSize || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromMemoryEx(d3dDevice, ddsData, ddsDataSize, usage, pool, generateMipsIfMissing, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_TEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemoryEx( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + DWORD usage, + D3DPOOL pool, + LPDIRECT3DCUBETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !ddsData || !ddsDataSize || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromMemoryEx(d3dDevice, ddsData, ddsDataSize, usage, pool, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_CUBETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromMemoryEx( + LPDIRECT3DDEVICE9 d3dDevice, + const uint8_t* ddsData, + size_t ddsDataSize, + DWORD usage, + D3DPOOL pool, + LPDIRECT3DVOLUMETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !ddsData || !ddsDataSize || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromMemoryEx(d3dDevice, ddsData, ddsDataSize, usage, pool, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_VOLUMETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFile( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* fileName, + LPDIRECT3DBASETEXTURE9* texture, + bool generateMipsIfMissing) noexcept +{ + return CreateDDSTextureFromFileEx(d3dDevice, fileName, 0u, D3DPOOL_DEFAULT, generateMipsIfMissing, texture); +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFileEx( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* fileName, + _In_ DWORD usage, + _In_ D3DPOOL pool, + bool generateMipsIfMissing, + LPDIRECT3DBASETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !fileName || !texture) + return E_INVALIDARG; + + const DDS_HEADER* header = nullptr; + const uint8_t* bitData = nullptr; + size_t bitSize = 0; + + std::unique_ptr ddsData; + HRESULT hr = LoadTextureDataFromFile(fileName, + ddsData, + &header, + &bitData, + &bitSize + ); + if (FAILED(hr)) + { + return hr; + } + + return CreateTextureFromDDS( + d3dDevice, + header, + bitData, + bitSize, + usage, + pool, + texture, + generateMipsIfMissing); +} + +// Type-specific standard versions +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFile( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* fileName, + LPDIRECT3DTEXTURE9* texture, + bool generateMipsIfMissing) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !fileName || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromFileEx(d3dDevice, fileName, 0u, D3DPOOL_DEFAULT, generateMipsIfMissing, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_TEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFile( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* fileName, + LPDIRECT3DCUBETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !fileName || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromFileEx(d3dDevice, fileName, 0u, D3DPOOL_DEFAULT, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_CUBETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFile( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* szFileName, + LPDIRECT3DVOLUMETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !szFileName || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromFileEx(d3dDevice, szFileName, 0u, D3DPOOL_DEFAULT, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_VOLUMETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +// Type-specific extended versions +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFileEx( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* fileName, + DWORD usage, + D3DPOOL pool, + bool generateMipsIfMissing, + LPDIRECT3DTEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !fileName || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromFileEx(d3dDevice, fileName, usage, pool, generateMipsIfMissing, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_TEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFileEx( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* fileName, + DWORD usage, + D3DPOOL pool, + LPDIRECT3DCUBETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !fileName || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromFileEx(d3dDevice, fileName, usage, pool, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_CUBETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} + +_Use_decl_annotations_ +HRESULT DirectX::CreateDDSTextureFromFileEx( + LPDIRECT3DDEVICE9 d3dDevice, + const wchar_t* szFileName, + DWORD usage, + D3DPOOL pool, + LPDIRECT3DVOLUMETEXTURE9* texture) noexcept +{ + if (texture) + { + *texture = nullptr; + } + + if (!d3dDevice || !szFileName || !texture) + return E_INVALIDARG; + + ComPtr tex; + HRESULT hr = CreateDDSTextureFromFileEx(d3dDevice, szFileName, usage, pool, false, tex.GetAddressOf()); + if (SUCCEEDED(hr)) + { + hr = E_FAIL; + if (tex->GetType() == D3DRTYPE_VOLUMETEXTURE) + { + *texture = static_cast(tex.Detach()); + return S_OK; + } + } + + return hr; +} diff --git a/src/EterImageLib/DDSTextureLoader9.h b/src/EterImageLib/DDSTextureLoader9.h new file mode 100644 index 0000000..3e1c7ca --- /dev/null +++ b/src/EterImageLib/DDSTextureLoader9.h @@ -0,0 +1,145 @@ +//-------------------------------------------------------------------------------------- +// File: DDSTextureLoader9.h +// +// Functions for loading a DDS texture and creating a Direct3D runtime resource for it +// +// Note these functions are useful as a light-weight runtime loader for DDS files. For +// a full-featured DDS file reader, writer, and texture processing pipeline see +// the 'Texconv' sample and the 'DirectXTex' library. +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +//-------------------------------------------------------------------------------------- + +#pragma once + +#ifndef DIRECT3D_VERSION +#define DIRECT3D_VERSION 0x900 +#endif + +#include + +#include +#include + + +namespace DirectX +{ + // Standard version + HRESULT CreateDDSTextureFromMemory( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _Outptr_ LPDIRECT3DBASETEXTURE9* texture, + bool generateMipsIfMissing = false) noexcept; + + HRESULT CreateDDSTextureFromFile( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _Outptr_ LPDIRECT3DBASETEXTURE9* texture, + bool generateMipsIfMissing = false) noexcept; + + // Extended version + HRESULT CreateDDSTextureFromMemoryEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _In_ DWORD usage, + _In_ D3DPOOL pool, + bool generateMipsIfMissing, + _Outptr_ LPDIRECT3DBASETEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromFileEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _In_ DWORD usage, + _In_ D3DPOOL pool, + bool generateMipsIfMissing, + _Outptr_ LPDIRECT3DBASETEXTURE9* texture) noexcept; + + // Type-specific standard versions + HRESULT CreateDDSTextureFromMemory( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _Outptr_ LPDIRECT3DTEXTURE9* texture, + bool generateMipsIfMissing = false) noexcept; + + HRESULT CreateDDSTextureFromFile( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _Outptr_ LPDIRECT3DTEXTURE9* texture, + bool generateMipsIfMissing = false) noexcept; + + HRESULT CreateDDSTextureFromMemory( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _Outptr_ LPDIRECT3DCUBETEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromFile( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _Outptr_ LPDIRECT3DCUBETEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromMemory( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _Outptr_ LPDIRECT3DVOLUMETEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromFile( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _Outptr_ LPDIRECT3DVOLUMETEXTURE9* texture) noexcept; + + // Type-specific extended versions + HRESULT CreateDDSTextureFromMemoryEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _In_ DWORD usage, + _In_ D3DPOOL pool, + bool generateMipsIfMissing, + _Outptr_ LPDIRECT3DTEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromFileEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _In_ DWORD usage, + _In_ D3DPOOL pool, + bool generateMipsIfMissing, + _Outptr_ LPDIRECT3DTEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromMemoryEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _In_ DWORD usage, + _In_ D3DPOOL pool, + _Outptr_ LPDIRECT3DCUBETEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromFileEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _In_ DWORD usage, + _In_ D3DPOOL pool, + _Outptr_ LPDIRECT3DCUBETEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromMemoryEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_reads_bytes_(ddsDataSize) const uint8_t* ddsData, + _In_ size_t ddsDataSize, + _In_ DWORD usage, + _In_ D3DPOOL pool, + _Outptr_ LPDIRECT3DVOLUMETEXTURE9* texture) noexcept; + + HRESULT CreateDDSTextureFromFileEx( + _In_ LPDIRECT3DDEVICE9 d3dDevice, + _In_z_ const wchar_t* fileName, + _In_ DWORD usage, + _In_ D3DPOOL pool, + _Outptr_ LPDIRECT3DVOLUMETEXTURE9* texture) noexcept; +} diff --git a/src/EterImageLib/DXTCImage.cpp b/src/EterImageLib/DXTCImage.cpp deleted file mode 100644 index f0fb112..0000000 --- a/src/EterImageLib/DXTCImage.cpp +++ /dev/null @@ -1,1604 +0,0 @@ -// need the d3d.h for things in format of .dds file -#include "StdAfx.h" - -#include -#include -#include -#include - -#include "../eterBase/MappedFile.h" -#include "../eterBase/Debug.h" - -#include "DXTCImage.h" - -struct DXTColBlock -{ - WORD col0; - WORD col1; - - // no bit fields - use bytes - BYTE row[4]; -}; - -struct DXTAlphaBlockExplicit -{ - WORD row[4]; -}; - -struct DXTAlphaBlock3BitLinear -{ - BYTE alpha0; - BYTE alpha1; - - BYTE stuff[6]; -}; - -// use cast to struct instead of RGBA_MAKE as struct is much -struct Color8888 -{ - BYTE b; // Last one is MSB, 1st is LSB. - BYTE g; // order of the output ARGB or BGRA, etc... - BYTE r; // change the order of names to change the - BYTE a; -}; - -struct Color565 -{ - unsigned nBlue : 5; // order of names changes - unsigned nGreen : 6; // byte order of output to 32 bit - unsigned nRed : 5; -}; - -///////////////////////////////////// -// should be in ddraw.h - -CDXTCImage::CDXTCImage() -{ - Initialize(); -} - -CDXTCImage::~CDXTCImage() -{ -} - -void CDXTCImage::Initialize() -{ - m_nWidth = 0; - m_nHeight = 0; - - for (int i = 0; i < MAX_MIPLEVELS; ++i) - m_pbCompBufferByLevels[i] = NULL; -} - -void CDXTCImage::Clear() -{ - for (int i = 0; i < MAX_MIPLEVELS; ++i) - m_bCompVector[i].clear(); - - Initialize(); -} - -bool CDXTCImage::LoadFromFile(const char * filename) -{ - // only understands .dds files for now - // return true if success - int next = 1; - - static char fileupper[MAX_PATH+1]; - - strncpy(fileupper, filename, MAX_PATH); - _strupr(fileupper); - - int i; - bool knownformat = false; - - for (i = 0; i < next; ++i) - { - char * found = strstr(fileupper, ".DDS"); - - if (found != NULL) - { - knownformat = true; - break; - } - } - - if (knownformat == false) - { - Tracef("Unknown file format encountered! [%s]\n", filename); - return(false); - } - - CMappedFile mappedFile; - LPCVOID pvMap; - - if (!mappedFile.Create(filename, &pvMap, 0, 0)) - { - Tracef("Can't open file for reading! [%s]\n", filename); - return false; - } - - return LoadFromMemory((const BYTE*) pvMap); -} - -bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap) -{ - ////////////////////////////////////// - // start reading the file - // from Microsoft's mssdk D3DIM example "Compress" - DWORD dwMagic; - - // Read magic number - dwMagic = *(DWORD *) c_pbMap; - c_pbMap += sizeof(DWORD); - -//!@# -// if (dwMagic != MAKEFOURCC('D','D','S',' ')) -// return false; - - DDSURFACEDESC2 ddsd; // read from dds file - - // Read the surface description - memcpy(&ddsd, c_pbMap, sizeof(DDSURFACEDESC2)); - c_pbMap += sizeof(DDSURFACEDESC2); - - // Does texture have mipmaps? - m_bMipTexture = (ddsd.dwMipMapCount > 0) ? TRUE : FALSE; - - // Clear unwanted flags - // Can't do this!!! surface not re-created here - // ddsd.dwFlags &= (~DDSD_PITCH); - // ddsd.dwFlags &= (~DDSD_LINEARSIZE); - - // Is it DXTC ? - // I sure hope pixelformat is valid! - m_xddPixelFormat.dwFlags = ddsd.ddpfPixelFormat.dwFlags; - m_xddPixelFormat.dwFourCC = ddsd.ddpfPixelFormat.dwFourCC; - m_xddPixelFormat.dwSize = ddsd.ddpfPixelFormat.dwSize; - m_xddPixelFormat.dwRGBBitCount = ddsd.ddpfPixelFormat.dwRGBBitCount; - m_xddPixelFormat.dwRGBAlphaBitMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; - m_xddPixelFormat.dwRBitMask = ddsd.ddpfPixelFormat.dwRBitMask; - m_xddPixelFormat.dwGBitMask = ddsd.ddpfPixelFormat.dwGBitMask; - m_xddPixelFormat.dwBBitMask = ddsd.ddpfPixelFormat.dwBBitMask; - - DecodePixelFormat(m_strFormat, &m_xddPixelFormat); - - if (m_CompFormat != PF_DXT1 && - m_CompFormat != PF_DXT3 && - m_CompFormat != PF_DXT5) - { - return false; - } - - if (ddsd.dwMipMapCount > MAX_MIPLEVELS) - ddsd.dwMipMapCount = MAX_MIPLEVELS; - - m_nWidth = ddsd.dwWidth; - m_nHeight = ddsd.dwHeight; - //!@# - m_dwMipMapCount = std::max(1ul, ddsd.dwMipMapCount); - m_dwFlags = ddsd.dwFlags; - - if (ddsd.dwFlags & DDSD_PITCH) - { - m_lPitch = ddsd.lPitch; - m_pbCompBufferByLevels[0] = c_pbMap; - } - else - { - m_lPitch = ddsd.dwLinearSize; - - if (ddsd.dwFlags & DDSD_MIPMAPCOUNT) - { - for (DWORD dwLinearSize = ddsd.dwLinearSize, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2) - { - m_pbCompBufferByLevels[i] = c_pbMap; - c_pbMap += dwLinearSize; - } - } - else - { - m_pbCompBufferByLevels[0] = c_pbMap; - } - } - - return true; -} - -////////////////////////////////////////////////////////////////////// -bool CDXTCImage::LoadFromMemory(const BYTE * c_pbMap) -{ - if (!LoadHeaderFromMemory(c_pbMap)) - return false; - - if (m_dwFlags & DDSD_PITCH) - { - DWORD dwBytesPerRow = m_nWidth * m_xddPixelFormat.dwRGBBitCount / 8; - - m_nCompSize = m_lPitch * m_nHeight; - m_nCompLineSz = dwBytesPerRow; - - m_bCompVector[0].resize(m_nCompSize); - BYTE * pDest = &m_bCompVector[0][0]; - - c_pbMap = m_pbCompBufferByLevels[0]; - - for (int yp = 0; yp < m_nHeight; ++yp) - { - memcpy(pDest, c_pbMap, dwBytesPerRow); - pDest += m_lPitch; - c_pbMap += m_lPitch; - } - } - else - { - if (m_dwFlags & DDSD_MIPMAPCOUNT) - { - for (DWORD dwLinearSize = m_lPitch, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2) - { - m_bCompVector[i].resize(dwLinearSize); - Copy(i, &m_bCompVector[i][0], dwLinearSize); - } - } - else - { - m_bCompVector[0].resize(m_lPitch); - Copy(0, &m_bCompVector[0][0], m_lPitch); - } - } - - // done reading file - return true; -} - -bool CDXTCImage::Copy(int miplevel, BYTE * pbDest, long lDestPitch) -{ - if (!(m_dwFlags & DDSD_MIPMAPCOUNT)) - if (miplevel) - return false; - - /* - DXTColBlock * pBlock; - WORD * pPos = (WORD *) &m_pbCompBufferByLevels[miplevel][0]; - int xblocks = (m_nWidth >> miplevel) / 4; - int yblocks = (m_nHeight >> miplevel) / 4; - - for (int y = 0; y < yblocks; ++y) - { - // 8 bytes per block - pBlock = (DXTColBlock*) ((DWORD) pPos + y * xblocks * 8); - - memcpy(pbDest, pBlock, xblocks * 8); - pbDest += lDestPitch; - } - */ - - memcpy(pbDest, m_pbCompBufferByLevels[miplevel], m_lPitch >> (miplevel * 2)); - pbDest += lDestPitch; - return true; -} - -void CDXTCImage::Unextract(BYTE * pbDest, int /*iWidth*/, int /*iHeight*/, int iPitch) -{ - if (!m_pbCompBufferByLevels[0]) - return; - - DXTColBlock * pBlock; - BYTE * pPos = (BYTE *) &m_pbCompBufferByLevels[0][0]; - int xblocks = m_nWidth / 4; - int yblocks = (m_nHeight / 4) * ((iPitch / m_nWidth) / 2); - - for (int y = 0; y < yblocks; ++y) - { - pBlock = (DXTColBlock*) (pPos + y * xblocks * 8); - - memcpy(pbDest, pBlock, xblocks * 8); - pbDest += xblocks * 8; - } - - /* - for (int y = 0; y < iHeight; ++y) - { - memcpy(pbDest, &m_pbCompBufferByLevels[0][0] + y*iWidth, iWidth); - pbDest += iWidth; - } - */ -} - -void CDXTCImage::Decompress(int miplevel, DWORD * pdwDest) -{ - switch (m_CompFormat) - { - case PF_DXT1: - DecompressDXT1(miplevel, pdwDest); - break; - - case PF_DXT3: - DecompressDXT3(miplevel, pdwDest); - break; - - case PF_DXT5: - DecompressDXT5(miplevel, pdwDest); - break; - - case PF_ARGB: - DecompressARGB(miplevel, pdwDest); - break; - - case PF_UNKNOWN: - break; - } -} - -inline void GetColorBlockColors(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd) -{ - // There are 4 methods to use - see the Time_ functions. - // 1st = shift = does normal approach per byte for color comps - // 2nd = use freak variable bit field color565 for component extraction - // 3rd = use super-freak DWORD adds BEFORE shifting the color components - // This lets you do only 1 add per color instead of 3 BYTE adds and - // might be faster - // Call RunTimingSession() to run each of them & output result to txt file - - // freak variable bit structure method - // normal math - // This method is fastest - Color565 * pCol; - - pCol = (Color565*) & (pBlock->col0); - - col_0->a = 0xff; - col_0->r = pCol->nRed; - col_0->r <<= 3; // shift to full precision - col_0->g = pCol->nGreen; - col_0->g <<= 2; - col_0->b = pCol->nBlue; - col_0->b <<= 3; - - pCol = (Color565*) & (pBlock->col1); - col_1->a = 0xff; - col_1->r = pCol->nRed; - col_1->r <<= 3; // shift to full precision - col_1->g = pCol->nGreen; - col_1->g <<= 2; - col_1->b = pCol->nBlue; - col_1->b <<= 3; - - if (pBlock->col0 > pBlock->col1) - { - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - wrd = (WORD) (((WORD) col_0->r * 2 + (WORD) col_1->r) / 3); - // no +1 for rounding - // as bits have been shifted to 888 - col_2->r = (BYTE)wrd; - - wrd = (WORD) (((WORD) col_0->g * 2 + (WORD) col_1->g) / 3); - col_2->g = (BYTE)wrd; - - wrd = (WORD) (((WORD) col_0->b * 2 + (WORD) col_1->b) / 3); - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - wrd = (WORD) (((WORD) col_0->r + (WORD) col_1->r * 2) / 3); - col_3->r = (BYTE)wrd; - - wrd = (WORD) (((WORD) col_0->g + (WORD) col_1->g * 2) / 3); - col_3->g = (BYTE)wrd; - - wrd = (WORD) (((WORD) col_0->b + (WORD) col_1->b * 2) / 3); - col_3->b = (BYTE)wrd; - col_3->a = 0xff; - } - else - { - // Three-color block: derive the other color. - // 00 = color_0, 01 = color_1, 10 = color_2, - // 11 = transparent. - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - - // explicit for each component, unlike some refrasts... - - // Tracef("block has alpha\n"); - wrd = (WORD) (((WORD) col_0->r + (WORD) col_1->r) / 2); - col_2->r = (BYTE)wrd; - wrd = (WORD) (((WORD) col_0->g + (WORD) col_1->g) / 2); - col_2->g = (BYTE)wrd; - wrd = (WORD) (((WORD) col_0->b + (WORD) col_1->b) / 2); - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0x00; - col_3->b = 0x00; - col_3->a = 0x00; - } -} // Get color block colors (...) - - -inline void DecodeColorBlock(DWORD * pImPos, - DXTColBlock * pColorBlock, - int width, - DWORD * col_0, - DWORD * col_1, - DWORD * col_2, - DWORD * col_3) -{ - // width is width of image in pixels - DWORD bits; - int y, n; - - // bit masks = 00000011, 00001100, 00110000, 11000000 - const DWORD masks[] = { 3, 12, 3 << 4, 3 << 6 }; - const int shift[] = { 0, 2, 4, 6 }; - - // r steps through lines in y - for (y = 0; y < 4; ++y, pImPos += width - 4) // no width * 4 as DWORD ptr inc will * 4 - { - // width * 4 bytes per pixel per line - // each j dxtc row is 4 lines of pixels - - // pImPos = (DWORD*) ((DWORD) pBase + i * 16 + (y + j * 4) * m_nWidth * 4); - - // n steps through pixels - for (n = 0; n < 4; ++n) - { - bits = pColorBlock->row[y] & masks[n]; - bits >>= shift[n]; - - switch (bits) - { - case 0: - *pImPos = *col_0; - pImPos++; // increment to next DWORD - break; - - case 1: - *pImPos = *col_1; - pImPos++; - break; - - case 2: - *pImPos = *col_2; - pImPos++; - break; - - case 3: - *pImPos = *col_3; - pImPos++; - break; - - default: - Tracef("Your logic is jacked! bits == 0x%x\n", bits); - pImPos++; - break; - } - } - } -} - -inline void DecodeAlphaExplicit(DWORD * pImPos, DXTAlphaBlockExplicit * pAlphaBlock, - int width, DWORD alphazero) -{ - // alphazero is a bit mask that when & with the image color - // will zero the alpha bits, so if the image DWORDs are - // ARGB then alphazero will be 0x00ffffff or if - // RGBA then alphazero will be 0xffffff00 - // alphazero constructed automaticaly from field order of Color8888 structure - - // decodes to 32 bit format only - int row, pix; - - WORD wrd; - - Color8888 col; - col.r = col.g = col.b = 0; - - //Tracef("\n"); - for (row = 0; row < 4; row++, pImPos += width - 4) - { - // pImPow += pImPos += width-4 moves to next row down - wrd = pAlphaBlock->row[row]; - - // Tracef("0x%.8x\t\t", wrd); - for (pix = 0; pix < 4; ++pix) - { - // zero the alpha bits of image pixel - *pImPos &= alphazero; - - col.a = (BYTE) (wrd & 0x000f); // get only low 4 bits - // col.a <<= 4; // shift to full byte precision - // NOTE: with just a << 4 you'll never have alpha - // of 0xff, 0xf0 is max so pure shift doesn't quite - // cover full alpha range. - // It's much cheaper than divide & scale though. - // To correct for this, and get 0xff for max alpha, - // or the low bits back in after left shifting - col.a = (BYTE) (col.a | (col.a << 4)); // This allows max 4 bit alpha to be 0xff alpha - // in final image, and is crude approach to full - // range scale - - *pImPos |= *((DWORD*)&col); // or the bits into the prev. nulled alpha - - wrd >>= 4; // move next bits to lowest 4 - - pImPos++; // move to next pixel in the row - } - } -} - -static BYTE gBits[4][4]; -static WORD gAlphas[8]; -static Color8888 gACol[4][4]; - -inline void DecodeAlpha3BitLinear(DWORD * pImPos, DXTAlphaBlock3BitLinear * pAlphaBlock, - int width, DWORD alphazero) -{ - gAlphas[0] = pAlphaBlock->alpha0; - gAlphas[1] = pAlphaBlock->alpha1; - - // 8-alpha or 6-alpha block? - if (gAlphas[0] > gAlphas[1]) - { - // 8-alpha block: derive the other 6 alphas. - // 000 = alpha_0, 001 = alpha_1, others are interpolated - gAlphas[2] = (WORD) ((6 * gAlphas[0] + gAlphas[1]) / 7); // Bit code 010 - gAlphas[3] = (WORD) ((5 * gAlphas[0] + 2 * gAlphas[1]) / 7); // Bit code 011 - gAlphas[4] = (WORD) ((4 * gAlphas[0] + 3 * gAlphas[1]) / 7); // Bit code 100 - gAlphas[5] = (WORD) ((3 * gAlphas[0] + 4 * gAlphas[1]) / 7); // Bit code 101 - gAlphas[6] = (WORD) ((2 * gAlphas[0] + 5 * gAlphas[1]) / 7); // Bit code 110 - gAlphas[7] = (WORD) (( gAlphas[0] + 6 * gAlphas[1]) / 7); // Bit code 111 - } - else - { - // 6-alpha block: derive the other alphas. - // 000 = alpha_0, 001 = alpha_1, others are interpolated - gAlphas[2] = (WORD) ((4 * gAlphas[0] + gAlphas[1]) / 5); // Bit code 010 - gAlphas[3] = (WORD) ((3 * gAlphas[0] + 2 * gAlphas[1]) / 5); // Bit code 011 - gAlphas[4] = (WORD) ((2 * gAlphas[0] + 3 * gAlphas[1]) / 5); // Bit code 100 - gAlphas[5] = (WORD) (( gAlphas[0] + 4 * gAlphas[1]) / 5); // Bit code 101 - gAlphas[6] = 0; // Bit code 110 - gAlphas[7] = 255; // Bit code 111 - } - - // Decode 3-bit fields into array of 16 BYTES with same value - - // first two rows of 4 pixels each: - // pRows = (Alpha3BitRows*) & (pAlphaBlock->stuff[0]); - const DWORD mask = 0x00000007; // bits = 00 00 01 11 - DWORD bits = *((DWORD*) & (pAlphaBlock->stuff[0])); - - gBits[0][0] = (BYTE) (bits & mask); - bits >>= 3; - gBits[0][1] = (BYTE) (bits & mask); - bits >>= 3; - gBits[0][2] = (BYTE) (bits & mask); - bits >>= 3; - gBits[0][3] = (BYTE) (bits & mask); - bits >>= 3; - gBits[1][0] = (BYTE) (bits & mask); - bits >>= 3; - gBits[1][1] = (BYTE) (bits & mask); - bits >>= 3; - gBits[1][2] = (BYTE) (bits & mask); - bits >>= 3; - gBits[1][3] = (BYTE) (bits & mask); - - // now for last two rows: - bits = *((DWORD*) & (pAlphaBlock->stuff[3])); // last 3 bytes - - gBits[2][0] = (BYTE) (bits & mask); - bits >>= 3; - gBits[2][1] = (BYTE) (bits & mask); - bits >>= 3; - gBits[2][2] = (BYTE) (bits & mask); - bits >>= 3; - gBits[2][3] = (BYTE) (bits & mask); - bits >>= 3; - gBits[3][0] = (BYTE) (bits & mask); - bits >>= 3; - gBits[3][1] = (BYTE) (bits & mask); - bits >>= 3; - gBits[3][2] = (BYTE) (bits & mask); - bits >>= 3; - gBits[3][3] = (BYTE) (bits & mask); - - // decode the codes into alpha values - int row, pix; - - for (row = 0; row < 4; ++row) - { - for (pix = 0; pix < 4; ++pix) - { - gACol[row][pix].a = (BYTE) gAlphas[gBits[row][pix]]; - - assert(gACol[row][pix].r == 0); - assert(gACol[row][pix].g == 0); - assert(gACol[row][pix].b == 0); - } - } - - // Write out alpha values to the image bits - for (row = 0; row < 4; ++row, pImPos += width - 4) - { - // pImPow += pImPos += width - 4 moves to next row down - for (pix = 0; pix < 4; ++pix) - { - // zero the alpha bits of image pixel - *pImPos &= alphazero; - *pImPos |= *((DWORD*) &(gACol[row][pix])); // or the bits into the prev. nulled alpha - pImPos++; - } - } -} - -void CDXTCImage::DecompressDXT1(int miplevel, DWORD * pdwDest) -{ - // This was hacked up pretty quick & slopily - // decompresses to 32 bit format 0xARGB - int xblocks, yblocks; - - UINT nWidth = m_nWidth >> miplevel; - UINT nHeight = m_nHeight >> miplevel; - - xblocks = nWidth / 4; - yblocks = nHeight / 4; - - int x, y; - DWORD * pBase = (DWORD *) pdwDest; - WORD * pPos = (WORD *) &m_bCompVector[miplevel][0];; // pos in compressed data - DWORD * pImPos; - - DXTColBlock * pBlock; - - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - - for (y = 0; y < yblocks; ++y) - { - // 8 bytes per block - pBlock = (DXTColBlock *) ((uintptr_t) pPos + y * xblocks * 8); - - for (x = 0; x < xblocks; ++x, ++pBlock) - { - // inline func: - GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD *) ((uintptr_t) pBase + x*16 + (y*4) * nWidth * 4); - DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3); - // Set to RGB test pattern - // pImPos = (DWORD*) ((DWORD) pBase + i * 4 + j * m_nWidth * 4); - // *pImPos = ((i * 4) << 16) | ((j * 4) << 8) | ((63 - i) * 4); - - // checkerboard of only col_0 and col_1 basis colors: - // pImPos = (DWORD *) ((DWORD) pBase + i * 8 + j * m_nWidth * 8); - // *pImPos = *((DWORD *) &col_0); - // pImPos += 1 + m_nWidth; - // *pImPos = *((DWORD *) &col_1); - } - } -} - -void CDXTCImage::DecompressDXT3(int miplevel, DWORD* pdwDest) -{ - int xblocks, yblocks; - - UINT nWidth = m_nWidth >> miplevel; - UINT nHeight = m_nHeight >> miplevel; - - xblocks = nWidth / 4; - yblocks = nHeight / 4; - - int x, y; - DWORD * pBase = (DWORD *) pdwDest; - WORD * pPos = (WORD *) &m_bCompVector[miplevel][0]; // pos in compressed data - DWORD * pImPos; // pos in decompressed data - - DXTColBlock * pBlock; - DXTAlphaBlockExplicit * pAlphaBlock; - - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - - DWORD alphazero = *((DWORD *) &col_0); - - for (y = 0; y < yblocks; ++y) - { - // 8 bytes per block - // 1 block for alpha, 1 block for color - pBlock = (DXTColBlock *) ((uintptr_t) (pPos + y * xblocks * 16)); - - for (x = 0; x < xblocks; ++x, ++pBlock) - { - // inline - // Get alpha block - pAlphaBlock = (DXTAlphaBlockExplicit *) pBlock; - - // inline func: - // Get color block & colors - pBlock++; - GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - // Decode the color block into the bitmap bits - // inline func: - pImPos = (DWORD *) ((uintptr_t) (pBase + x * 16 + (y * 4) * nWidth * 4)); - - DecodeColorBlock(pImPos, - pBlock, - nWidth, - (DWORD *) &col_0, (DWORD *) &col_1, (DWORD *) &col_2, (DWORD *) &col_3); - - // Overwrite the previous alpha bits with the alpha block - // info - // inline func: - DecodeAlphaExplicit(pImPos, pAlphaBlock, nWidth, alphazero); - } - } -} - -void CDXTCImage::DecompressDXT5(int level, DWORD * pdwDest) -{ - int xblocks, yblocks; - - UINT nWidth = m_nWidth >> level; - UINT nHeight = m_nHeight >> level; - - xblocks = nWidth / 4; - yblocks = nHeight / 4; - - int x, y; - - DWORD * pBase = (DWORD *) pdwDest; - WORD * pPos = pPos = (WORD *) &m_bCompVector[level][0]; // pos in compressed data - DWORD * pImPos; // pos in decompressed data - - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD *) &col_0); - - //////////////////////////////// - // Tracef("blocks: x: %d y: %d\n", xblocks, yblocks); - for (y = 0; y < yblocks; ++y) - { - // 8 bytes per block - // 1 block for alpha, 1 block for color - pBlock = (DXTColBlock*) ((uintptr_t) (pPos + y * xblocks * 16)); - - for (x = 0; x < xblocks; ++x, ++pBlock) - { - // inline - // Get alpha block - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - - // inline func: - // Get color block & colors - pBlock++; - - // Tracef("pBlock: 0x%.8x\n", pBlock); - GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - // Decode the color block into the bitmap bits - // inline func: - pImPos = (DWORD *) ((uintptr_t) (pBase + x * 16 + (y * 4) * nWidth * 4)); - - //DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3); - DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3); - - // Overwrite the previous alpha bits with the alpha block - // info - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, nWidth, alphazero); - } - } -} // dxt5 - -void CDXTCImage::DecompressARGB(int level, DWORD * pdwDest) -{ - UINT lPitch = m_lPitch >> (level * 2); - memcpy(pdwDest, &m_bCompVector[level][0], lPitch); -} -/* -typedef struct _DDSURFACEDESC2 { -DWORD dwSize; -DWORD dwFlags; -DWORD dwHeight; -DWORD dwWidth; -union -{ -LONG lPitch; -DWORD dwLinearSize; -} DUMMYUNIONNAMEN(1); -DWORD dwBackBufferCount; -union -{ -DWORD dwMipMapCount; -DWORD dwRefreshRate; -} DUMMYUNIONNAMEN(2); -DWORD dwAlphaBitDepth; -DWORD dwReserved; -LPVOID lpSurface; -union -{ -DDCOLORKEY ddckCKDestOverlay; -DWORD dwEmptyFaceColor; -} DUMMYUNIONNAMEN(3); -DDCOLORKEY ddckCKDestBlt; -DDCOLORKEY ddckCKSrcOverlay; -DDCOLORKEY ddckCKSrcBlt; -DDPIXELFORMAT ddpfPixelFormat; -DDSCAPS2 ddsCaps; -DWORD dwTextureStage; -} DDSURFACEDESC2, FAR* LPDDSURFACEDESC2; -*/ - -//----------------------------------------------------------------------------- -// Name: GetNumberOfBits() -// Desc: Returns the number of bits set in a DWORD mask -// from microsoft mssdk d3dim sample "Compress" -//----------------------------------------------------------------------------- -static WORD GetNumberOfBits(DWORD dwMask) -{ - WORD wBits; - for (wBits = 0; dwMask; wBits++) - dwMask = (dwMask & (dwMask - 1)); - - return wBits; -} - -//----------------------------------------------------------------------------- -// Name: PixelFormatToString() -// Desc: Creates a string describing a pixel format. -// adapted from microsoft mssdk D3DIM Compress example -// PixelFormatToString() -//----------------------------------------------------------------------------- -VOID CDXTCImage::DecodePixelFormat(CHAR* strPixelFormat, XDDPIXELFORMAT* pxddpf) -{ - switch (pxddpf->dwFourCC) - { - case 0: - { - // This dds texture isn't compressed so write out ARGB format - WORD a = GetNumberOfBits(pxddpf->dwRGBAlphaBitMask); - WORD r = GetNumberOfBits(pxddpf->dwRBitMask); - WORD g = GetNumberOfBits(pxddpf->dwGBitMask); - WORD b = GetNumberOfBits(pxddpf->dwBBitMask); - - _snprintf(strPixelFormat, 31, "ARGB-%d%d%d%d%s", a, r, g, b, - pxddpf->dwBBitMask & DDPF_ALPHAPREMULT ? "-premul" : ""); - m_CompFormat = PF_ARGB; - } - break; - - case MAKEFOURCC('D','X','T','1'): - strncpy(strPixelFormat, "DXT1", 31); - m_CompFormat = PF_DXT1; - break; - - case MAKEFOURCC('D','X','T','2'): - strncpy(strPixelFormat, "DXT2", 31); - m_CompFormat = PF_DXT2; - break; - - case MAKEFOURCC('D','X','T','3'): - strncpy(strPixelFormat, "DXT3", 31); - m_CompFormat = PF_DXT3; - break; - - case MAKEFOURCC('D','X','T','4'): - strncpy(strPixelFormat, "DXT4", 31); - m_CompFormat = PF_DXT4; - break; - - case MAKEFOURCC('D','X','T','5'): - strncpy(strPixelFormat, "DXT5", 31); - m_CompFormat = PF_DXT5; - break; - - default: - strcpy(strPixelFormat, "Format Unknown"); - m_CompFormat = PF_UNKNOWN; - break; - } -} - -/* -// Struct to hold various timing values -struct TimingInfo -{ - LARGE_INTEGER m_start_clk; - LARGE_INTEGER m_end_clk; - - int m_nSamples; - LARGE_INTEGER m_interval_sum; // sum of all end-start, nSamples number added in - - CString m_csName; // text desc of what timed -}; - -void CDXTCImage::RunTimingSession() -{ - // Must have a dxt5 texture loaded - // No special reason - just lazy coding - // Functions called to time code are separate from non-timed - // code. It's alogorithm that counts. - ASSERT(m_pCompBytes != NULL); - ASSERT(m_pDecompBytes != NULL); // must already have allocated memory - - switch (m_CompFormat) - { - case PF_DXT1: - case PF_DXT2: - case PF_DXT3: - case PF_DXT4: - case PF_UNKNOWN: - Tracef("You must have a DXT5 texture loaded to RunTimingSession()!!\n"); - Tracef("Now I will be nasty and ASSERT(false)!\n"); - ASSERT(false); - break; - - case PF_DXT5: - Tracef("Running code timing session on DXT5 color decompress\n"); - break; - } - - LARGE_INTEGER start_clk, end_clk; - QueryPerformanceCounter(&start_clk); -#define NMETHOD 4 -#define NBATCHES 4 - int passes[NBATCHES]; - passes[0] = 1; - passes[1] = 10; - passes[2] = 30; - passes[3] = 50; - - TimingInfo method[NMETHOD][NBATCHES]; - - int i, n; - - FILE * pf = fopen("timing.txt", "wt"); - - if (pf == NULL) - { - return; - } - - fprintf(pf, "\n\n"); - - for (i = 0; i < NBATCHES; ++i) - { - Sleep(50); - fprintf(pf,"i: %d passes[i]: %d\n", i, passes[i]); - Time_Decomp5_01(passes[i], &(method[0][i])); - Time_Decomp5_02(passes[i], &(method[1][i])); - Time_Decomp5_03(passes[i], &(method[2][i])); - Time_Decomp5_04(passes[i], &(method[3][i])); - } - - QueryPerformanceCounter(&end_clk); - - // unsigned long total; - // total = (unsigned long) (end_clk - start_clk); - LARGE_INTEGER freq; - QueryPerformanceFrequency(& freq); - - fprintf(pf, "\nCounter freq = %u %d \n", freq.LowPart, freq.HighPart); - fprintf(pf, "start: %u %u end: %u %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart); - - Tracef("\nCounter freq = %u %d \n", freq.LowPart, freq.HighPart); - Tracef("start: %u %u end: %u %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart); - - double dur = ((double)end_clk.LowPart - (double)start_clk.LowPart) / (double)freq.LowPart; - - fprintf(pf, "Total timing session took: %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur); - fprintf(pf, "\n\n"); - - Tracef("Total timing session took: %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur); - Tracef("\n\n"); - - for (n = 0; n < NMETHOD; ++n) - { - for (i = 0; i < NBATCHES; ++i) - { - fprintf(pf, "method %d:\n", n); - fprintf(pf, " %s", method[n][i].m_csName); - fprintf(pf, " tot: %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); - - Tracef("method %d:\n", n); - Tracef(" %s", method[n][i].m_csName); - Tracef(" tot: %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); - - dur = ((double)method[n][i].m_interval_sum.LowPart) / ((double)method[n][i].m_nSamples * (double)freq.LowPart); - - fprintf(pf, " avg: %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples); - fprintf(pf, " avg time: %f sec\n", dur); - - Tracef(" avg: %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples); - Tracef(" avg time: %f sec\n", dur); - } - - fprintf(pf, "\n\n"); - Tracef("\n\n"); - } - - fclose(pf); - - MessageBeep(MB_OK); - //BOOL QueryPerformanceFrequency( - // LARGE_INTEGER *lpFrequency // address of current frequency - //); -} - -inline void GetColorBlockColors_m2(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - // method 2 - // freak variable bit structure method - // normal math - Color565 * pCol; - - pCol = (Color565*) & (pBlock->col0); - - col_0->a = 0xff; - col_0->r = pCol->nRed; - col_0->r <<= 3; // shift to full precision - col_0->g = pCol->nGreen; - col_0->g <<= 2; - col_0->b = pCol->nBlue; - col_0->b <<= 3; - - pCol = (Color565*) & (pBlock->col1); - col_1->a = 0xff; - col_1->r = pCol->nRed; - col_1->r <<= 3; // shift to full precision - col_1->g = pCol->nGreen; - col_1->g <<= 2; - col_1->b = pCol->nBlue; - col_1->b <<= 3; - - if (pBlock->col0 > pBlock->col1) - { - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3; - // no +1 for rounding - // as bits have been shifted to 888 - col_2->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3; - col_2->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3; - col_3->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3; - col_3->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3; - col_3->b = (BYTE)wrd; - col_3->a = 0xff; - - } - else - { - // Three-color block: derive the other color. - // 00 = color_0, 01 = color_1, 10 = color_2, - // 11 = transparent. - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - - // explicit for each component, unlike some refrasts... - - // Tracef("block has alpha\n"); - wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2; - col_2->r = (BYTE)wrd; - wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2; - col_2->g = (BYTE)wrd; - wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - col_3->a = 0x00; - } -} - - - -inline void GetColorBlockColors_m3(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - // method 3 - ////////////////////////////////////////////////////// - // super-freak variable bit structure with - // Cool Math Trick (tm) - - // Do 2/3 1/3 math BEFORE bit shift on the whole DWORD - // as the fields will NEVER carry into the next - // or overflow!! =) - - Color565 * pCol; - - pCol = (Color565*) & (pBlock->col0); - - col_0->a = 0x00; // must set to 0 to avoid overflow in DWORD add - col_0->r = pCol->nRed; - col_0->g = pCol->nGreen; - col_0->b = pCol->nBlue; - - pCol = (Color565*) & (pBlock->col1); - col_1->a = 0x00; - col_1->r = pCol->nRed; - col_1->g = pCol->nGreen; - col_1->b = pCol->nBlue; - - if (pBlock->col0 > pBlock->col1) - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1))); - - *((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2); - - // now shift to appropriate precision & divide by 3. - col_2->r = ((WORD) col_2->r << 3) / (WORD)3; - col_2->g = ((WORD) col_2->g << 2) / (WORD)3; - col_2->b = ((WORD) col_2->b << 3) / (WORD)3; - - col_3->r = ((WORD) col_3->r << 3) / (WORD)3; - col_3->g = ((WORD) col_3->g << 2) / (WORD)3; - col_3->b = ((WORD) col_3->b << 3) / (WORD)3; - - col_0->a = 0xff; // now set appropriate alpha - col_1->a = 0xff; - col_2->a = 0xff; - col_3->a = 0xff; - } - else - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1))); - - // now shift to appropriate precision & divide by 2. - // << 3) / 2 == << 2 - // << 2) / 2 == << 1 - col_2->r = ((WORD) col_2->r << 2); - col_2->g = ((WORD) col_2->g << 1); - col_2->b = ((WORD) col_2->b << 2); - - col_2->a = 0xff; - - col_3->a = 0x00; // - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - } - - // now shift orig color components - col_0->r <<= 3; - col_0->g <<= 2; - col_0->b <<= 3; - - col_1->r <<= 3; - col_1->g <<= 2; - col_1->b <<= 3; -} - - -inline void GetColorBlockColors_m4(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - - // m1 color extraction from 5-6-5 - // m3 color math on DWORD before bit shift to full precision - wrd = pBlock->col0; - col_0->a = 0x00; // must set to 0 to avoid possible overflow & carry to next field in DWORD add - - // extract r,g,b bits - col_0->b = (unsigned char) wrd & 0x1f; // 0x1f = 0001 1111 to mask out upper 3 bits - wrd >>= 5; - col_0->g = (unsigned char) wrd & 0x3f; // 0x3f = 0011 1111 to mask out upper 2 bits - wrd >>= 6; - col_0->r = (unsigned char) wrd & 0x1f; - - - // same for col # 2: - wrd = pBlock->col1; - col_1->a = 0x00; // must set to 0 to avoid possible overflow in DWORD add - - // extract r,g,b bits - col_1->b = (unsigned char) wrd & 0x1f; - wrd >>= 5; - col_1->g = (unsigned char) wrd & 0x3f; - wrd >>= 6; - col_1->r = (unsigned char) wrd & 0x1f; - - if (pBlock->col0 > pBlock->col1) - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1))); - *((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2); - - // shift to appropriate precision & divide by 3. - col_2->r = ((WORD) col_2->r << 3) / (WORD)3; - col_2->g = ((WORD) col_2->g << 2) / (WORD)3; - col_2->b = ((WORD) col_2->b << 3) / (WORD)3; - - col_3->r = ((WORD) col_3->r << 3) / (WORD)3; - col_3->g = ((WORD) col_3->g << 2) / (WORD)3; - col_3->b = ((WORD) col_3->b << 3) / (WORD)3; - - col_0->a = 0xff; // set appropriate alpha - col_1->a = 0xff; - col_2->a = 0xff; - col_3->a = 0xff; - } - else - { - *((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1))); - - // shift to appropriate precision & divide by 2. - // << 3) / 2 == << 2 - // << 2) / 2 == << 1 - col_2->r = ((WORD) col_2->r << 2); - col_2->g = ((WORD) col_2->g << 1); - col_2->b = ((WORD) col_2->b << 2); - - col_2->a = 0xff; - - col_3->a = 0x00; // - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - } - - // shift orig color components to full precision - col_0->r <<= 3; - col_0->g <<= 2; - col_0->b <<= 3; - - col_1->r <<= 3; - col_1->g <<= 2; - col_1->b <<= 3; -} - - -inline void GetColorBlockColors_m1(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, - Color8888 * col_2, Color8888 * col_3, - WORD & wrd ) -{ - - // Method 1: - // Shifty method - wrd = pBlock->col0; - col_0->a = 0xff; - - // extract r,g,b bits - col_0->b = (unsigned char) wrd; - col_0->b <<= 3; // shift to full precision - wrd >>= 5; - col_0->g = (unsigned char) wrd; - col_0->g <<= 2; // shift to full precision - wrd >>= 6; - col_0->r = (unsigned char) wrd; - col_0->r <<= 3; // shift to full precision - - // same for col # 2: - wrd = pBlock->col1; - col_1->a = 0xff; - - // extract r,g,b bits - col_1->b = (unsigned char) wrd; - col_1->b <<= 3; // shift to full precision - wrd >>= 5; - col_1->g = (unsigned char) wrd; - col_1->g <<= 2; // shift to full precision - wrd >>= 6; - col_1->r = (unsigned char) wrd; - col_1->r <<= 3; // shift to full precision - - // use this for all but the super-freak math method - if (pBlock->col0 > pBlock->col1) - { - // Four-color block: derive the other two colors. - // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - - wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3; - // no +1 for rounding - // as bits have been shifted to 888 - col_2->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3; - col_2->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3; - col_3->r = (BYTE)wrd; - - wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3; - col_3->g = (BYTE)wrd; - - wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3; - col_3->b = (BYTE)wrd; - col_3->a = 0xff; - } - else - { - // Three-color block: derive the other color. - // 00 = color_0, 01 = color_1, 10 = color_2, - // 11 = transparent. - // These two bit codes correspond to the 2-bit fields - // stored in the 64-bit block. - - // explicit for each component, unlike some refrasts... - - // Tracef("block has alpha\n"); - - wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2; - col_2->r = (BYTE)wrd; - wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2; - col_2->g = (BYTE)wrd; - wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2; - col_2->b = (BYTE)wrd; - col_2->a = 0xff; - - col_3->r = 0x00; // random color to indicate alpha - col_3->g = 0xff; - col_3->b = 0xff; - col_3->a = 0x00; - } -} // Get color block colors (...) - -void CDXTCImage::Time_Decomp5_01(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 1: bit shift, for %d times\n", ntimes); - - for (n = 0; n < ntimes; n++) - { - QueryPerformanceCounter(& info->m_start_clk); - - int xblocks, yblocks; - - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - - int i,j; - - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m1(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples ++; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - } -} - - -void CDXTCImage::Time_Decomp5_02(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 2: bit field struct, for %d times\n", ntimes); - - for (n = 0; n < ntimes; n++) - { - QueryPerformanceCounter(& info->m_start_clk); - - int xblocks, yblocks; - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - int i,j; - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m2(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples ++; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - } -} - -void CDXTCImage::Time_Decomp5_03(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 3: bit field struct w/ pre-shift math, for %d times\n", ntimes); - - for (n = 0; n < ntimes; n++) - { - QueryPerformanceCounter(& info->m_start_clk); - - int xblocks, yblocks; - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - int i,j; - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m3(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples ++; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - } -} - - -void CDXTCImage::Time_Decomp5_04(int ntimes, TimingInfo * info) -{ - int n; - - info->m_nSamples = 0; - info->m_interval_sum.QuadPart = 0; - info->m_csName.Format("Timing decomp method 4: shift extract w/ pre-shift math, for %d times\n", ntimes); - - QueryPerformanceCounter(& info->m_start_clk); - - for (n = 0; n < ntimes; n++) - { - int xblocks, yblocks; - xblocks = m_DDSD.dwWidth / 4; - yblocks = m_DDSD.dwHeight / 4; - int i,j; - DWORD * pBase = (DWORD*) m_pDecompBytes; - DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data - WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data - DXTColBlock * pBlock; - DXTAlphaBlock3BitLinear * pAlphaBlock; - Color8888 col_0, col_1, col_2, col_3; - WORD wrd; - // fill alphazero with appropriate value to zero out alpha when - // alphazero is ANDed with the image color 32 bit DWORD: - col_0.a = 0; - col_0.r = col_0.g = col_0.b = 0xff; - DWORD alphazero = *((DWORD*) &col_0); - - // ** See DecompressDXT5 code for comments!! - for (j = 0; j < yblocks; ++j) - { - pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); - for (i = 0; i < xblocks; ++i, ++pBlock) - { - pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; - pBlock++; - - GetColorBlockColors_m4(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); - - pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); - DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, - (DWORD*)&col_2, (DWORD*)&col_3); - DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); - } - } - } - - QueryPerformanceCounter(& info->m_end_clk); - - info->m_nSamples = ntimes; - info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; - -} -*/ diff --git a/src/EterImageLib/DXTCImage.h b/src/EterImageLib/DXTCImage.h deleted file mode 100644 index 7337fd5..0000000 --- a/src/EterImageLib/DXTCImage.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef AFX_IMAGE_DXTC_H__4B89D8D0_7857_11D4_9630_00A0C996DE3D__INCLUDED_ -#define AFX_IMAGE_DXTC_H__4B89D8D0_7857_11D4_9630_00A0C996DE3D__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include - -enum EPixFormat -{ - PF_ARGB, - PF_DXT1, - PF_DXT2, - PF_DXT3, - PF_DXT4, - PF_DXT5, - PF_UNKNOWN -}; - -#define MAX_MIPLEVELS 12 - -#ifndef DUMMYUNIONNAMEN -#if defined(__cplusplus) || !defined(NONAMELESSUNION) -#define DUMMYUNIONNAMEN(n) -#else -#define DUMMYUNIONNAMEN(n) u##n -#endif -#endif - -typedef struct _XDDPIXELFORMAT -{ - DWORD dwSize; // size of structure - DWORD dwFlags; // pixel format flags - DWORD dwFourCC; // (FOURCC code) - - union - { - DWORD dwRGBBitCount; // how many bits per pixel - DWORD dwYUVBitCount; // how many bits per pixel - DWORD dwZBufferBitDepth; // how many total bits/pixel in z buffer (including any stencil bits) - DWORD dwAlphaBitDepth; // how many bits for alpha channels - DWORD dwLuminanceBitCount; // how many bits per pixel - DWORD dwBumpBitCount; // how many bits per "buxel", total - DWORD dwPrivateFormatBitCount;// Bits per pixel of private driver formats. Only valid in texture - // format list and if DDPF_D3DFORMAT is set - } DUMMYUNIONNAMEN(1); - union - { - DWORD dwRBitMask; // mask for red bit - DWORD dwYBitMask; // mask for Y bits - DWORD dwStencilBitDepth; // how many stencil bits (note: dwZBufferBitDepth-dwStencilBitDepth is total Z-only bits) - DWORD dwLuminanceBitMask; // mask for luminance bits - DWORD dwBumpDuBitMask; // mask for bump map U delta bits - DWORD dwOperations; // DDPF_D3DFORMAT Operations - } DUMMYUNIONNAMEN(2); - union - { - DWORD dwGBitMask; // mask for green bits - DWORD dwUBitMask; // mask for U bits - DWORD dwZBitMask; // mask for Z bits - DWORD dwBumpDvBitMask; // mask for bump map V delta bits - struct - { - WORD wFlipMSTypes; // Multisample methods supported via flip for this D3DFORMAT - WORD wBltMSTypes; // Multisample methods supported via blt for this D3DFORMAT - } MultiSampleCaps; - - } DUMMYUNIONNAMEN(3); - union - { - DWORD dwBBitMask; // mask for blue bits - DWORD dwVBitMask; // mask for V bits - DWORD dwStencilBitMask; // mask for stencil bits - DWORD dwBumpLuminanceBitMask; // mask for luminance in bump map - } DUMMYUNIONNAMEN(4); - union - { - DWORD dwRGBAlphaBitMask; // mask for alpha channel - DWORD dwYUVAlphaBitMask; // mask for alpha channel - DWORD dwLuminanceAlphaBitMask;// mask for alpha channel - DWORD dwRGBZBitMask; // mask for Z channel - DWORD dwYUVZBitMask; // mask for Z channel - } DUMMYUNIONNAMEN(5); -} XDDPIXELFORMAT; - - -class CDXTCImage -{ - public: - CDXTCImage(); - virtual ~CDXTCImage(); - - void Initialize(); - void Clear(); - - public: - const BYTE * m_pbCompBufferByLevels[MAX_MIPLEVELS]; - std::vector m_bCompVector[MAX_MIPLEVELS]; - - int m_nCompSize; - int m_nCompLineSz; - - char m_strFormat[32]; - EPixFormat m_CompFormat; - - long m_lPitch; - DWORD m_dwMipMapCount; - bool m_bMipTexture; // texture has mipmaps? - DWORD m_dwFlags; - - int m_nWidth; // in pixels of uncompressed image - int m_nHeight; - - XDDPIXELFORMAT m_xddPixelFormat; - - bool LoadFromFile(const char * filename); // true if success - bool LoadFromMemory(const BYTE * c_pbMap); - bool LoadHeaderFromMemory(const BYTE * c_pbMap); - bool Copy(int miplevel, BYTE * pbDest, long lDestPitch); - - void Decompress(int miplevel, DWORD * pdwDest); - void DecompressDXT1(int miplevel, DWORD * pdwDest); - void DecompressDXT3(int miplevel, DWORD * pdwDest); - void DecompressDXT5(int miplevel, DWORD * pdwDest); - void DecompressARGB(int miplevel, DWORD * pdwDest); - - VOID DecodePixelFormat(CHAR* strPixelFormat, XDDPIXELFORMAT* pddpf); - - void Unextract(BYTE * pbDest, int iWidth, int iHeight, int iPitch); - /* - struct TimingInfo; // defined in Image_DXTC.cpp - void RunTimingSession(); // run a few methods & time the code - - // must use dxt5 texture - void Time_Decomp5_01(int ntimes, TimingInfo * info); - void Time_Decomp5_02(int ntimes, TimingInfo * info); - void Time_Decomp5_03(int ntimes, TimingInfo * info); - void Time_Decomp5_04(int ntimes, TimingInfo * info); - */ -}; - -#endif // #ifndef AFX_IMAGE_DXTC_H__4B89D8D0_7857_11D4_9630_00A0C996DE3D__INCLUDED_ diff --git a/src/EterImageLib/STBImageImplementation.cpp b/src/EterImageLib/STBImageImplementation.cpp new file mode 100644 index 0000000..45ae7f7 --- /dev/null +++ b/src/EterImageLib/STBImageImplementation.cpp @@ -0,0 +1,7 @@ +#include "StdAfx.h" + +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION + +#include +#include diff --git a/src/EterLib/GrpImageTexture.cpp b/src/EterLib/GrpImageTexture.cpp index 331cc76..0dd408a 100644 --- a/src/EterLib/GrpImageTexture.cpp +++ b/src/EterLib/GrpImageTexture.cpp @@ -1,7 +1,10 @@ #include "StdAfx.h" -#include "../eterBase/MappedFile.h" -#include "../eterPack/EterPackManager.h" +#include "EterBase/MappedFile.h" +#include "EterPack/EterPackManager.h" #include "GrpImageTexture.h" +#include "EterImageLib/DDSTextureLoader9.h" + +#include bool CGraphicImageTexture::Lock(int* pRetPitch, void** ppRetPixels, int level) { @@ -76,130 +79,66 @@ bool CGraphicImageTexture::Create(UINT width, UINT height, D3DFORMAT d3dFmt, DWO return CreateDeviceObjects(); } -void CGraphicImageTexture::CreateFromTexturePointer(const CGraphicTexture * c_pSrcTexture) +void CGraphicImageTexture::CreateFromTexturePointer(const CGraphicTexture* c_pSrcTexture) { if (m_lpd3dTexture) m_lpd3dTexture->Release(); - + m_width = c_pSrcTexture->GetWidth(); m_height = c_pSrcTexture->GetHeight(); m_lpd3dTexture = c_pSrcTexture->GetD3DTexture(); - + if (m_lpd3dTexture) m_lpd3dTexture->AddRef(); m_bEmpty = false; } -bool CGraphicImageTexture::CreateDDSTexture(CDXTCImage & image, const BYTE * /*c_pbBuf*/) +bool CGraphicImageTexture::CreateFromDDSTexture(UINT bufSize, const void* c_pvBuf) { - int mipmapCount = image.m_dwMipMapCount == 0 ? 1 : image.m_dwMipMapCount; - - D3DFORMAT format; - LPDIRECT3DTEXTURE9 lpd3dTexture; - D3DPOOL pool = ms_bSupportDXT ? D3DPOOL_MANAGED : D3DPOOL_SCRATCH;; - - if(image.m_CompFormat == PF_DXT5) - format = D3DFMT_DXT5; - else if(image.m_CompFormat == PF_DXT3) - format = D3DFMT_DXT3; - else - format = D3DFMT_DXT1; - - UINT uTexBias=0; - if (IsLowTextureMemory()) - uTexBias=1; - - UINT uMinMipMapIndex=0; - if (uTexBias>0) - { - if (mipmapCount>uTexBias) - { - uMinMipMapIndex=uTexBias; - image.m_nWidth>>=uTexBias; - image.m_nHeight>>=uTexBias; - mipmapCount-=uTexBias; - } - } - - if (FAILED(D3DXCreateTexture( ms_lpd3dDevice, image.m_nWidth, image.m_nHeight, - mipmapCount, 0, format, pool, &lpd3dTexture))) - { - TraceError("CreateDDSTexture: Cannot creatre texture"); + if (FAILED(DirectX::CreateDDSTextureFromMemoryEx(ms_lpd3dDevice, reinterpret_cast(c_pvBuf), bufSize, 0, D3DPOOL_MANAGED, false, &m_lpd3dTexture))) return false; - } - for (DWORD i = 0; i < mipmapCount; ++i) - { - D3DLOCKED_RECT lockedRect; + D3DSURFACE_DESC desc; + m_lpd3dTexture->GetLevelDesc(0, &desc); + m_width = desc.Width; + m_height = desc.Height; + m_bEmpty = false; + return true; +} - if (FAILED(lpd3dTexture->LockRect(i, &lockedRect, NULL, 0))) - { - TraceError("CreateDDSTexture: Cannot lock texture"); - } - else - { - image.Copy(i+uMinMipMapIndex, (BYTE*)lockedRect.pBits, lockedRect.Pitch); - lpd3dTexture->UnlockRect(i); - } - } - - if(ms_bSupportDXT) - { - m_lpd3dTexture = lpd3dTexture; - } - else - { - if(image.m_CompFormat == PF_DXT3 || image.m_CompFormat == PF_DXT5) - format = D3DFMT_A4R4G4B4; - else - format = D3DFMT_A1R5G5B5; - - UINT imgWidth=image.m_nWidth; - UINT imgHeight=image.m_nHeight; - - extern bool GRAPHICS_CAPS_HALF_SIZE_IMAGE; - - if (GRAPHICS_CAPS_HALF_SIZE_IMAGE && uTexBias>0 && mipmapCount==0) - { - imgWidth>>=uTexBias; - imgHeight>>=uTexBias; - } - - if (FAILED(D3DXCreateTexture( ms_lpd3dDevice, imgWidth, imgHeight, - mipmapCount, 0, format, D3DPOOL_MANAGED, &m_lpd3dTexture))) - { - TraceError("CreateDDSTexture: Cannot creatre texture"); - return false; - } - - IDirect3DTexture9* pkTexSrc=lpd3dTexture; - IDirect3DTexture9* pkTexDst=m_lpd3dTexture; - - for(int i=0; iGetSurfaceLevel(i, &ppsSrc))) - { - if (SUCCEEDED(pkTexDst->GetSurfaceLevel(i, &ppsDst))) - { - D3DXLoadSurfaceFromSurface(ppsDst, NULL, NULL, ppsSrc, NULL, NULL, D3DX_FILTER_NONE, 0); - ppsDst->Release(); +bool CGraphicImageTexture::CreateFromSTB(UINT bufSize, const void* c_pvBuf) +{ + int width, height, channels; + unsigned char* data = stbi_load_from_memory((stbi_uc*)c_pvBuf, bufSize, &width, &height, &channels, 4); // force RGBA + if (data) { + LPDIRECT3DTEXTURE9 texture; + if (SUCCEEDED(ms_lpd3dDevice->CreateTexture(width, height, 1, 0, channels == 4 ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &texture, nullptr))) { + D3DLOCKED_RECT rect; + if (SUCCEEDED(texture->LockRect(0, &rect, nullptr, 0))) { + uint8_t* dstData = (uint8_t*)rect.pBits; + uint8_t* srcData = (uint8_t*)data; + for (size_t i = 0; i < width * height; ++i, dstData += 4, srcData += 4) { + dstData[0] = srcData[2]; + dstData[1] = srcData[1]; + dstData[2] = srcData[0]; + dstData[3] = srcData[3]; } - ppsSrc->Release(); + + texture->UnlockRect(0); + m_width = width; + m_height = height; + m_bEmpty = false; + m_lpd3dTexture = texture; + } + else { + texture->Release(); } } - - lpd3dTexture->Release(); + stbi_image_free(data); } - m_width = image.m_nWidth; - m_height = image.m_nHeight; - m_bEmpty = false; - - return true; + return !m_bEmpty; } bool CGraphicImageTexture::CreateFromMemoryFile(UINT bufSize, const void * c_pvBuf, D3DFORMAT d3dFmt, DWORD dwFilter) @@ -207,41 +146,24 @@ bool CGraphicImageTexture::CreateFromMemoryFile(UINT bufSize, const void * c_pvB assert(ms_lpd3dDevice != NULL); assert(m_lpd3dTexture == NULL); - static CDXTCImage image; + m_bEmpty = true; - if (image.LoadHeaderFromMemory((const BYTE *) c_pvBuf)) // DDS인가 확인 - { - return (CreateDDSTexture(image, (const BYTE *) c_pvBuf)); - } - else - { - D3DXIMAGE_INFO imageInfo; - if (FAILED(D3DXCreateTextureFromFileInMemoryEx( - ms_lpd3dDevice, - c_pvBuf, - bufSize, - D3DX_DEFAULT, - D3DX_DEFAULT, - D3DX_DEFAULT, - 0, - d3dFmt, - D3DPOOL_MANAGED, - dwFilter, - dwFilter, - 0xffff00ff, - &imageInfo, - NULL, - &m_lpd3dTexture))) - { - TraceError("CreateFromMemoryFile: Cannot create texture"); - return false; - } + if (!CreateFromDDSTexture(bufSize, c_pvBuf)) { + if (!CreateFromSTB(bufSize, c_pvBuf)) { - m_width = imageInfo.Width; - m_height = imageInfo.Height; + D3DXIMAGE_INFO imageInfo; + if (FAILED(D3DXCreateTextureFromFileInMemoryEx(ms_lpd3dDevice, c_pvBuf, bufSize + , D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT, 0, d3dFmt, D3DPOOL_MANAGED + , dwFilter, dwFilter, 0xffff00ff, &imageInfo, NULL, &m_lpd3dTexture))) { + TraceError("CreateFromMemoryFile: Cannot create texture"); + return false; + } - D3DFORMAT format=imageInfo.Format; - switch(imageInfo.Format) { + m_width = imageInfo.Width; + m_height = imageInfo.Height; + + D3DFORMAT format = imageInfo.Format; + switch (imageInfo.Format) { case D3DFMT_A8R8G8B8: format = D3DFMT_A4R4G4B4; break; @@ -250,50 +172,41 @@ bool CGraphicImageTexture::CreateFromMemoryFile(UINT bufSize, const void * c_pvB case D3DFMT_R8G8B8: format = D3DFMT_A1R5G5B5; break; - } + } - UINT uTexBias=0; + UINT uTexBias = 0; - extern bool GRAPHICS_CAPS_HALF_SIZE_IMAGE; - if (GRAPHICS_CAPS_HALF_SIZE_IMAGE) - uTexBias=1; + extern bool GRAPHICS_CAPS_HALF_SIZE_IMAGE; + if (GRAPHICS_CAPS_HALF_SIZE_IMAGE) + uTexBias = 1; - if (IsLowTextureMemory()) - if (uTexBias || format!=imageInfo.Format) - { - IDirect3DTexture9* pkTexSrc=m_lpd3dTexture; - IDirect3DTexture9* pkTexDst; - - - if (SUCCEEDED(D3DXCreateTexture( - ms_lpd3dDevice, - imageInfo.Width>>uTexBias, - imageInfo.Height>>uTexBias, - imageInfo.MipLevels, - 0, - format, - D3DPOOL_MANAGED, - &pkTexDst))) - { - m_lpd3dTexture=pkTexDst; - - for(int i=0; iGetSurfaceLevel(i, &ppsSrc))) - { - if (SUCCEEDED(pkTexDst->GetSurfaceLevel(i, &ppsDst))) - { - D3DXLoadSurfaceFromSurface(ppsDst, NULL, NULL, ppsSrc, NULL, NULL, D3DX_FILTER_LINEAR, 0); - ppsDst->Release(); + if (SUCCEEDED(D3DXCreateTexture(ms_lpd3dDevice + , imageInfo.Width >> uTexBias, imageInfo.Height >> uTexBias + , imageInfo.MipLevels, 0, format, D3DPOOL_MANAGED, &pkTexDst))) { + m_lpd3dTexture = pkTexDst; + for (int i = 0; i < imageInfo.MipLevels; ++i) { + + IDirect3DSurface9* ppsSrc = NULL; + IDirect3DSurface9* ppsDst = NULL; + + if (SUCCEEDED(pkTexSrc->GetSurfaceLevel(i, &ppsSrc))) { + if (SUCCEEDED(pkTexDst->GetSurfaceLevel(i, &ppsDst))) { + D3DXLoadSurfaceFromSurface(ppsDst, NULL, NULL, ppsSrc, NULL, NULL, D3DX_FILTER_LINEAR, 0); + ppsDst->Release(); + } + ppsSrc->Release(); + } } - ppsSrc->Release(); + + pkTexSrc->Release(); } } - - pkTexSrc->Release(); } } } diff --git a/src/EterLib/GrpImageTexture.h b/src/EterLib/GrpImageTexture.h index 18f4588..34b6f69 100644 --- a/src/EterLib/GrpImageTexture.h +++ b/src/EterLib/GrpImageTexture.h @@ -1,7 +1,6 @@ #pragma once #include "GrpTexture.h" -#include "../eterImageLib/DXTCImage.h" class CGraphicImageTexture : public CGraphicTexture { @@ -17,7 +16,8 @@ class CGraphicImageTexture : public CGraphicTexture void CreateFromTexturePointer(const CGraphicTexture* c_pSrcTexture); bool CreateFromDiskFile(const char* c_szFileName, D3DFORMAT d3dFmt, DWORD dwFilter = D3DX_FILTER_LINEAR); bool CreateFromMemoryFile(UINT bufSize, const void* c_pvBuf, D3DFORMAT d3dFmt, DWORD dwFilter = D3DX_FILTER_LINEAR); - bool CreateDDSTexture(CDXTCImage & image, const BYTE * c_pbBuf); + bool CreateFromDDSTexture(UINT bufSize, const void* c_pvBuf); + bool CreateFromSTB(UINT bufSize, const void* c_pvBuf); void SetFileName(const char * c_szFileName); diff --git a/src/UserInterface/MarkImage.cpp b/src/UserInterface/MarkImage.cpp index b77e802..5be6482 100644 --- a/src/UserInterface/MarkImage.cpp +++ b/src/UserInterface/MarkImage.cpp @@ -1,10 +1,8 @@ #include "stdafx.h" #include "MarkImage.h" -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image.h" -#include "stb_image_write.h" +#include +#include #if !defined(_MSC_VER) #include