Initial commit

This commit is contained in:
sean
2021-10-19 03:48:18 +02:00
commit aca51cdd61
6 changed files with 686 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
cmake-build-debug/*
cmake-build-release/*

6
CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.0)
project(dds_image LANGUAGES CXX)
add_library(dds_image INTERFACE)
target_include_directories(dds_image INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/)

22
LICENSE Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2021 spnda.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

42
README.md Normal file
View File

@@ -0,0 +1,42 @@
# dds_image
A C++11 single-header DDS (DirectDraw Surface) image library,
with no dependencies.
It also includes utilities to work with Vulkan, as well
as optional support for C++17 specific features.
You can quickly add this as a submodule and add the header files,
or import it as a subdirectory in CMake.
### Example
```cpp
#include <dds.hpp>
dds::Image image;
dds::readFile("example.dds", &image);
```
On MSVC you might need to build with `/Zc:__cplusplus` for the built-in C++17 features to work.
You can then optionally also define `DDS_USE_STD_FILESYSTEM`, which will make `dds::readFile` accept
a `std::filesystem::path` instead.
### Vulkan Usage
If you want to use the built-in Vulkan features, you **have** to include
the Vulkan header before you import this library.
To create the VkImage and VkImageView you can use the following two functions.
Note that you still need to set some fields yourself, most notably `VkImageCreateInfo::usage`,
`VkImageCreateInfo::samples` and `VkImageViewCreateInfo::image`.
```cpp
#include <vulkan/vulkan.h> // Before!
#include <dds.hpp>
```
```cpp
// Optional, for own usage.
VkImageFormat imageFormat = dds::getVulkanFormat(image.format, image.supportsAlpha);
// Will automatically fill VkImageCreateInfo::format with a separate call to dds::getVulkanFormat.
VkImageCreateInfo imageCreateInfo = dds::getVulkanImageCreateInfo(&image);
VkImageViewCreateInfo imageViewCreateInfo = dds::getVulkanImageViewCreateInfo(&image);
```

346
include/dds.hpp Normal file
View File

@@ -0,0 +1,346 @@
#pragma once
#if __cplusplus > 201703L && defined(DDS_USE_STD_FILESYSTEM)
#include <filesystem>
namespace fs = std::filesystem;
#endif
#include <fstream>
#include <iostream>
#include "dds_formats.hpp"
#if __cplusplus > 201703L
#define NO_DISCARD [[nodiscard]]
#else
#define NO_DISCARD
#endif
namespace dds {
NO_DISCARD inline uint32_t getBlockSize(const DXGI_FORMAT format) {
switch (format) {
case DXGI_FORMAT_BC1_UNORM:
case DXGI_FORMAT_BC1_UNORM_SRGB:
case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM:
return 8;
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC2_UNORM_SRGB:
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC3_UNORM_SRGB:
case DXGI_FORMAT_BC5_UNORM:
case DXGI_FORMAT_BC5_SNORM:
return 16;
default:
return 0;
}
}
NO_DISCARD inline uint32_t getBitsPerPixel(const DXGI_FORMAT format) {
switch (format) {
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_R32G32B32A32_UINT:
case DXGI_FORMAT_R32G32B32A32_SINT:
return 128;
case DXGI_FORMAT_R32G32B32_TYPELESS:
case DXGI_FORMAT_R32G32B32_FLOAT:
case DXGI_FORMAT_R32G32B32_UINT:
case DXGI_FORMAT_R32G32B32_SINT:
return 96;
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
case DXGI_FORMAT_R16G16B16A16_FLOAT:
case DXGI_FORMAT_R16G16B16A16_UNORM:
case DXGI_FORMAT_R16G16B16A16_UINT:
case DXGI_FORMAT_R16G16B16A16_SNORM:
case DXGI_FORMAT_R16G16B16A16_SINT:
case DXGI_FORMAT_R32G32_TYPELESS:
case DXGI_FORMAT_R32G32_FLOAT:
case DXGI_FORMAT_R32G32_UINT:
case DXGI_FORMAT_R32G32_SINT:
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
return 64;
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_R10G10B10A2_UINT:
case DXGI_FORMAT_R11G11B10_FLOAT:
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
case DXGI_FORMAT_R8G8B8A8_UINT:
case DXGI_FORMAT_R8G8B8A8_SNORM:
case DXGI_FORMAT_R8G8B8A8_SINT:
case DXGI_FORMAT_R16G16_TYPELESS:
case DXGI_FORMAT_R16G16_FLOAT:
case DXGI_FORMAT_R16G16_UNORM:
case DXGI_FORMAT_R16G16_UINT:
case DXGI_FORMAT_R16G16_SNORM:
case DXGI_FORMAT_R16G16_SINT:
case DXGI_FORMAT_R32_TYPELESS:
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_UINT:
case DXGI_FORMAT_R32_SINT:
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
case DXGI_FORMAT_R8G8_B8G8_UNORM:
case DXGI_FORMAT_G8R8_G8B8_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8X8_UNORM:
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
return 32;
case DXGI_FORMAT_R8G8_TYPELESS:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R8G8_UINT:
case DXGI_FORMAT_R8G8_SNORM:
case DXGI_FORMAT_R8G8_SINT:
case DXGI_FORMAT_R16_TYPELESS:
case DXGI_FORMAT_R16_FLOAT:
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16_UINT:
case DXGI_FORMAT_R16_SNORM:
case DXGI_FORMAT_R16_SINT:
case DXGI_FORMAT_B5G6R5_UNORM:
case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_B4G4R4A4_UNORM:
return 16;
case DXGI_FORMAT_R8_TYPELESS:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8_UINT:
case DXGI_FORMAT_R8_SNORM:
case DXGI_FORMAT_R8_SINT:
case DXGI_FORMAT_A8_UNORM:
return 8;
case DXGI_FORMAT_R1_UNORM:
return 1;
case DXGI_FORMAT_BC1_TYPELESS:
case DXGI_FORMAT_BC1_UNORM:
case DXGI_FORMAT_BC1_UNORM_SRGB:
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
case DXGI_FORMAT_BC4_SNORM:
return 4;
case DXGI_FORMAT_BC2_TYPELESS:
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC2_UNORM_SRGB:
case DXGI_FORMAT_BC3_TYPELESS:
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC3_UNORM_SRGB:
case DXGI_FORMAT_BC5_TYPELESS:
case DXGI_FORMAT_BC5_UNORM:
case DXGI_FORMAT_BC5_SNORM:
case DXGI_FORMAT_BC6H_TYPELESS:
case DXGI_FORMAT_BC6H_UF16:
case DXGI_FORMAT_BC6H_SF16:
case DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT_BC7_UNORM_SRGB:
return 8;
default:
return 0;
}
}
#ifdef VK_VERSION_1_0
NO_DISCARD inline VkFormat getVulkanFormat(DXGI_FORMAT format, const bool alphaFlag) {
switch (format) {
case DXGI_FORMAT_BC1_UNORM: {
if (alphaFlag) return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
else return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
}
case DXGI_FORMAT_BC1_UNORM_SRGB: {
if (alphaFlag) return VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
else return VK_FORMAT_BC1_RGB_SRGB_BLOCK;
}
case DXGI_FORMAT_BC2_UNORM: return VK_FORMAT_BC2_UNORM_BLOCK;
case DXGI_FORMAT_BC2_UNORM_SRGB: return VK_FORMAT_BC2_SRGB_BLOCK;
case DXGI_FORMAT_BC3_UNORM: return VK_FORMAT_BC3_UNORM_BLOCK;
case DXGI_FORMAT_BC3_UNORM_SRGB: return VK_FORMAT_BC3_SRGB_BLOCK;
case DXGI_FORMAT_BC4_UNORM: return VK_FORMAT_BC4_UNORM_BLOCK;
case DXGI_FORMAT_BC4_SNORM: return VK_FORMAT_BC4_SNORM_BLOCK;
case DXGI_FORMAT_BC5_UNORM: return VK_FORMAT_BC5_UNORM_BLOCK;
case DXGI_FORMAT_BC5_SNORM: return VK_FORMAT_BC5_SNORM_BLOCK;
case DXGI_FORMAT_R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM;
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return VK_FORMAT_R8G8B8A8_SRGB;
case DXGI_FORMAT_R8G8B8A8_UINT: return VK_FORMAT_R8G8B8A8_UINT;
case DXGI_FORMAT_R8G8B8A8_SNORM: return VK_FORMAT_R8G8B8A8_SNORM;
case DXGI_FORMAT_R8G8B8A8_SINT: return VK_FORMAT_R8G8B8A8_SINT;
case DXGI_FORMAT_B8G8R8A8_UNORM: return VK_FORMAT_B8G8R8A8_UNORM;
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return VK_FORMAT_B8G8R8A8_SRGB;
case DXGI_FORMAT_R16G16B16A16_FLOAT: return VK_FORMAT_R16G16B16A16_SFLOAT;
case DXGI_FORMAT_R16G16B16A16_SINT: return VK_FORMAT_R16G16B16A16_SINT;
case DXGI_FORMAT_R16G16B16A16_UINT: return VK_FORMAT_R16G16B16A16_UINT;
case DXGI_FORMAT_R16G16B16A16_UNORM: return VK_FORMAT_R16G16B16A16_UNORM;
case DXGI_FORMAT_R16G16B16A16_SNORM: return VK_FORMAT_R16G16B16A16_SNORM;
case DXGI_FORMAT_R8G8_B8G8_UNORM:
case DXGI_FORMAT_G8R8_G8B8_UNORM:
case DXGI_FORMAT_YUY2:
default:
return VK_FORMAT_UNDEFINED;
}
}
NO_DISCARD inline VkImageCreateInfo getVulkanImageCreateInfo(dds::Image* image) {
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
switch (image->dimension) {
case Texture1D: imageInfo.imageType = VK_IMAGE_TYPE_1D; break;
case Texture2D: imageInfo.imageType = VK_IMAGE_TYPE_2D; break;
case Texture3D: imageInfo.imageType = VK_IMAGE_TYPE_3D; break;
default: break;
}
imageInfo.format = getVulkanFormat(image->format, image->supportsAlpha);
imageInfo.extent.width = image->width;
imageInfo.extent.height = image->height;
imageInfo.extent.depth = image->depth;
imageInfo.mipLevels = image->numMips;
imageInfo.arrayLayers = image->arraySize;
return imageInfo;
}
NO_DISCARD inline VkImageViewCreateInfo getVulkanImageViewCreateInfo(dds::Image* image) {
VkImageViewCreateInfo imageViewInfo = {};
imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.format = getVulkanFormat(image->format, image->supportsAlpha);
imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewInfo.subresourceRange.baseMipLevel = 0;
imageViewInfo.subresourceRange.levelCount = image->numMips;
imageViewInfo.subresourceRange.baseArrayLayer = 0;
imageViewInfo.subresourceRange.layerCount = image->arraySize;
return imageViewInfo;
}
#endif // #ifdef VK_VERSION_1_0
#if __cplusplus > 201703L && defined(DDS_USE_STD_FILESYSTEM)
NO_DISCARD inline dds::ReadResult readFile(const fs::path& filepath, dds::Image* image) {
#else
NO_DISCARD inline dds::ReadResult readFile(const std::string& filepath, dds::Image* image) {
#endif
std::ifstream filestream(filepath, std::ios::binary | std::ios::in);
if (!filestream.is_open())
return dds::ReadResult::Failure;
// Read the file into a vector.
filestream.seekg(0, std::ios::end);
size_t fileSize = filestream.tellg();
image->data.resize(fileSize);
filestream.seekg(0);
filestream.read(image->data.data(), static_cast<int64_t>(fileSize));
// Read the magic number
auto* ptr = image->data.data();
auto* ddsMagic = reinterpret_cast<uint32_t*>(ptr);
ptr += 4;
// Read the header
if (fileSize < sizeof(dds::FileHeader))
return dds::ReadResult::Failure;
const auto* header = reinterpret_cast<const dds::FileHeader*>(ptr);
ptr += sizeof(dds::FileHeader);
// Validate header
if (*ddsMagic != dds::DdsMagicNumber::DDS)
return dds::ReadResult::Failure;
// UNDO_FOUR_CHARACTER_CODE(header->pixelFormat.fourCC, fourCCStr);
// std::cout << fourCCStr << std::endl;
if (header->pixelFormat.flags & PixelFormatFlags::FourCC) {
const dds::Dx10Header* additionalHeader;
switch (header->pixelFormat.fourCC) {
case dds::DdsMagicNumber::DX10: {
additionalHeader = reinterpret_cast<const dds::Dx10Header*>(ptr);
ptr += sizeof(dds::Dx10Header);
image->arraySize = additionalHeader->arraySize;
image->format = additionalHeader->dxgiFormat;
image->dimension = additionalHeader->resourceDimension;
break;
}
case DXT1: image->format = DXGI_FORMAT_BC1_UNORM; break;
case DXT2: case DXT3: image->format = DXGI_FORMAT_BC2_UNORM; break;
case DXT4: case DXT5: image->format = DXGI_FORMAT_BC3_UNORM; break;
case ATI1: case BC4U: image->format = DXGI_FORMAT_BC4_UNORM; break;
case BC4S: image->format = DXGI_FORMAT_BC4_SNORM; break;
case ATI2: case BC5U: image->format = DXGI_FORMAT_BC5_UNORM; break;
case BC5S: image->format = DXGI_FORMAT_BC5_SNORM; break;
default:
return ReadResult::UnsupportedFormat;
}
} else {
if (header->pixelFormat.flags & PixelFormatFlags::RGB) {
}
}
if (header->flags & HeaderFlags::Volume || header->caps2 & Caps2Flags::Cubemap) {
image->dimension = Texture3D;
} else {
image->dimension = Texture2D;
}
const auto blockSizeBytes = getBlockSize(image->format);
const auto pixelSizeBits = getBitsPerPixel(image->format);
if (!blockSizeBytes && !pixelSizeBits)
return dds::ReadResult::UnsupportedFormat;
// Read the image fileSize
uint32_t totalOffset = 0;
{
auto width = header->width;
auto height = header->height;
for (uint32_t mip = 0; mip < header->mipmapCount; ++mip) {
uint32_t surfaceSize;
if (blockSizeBytes) {
auto temp = ((width + 3) / 4);
surfaceSize = ((1 < temp) ? temp : 1) * blockSizeBytes;
} else {
const auto pitch = ((width * pixelSizeBits) + 7) / 8; // Divide by 8 for byte alignment.
surfaceSize = pitch * height;
}
totalOffset += surfaceSize;
// Not going to include <algorithm> just for std::max.
uint32_t halfWidth = width / 2;
width = (1u < halfWidth) ? halfWidth : 1u;
uint32_t halfHeight = height / 2;
height = (1u < halfHeight) ? halfHeight : 1u;
}
}
const auto ddsSize = ptr - fileSize + size_t(totalOffset);
// if (ddsSize > fileSize || ddsSize < fileSize)
// return dds::ReadResult::InvalidSize;
image->numMips = header->mipmapCount;
image->width = header->width;
image->height = header->height;
image->supportsAlpha = header->hasAlphaFlag();
// Close the file and return success
filestream.close();
return dds::ReadResult::Success;
}
}

268
include/dds_formats.hpp Normal file
View File

@@ -0,0 +1,268 @@
#pragma once
#include <vector>
#define MAKE_FOUR_CHARACTER_CODE(char1, char2, char3, char4) \
static_cast<uint32_t>(char1) | \
(static_cast<uint32_t>(char2) << 8) | \
(static_cast<uint32_t>(char3) << 16) | \
(static_cast<uint32_t>(char4) << 24)
#define UNDO_FOUR_CHARACTER_CODE(x, name) \
std::string name; \
name.reserve(4); \
name.push_back(x >> 0); \
name.push_back(x >> 8); \
name.push_back(x >> 16); \
name.push_back(x >> 24); \
#ifndef __dxgiformat_h__ // We'll try and act as if we're the actual dxgiformat.h header.
#define __dxgiformat_h__
// See https://docs.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
enum DXGI_FORMAT {
DXGI_FORMAT_UNKNOWN = 0,
DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
DXGI_FORMAT_R32G32B32A32_UINT = 3,
DXGI_FORMAT_R32G32B32A32_SINT = 4,
DXGI_FORMAT_R32G32B32_TYPELESS = 5,
DXGI_FORMAT_R32G32B32_FLOAT = 6,
DXGI_FORMAT_R32G32B32_UINT = 7,
DXGI_FORMAT_R32G32B32_SINT = 8,
DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
DXGI_FORMAT_R16G16B16A16_UNORM = 11,
DXGI_FORMAT_R16G16B16A16_UINT = 12,
DXGI_FORMAT_R16G16B16A16_SNORM = 13,
DXGI_FORMAT_R16G16B16A16_SINT = 14,
DXGI_FORMAT_R32G32_TYPELESS = 15,
DXGI_FORMAT_R32G32_FLOAT = 16,
DXGI_FORMAT_R32G32_UINT = 17,
DXGI_FORMAT_R32G32_SINT = 18,
DXGI_FORMAT_R32G8X24_TYPELESS = 19,
DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
DXGI_FORMAT_R10G10B10A2_UNORM = 24,
DXGI_FORMAT_R10G10B10A2_UINT = 25,
DXGI_FORMAT_R11G11B10_FLOAT = 26,
DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
DXGI_FORMAT_R8G8B8A8_UNORM = 28,
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
DXGI_FORMAT_R8G8B8A8_UINT = 30,
DXGI_FORMAT_R8G8B8A8_SNORM = 31,
DXGI_FORMAT_R8G8B8A8_SINT = 32,
DXGI_FORMAT_R16G16_TYPELESS = 33,
DXGI_FORMAT_R16G16_FLOAT = 34,
DXGI_FORMAT_R16G16_UNORM = 35,
DXGI_FORMAT_R16G16_UINT = 36,
DXGI_FORMAT_R16G16_SNORM = 37,
DXGI_FORMAT_R16G16_SINT = 38,
DXGI_FORMAT_R32_TYPELESS = 39,
DXGI_FORMAT_D32_FLOAT = 40,
DXGI_FORMAT_R32_FLOAT = 41,
DXGI_FORMAT_R32_UINT = 42,
DXGI_FORMAT_R32_SINT = 43,
DXGI_FORMAT_R24G8_TYPELESS = 44,
DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
DXGI_FORMAT_R8G8_TYPELESS = 48,
DXGI_FORMAT_R8G8_UNORM = 49,
DXGI_FORMAT_R8G8_UINT = 50,
DXGI_FORMAT_R8G8_SNORM = 51,
DXGI_FORMAT_R8G8_SINT = 52,
DXGI_FORMAT_R16_TYPELESS = 53,
DXGI_FORMAT_R16_FLOAT = 54,
DXGI_FORMAT_D16_UNORM = 55,
DXGI_FORMAT_R16_UNORM = 56,
DXGI_FORMAT_R16_UINT = 57,
DXGI_FORMAT_R16_SNORM = 58,
DXGI_FORMAT_R16_SINT = 59,
DXGI_FORMAT_R8_TYPELESS = 60,
DXGI_FORMAT_R8_UNORM = 61,
DXGI_FORMAT_R8_UINT = 62,
DXGI_FORMAT_R8_SNORM = 63,
DXGI_FORMAT_R8_SINT = 64,
DXGI_FORMAT_A8_UNORM = 65,
DXGI_FORMAT_R1_UNORM = 66,
DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
DXGI_FORMAT_BC1_TYPELESS = 70,
DXGI_FORMAT_BC1_UNORM = 71,
DXGI_FORMAT_BC1_UNORM_SRGB = 72,
DXGI_FORMAT_BC2_TYPELESS = 73,
DXGI_FORMAT_BC2_UNORM = 74,
DXGI_FORMAT_BC2_UNORM_SRGB = 75,
DXGI_FORMAT_BC3_TYPELESS = 76,
DXGI_FORMAT_BC3_UNORM = 77,
DXGI_FORMAT_BC3_UNORM_SRGB = 78,
DXGI_FORMAT_BC4_TYPELESS = 79,
DXGI_FORMAT_BC4_UNORM = 80,
DXGI_FORMAT_BC4_SNORM = 81,
DXGI_FORMAT_BC5_TYPELESS = 82,
DXGI_FORMAT_BC5_UNORM = 83,
DXGI_FORMAT_BC5_SNORM = 84,
DXGI_FORMAT_B5G6R5_UNORM = 85,
DXGI_FORMAT_B5G5R5A1_UNORM = 86,
DXGI_FORMAT_B8G8R8A8_UNORM = 87,
DXGI_FORMAT_B8G8R8X8_UNORM = 88,
DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
DXGI_FORMAT_BC6H_TYPELESS = 94,
DXGI_FORMAT_BC6H_UF16 = 95,
DXGI_FORMAT_BC6H_SF16 = 96,
DXGI_FORMAT_BC7_TYPELESS = 97,
DXGI_FORMAT_BC7_UNORM = 98,
DXGI_FORMAT_BC7_UNORM_SRGB = 99,
DXGI_FORMAT_AYUV = 100,
DXGI_FORMAT_Y410 = 101,
DXGI_FORMAT_Y416 = 102,
DXGI_FORMAT_NV12 = 103,
DXGI_FORMAT_P010 = 104,
DXGI_FORMAT_P016 = 105,
DXGI_FORMAT_420_OPAQUE = 106,
DXGI_FORMAT_YUY2 = 107,
DXGI_FORMAT_Y210 = 108,
DXGI_FORMAT_Y216 = 109,
DXGI_FORMAT_NV11 = 110,
DXGI_FORMAT_AI44 = 111,
DXGI_FORMAT_IA44 = 112,
DXGI_FORMAT_P8 = 113,
DXGI_FORMAT_A8P8 = 114,
DXGI_FORMAT_B4G4R4A4_UNORM = 115,
DXGI_FORMAT_P208 = 130,
DXGI_FORMAT_V208 = 131,
DXGI_FORMAT_V408 = 132,
DXGI_FORMAT_FORCE_UINT = 0xffffffff
};
#endif // #ifndef __dxgiformat_h__
namespace dds {
enum ResourceDimension {
Unknown,
Buffer,
Texture1D,
Texture2D,
Texture3D
};
enum ReadResult {
Success = 0,
Failure = -1,
UnsupportedFormat = -2,
NoDx10Header = -3,
InvalidSize = -4,
};
enum DdsMagicNumber {
DDS = MAKE_FOUR_CHARACTER_CODE('D', 'D', 'S', ' '),
DXT1 = MAKE_FOUR_CHARACTER_CODE('D', 'X', 'T', '1'), // BC1_UNORM
DXT2 = MAKE_FOUR_CHARACTER_CODE('D', 'X', 'T', '2'), // BC2_UNORM
DXT3 = MAKE_FOUR_CHARACTER_CODE('D', 'X', 'T', '3'), // BC2_UNORM
DXT4 = MAKE_FOUR_CHARACTER_CODE('D', 'X', 'T', '4'), // BC3_UNORM
DXT5 = MAKE_FOUR_CHARACTER_CODE('D', 'X', 'T', '5'), // BC3_UNORM
ATI1 = MAKE_FOUR_CHARACTER_CODE('A', 'T', 'I', '1'), // BC4_UNORM
BC4U = MAKE_FOUR_CHARACTER_CODE('B', 'C', '4', 'U'), // BC4_UNORM
BC4S = MAKE_FOUR_CHARACTER_CODE('B', 'C', '4', 'S'), // BC4_SNORM
ATI2 = MAKE_FOUR_CHARACTER_CODE('A', 'T', 'I', '2'), // BC5_UNORM
BC5U = MAKE_FOUR_CHARACTER_CODE('B', 'C', '5', 'U'), // BC5_UNORM
BC5S = MAKE_FOUR_CHARACTER_CODE('B', 'C', '5', 'S'), // BC5_SNORM
RGBG = MAKE_FOUR_CHARACTER_CODE('R', 'G', 'B', 'G'), // R8G8_B8G8_UNORM
GRBG = MAKE_FOUR_CHARACTER_CODE('G', 'R', 'B', 'G'), // G8R8_G8B8_UNORM
YUY2 = MAKE_FOUR_CHARACTER_CODE('Y', 'U', 'Y', '2'), // YUY2
UYVY = MAKE_FOUR_CHARACTER_CODE('U', 'Y', 'V', 'Y'),
DX10 = MAKE_FOUR_CHARACTER_CODE('D', 'X', '1', '0'),
};
enum PixelFormatFlags : uint32_t {
AlphaPixels = 0x1,
Alpha = 0x2,
FourCC = 0x4,
PAL8 = 0x20,
RGB = 0x40,
RGBA = RGB | AlphaPixels,
YUV = 0x200,
Luminance = 0x20000,
LuminanceA = Luminance | AlphaPixels,
};
struct FilePixelFormat {
uint32_t size;
PixelFormatFlags flags;
uint32_t fourCC;
uint32_t bitCount;
uint32_t rBitMask;
uint32_t gBitMask;
uint32_t bBitMask;
uint32_t aBitMask;
};
enum HeaderFlags : uint32_t {
Caps = 0x1,
Height = 0x2,
Width = 0x4,
Pitch = 0x8,
PixelFormat = 0x1000,
Texture = Caps | Height | Width | PixelFormat,
Mipmap = 0x20000,
Volume = 0x800000,
LinearSize = 0x00080000,
};
enum Caps2Flags : uint32_t {
Cubemap = 0x200,
};
struct FileHeader {
uint32_t size;
HeaderFlags flags;
uint32_t height;
uint32_t width;
uint32_t pitch;
uint32_t depth;
uint32_t mipmapCount;
uint32_t reserved[11];
FilePixelFormat pixelFormat;
uint32_t caps1;
uint32_t caps2;
uint32_t caps3;
uint32_t caps4;
uint32_t reserved2;
bool hasAlphaFlag() const;
};
static_assert(sizeof(FileHeader) == 124, "DDS Header size mismatch. Must be 124 bytes.");
bool FileHeader::hasAlphaFlag() const {
return !!(pixelFormat.flags & PixelFormatFlags::AlphaPixels);
}
/** An additional header for DX10 */
struct Dx10Header {
DXGI_FORMAT dxgiFormat;
ResourceDimension resourceDimension;
uint32_t miscFlags;
uint32_t arraySize;
uint32_t miscFlags2;
};
struct Image {
uint32_t numMips;
uint32_t arraySize = 1;
uint32_t width = 1;
uint32_t height = 1;
uint32_t depth = 1;
ResourceDimension dimension;
bool supportsAlpha = false;
DXGI_FORMAT format;
std::vector<char> data = {};
};
}