2085 lines
73 KiB
C
2085 lines
73 KiB
C
|
// MIT license see full LICENSE text at end of file
|
||
|
#pragma once
|
||
|
#ifndef TINY_DDS_TINYDDS_H
|
||
|
#define TINY_DDS_TINYDDS_H
|
||
|
|
||
|
#ifndef TINYDDS_HAVE_UINTXX_T
|
||
|
#include <stdint.h> // for uint32_t and int64_t
|
||
|
#endif
|
||
|
#ifndef TINYDDS_HAVE_BOOL
|
||
|
#include <stdbool.h> // for bool
|
||
|
#endif
|
||
|
#ifndef TINYDDS_HAVE_SIZE_T
|
||
|
#include <stddef.h> // for size_t
|
||
|
#endif
|
||
|
#ifndef TINYDDS_HAVE_MEMCPY
|
||
|
#include <string.h> // for memcpy
|
||
|
#endif
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
|
||
|
#define TINYDDS_MAX_MIPMAPLEVELS 16
|
||
|
|
||
|
typedef struct TinyDDS_Context *TinyDDS_ContextHandle;
|
||
|
|
||
|
typedef void *(*TinyDDS_AllocFunc)(void *user, size_t size);
|
||
|
typedef void (*TinyDDS_FreeFunc)(void *user, void *memory);
|
||
|
typedef size_t (*TinyDDS_ReadFunc)(void *user, void *buffer, size_t byteCount);
|
||
|
typedef bool (*TinyDDS_SeekFunc)(void *user, int64_t offset);
|
||
|
typedef int64_t (*TinyDDS_TellFunc)(void *user);
|
||
|
typedef void (*TinyDDS_ErrorFunc)(void *user, char const *msg);
|
||
|
|
||
|
typedef struct TinyDDS_Callbacks {
|
||
|
TinyDDS_ErrorFunc errorFn;
|
||
|
TinyDDS_AllocFunc allocFn;
|
||
|
TinyDDS_FreeFunc freeFn;
|
||
|
TinyDDS_ReadFunc readFn;
|
||
|
TinyDDS_SeekFunc seekFn;
|
||
|
TinyDDS_TellFunc tellFn;
|
||
|
} TinyDDS_Callbacks;
|
||
|
|
||
|
TinyDDS_ContextHandle TinyDDS_CreateContext(TinyDDS_Callbacks const *callbacks, void *user);
|
||
|
void TinyDDS_DestroyContext(TinyDDS_ContextHandle handle);
|
||
|
|
||
|
// reset lets you reuse the context for another file (saves an alloc/free cycle)
|
||
|
void TinyDDS_Reset(TinyDDS_ContextHandle handle);
|
||
|
|
||
|
// call this to read the header file should already be at the start of the KTX data
|
||
|
bool TinyDDS_ReadHeader(TinyDDS_ContextHandle handle);
|
||
|
|
||
|
bool TinyDDS_Is1D(TinyDDS_ContextHandle handle);
|
||
|
bool TinyDDS_Is2D(TinyDDS_ContextHandle handle);
|
||
|
bool TinyDDS_Is3D(TinyDDS_ContextHandle handle);
|
||
|
bool TinyDDS_IsCubemap(TinyDDS_ContextHandle handle);
|
||
|
bool TinyDDS_IsArray(TinyDDS_ContextHandle handle);
|
||
|
|
||
|
bool TinyDDS_Dimensions(TinyDDS_ContextHandle handle,
|
||
|
uint32_t *width,
|
||
|
uint32_t *height,
|
||
|
uint32_t *depth,
|
||
|
uint32_t *slices);
|
||
|
uint32_t TinyDDS_Width(TinyDDS_ContextHandle handle);
|
||
|
uint32_t TinyDDS_Height(TinyDDS_ContextHandle handle);
|
||
|
uint32_t TinyDDS_Depth(TinyDDS_ContextHandle handle);
|
||
|
uint32_t TinyDDS_ArraySlices(TinyDDS_ContextHandle handle);
|
||
|
|
||
|
bool TinyDDS_NeedsGenerationOfMipmaps(TinyDDS_ContextHandle handle);
|
||
|
bool TinyDDS_NeedsEndianCorrecting(TinyDDS_ContextHandle handle);
|
||
|
|
||
|
uint32_t TinyDDS_NumberOfMipmaps(TinyDDS_ContextHandle handle);
|
||
|
uint32_t TinyDDS_ImageSize(TinyDDS_ContextHandle handle, uint32_t mipmaplevel);
|
||
|
|
||
|
// data return by ImageRawData is owned by the context. Don't free it!
|
||
|
void const *TinyDDS_ImageRawData(TinyDDS_ContextHandle handle, uint32_t mipmaplevel);
|
||
|
|
||
|
typedef void (*TinyDDS_WriteFunc)(void *user, void const *buffer, size_t byteCount);
|
||
|
|
||
|
typedef struct TinyDDS_WriteCallbacks {
|
||
|
TinyDDS_ErrorFunc error;
|
||
|
TinyDDS_AllocFunc alloc;
|
||
|
TinyDDS_FreeFunc free;
|
||
|
TinyDDS_WriteFunc write;
|
||
|
} TinyDDS_WriteCallbacks;
|
||
|
|
||
|
#ifndef TINYIMAGEFORMAT_DXGIFORMAT
|
||
|
#define TINYIMAGEFORMAT_DXGIFORMAT
|
||
|
|
||
|
// early DDS was a direct copy of the Draw Draw surface bits, later on (Dx10) it moved to
|
||
|
// DXGI_FORMAT we use a similar thing to DXGI_FORMAT second form but will synthesis
|
||
|
// the old style when required when saving and vice versa when loading.
|
||
|
typedef enum TinyImageFormat_DXGI_FORMAT {
|
||
|
TIF_DXGI_FORMAT_UNKNOWN = 0,
|
||
|
TIF_DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
|
||
|
TIF_DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
|
||
|
TIF_DXGI_FORMAT_R32G32B32A32_UINT = 3,
|
||
|
TIF_DXGI_FORMAT_R32G32B32A32_SINT = 4,
|
||
|
TIF_DXGI_FORMAT_R32G32B32_TYPELESS = 5,
|
||
|
TIF_DXGI_FORMAT_R32G32B32_FLOAT = 6,
|
||
|
TIF_DXGI_FORMAT_R32G32B32_UINT = 7,
|
||
|
TIF_DXGI_FORMAT_R32G32B32_SINT = 8,
|
||
|
TIF_DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
|
||
|
TIF_DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
|
||
|
TIF_DXGI_FORMAT_R16G16B16A16_UNORM = 11,
|
||
|
TIF_DXGI_FORMAT_R16G16B16A16_UINT = 12,
|
||
|
TIF_DXGI_FORMAT_R16G16B16A16_SNORM = 13,
|
||
|
TIF_DXGI_FORMAT_R16G16B16A16_SINT = 14,
|
||
|
TIF_DXGI_FORMAT_R32G32_TYPELESS = 15,
|
||
|
TIF_DXGI_FORMAT_R32G32_FLOAT = 16,
|
||
|
TIF_DXGI_FORMAT_R32G32_UINT = 17,
|
||
|
TIF_DXGI_FORMAT_R32G32_SINT = 18,
|
||
|
TIF_DXGI_FORMAT_R32G8X24_TYPELESS = 19,
|
||
|
TIF_DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
|
||
|
TIF_DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
|
||
|
TIF_DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
|
||
|
TIF_DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
|
||
|
TIF_DXGI_FORMAT_R10G10B10A2_UNORM = 24,
|
||
|
TIF_DXGI_FORMAT_R10G10B10A2_UINT = 25,
|
||
|
TIF_DXGI_FORMAT_R11G11B10_FLOAT = 26,
|
||
|
TIF_DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
|
||
|
TIF_DXGI_FORMAT_R8G8B8A8_UNORM = 28,
|
||
|
TIF_DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
|
||
|
TIF_DXGI_FORMAT_R8G8B8A8_UINT = 30,
|
||
|
TIF_DXGI_FORMAT_R8G8B8A8_SNORM = 31,
|
||
|
TIF_DXGI_FORMAT_R8G8B8A8_SINT = 32,
|
||
|
TIF_DXGI_FORMAT_R16G16_TYPELESS = 33,
|
||
|
TIF_DXGI_FORMAT_R16G16_FLOAT = 34,
|
||
|
TIF_DXGI_FORMAT_R16G16_UNORM = 35,
|
||
|
TIF_DXGI_FORMAT_R16G16_UINT = 36,
|
||
|
TIF_DXGI_FORMAT_R16G16_SNORM = 37,
|
||
|
TIF_DXGI_FORMAT_R16G16_SINT = 38,
|
||
|
TIF_DXGI_FORMAT_R32_TYPELESS = 39,
|
||
|
TIF_DXGI_FORMAT_D32_FLOAT = 40,
|
||
|
TIF_DXGI_FORMAT_R32_FLOAT = 41,
|
||
|
TIF_DXGI_FORMAT_R32_UINT = 42,
|
||
|
TIF_DXGI_FORMAT_R32_SINT = 43,
|
||
|
TIF_DXGI_FORMAT_R24G8_TYPELESS = 44,
|
||
|
TIF_DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
|
||
|
TIF_DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
|
||
|
TIF_DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
|
||
|
TIF_DXGI_FORMAT_R8G8_TYPELESS = 48,
|
||
|
TIF_DXGI_FORMAT_R8G8_UNORM = 49,
|
||
|
TIF_DXGI_FORMAT_R8G8_UINT = 50,
|
||
|
TIF_DXGI_FORMAT_R8G8_SNORM = 51,
|
||
|
TIF_DXGI_FORMAT_R8G8_SINT = 52,
|
||
|
TIF_DXGI_FORMAT_R16_TYPELESS = 53,
|
||
|
TIF_DXGI_FORMAT_R16_FLOAT = 54,
|
||
|
TIF_DXGI_FORMAT_D16_UNORM = 55,
|
||
|
TIF_DXGI_FORMAT_R16_UNORM = 56,
|
||
|
TIF_DXGI_FORMAT_R16_UINT = 57,
|
||
|
TIF_DXGI_FORMAT_R16_SNORM = 58,
|
||
|
TIF_DXGI_FORMAT_R16_SINT = 59,
|
||
|
TIF_DXGI_FORMAT_R8_TYPELESS = 60,
|
||
|
TIF_DXGI_FORMAT_R8_UNORM = 61,
|
||
|
TIF_DXGI_FORMAT_R8_UINT = 62,
|
||
|
TIF_DXGI_FORMAT_R8_SNORM = 63,
|
||
|
TIF_DXGI_FORMAT_R8_SINT = 64,
|
||
|
TIF_DXGI_FORMAT_A8_UNORM = 65,
|
||
|
TIF_DXGI_FORMAT_R1_UNORM = 66,
|
||
|
TIF_DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
|
||
|
TIF_DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
|
||
|
TIF_DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
|
||
|
TIF_DXGI_FORMAT_BC1_TYPELESS = 70,
|
||
|
TIF_DXGI_FORMAT_BC1_UNORM = 71,
|
||
|
TIF_DXGI_FORMAT_BC1_UNORM_SRGB = 72,
|
||
|
TIF_DXGI_FORMAT_BC2_TYPELESS = 73,
|
||
|
TIF_DXGI_FORMAT_BC2_UNORM = 74,
|
||
|
TIF_DXGI_FORMAT_BC2_UNORM_SRGB = 75,
|
||
|
TIF_DXGI_FORMAT_BC3_TYPELESS = 76,
|
||
|
TIF_DXGI_FORMAT_BC3_UNORM = 77,
|
||
|
TIF_DXGI_FORMAT_BC3_UNORM_SRGB = 78,
|
||
|
TIF_DXGI_FORMAT_BC4_TYPELESS = 79,
|
||
|
TIF_DXGI_FORMAT_BC4_UNORM = 80,
|
||
|
TIF_DXGI_FORMAT_BC4_SNORM = 81,
|
||
|
TIF_DXGI_FORMAT_BC5_TYPELESS = 82,
|
||
|
TIF_DXGI_FORMAT_BC5_UNORM = 83,
|
||
|
TIF_DXGI_FORMAT_BC5_SNORM = 84,
|
||
|
TIF_DXGI_FORMAT_B5G6R5_UNORM = 85,
|
||
|
TIF_DXGI_FORMAT_B5G5R5A1_UNORM = 86,
|
||
|
TIF_DXGI_FORMAT_B8G8R8A8_UNORM = 87,
|
||
|
TIF_DXGI_FORMAT_B8G8R8X8_UNORM = 88,
|
||
|
TIF_DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
|
||
|
TIF_DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
|
||
|
TIF_DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
|
||
|
TIF_DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
|
||
|
TIF_DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
|
||
|
TIF_DXGI_FORMAT_BC6H_TYPELESS = 94,
|
||
|
TIF_DXGI_FORMAT_BC6H_UF16 = 95,
|
||
|
TIF_DXGI_FORMAT_BC6H_SF16 = 96,
|
||
|
TIF_DXGI_FORMAT_BC7_TYPELESS = 97,
|
||
|
TIF_DXGI_FORMAT_BC7_UNORM = 98,
|
||
|
TIF_DXGI_FORMAT_BC7_UNORM_SRGB = 99,
|
||
|
TIF_DXGI_FORMAT_AYUV = 100,
|
||
|
TIF_DXGI_FORMAT_Y410 = 101,
|
||
|
TIF_DXGI_FORMAT_Y416 = 102,
|
||
|
TIF_DXGI_FORMAT_NV12 = 103,
|
||
|
TIF_DXGI_FORMAT_P010 = 104,
|
||
|
TIF_DXGI_FORMAT_P016 = 105,
|
||
|
TIF_DXGI_FORMAT_420_OPAQUE = 106,
|
||
|
TIF_DXGI_FORMAT_YUY2 = 107,
|
||
|
TIF_DXGI_FORMAT_Y210 = 108,
|
||
|
TIF_DXGI_FORMAT_Y216 = 109,
|
||
|
TIF_DXGI_FORMAT_NV11 = 110,
|
||
|
TIF_DXGI_FORMAT_AI44 = 111,
|
||
|
TIF_DXGI_FORMAT_IA44 = 112,
|
||
|
TIF_DXGI_FORMAT_P8 = 113,
|
||
|
TIF_DXGI_FORMAT_A8P8 = 114,
|
||
|
TIF_DXGI_FORMAT_B4G4R4A4_UNORM = 115,
|
||
|
|
||
|
// xbox 360 formats
|
||
|
TIF_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT = 116,
|
||
|
TIF_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT = 117,
|
||
|
TIF_DXGI_FORMAT_D16_UNORM_S8_UINT = 118,
|
||
|
TIF_DXGI_FORMAT_R16_UNORM_X8_TYPELESS = 119,
|
||
|
TIF_DXGI_FORMAT_X16_TYPELESS_G8_UINT = 120,
|
||
|
|
||
|
TIF_DXGI_FORMAT_P208 = 130,
|
||
|
TIF_DXGI_FORMAT_V208 = 131,
|
||
|
TIF_DXGI_FORMAT_V408 = 132,
|
||
|
|
||
|
// XBox One formats
|
||
|
TIF_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM = 189,
|
||
|
TIF_DXGI_FORMAT_R4G4_UNORM = 190,
|
||
|
|
||
|
} TinyImageFormat_DXGI_FORMAT;
|
||
|
#endif
|
||
|
|
||
|
typedef enum TinyDDS_Format {
|
||
|
TDDS_UNDEFINED = TIF_DXGI_FORMAT_UNKNOWN,
|
||
|
TDDS_B5G6R5_UNORM = TIF_DXGI_FORMAT_B5G6R5_UNORM,
|
||
|
TDDS_B5G5R5A1_UNORM = TIF_DXGI_FORMAT_B5G5R5A1_UNORM,
|
||
|
TDDS_R8_UNORM = TIF_DXGI_FORMAT_R8_UNORM,
|
||
|
TDDS_R8_SNORM = TIF_DXGI_FORMAT_R8_SNORM,
|
||
|
TDDS_A8_UNORM = TIF_DXGI_FORMAT_A8_UNORM,
|
||
|
TDDS_R1_UNORM = TIF_DXGI_FORMAT_R1_UNORM,
|
||
|
TDDS_R8_UINT = TIF_DXGI_FORMAT_R8_UINT,
|
||
|
TDDS_R8_SINT = TIF_DXGI_FORMAT_R8_SINT,
|
||
|
TDDS_R8G8_UNORM = TIF_DXGI_FORMAT_R8G8_UNORM,
|
||
|
TDDS_R8G8_SNORM = TIF_DXGI_FORMAT_R8G8_SNORM,
|
||
|
TDDS_R8G8_UINT = TIF_DXGI_FORMAT_R8G8_UINT,
|
||
|
TDDS_R8G8_SINT = TIF_DXGI_FORMAT_R8G8_SINT,
|
||
|
TDDS_R8G8B8A8_UNORM = TIF_DXGI_FORMAT_R8G8B8A8_UNORM,
|
||
|
TDDS_R8G8B8A8_SNORM = TIF_DXGI_FORMAT_R8G8B8A8_SNORM,
|
||
|
TDDS_R8G8B8A8_UINT = TIF_DXGI_FORMAT_R8G8B8A8_UINT,
|
||
|
TDDS_R8G8B8A8_SINT = TIF_DXGI_FORMAT_R8G8B8A8_SINT,
|
||
|
TDDS_R8G8B8A8_SRGB = TIF_DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
|
||
|
TDDS_B8G8R8A8_UNORM = TIF_DXGI_FORMAT_B8G8R8A8_UNORM,
|
||
|
TDDS_B8G8R8A8_SRGB = TIF_DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
|
||
|
|
||
|
TDDS_R9G9B9E5_UFLOAT = TIF_DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
|
||
|
TDDS_R10G10B10A2_UNORM = TIF_DXGI_FORMAT_R10G10B10A2_UNORM,
|
||
|
TDDS_R10G10B10A2_UINT = TIF_DXGI_FORMAT_R10G10B10A2_UINT,
|
||
|
TDDS_R11G11B10_UFLOAT = TIF_DXGI_FORMAT_R11G11B10_FLOAT,
|
||
|
|
||
|
TDDS_R16_UNORM = TIF_DXGI_FORMAT_R16_UNORM,
|
||
|
TDDS_R16_SNORM = TIF_DXGI_FORMAT_R16_SNORM,
|
||
|
TDDS_R16_UINT = TIF_DXGI_FORMAT_R16_UINT,
|
||
|
TDDS_R16_SINT = TIF_DXGI_FORMAT_R16_SINT,
|
||
|
TDDS_R16_SFLOAT = TIF_DXGI_FORMAT_R16_FLOAT,
|
||
|
|
||
|
TDDS_R16G16_UNORM = TIF_DXGI_FORMAT_R16G16_UNORM,
|
||
|
TDDS_R16G16_SNORM = TIF_DXGI_FORMAT_R16G16_SNORM,
|
||
|
TDDS_R16G16_UINT = TIF_DXGI_FORMAT_R16G16_UINT,
|
||
|
TDDS_R16G16_SINT = TIF_DXGI_FORMAT_R16G16_SINT,
|
||
|
TDDS_R16G16_SFLOAT = TIF_DXGI_FORMAT_R16G16_FLOAT,
|
||
|
|
||
|
TDDS_R16G16B16A16_UNORM = TIF_DXGI_FORMAT_R16G16B16A16_UNORM,
|
||
|
TDDS_R16G16B16A16_SNORM = TIF_DXGI_FORMAT_R16G16B16A16_SNORM,
|
||
|
TDDS_R16G16B16A16_UINT = TIF_DXGI_FORMAT_R16G16B16A16_UINT,
|
||
|
TDDS_R16G16B16A16_SINT = TIF_DXGI_FORMAT_R16G16B16A16_SINT,
|
||
|
TDDS_R16G16B16A16_SFLOAT = TIF_DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||
|
|
||
|
TDDS_R32_UINT = TIF_DXGI_FORMAT_R32_UINT,
|
||
|
TDDS_R32_SINT = TIF_DXGI_FORMAT_R32_SINT,
|
||
|
TDDS_R32_SFLOAT = TIF_DXGI_FORMAT_R32_FLOAT,
|
||
|
|
||
|
TDDS_R32G32_UINT = TIF_DXGI_FORMAT_R32G32_UINT,
|
||
|
TDDS_R32G32_SINT = TIF_DXGI_FORMAT_R32G32_SINT,
|
||
|
TDDS_R32G32_SFLOAT = TIF_DXGI_FORMAT_R32G32_FLOAT,
|
||
|
|
||
|
TDDS_R32G32B32_UINT = TIF_DXGI_FORMAT_R32G32B32_UINT,
|
||
|
TDDS_R32G32B32_SINT = TIF_DXGI_FORMAT_R32G32B32_SINT,
|
||
|
TDDS_R32G32B32_SFLOAT = TIF_DXGI_FORMAT_R32G32B32_FLOAT,
|
||
|
|
||
|
TDDS_R32G32B32A32_UINT = TIF_DXGI_FORMAT_R32G32B32A32_UINT,
|
||
|
TDDS_R32G32B32A32_SINT = TIF_DXGI_FORMAT_R32G32B32A32_SINT,
|
||
|
TDDS_R32G32B32A32_SFLOAT = TIF_DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||
|
|
||
|
TDDS_BC1_RGBA_UNORM_BLOCK = TIF_DXGI_FORMAT_BC1_UNORM,
|
||
|
TDDS_BC1_RGBA_SRGB_BLOCK = TIF_DXGI_FORMAT_BC1_UNORM_SRGB,
|
||
|
TDDS_BC2_UNORM_BLOCK = TIF_DXGI_FORMAT_BC2_UNORM,
|
||
|
TDDS_BC2_SRGB_BLOCK = TIF_DXGI_FORMAT_BC2_UNORM_SRGB,
|
||
|
TDDS_BC3_UNORM_BLOCK = TIF_DXGI_FORMAT_BC3_UNORM,
|
||
|
TDDS_BC3_SRGB_BLOCK = TIF_DXGI_FORMAT_BC3_UNORM_SRGB,
|
||
|
TDDS_BC4_UNORM_BLOCK = TIF_DXGI_FORMAT_BC4_UNORM,
|
||
|
TDDS_BC4_SNORM_BLOCK = TIF_DXGI_FORMAT_BC4_SNORM,
|
||
|
TDDS_BC5_UNORM_BLOCK = TIF_DXGI_FORMAT_BC5_UNORM,
|
||
|
TDDS_BC5_SNORM_BLOCK = TIF_DXGI_FORMAT_BC5_SNORM,
|
||
|
|
||
|
TDDS_BC6H_UFLOAT_BLOCK = TIF_DXGI_FORMAT_BC6H_UF16,
|
||
|
TDDS_BC6H_SFLOAT_BLOCK = TIF_DXGI_FORMAT_BC6H_SF16,
|
||
|
TDDS_BC7_UNORM_BLOCK = TIF_DXGI_FORMAT_BC7_UNORM,
|
||
|
TDDS_BC7_SRGB_BLOCK = TIF_DXGI_FORMAT_BC7_UNORM_SRGB,
|
||
|
|
||
|
TDDS_AYUV = TIF_DXGI_FORMAT_AYUV,
|
||
|
TDDS_Y410 = TIF_DXGI_FORMAT_Y410,
|
||
|
TDDS_Y416 = TIF_DXGI_FORMAT_Y416,
|
||
|
TDDS_NV12 = TIF_DXGI_FORMAT_NV12,
|
||
|
TDDS_P010 = TIF_DXGI_FORMAT_P010,
|
||
|
TDDS_P016 = TIF_DXGI_FORMAT_P016,
|
||
|
TDDS_420_OPAQUE = TIF_DXGI_FORMAT_420_OPAQUE,
|
||
|
TDDS_YUY2 = TIF_DXGI_FORMAT_YUY2,
|
||
|
TDDS_Y210 = TIF_DXGI_FORMAT_Y210,
|
||
|
TDDS_Y216 = TIF_DXGI_FORMAT_Y216,
|
||
|
TDDS_NV11 = TIF_DXGI_FORMAT_NV11,
|
||
|
TDDS_AI44 = TIF_DXGI_FORMAT_AI44,
|
||
|
TDDS_IA44 = TIF_DXGI_FORMAT_IA44,
|
||
|
TDDS_P8 = TIF_DXGI_FORMAT_P8,
|
||
|
TDDS_A8P8 = TIF_DXGI_FORMAT_A8P8,
|
||
|
TDDS_B4G4R4A4_UNORM = TIF_DXGI_FORMAT_B4G4R4A4_UNORM,
|
||
|
TDDS_R10G10B10_7E3_A2_FLOAT = TIF_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT,
|
||
|
TDDS_R10G10B10_6E4_A2_FLOAT = TIF_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT,
|
||
|
TDDS_D16_UNORM_S8_UINT = TIF_DXGI_FORMAT_D16_UNORM_S8_UINT,
|
||
|
TDDS_R16_UNORM_X8_TYPELESS = TIF_DXGI_FORMAT_R16_UNORM_X8_TYPELESS,
|
||
|
TDDS_X16_TYPELESS_G8_UINT = TIF_DXGI_FORMAT_X16_TYPELESS_G8_UINT,
|
||
|
TDDS_P208 = TIF_DXGI_FORMAT_P208,
|
||
|
TDDS_V208 = TIF_DXGI_FORMAT_V208,
|
||
|
TDDS_V408 = TIF_DXGI_FORMAT_V408,
|
||
|
TDDS_R10G10B10_SNORM_A2_UNORM = TIF_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM,
|
||
|
TDDS_R4G4_UNORM = TIF_DXGI_FORMAT_R4G4_UNORM,
|
||
|
|
||
|
TDDS_SYNTHESISED_DXGIFORMATS = 0xFFFF,
|
||
|
TDDS_G4R4_UNORM = TDDS_SYNTHESISED_DXGIFORMATS,
|
||
|
|
||
|
TDDS_A4B4G4R4_UNORM,
|
||
|
TDDS_X4B4G4R4_UNORM,
|
||
|
|
||
|
TDDS_A4R4G4B4_UNORM,
|
||
|
TDDS_X4R4G4B4_UNORM,
|
||
|
|
||
|
TDDS_B4G4R4X4_UNORM,
|
||
|
|
||
|
TDDS_R4G4B4A4_UNORM,
|
||
|
TDDS_R4G4B4X4_UNORM,
|
||
|
|
||
|
TDDS_B5G5R5X1_UNORM,
|
||
|
|
||
|
TDDS_R5G5B5A1_UNORM,
|
||
|
TDDS_R5G5B5X1_UNORM,
|
||
|
|
||
|
TDDS_A1R5G5B5_UNORM,
|
||
|
TDDS_X1R5G5B5_UNORM,
|
||
|
|
||
|
TDDS_A1B5G5R5_UNORM,
|
||
|
TDDS_X1B5G5R5_UNORM,
|
||
|
|
||
|
TDDS_R5G6B5_UNORM,
|
||
|
|
||
|
TDDS_B2G3R3_UNORM,
|
||
|
TDDS_B2G3R3A8_UNORM,
|
||
|
|
||
|
TDDS_G8R8_UNORM,
|
||
|
TDDS_G8R8_SNORM,
|
||
|
|
||
|
TDDS_R8G8B8_UNORM,
|
||
|
TDDS_B8G8R8_UNORM,
|
||
|
|
||
|
TDDS_A8B8G8R8_SNORM,
|
||
|
TDDS_B8G8R8A8_SNORM,
|
||
|
|
||
|
TDDS_R8G8B8X8_UNORM,
|
||
|
TDDS_B8G8R8X8_UNORM,
|
||
|
TDDS_A8B8G8R8_UNORM,
|
||
|
TDDS_X8B8G8R8_UNORM,
|
||
|
TDDS_A8R8G8B8_UNORM,
|
||
|
TDDS_X8R8G8B8_UNORM,
|
||
|
|
||
|
TDDS_R10G10B10A2_SNORM,
|
||
|
TDDS_B10G10R10A2_UNORM,
|
||
|
TDDS_B10G10R10A2_SNORM,
|
||
|
TDDS_A2B10G10R10_UNORM,
|
||
|
TDDS_A2B10G10R10_SNORM,
|
||
|
TDDS_A2R10G10B10_UNORM,
|
||
|
TDDS_A2R10G10B10_SNORM,
|
||
|
|
||
|
TDDS_G16R16_UNORM,
|
||
|
TDDS_G16R16_SNORM,
|
||
|
|
||
|
} TinyDDS_Format;
|
||
|
|
||
|
// tiny_imageformat/format needs included before tinydds.h for this functionality
|
||
|
#ifdef TINYIMAGEFORMAT_BASE_H_
|
||
|
|
||
|
static TinyImageFormat TinyImageFormat_FromTinyDDSFormat(TinyDDS_Format fmt) {
|
||
|
switch (fmt) {
|
||
|
case TDDS_UNDEFINED: return TinyImageFormat_UNDEFINED;
|
||
|
|
||
|
case TDDS_R32G32B32A32_SFLOAT: return TinyImageFormat_R32G32B32A32_SFLOAT;
|
||
|
case TDDS_R32G32B32A32_UINT: return TinyImageFormat_R32G32B32A32_UINT;
|
||
|
case TDDS_R32G32B32A32_SINT: return TinyImageFormat_R32G32B32A32_SINT;
|
||
|
case TDDS_R32G32B32_SFLOAT: return TinyImageFormat_R32G32B32_SFLOAT;
|
||
|
case TDDS_R32G32B32_UINT: return TinyImageFormat_R32G32B32_UINT;
|
||
|
case TDDS_R32G32B32_SINT: return TinyImageFormat_R32G32B32_SINT;
|
||
|
case TDDS_R16G16B16A16_SFLOAT: return TinyImageFormat_R16G16B16A16_SFLOAT;
|
||
|
case TDDS_R16G16B16A16_UNORM: return TinyImageFormat_R16G16B16A16_UNORM;
|
||
|
case TDDS_R16G16B16A16_UINT: return TinyImageFormat_R16G16B16A16_UINT;
|
||
|
case TDDS_R16G16B16A16_SNORM: return TinyImageFormat_R16G16B16A16_SNORM;
|
||
|
case TDDS_R16G16B16A16_SINT: return TinyImageFormat_R16G16B16A16_SINT;
|
||
|
case TDDS_R32G32_SFLOAT: return TinyImageFormat_R32G32_SFLOAT;
|
||
|
case TDDS_R32G32_UINT: return TinyImageFormat_R32G32_UINT;
|
||
|
case TDDS_R32G32_SINT: return TinyImageFormat_R32G32_SINT;
|
||
|
case TDDS_R8G8B8A8_UNORM: return TinyImageFormat_R8G8B8A8_UNORM;
|
||
|
case TDDS_R8G8B8A8_SRGB: return TinyImageFormat_R8G8B8A8_SRGB;
|
||
|
case TDDS_R8G8B8A8_UINT: return TinyImageFormat_R8G8B8A8_UINT;
|
||
|
case TDDS_R8G8B8A8_SNORM: return TinyImageFormat_R8G8B8A8_SNORM;
|
||
|
case TDDS_R8G8B8A8_SINT: return TinyImageFormat_R8G8B8A8_SINT;
|
||
|
case TDDS_R16G16_SFLOAT: return TinyImageFormat_R16G16_SFLOAT;
|
||
|
case TDDS_R16G16_UNORM: return TinyImageFormat_R16G16_UNORM;
|
||
|
case TDDS_R16G16_UINT: return TinyImageFormat_R16G16_UINT;
|
||
|
case TDDS_R16G16_SNORM: return TinyImageFormat_R16G16_SNORM;
|
||
|
case TDDS_R16G16_SINT: return TinyImageFormat_R16G16_SINT;
|
||
|
case TDDS_R32_SFLOAT: return TinyImageFormat_R32_SFLOAT;
|
||
|
case TDDS_R32_UINT: return TinyImageFormat_R32_UINT;
|
||
|
case TDDS_R32_SINT: return TinyImageFormat_R32_SINT;
|
||
|
|
||
|
case TDDS_R8G8_UNORM: return TinyImageFormat_R8G8_UNORM;
|
||
|
case TDDS_R8G8_UINT: return TinyImageFormat_R8G8_UINT;
|
||
|
case TDDS_R8G8_SNORM: return TinyImageFormat_R8G8_SNORM;
|
||
|
case TDDS_R8G8_SINT: return TinyImageFormat_R8G8_SINT;
|
||
|
case TDDS_G8R8_UNORM: return TinyImageFormat_G8R8_UNORM;
|
||
|
case TDDS_G8R8_SNORM: return TinyImageFormat_G8R8_SNORM;
|
||
|
|
||
|
case TDDS_R16_SFLOAT: return TinyImageFormat_R16_SFLOAT;
|
||
|
case TDDS_R16_UNORM: return TinyImageFormat_R16_UNORM;
|
||
|
case TDDS_R16_UINT: return TinyImageFormat_R16_UINT;
|
||
|
case TDDS_R16_SNORM: return TinyImageFormat_R16_SNORM;
|
||
|
case TDDS_R16_SINT: return TinyImageFormat_R16_SINT;
|
||
|
case TDDS_R8_UNORM: return TinyImageFormat_R8_UNORM;
|
||
|
case TDDS_R8_UINT: return TinyImageFormat_R8_UINT;
|
||
|
case TDDS_R8_SNORM: return TinyImageFormat_R8_SNORM;
|
||
|
case TDDS_R8_SINT: return TinyImageFormat_R8_SINT;
|
||
|
case TDDS_A8_UNORM: return TinyImageFormat_A8_UNORM;
|
||
|
case TDDS_BC1_RGBA_UNORM_BLOCK: return TinyImageFormat_DXBC1_RGBA_UNORM;
|
||
|
case TDDS_BC1_RGBA_SRGB_BLOCK: return TinyImageFormat_DXBC1_RGBA_SRGB;
|
||
|
case TDDS_BC2_UNORM_BLOCK: return TinyImageFormat_DXBC2_UNORM;
|
||
|
case TDDS_BC2_SRGB_BLOCK: return TinyImageFormat_DXBC2_SRGB;
|
||
|
case TDDS_BC3_UNORM_BLOCK: return TinyImageFormat_DXBC3_UNORM;
|
||
|
case TDDS_BC3_SRGB_BLOCK: return TinyImageFormat_DXBC3_SRGB;
|
||
|
case TDDS_BC4_UNORM_BLOCK: return TinyImageFormat_DXBC4_UNORM;
|
||
|
case TDDS_BC4_SNORM_BLOCK: return TinyImageFormat_DXBC4_SNORM;
|
||
|
case TDDS_BC5_UNORM_BLOCK: return TinyImageFormat_DXBC5_UNORM;
|
||
|
case TDDS_BC5_SNORM_BLOCK: return TinyImageFormat_DXBC5_SNORM;
|
||
|
case TDDS_BC6H_UFLOAT_BLOCK: return TinyImageFormat_DXBC6H_UFLOAT;
|
||
|
case TDDS_BC6H_SFLOAT_BLOCK: return TinyImageFormat_DXBC6H_SFLOAT;
|
||
|
case TDDS_BC7_UNORM_BLOCK: return TinyImageFormat_DXBC7_UNORM;
|
||
|
case TDDS_BC7_SRGB_BLOCK: return TinyImageFormat_DXBC7_SRGB;
|
||
|
case TDDS_B8G8R8A8_UNORM: return TinyImageFormat_B8G8R8A8_UNORM;
|
||
|
case TDDS_B8G8R8A8_SRGB: return TinyImageFormat_B8G8R8A8_SRGB;
|
||
|
|
||
|
case TDDS_B2G3R3A8_UNORM: return TinyImageFormat_B2G3R3A8_UNORM;
|
||
|
case TDDS_B2G3R3_UNORM: return TinyImageFormat_B2G3R3_UNORM;
|
||
|
case TDDS_R4G4_UNORM: return TinyImageFormat_R4G4_UNORM;
|
||
|
|
||
|
case TDDS_R8G8B8_UNORM: return TinyImageFormat_R8G8B8_UNORM;
|
||
|
case TDDS_B8G8R8_UNORM: return TinyImageFormat_B8G8R8_UNORM;
|
||
|
case TDDS_B8G8R8A8_SNORM: return TinyImageFormat_B8G8R8A8_SNORM;
|
||
|
|
||
|
case TDDS_R9G9B9E5_UFLOAT: return TinyImageFormat_E5B9G9R9_UFLOAT;
|
||
|
case TDDS_R11G11B10_UFLOAT: return TinyImageFormat_B10G11R11_UFLOAT;
|
||
|
case TDDS_G4R4_UNORM: return TinyImageFormat_G4R4_UNORM;
|
||
|
|
||
|
case TDDS_R5G6B5_UNORM: return TinyImageFormat_R5G6B5_UNORM;
|
||
|
case TDDS_B5G6R5_UNORM: return TinyImageFormat_B5G6R5_UNORM;
|
||
|
|
||
|
case TDDS_B5G5R5A1_UNORM: return TinyImageFormat_B5G5R5A1_UNORM;
|
||
|
case TDDS_B5G5R5X1_UNORM: return TinyImageFormat_B5G5R5X1_UNORM;
|
||
|
|
||
|
case TDDS_R5G5B5A1_UNORM: return TinyImageFormat_R5G5B5A1_UNORM;
|
||
|
case TDDS_R5G5B5X1_UNORM: return TinyImageFormat_R5G5B5X1_UNORM;
|
||
|
|
||
|
case TDDS_A1R5G5B5_UNORM: return TinyImageFormat_A1R5G5B5_UNORM;
|
||
|
case TDDS_X1R5G5B5_UNORM: return TinyImageFormat_X1R5G5B5_UNORM;
|
||
|
|
||
|
case TDDS_X1B5G5R5_UNORM: return TinyImageFormat_X1B5G5R5_UNORM;
|
||
|
case TDDS_A1B5G5R5_UNORM: return TinyImageFormat_A1B5G5R5_UNORM;
|
||
|
|
||
|
case TDDS_X4B4G4R4_UNORM: return TinyImageFormat_X4B4G4R4_UNORM;
|
||
|
case TDDS_X4R4G4B4_UNORM: return TinyImageFormat_X4R4G4B4_UNORM;
|
||
|
case TDDS_A4R4G4B4_UNORM: return TinyImageFormat_A4R4G4B4_UNORM;
|
||
|
case TDDS_B4G4R4A4_UNORM: return TinyImageFormat_B4G4R4A4_UNORM;
|
||
|
case TDDS_A4B4G4R4_UNORM: return TinyImageFormat_A4B4G4R4_UNORM;
|
||
|
case TDDS_B4G4R4X4_UNORM: return TinyImageFormat_B4G4R4X4_UNORM;
|
||
|
case TDDS_R4G4B4A4_UNORM: return TinyImageFormat_R4G4B4A4_UNORM;
|
||
|
case TDDS_R4G4B4X4_UNORM: return TinyImageFormat_R4G4B4X4_UNORM;
|
||
|
|
||
|
case TDDS_R8G8B8X8_UNORM: return TinyImageFormat_R8G8B8X8_UNORM;
|
||
|
|
||
|
// DDS A2R10B10G10 support is basically broken historically so expect channels to need swapping
|
||
|
case TDDS_A2B10G10R10_UNORM: return TinyImageFormat_A2B10G10R10_UNORM;
|
||
|
case TDDS_A2B10G10R10_SNORM: return TinyImageFormat_A2B10G10R10_SNORM;
|
||
|
case TDDS_A2R10G10B10_UNORM: return TinyImageFormat_A2R10G10B10_UNORM;
|
||
|
case TDDS_A2R10G10B10_SNORM: return TinyImageFormat_A2R10G10B10_SNORM;
|
||
|
case TDDS_B10G10R10A2_UNORM: return TinyImageFormat_R10G10B10A2_UNORM;
|
||
|
case TDDS_B10G10R10A2_SNORM: return TinyImageFormat_R10G10B10A2_SNORM;
|
||
|
case TDDS_R10G10B10A2_UNORM: return TinyImageFormat_B10G10R10A2_UNORM;
|
||
|
case TDDS_R10G10B10A2_SNORM: return TinyImageFormat_B10G10R10A2_SNORM;
|
||
|
case TDDS_R10G10B10A2_UINT: return TinyImageFormat_B10G10R10A2_UINT;
|
||
|
|
||
|
case TDDS_B8G8R8X8_UNORM: return TinyImageFormat_B8G8R8X8_UNORM;
|
||
|
|
||
|
case TDDS_G16R16_UNORM: return TinyImageFormat_G16R16_UNORM;
|
||
|
case TDDS_G16R16_SNORM: return TinyImageFormat_G16R16_SNORM;
|
||
|
case TDDS_X8B8G8R8_UNORM: return TinyImageFormat_R8G8B8X8_UNORM;
|
||
|
case TDDS_X8R8G8B8_UNORM: return TinyImageFormat_B8G8R8X8_UNORM;
|
||
|
case TDDS_A8B8G8R8_UNORM: return TinyImageFormat_R8G8B8A8_UNORM;
|
||
|
case TDDS_A8R8G8B8_UNORM: return TinyImageFormat_B8G8R8A8_UNORM;
|
||
|
case TDDS_A8B8G8R8_SNORM: return TinyImageFormat_R8G8B8X8_UNORM;
|
||
|
case TDDS_P8: return TinyImageFormat_CLUT_P8;
|
||
|
case TDDS_A8P8: return TinyImageFormat_CLUT_P8A8;
|
||
|
case TDDS_R1_UNORM: return TinyImageFormat_R1_UNORM;
|
||
|
|
||
|
case TDDS_AYUV:break;
|
||
|
case TDDS_Y410:break;
|
||
|
case TDDS_Y416:break;
|
||
|
case TDDS_NV12:break;
|
||
|
case TDDS_P010:break;
|
||
|
case TDDS_P016:break;
|
||
|
case TDDS_420_OPAQUE:break;
|
||
|
case TDDS_YUY2:break;
|
||
|
case TDDS_Y210:break;
|
||
|
case TDDS_Y216:break;
|
||
|
case TDDS_NV11:break;
|
||
|
case TDDS_AI44:break;
|
||
|
case TDDS_IA44:break;
|
||
|
case TDDS_R10G10B10_7E3_A2_FLOAT:break;
|
||
|
case TDDS_R10G10B10_6E4_A2_FLOAT:break;
|
||
|
case TDDS_D16_UNORM_S8_UINT:break;
|
||
|
case TDDS_R16_UNORM_X8_TYPELESS:break;
|
||
|
case TDDS_X16_TYPELESS_G8_UINT:break;
|
||
|
case TDDS_P208:break;
|
||
|
case TDDS_V208:break;
|
||
|
case TDDS_V408:break;
|
||
|
case TDDS_R10G10B10_SNORM_A2_UNORM:break;
|
||
|
}
|
||
|
|
||
|
return TinyImageFormat_UNDEFINED;
|
||
|
}
|
||
|
|
||
|
static TinyDDS_Format TinyImageFormat_ToTinyDDSFormat(TinyImageFormat fmt) {
|
||
|
switch (fmt) {
|
||
|
case TinyImageFormat_R4G4_UNORM: return TDDS_R4G4_UNORM;
|
||
|
case TinyImageFormat_G4R4_UNORM: return TDDS_G4R4_UNORM;
|
||
|
|
||
|
case TinyImageFormat_A4R4G4B4_UNORM: return TDDS_A4R4G4B4_UNORM;
|
||
|
case TinyImageFormat_B4G4R4A4_UNORM: return TDDS_B4G4R4A4_UNORM;
|
||
|
case TinyImageFormat_A4B4G4R4_UNORM: return TDDS_A4B4G4R4_UNORM;
|
||
|
case TinyImageFormat_X4R4G4B4_UNORM: return TDDS_X4R4G4B4_UNORM;
|
||
|
case TinyImageFormat_X4B4G4R4_UNORM: return TDDS_X4B4G4R4_UNORM;
|
||
|
case TinyImageFormat_R4G4B4A4_UNORM: return TDDS_R4G4B4A4_UNORM;
|
||
|
case TinyImageFormat_R4G4B4X4_UNORM: return TDDS_R4G4B4X4_UNORM;
|
||
|
|
||
|
case TinyImageFormat_A1B5G5R5_UNORM: return TDDS_A1B5G5R5_UNORM;
|
||
|
case TinyImageFormat_X1B5G5R5_UNORM: return TDDS_X1B5G5R5_UNORM;
|
||
|
|
||
|
case TinyImageFormat_A1R5G5B5_UNORM: return TDDS_A1R5G5B5_UNORM;
|
||
|
case TinyImageFormat_X1R5G5B5_UNORM: return TDDS_X1R5G5B5_UNORM;
|
||
|
|
||
|
case TinyImageFormat_B5G5R5A1_UNORM: return TDDS_B5G5R5A1_UNORM;
|
||
|
case TinyImageFormat_B5G5R5X1_UNORM: return TDDS_B5G5R5X1_UNORM;
|
||
|
|
||
|
case TinyImageFormat_R5G5B5A1_UNORM: return TDDS_R5G5B5A1_UNORM;
|
||
|
case TinyImageFormat_R5G5B5X1_UNORM: return TDDS_R5G5B5X1_UNORM;
|
||
|
|
||
|
case TinyImageFormat_R5G6B5_UNORM: return TDDS_R5G6B5_UNORM;
|
||
|
case TinyImageFormat_B5G6R5_UNORM: return TDDS_B5G6R5_UNORM;
|
||
|
|
||
|
case TinyImageFormat_A2B10G10R10_UNORM: return TDDS_A2B10G10R10_UNORM;
|
||
|
case TinyImageFormat_A2B10G10R10_SNORM: return TDDS_A2B10G10R10_SNORM;
|
||
|
case TinyImageFormat_A2R10G10B10_UNORM: return TDDS_A2R10G10B10_UNORM;
|
||
|
case TinyImageFormat_A2R10G10B10_SNORM: return TDDS_A2R10G10B10_SNORM;
|
||
|
case TinyImageFormat_R10G10B10A2_UNORM: return TDDS_B10G10R10A2_UNORM;
|
||
|
case TinyImageFormat_R10G10B10A2_SNORM: return TDDS_B10G10R10A2_SNORM;
|
||
|
case TinyImageFormat_B10G10R10A2_UNORM: return TDDS_R10G10B10A2_UNORM;
|
||
|
case TinyImageFormat_B10G10R10A2_SNORM: return TDDS_R10G10B10A2_SNORM;
|
||
|
case TinyImageFormat_B10G10R10A2_UINT: return TDDS_R10G10B10A2_UINT;
|
||
|
|
||
|
case TinyImageFormat_E5B9G9R9_UFLOAT: return TDDS_R9G9B9E5_UFLOAT;
|
||
|
case TinyImageFormat_B10G11R11_UFLOAT: return TDDS_R11G11B10_UFLOAT;
|
||
|
|
||
|
case TinyImageFormat_R8_UNORM: return TDDS_R8_UNORM;
|
||
|
case TinyImageFormat_R8_SNORM: return TDDS_R8_SNORM;
|
||
|
case TinyImageFormat_R8_UINT: return TDDS_R8_UINT;
|
||
|
case TinyImageFormat_R8_SINT: return TDDS_R8_SINT;
|
||
|
case TinyImageFormat_A8_UNORM: return TDDS_A8_UNORM;
|
||
|
case TinyImageFormat_B2G3R3_UNORM: return TDDS_B2G3R3_UNORM;
|
||
|
|
||
|
case TinyImageFormat_B2G3R3A8_UNORM: return TDDS_B2G3R3A8_UNORM;
|
||
|
case TinyImageFormat_R8G8_UNORM: return TDDS_R8G8_UNORM;
|
||
|
case TinyImageFormat_R8G8_SNORM: return TDDS_R8G8_SNORM;
|
||
|
case TinyImageFormat_R8G8_UINT: return TDDS_R8G8_UINT;
|
||
|
case TinyImageFormat_R8G8_SINT: return TDDS_R8G8_SINT;
|
||
|
case TinyImageFormat_G8R8_UNORM: return TDDS_G8R8_UNORM;
|
||
|
case TinyImageFormat_G8R8_SNORM: return TDDS_G8R8_SNORM;
|
||
|
|
||
|
case TinyImageFormat_R8G8B8_UNORM: return TDDS_R8G8B8_UNORM;
|
||
|
case TinyImageFormat_B8G8R8_UNORM: return TDDS_B8G8R8_UNORM;
|
||
|
|
||
|
case TinyImageFormat_R8G8B8A8_UNORM: return TDDS_R8G8B8A8_UNORM;
|
||
|
case TinyImageFormat_R8G8B8A8_SNORM: return TDDS_R8G8B8A8_SNORM;
|
||
|
case TinyImageFormat_R8G8B8A8_UINT: return TDDS_R8G8B8A8_UINT;
|
||
|
case TinyImageFormat_R8G8B8A8_SINT: return TDDS_R8G8B8A8_SINT;
|
||
|
case TinyImageFormat_R8G8B8A8_SRGB: return TDDS_R8G8B8A8_SRGB;
|
||
|
case TinyImageFormat_B8G8R8A8_UNORM: return TDDS_B8G8R8A8_UNORM;
|
||
|
case TinyImageFormat_B8G8R8A8_SRGB: return TDDS_B8G8R8A8_SRGB;
|
||
|
|
||
|
case TinyImageFormat_R16_UNORM: return TDDS_R16_UNORM;
|
||
|
case TinyImageFormat_R16_SNORM: return TDDS_R16_SNORM;
|
||
|
case TinyImageFormat_R16_UINT: return TDDS_R16_UINT;
|
||
|
case TinyImageFormat_R16_SINT: return TDDS_R16_SINT;
|
||
|
case TinyImageFormat_R16_SFLOAT: return TDDS_R16_SFLOAT;
|
||
|
|
||
|
case TinyImageFormat_R16G16_UNORM: return TDDS_R16G16_UNORM;
|
||
|
case TinyImageFormat_R16G16_SNORM: return TDDS_R16G16_SNORM;
|
||
|
case TinyImageFormat_R16G16_UINT: return TDDS_R16G16_UINT;
|
||
|
case TinyImageFormat_R16G16_SINT: return TDDS_R16G16_SINT;
|
||
|
case TinyImageFormat_R16G16_SFLOAT: return TDDS_R16G16_SFLOAT;
|
||
|
|
||
|
case TinyImageFormat_G16R16_UNORM: return TDDS_G16R16_UNORM;
|
||
|
case TinyImageFormat_G16R16_SNORM: return TDDS_G16R16_SNORM;
|
||
|
|
||
|
case TinyImageFormat_R16G16B16A16_UNORM: return TDDS_R16G16B16A16_UNORM;
|
||
|
case TinyImageFormat_R16G16B16A16_SNORM: return TDDS_R16G16B16A16_SNORM;
|
||
|
case TinyImageFormat_R16G16B16A16_UINT: return TDDS_R16G16B16A16_UINT;
|
||
|
case TinyImageFormat_R16G16B16A16_SINT: return TDDS_R16G16B16A16_SINT;
|
||
|
case TinyImageFormat_R16G16B16A16_SFLOAT: return TDDS_R16G16B16A16_SFLOAT;
|
||
|
|
||
|
case TinyImageFormat_R32_UINT: return TDDS_R32_UINT;
|
||
|
case TinyImageFormat_R32_SINT: return TDDS_R32_SINT;
|
||
|
case TinyImageFormat_R32_SFLOAT: return TDDS_R32_SFLOAT;
|
||
|
|
||
|
case TinyImageFormat_R32G32_UINT: return TDDS_R32G32_UINT;
|
||
|
case TinyImageFormat_R32G32_SINT: return TDDS_R32G32_SINT;
|
||
|
case TinyImageFormat_R32G32_SFLOAT: return TDDS_R32G32_SFLOAT;
|
||
|
|
||
|
case TinyImageFormat_R32G32B32_UINT: return TDDS_R32G32B32_UINT;
|
||
|
case TinyImageFormat_R32G32B32_SINT: return TDDS_R32G32B32_SINT;
|
||
|
case TinyImageFormat_R32G32B32_SFLOAT:return TDDS_R32G32B32_SFLOAT;
|
||
|
|
||
|
case TinyImageFormat_R32G32B32A32_UINT: return TDDS_R32G32B32A32_UINT;
|
||
|
case TinyImageFormat_R32G32B32A32_SINT: return TDDS_R32G32B32A32_SINT;
|
||
|
case TinyImageFormat_R32G32B32A32_SFLOAT: return TDDS_R32G32B32A32_SFLOAT;
|
||
|
|
||
|
case TinyImageFormat_D16_UNORM: return TDDS_R16_UNORM;
|
||
|
case TinyImageFormat_D32_SFLOAT: return TDDS_R32_SFLOAT;
|
||
|
case TinyImageFormat_S8_UINT: return TDDS_R8_UINT;
|
||
|
case TinyImageFormat_DXBC1_RGB_UNORM: return TDDS_BC1_RGBA_UNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC1_RGB_SRGB: return TDDS_BC1_RGBA_SRGB_BLOCK;
|
||
|
case TinyImageFormat_DXBC1_RGBA_UNORM: return TDDS_BC1_RGBA_UNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC1_RGBA_SRGB: return TDDS_BC1_RGBA_SRGB_BLOCK;
|
||
|
case TinyImageFormat_DXBC2_UNORM: return TDDS_BC2_UNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC2_SRGB: return TDDS_BC2_SRGB_BLOCK;
|
||
|
case TinyImageFormat_DXBC3_UNORM: return TDDS_BC3_UNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC3_SRGB: return TDDS_BC3_SRGB_BLOCK;
|
||
|
case TinyImageFormat_DXBC4_UNORM: return TDDS_BC4_UNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC4_SNORM: return TDDS_BC4_SNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC5_UNORM: return TDDS_BC5_UNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC5_SNORM: return TDDS_BC5_SNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC6H_UFLOAT: return TDDS_BC6H_UFLOAT_BLOCK;
|
||
|
case TinyImageFormat_DXBC6H_SFLOAT: return TDDS_BC6H_SFLOAT_BLOCK;
|
||
|
case TinyImageFormat_DXBC7_UNORM: return TDDS_BC7_UNORM_BLOCK;
|
||
|
case TinyImageFormat_DXBC7_SRGB: return TDDS_BC7_SRGB_BLOCK;
|
||
|
|
||
|
case TinyImageFormat_CLUT_P8: return TDDS_P8;
|
||
|
case TinyImageFormat_CLUT_P8A8: return TDDS_A8P8;
|
||
|
case TinyImageFormat_R1_UNORM: return TDDS_R1_UNORM;
|
||
|
|
||
|
// unsupported
|
||
|
// TODO Some of these can be via Dx10/4CC codes I think
|
||
|
default: return TDDS_UNDEFINED;
|
||
|
}
|
||
|
|
||
|
return TDDS_UNDEFINED;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
TinyDDS_Format TinyDDS_GetFormat(TinyDDS_ContextHandle handle);
|
||
|
|
||
|
bool TinyDDS_WriteImage(TinyDDS_WriteCallbacks const *callbacks,
|
||
|
void *user,
|
||
|
uint32_t width,
|
||
|
uint32_t height,
|
||
|
uint32_t depth,
|
||
|
uint32_t slices,
|
||
|
uint32_t mipmaplevels,
|
||
|
TinyDDS_Format format,
|
||
|
bool cubemap,
|
||
|
bool preferDx10Format,
|
||
|
uint32_t const *mipmapsizes,
|
||
|
void const **mipmaps);
|
||
|
|
||
|
#ifdef TINYDDS_IMPLEMENTATION
|
||
|
|
||
|
#define TINYDDS_DDSD_CAPS 0x00000001
|
||
|
#define TINYDDS_DDSD_HEIGHT 0x00000002
|
||
|
#define TINYDDS_DDSD_WIDTH 0x00000004
|
||
|
#define TINYDDS_DDSD_PITCH 0x00000008
|
||
|
#define TINYDDS_DDSD_PIXELFORMAT 0x00001000
|
||
|
#define TINYDDS_DDSD_MIPMAPCOUNT 0x00020000
|
||
|
#define TINYDDS_DDSD_LINEARSIZE 0x00080000
|
||
|
#define TINYDDS_DDSD_DEPTH 0x00800000
|
||
|
#define TINYDDS_DDSCAPS_COMPLEX 0x00000008
|
||
|
#define TINYDDS_DDSCAPS_TEXTURE 0x00001000
|
||
|
#define TINYDDS_DDSCAPS_MIPMAP 0x00400000
|
||
|
#define TINYDDS_DDSCAPS2_CUBEMAP 0x00000200
|
||
|
#define TINYDDS_DDSCAPS2_VOLUME 0x00200000
|
||
|
#define TINYDDS_DDSCAPS2_CUBEMAP_ALL 0x0000FC000
|
||
|
#define TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE 0x4
|
||
|
#define TINYDDS_D3D10_RESOURCE_DIMENSION_BUFFER 1
|
||
|
#define TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE1D 2
|
||
|
#define TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE2D 3
|
||
|
#define TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE3D 4
|
||
|
#define TINYDDS_DDPF_ALPHAPIXELS 0x00000001l
|
||
|
#define TINYDDS_DDPF_ALPHA 0x00000002l
|
||
|
#define TINYDDS_DDPF_FOURCC 0x00000004l
|
||
|
#define TINYDDS_DDPF_PALETTEINDEXED4 0x00000008l
|
||
|
#define TINYDDS_DDPF_PALETTEINDEXEDTO8 0x00000010l
|
||
|
#define TINYDDS_DDPF_PALETTEINDEXED8 0x00000020l
|
||
|
#define TINYDDS_DDPF_RGB 0x00000040l
|
||
|
#define TINYDDS_DDPF_LUMINANCE 0x00020000l
|
||
|
#define TINYDDS_DDPF_BUMPLUMINANCE 0x00040000l
|
||
|
#define TINYDDS_DDPF_BUMPDUDV 0x00080000l
|
||
|
|
||
|
// some of these get stuck in unofficial DDS v9 FourCC code
|
||
|
typedef enum TINYDDS_D3DFORMAT {
|
||
|
TINYDDS_D3DFMT_UNKNOWN = 0,
|
||
|
TINYDDS_D3DFMT_R8G8B8 = 20,
|
||
|
TINYDDS_D3DFMT_A8R8G8B8 = 21,
|
||
|
TINYDDS_D3DFMT_X8R8G8B8 = 22,
|
||
|
TINYDDS_D3DFMT_R5G6B5 = 23,
|
||
|
TINYDDS_D3DFMT_X1R5G5B5 = 24,
|
||
|
TINYDDS_D3DFMT_A1R5G5B5 = 25,
|
||
|
TINYDDS_D3DFMT_A4R4G4B4 = 26,
|
||
|
TINYDDS_D3DFMT_R3G3B2 = 27,
|
||
|
TINYDDS_D3DFMT_A8 = 28,
|
||
|
TINYDDS_D3DFMT_A8R3G3B2 = 29,
|
||
|
TINYDDS_D3DFMT_X4R4G4B4 = 30,
|
||
|
TINYDDS_D3DFMT_A2B10G10R10 = 31,
|
||
|
TINYDDS_D3DFMT_A8B8G8R8 = 32,
|
||
|
TINYDDS_D3DFMT_X8B8G8R8 = 33,
|
||
|
TINYDDS_D3DFMT_G16R16 = 34,
|
||
|
TINYDDS_D3DFMT_A2R10G10B10 = 35,
|
||
|
TINYDDS_D3DFMT_A16B16G16R16 = 36,
|
||
|
TINYDDS_D3DFMT_A8P8 = 40,
|
||
|
TINYDDS_D3DFMT_P8 = 41,
|
||
|
TINYDDS_D3DFMT_L8 = 50,
|
||
|
TINYDDS_D3DFMT_A8L8 = 51,
|
||
|
TINYDDS_D3DFMT_A4L4 = 52,
|
||
|
TINYDDS_D3DFMT_V8U8 = 60,
|
||
|
TINYDDS_D3DFMT_L6V5U5 = 61,
|
||
|
TINYDDS_D3DFMT_X8L8V8U8 = 62,
|
||
|
TINYDDS_D3DFMT_Q8W8V8U8 = 63,
|
||
|
TINYDDS_D3DFMT_V16U16 = 64,
|
||
|
TINYDDS_D3DFMT_A2W10V10U10 = 67,
|
||
|
TINYDDS_D3DFMT_L16 = 81,
|
||
|
TINYDDS_D3DFMT_Q16W16V16U16 = 110,
|
||
|
TINYDDS_D3DFMT_R16F = 111,
|
||
|
TINYDDS_D3DFMT_G16R16F = 112,
|
||
|
TINYDDS_D3DFMT_A16B16G16R16F = 113,
|
||
|
TINYDDS_D3DFMT_R32F = 114,
|
||
|
TINYDDS_D3DFMT_G32R32F = 115,
|
||
|
TINYDDS_D3DFMT_A32B32G32R32F = 116,
|
||
|
TINYDDS_D3DFMT_CxV8U8 = 117,
|
||
|
TINYDDS_D3DFMT_A1 = 118,
|
||
|
TINYDDS_D3DFMT_A2B10G10R10_XR_BIAS = 119,
|
||
|
} TINYDDS_D3DFORMAT;
|
||
|
|
||
|
typedef struct TinyDDS_Header {
|
||
|
uint32_t magic;
|
||
|
uint32_t size;
|
||
|
uint32_t flags;
|
||
|
uint32_t height;
|
||
|
uint32_t width;
|
||
|
uint32_t pitchOrLinearSize;
|
||
|
uint32_t depth;
|
||
|
uint32_t mipMapCount;
|
||
|
uint32_t reserved0[11];
|
||
|
|
||
|
uint32_t formatSize;
|
||
|
uint32_t formatFlags;
|
||
|
uint32_t formatFourCC;
|
||
|
uint32_t formatRGBBitCount;
|
||
|
uint32_t formatRBitMask;
|
||
|
uint32_t formatGBitMask;
|
||
|
uint32_t formatBBitMask;
|
||
|
uint32_t formatABitMask;
|
||
|
|
||
|
uint32_t caps1;
|
||
|
uint32_t caps2;
|
||
|
uint32_t caps3; // not used?
|
||
|
uint32_t caps4; // not used?
|
||
|
|
||
|
uint32_t reserved1;
|
||
|
} TinyDDS_Header;
|
||
|
|
||
|
typedef struct TinyDDS_HeaderDX10 {
|
||
|
uint32_t DXGIFormat;
|
||
|
uint32_t resourceDimension;
|
||
|
uint32_t miscFlag;
|
||
|
uint32_t arraySize;
|
||
|
uint32_t reserved;
|
||
|
} TinyDDS_HeaderDX10;
|
||
|
|
||
|
typedef struct TinyDDS_Context {
|
||
|
TinyDDS_Callbacks callbacks;
|
||
|
void *user;
|
||
|
uint64_t headerPos;
|
||
|
uint64_t firstImagePos;
|
||
|
|
||
|
TinyDDS_Header header;
|
||
|
TinyDDS_HeaderDX10 headerDx10;
|
||
|
TinyDDS_Format format;
|
||
|
|
||
|
bool headerValid;
|
||
|
uint8_t const *mipmaps[TINYDDS_MAX_MIPMAPLEVELS];
|
||
|
uint32_t const *clut;
|
||
|
|
||
|
} TinyDDS_Context;
|
||
|
|
||
|
#define TINYDDS_MAKE_RIFFCODE(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24))
|
||
|
|
||
|
static uint32_t TinyDDS_fileIdentifier = TINYDDS_MAKE_RIFFCODE('D', 'D', 'S', ' ');
|
||
|
|
||
|
static void TinyDDS_NullErrorFunc(void *user, char const *msg) { BASISU_NOTE_UNUSED(user); BASISU_NOTE_UNUSED(msg); }
|
||
|
|
||
|
TinyDDS_ContextHandle TinyDDS_CreateContext(TinyDDS_Callbacks const *callbacks, void *user) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) callbacks->allocFn(user, sizeof(TinyDDS_Context));
|
||
|
if (ctx == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
memset(ctx, 0, sizeof(TinyDDS_Context));
|
||
|
memcpy(&ctx->callbacks, callbacks, sizeof(TinyDDS_Callbacks));
|
||
|
ctx->user = user;
|
||
|
if (ctx->callbacks.errorFn == NULL) {
|
||
|
ctx->callbacks.errorFn = &TinyDDS_NullErrorFunc;
|
||
|
}
|
||
|
|
||
|
if (ctx->callbacks.readFn == NULL) {
|
||
|
ctx->callbacks.errorFn(user, "TinyDDS must have read callback");
|
||
|
return NULL;
|
||
|
}
|
||
|
if (ctx->callbacks.allocFn == NULL) {
|
||
|
ctx->callbacks.errorFn(user, "TinyDDS must have alloc callback");
|
||
|
return NULL;
|
||
|
}
|
||
|
if (ctx->callbacks.freeFn == NULL) {
|
||
|
ctx->callbacks.errorFn(user, "TinyDDS must have free callback");
|
||
|
return NULL;
|
||
|
}
|
||
|
if (ctx->callbacks.seekFn == NULL) {
|
||
|
ctx->callbacks.errorFn(user, "TinyDDS must have seek callback");
|
||
|
return NULL;
|
||
|
}
|
||
|
if (ctx->callbacks.tellFn == NULL) {
|
||
|
ctx->callbacks.errorFn(user, "TinyDDS must have tell callback");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
TinyDDS_Reset(ctx);
|
||
|
|
||
|
return ctx;
|
||
|
}
|
||
|
|
||
|
void TinyDDS_DestroyContext(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return;
|
||
|
TinyDDS_Reset(handle);
|
||
|
|
||
|
ctx->callbacks.freeFn(ctx->user, ctx);
|
||
|
}
|
||
|
|
||
|
void TinyDDS_Reset(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return;
|
||
|
|
||
|
// backup user provided callbacks and data
|
||
|
TinyDDS_Callbacks callbacks;
|
||
|
memcpy(&callbacks, &ctx->callbacks, sizeof(TinyDDS_Callbacks));
|
||
|
void *user = ctx->user;
|
||
|
|
||
|
for (int i = 0; i < TINYDDS_MAX_MIPMAPLEVELS; ++i) {
|
||
|
if (ctx->mipmaps[i] != NULL) {
|
||
|
callbacks.freeFn(user, (void *) ctx->mipmaps[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(ctx->clut) {
|
||
|
callbacks.freeFn(user, (void *) ctx->clut);
|
||
|
ctx->clut = NULL;
|
||
|
}
|
||
|
|
||
|
// reset to default state
|
||
|
memset(ctx, 0, sizeof(TinyDDS_Context));
|
||
|
memcpy(&ctx->callbacks, &callbacks, sizeof(TinyDDS_Callbacks));
|
||
|
ctx->user = user;
|
||
|
|
||
|
}
|
||
|
|
||
|
static bool TinyDDS_IsCLUT(TinyDDS_Format fmt) {
|
||
|
switch (fmt) {
|
||
|
case TDDS_P8:
|
||
|
case TDDS_A8P8:
|
||
|
return true;
|
||
|
default: return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool TinyDDS_IsCompressed(TinyDDS_Format fmt) {
|
||
|
switch (fmt) {
|
||
|
case TDDS_BC1_RGBA_UNORM_BLOCK:
|
||
|
case TDDS_BC1_RGBA_SRGB_BLOCK:
|
||
|
case TDDS_BC2_UNORM_BLOCK:
|
||
|
case TDDS_BC2_SRGB_BLOCK:
|
||
|
case TDDS_BC3_UNORM_BLOCK:
|
||
|
case TDDS_BC3_SRGB_BLOCK:
|
||
|
case TDDS_BC4_UNORM_BLOCK:
|
||
|
case TDDS_BC4_SNORM_BLOCK:
|
||
|
case TDDS_BC5_UNORM_BLOCK:
|
||
|
case TDDS_BC5_SNORM_BLOCK:
|
||
|
case TDDS_BC6H_UFLOAT_BLOCK:
|
||
|
case TDDS_BC6H_SFLOAT_BLOCK:
|
||
|
case TDDS_BC7_UNORM_BLOCK:
|
||
|
case TDDS_BC7_SRGB_BLOCK: return true;
|
||
|
default: return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// the size is per pixel (except R1) for uncompressed and per block of 16 pixels for compressed
|
||
|
static uint32_t TinyDDS_FormatSize(TinyDDS_Format fmt) {
|
||
|
switch(fmt) {
|
||
|
// 8 pixels at 1 bits each
|
||
|
case TDDS_R1_UNORM:
|
||
|
return 1;
|
||
|
// 2 * 4 bits
|
||
|
case TDDS_R4G4_UNORM:
|
||
|
case TDDS_G4R4_UNORM:
|
||
|
// 1 * 8 bits
|
||
|
case TDDS_P8:;
|
||
|
case TDDS_R8_UNORM:
|
||
|
case TDDS_R8_SNORM:
|
||
|
case TDDS_R8_UINT:
|
||
|
case TDDS_R8_SINT:
|
||
|
case TDDS_A8_UNORM:
|
||
|
// 2 + 2 * 3 bits
|
||
|
case TDDS_B2G3R3_UNORM:
|
||
|
return 1;
|
||
|
|
||
|
// 2 + 2 * 3 +8 bits
|
||
|
case TDDS_B2G3R3A8_UNORM:
|
||
|
// 4 * 4 bits
|
||
|
case TDDS_B4G4R4A4_UNORM:
|
||
|
case TDDS_A4B4G4R4_UNORM:
|
||
|
case TDDS_X4B4G4R4_UNORM:
|
||
|
case TDDS_A4R4G4B4_UNORM:
|
||
|
case TDDS_X4R4G4B4_UNORM:
|
||
|
case TDDS_B4G4R4X4_UNORM:
|
||
|
case TDDS_R4G4B4A4_UNORM:
|
||
|
case TDDS_R4G4B4X4_UNORM:
|
||
|
|
||
|
// 3 * 5 bits + 1 bit
|
||
|
case TDDS_B5G5R5A1_UNORM:
|
||
|
case TDDS_B5G5R5X1_UNORM:
|
||
|
case TDDS_R5G5B5A1_UNORM:
|
||
|
case TDDS_R5G5B5X1_UNORM:
|
||
|
case TDDS_A1R5G5B5_UNORM:
|
||
|
case TDDS_X1R5G5B5_UNORM:
|
||
|
case TDDS_A1B5G5R5_UNORM:
|
||
|
case TDDS_X1B5G5R5_UNORM:
|
||
|
|
||
|
// 1 * 6 bit + 2 * 5 bits
|
||
|
case TDDS_R5G6B5_UNORM:
|
||
|
case TDDS_B5G6R5_UNORM:
|
||
|
// 2 x 8 bits
|
||
|
case TDDS_A8P8:
|
||
|
case TDDS_R8G8_UNORM:
|
||
|
case TDDS_R8G8_SNORM:
|
||
|
case TDDS_G8R8_UNORM:
|
||
|
case TDDS_G8R8_SNORM:
|
||
|
case TDDS_R8G8_UINT:
|
||
|
case TDDS_R8G8_SINT:
|
||
|
// 1 * 16 bits
|
||
|
case TDDS_R16_UNORM:
|
||
|
case TDDS_R16_SNORM:
|
||
|
case TDDS_R16_UINT:
|
||
|
case TDDS_R16_SINT:
|
||
|
case TDDS_R16_SFLOAT:
|
||
|
return 2;
|
||
|
|
||
|
// 3 * 8 bits
|
||
|
case TDDS_R8G8B8_UNORM:
|
||
|
case TDDS_B8G8R8_UNORM:
|
||
|
return 3;
|
||
|
// 4 * 8 bits
|
||
|
case TDDS_A8B8G8R8_SNORM:
|
||
|
case TDDS_R8G8B8A8_SNORM:
|
||
|
case TDDS_R8G8B8A8_UINT:
|
||
|
case TDDS_R8G8B8A8_SINT:
|
||
|
case TDDS_R8G8B8A8_SRGB:
|
||
|
case TDDS_B8G8R8A8_SRGB:
|
||
|
case TDDS_B8G8R8A8_SNORM:
|
||
|
|
||
|
case TDDS_R8G8B8A8_UNORM:
|
||
|
case TDDS_R8G8B8X8_UNORM:
|
||
|
case TDDS_B8G8R8A8_UNORM:
|
||
|
case TDDS_B8G8R8X8_UNORM:
|
||
|
case TDDS_A8B8G8R8_UNORM:
|
||
|
case TDDS_X8B8G8R8_UNORM:
|
||
|
case TDDS_A8R8G8B8_UNORM:
|
||
|
case TDDS_X8R8G8B8_UNORM:
|
||
|
|
||
|
// 3 * 9 bits + 5 bits
|
||
|
case TDDS_R9G9B9E5_UFLOAT:
|
||
|
// 3 * 10 bits + 2 bits
|
||
|
case TDDS_R10G10B10_7E3_A2_FLOAT:
|
||
|
case TDDS_R10G10B10_6E4_A2_FLOAT:
|
||
|
case TDDS_R10G10B10_SNORM_A2_UNORM:
|
||
|
|
||
|
case TDDS_B10G10R10A2_UNORM:
|
||
|
case TDDS_B10G10R10A2_SNORM:
|
||
|
case TDDS_A2B10G10R10_UNORM:
|
||
|
case TDDS_A2B10G10R10_SNORM:
|
||
|
case TDDS_A2R10G10B10_UNORM:
|
||
|
case TDDS_A2R10G10B10_SNORM:
|
||
|
case TDDS_R10G10B10A2_UNORM:
|
||
|
case TDDS_R10G10B10A2_SNORM:
|
||
|
case TDDS_R10G10B10A2_UINT:
|
||
|
|
||
|
// 2 * 11 bits + 10 bits
|
||
|
case TDDS_R11G11B10_UFLOAT:
|
||
|
// 2 * 16 bits
|
||
|
case TDDS_R16G16_UNORM:
|
||
|
case TDDS_R16G16_SNORM:
|
||
|
case TDDS_R16G16_UINT:
|
||
|
case TDDS_R16G16_SINT:
|
||
|
case TDDS_R16G16_SFLOAT:
|
||
|
case TDDS_G16R16_UNORM:
|
||
|
case TDDS_G16R16_SNORM:
|
||
|
// 1 * 32 bits
|
||
|
case TDDS_R32_UINT:
|
||
|
case TDDS_R32_SINT:
|
||
|
case TDDS_R32_SFLOAT:
|
||
|
return 4;
|
||
|
// 4 * 16 bits
|
||
|
case TDDS_R16G16B16A16_UNORM:
|
||
|
case TDDS_R16G16B16A16_SNORM:
|
||
|
case TDDS_R16G16B16A16_UINT:
|
||
|
case TDDS_R16G16B16A16_SINT:
|
||
|
case TDDS_R16G16B16A16_SFLOAT:
|
||
|
// 2 * 32 bits
|
||
|
case TDDS_R32G32_UINT:
|
||
|
case TDDS_R32G32_SINT:
|
||
|
case TDDS_R32G32_SFLOAT:
|
||
|
return 8;
|
||
|
// 3 * 32 bits
|
||
|
case TDDS_R32G32B32_UINT:
|
||
|
case TDDS_R32G32B32_SINT:
|
||
|
case TDDS_R32G32B32_SFLOAT:
|
||
|
return 12;
|
||
|
// 4 * 32 bits
|
||
|
case TDDS_R32G32B32A32_UINT:
|
||
|
case TDDS_R32G32B32A32_SINT:
|
||
|
case TDDS_R32G32B32A32_SFLOAT:
|
||
|
return 16;
|
||
|
// block formats
|
||
|
case TDDS_BC1_RGBA_UNORM_BLOCK:
|
||
|
case TDDS_BC1_RGBA_SRGB_BLOCK:
|
||
|
case TDDS_BC4_UNORM_BLOCK:
|
||
|
case TDDS_BC4_SNORM_BLOCK:
|
||
|
return 8;
|
||
|
|
||
|
case TDDS_BC2_UNORM_BLOCK:
|
||
|
case TDDS_BC2_SRGB_BLOCK:
|
||
|
case TDDS_BC3_UNORM_BLOCK:
|
||
|
case TDDS_BC3_SRGB_BLOCK:
|
||
|
case TDDS_BC5_UNORM_BLOCK:
|
||
|
case TDDS_BC5_SNORM_BLOCK:
|
||
|
case TDDS_BC6H_UFLOAT_BLOCK:
|
||
|
case TDDS_BC6H_SFLOAT_BLOCK:
|
||
|
case TDDS_BC7_UNORM_BLOCK:
|
||
|
case TDDS_BC7_SRGB_BLOCK:
|
||
|
return 16;
|
||
|
|
||
|
case TDDS_UNDEFINED: return 0;
|
||
|
// default: return 0;
|
||
|
case TDDS_AYUV:break;
|
||
|
case TDDS_Y410:break;
|
||
|
case TDDS_Y416:break;
|
||
|
case TDDS_NV12:break;
|
||
|
case TDDS_P010:break;
|
||
|
case TDDS_P016:break;
|
||
|
case TDDS_420_OPAQUE:break;
|
||
|
case TDDS_YUY2:break;
|
||
|
case TDDS_Y210:break;
|
||
|
case TDDS_Y216:break;
|
||
|
case TDDS_NV11:break;
|
||
|
case TDDS_AI44:break;
|
||
|
case TDDS_IA44:break;
|
||
|
case TDDS_D16_UNORM_S8_UINT:break;
|
||
|
case TDDS_R16_UNORM_X8_TYPELESS:break;
|
||
|
case TDDS_X16_TYPELESS_G8_UINT:break;
|
||
|
case TDDS_P208:break;
|
||
|
case TDDS_V208:break;
|
||
|
case TDDS_V408:break;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#define TINYDDS_CHK_DDSFORMAT(bits, rm, gm, bm, am, fmt) \
|
||
|
if ((ctx->header.formatRGBBitCount == bits) && \
|
||
|
(ctx->header.formatRBitMask == rm) && \
|
||
|
(ctx->header.formatGBitMask == gm) && \
|
||
|
(ctx->header.formatBBitMask == bm) && \
|
||
|
(ctx->header.formatABitMask == am)) { return fmt; }
|
||
|
|
||
|
static TinyDDS_Format TinyDDS_DecodeFormat(TinyDDS_Context *ctx) {
|
||
|
if (ctx->header.formatFlags & TINYDDS_DDPF_FOURCC) {
|
||
|
if (ctx->headerDx10.DXGIFormat != TIF_DXGI_FORMAT_UNKNOWN) {
|
||
|
return (TinyDDS_Format) ctx->headerDx10.DXGIFormat;
|
||
|
}
|
||
|
|
||
|
// check fourCC and some special numbers..
|
||
|
// unofficially during the dx9 timeline, D3D_FORMAT were stuck directly into
|
||
|
// formatFourCC field we handle FourCC and these < 119 codes here
|
||
|
// its unclear if this was only for formats that couldn't be exposed via
|
||
|
// Direct Draw Surfaces (like floats etc.) so I decode most of them anyway
|
||
|
switch (ctx->header.formatFourCC) {
|
||
|
case TINYDDS_D3DFMT_R8G8B8: return TDDS_R8G8B8_UNORM;
|
||
|
case TINYDDS_D3DFMT_A8R8G8B8: return TDDS_A8R8G8B8_UNORM;
|
||
|
case TINYDDS_D3DFMT_X8R8G8B8: return TDDS_X8R8G8B8_UNORM;
|
||
|
case TINYDDS_D3DFMT_R5G6B5: return TDDS_R5G6B5_UNORM;
|
||
|
case TINYDDS_D3DFMT_X1R5G5B5: return TDDS_X1R5G5B5_UNORM;
|
||
|
case TINYDDS_D3DFMT_A1R5G5B5: return TDDS_A1R5G5B5_UNORM;
|
||
|
case TINYDDS_D3DFMT_A4R4G4B4: return TDDS_A4R4G4B4_UNORM;
|
||
|
case TINYDDS_D3DFMT_R3G3B2: return TDDS_B2G3R3_UNORM;
|
||
|
case TINYDDS_D3DFMT_A8: return TDDS_A8_UNORM;
|
||
|
case TINYDDS_D3DFMT_A8R3G3B2: return TDDS_B2G3R3A8_UNORM;
|
||
|
case TINYDDS_D3DFMT_X4R4G4B4: return TDDS_A4R4G4B4_UNORM;
|
||
|
case TINYDDS_D3DFMT_A2B10G10R10: return TDDS_A2B10G10R10_UNORM;
|
||
|
case TINYDDS_D3DFMT_A8B8G8R8: return TDDS_A8B8G8R8_UNORM;
|
||
|
case TINYDDS_D3DFMT_X8B8G8R8: return TDDS_A8B8G8R8_UNORM;
|
||
|
case TINYDDS_D3DFMT_A2R10G10B10: return TDDS_A2R10G10B10_UNORM;
|
||
|
case TINYDDS_D3DFMT_G16R16: return TDDS_R16G16_UNORM;
|
||
|
case TINYDDS_D3DFMT_A16B16G16R16: return TDDS_R16G16B16A16_UNORM;
|
||
|
case TINYDDS_D3DFMT_R16F: return TDDS_R16_SFLOAT;
|
||
|
case TINYDDS_D3DFMT_G16R16F: return TDDS_R16G16_SFLOAT;
|
||
|
case TINYDDS_D3DFMT_A16B16G16R16F: return TDDS_R16G16B16A16_SFLOAT;
|
||
|
case TINYDDS_D3DFMT_A8P8: return TDDS_A8P8;
|
||
|
case TINYDDS_D3DFMT_P8: return TDDS_P8;
|
||
|
case TINYDDS_D3DFMT_L8: return TDDS_R8_UNORM;
|
||
|
case TINYDDS_D3DFMT_A8L8: return TDDS_R8G8_UNORM;
|
||
|
case TINYDDS_D3DFMT_A4L4: return TDDS_R4G4_UNORM;
|
||
|
case TINYDDS_D3DFMT_V8U8: return TDDS_G8R8_SNORM;
|
||
|
case TINYDDS_D3DFMT_L6V5U5: return TDDS_UNDEFINED; // TODO TDDS_R5G6B5_SNORM_PACK16;
|
||
|
case TINYDDS_D3DFMT_X8L8V8U8: return TDDS_R8G8B8A8_SNORM;
|
||
|
case TINYDDS_D3DFMT_Q8W8V8U8: return TDDS_R8G8B8A8_SNORM;
|
||
|
case TINYDDS_D3DFMT_V16U16: return TDDS_R16G16_SNORM;
|
||
|
case TINYDDS_D3DFMT_A2W10V10U10: return TDDS_A2B10G10R10_SNORM;
|
||
|
case TINYDDS_D3DFMT_L16: return TDDS_R16_UNORM;
|
||
|
case TINYDDS_D3DFMT_Q16W16V16U16: return TDDS_R16G16B16A16_SNORM;
|
||
|
case TINYDDS_D3DFMT_R32F: return TDDS_R32_SFLOAT;
|
||
|
case TINYDDS_D3DFMT_G32R32F: return TDDS_R32G32_SFLOAT;
|
||
|
case TINYDDS_D3DFMT_A32B32G32R32F: return TDDS_R32G32B32A32_SFLOAT;
|
||
|
case TINYDDS_D3DFMT_CxV8U8: return TDDS_UNDEFINED;
|
||
|
case TINYDDS_D3DFMT_A1: return TDDS_R1_UNORM;
|
||
|
case TINYDDS_D3DFMT_A2B10G10R10_XR_BIAS: return TDDS_UNDEFINED;
|
||
|
|
||
|
// real 4CC no exotics yet just the block compression ones
|
||
|
case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '1'): return TDDS_BC1_RGBA_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '2'): return TDDS_BC2_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '3'): return TDDS_BC2_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '4'): return TDDS_BC3_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '5'): return TDDS_BC3_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('A', 'T', 'I', '1'): return TDDS_BC4_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('A', 'T', 'I', '2'): return TDDS_BC5_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('B', 'C', '4', 'U'): return TDDS_BC4_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('B', 'C', '4', 'S'): return TDDS_BC4_SNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('B', 'C', '5', 'U'): return TDDS_BC5_UNORM_BLOCK;
|
||
|
case TINYDDS_MAKE_RIFFCODE('B', 'C', '5', 'S'): return TDDS_BC5_SNORM_BLOCK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// okay back to direct draw surface bit fields to try and work format out.
|
||
|
// TODO this could be better i'm sure
|
||
|
|
||
|
if ((ctx->header.formatFlags & TINYDDS_DDPF_PALETTEINDEXED4)) {
|
||
|
return TDDS_UNDEFINED; // TODO 4 bit CLUTs
|
||
|
}
|
||
|
|
||
|
if ((ctx->header.formatFlags & TINYDDS_DDPF_PALETTEINDEXED8)) {
|
||
|
if(ctx->header.formatRGBBitCount != 8) return TDDS_UNDEFINED;
|
||
|
if(ctx->header.formatFlags & TINYDDS_DDPF_ALPHA) {
|
||
|
return TDDS_A8P8;
|
||
|
} else {
|
||
|
return TDDS_P8;
|
||
|
}
|
||
|
}
|
||
|
// what is this? TINYDDS_DDPF_PALETTEINDEXEDTO8
|
||
|
|
||
|
// most have RGB data and/or alpha
|
||
|
if ((ctx->header.formatFlags & TINYDDS_DDPF_RGB) ||
|
||
|
(ctx->header.formatFlags & TINYDDS_DDPF_ALPHA)) {
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(1, 0x1, 0x0, 0, 0, TDDS_R1_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(8, 0xF0, 0x0F, 0, 0, TDDS_G4R4_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(8, 0x0F, 0xF0, 0, 0, TDDS_R4G4_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(8, 0xFF, 0, 0, 0, TDDS_R8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(8, 0, 0, 0, 0xFF, TDDS_A8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(8, 0xE0, 0x1C, 0x3, 0, TDDS_B2G3R3_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xF000, 0x0F00, 0x00F0, 0x000F, TDDS_A4B4G4R4_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xF000, 0x0F00, 0x00F0, 0x0000, TDDS_X4B4G4R4_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x00F0, 0x0F00, 0xF000, 0x000F, TDDS_A4R4G4B4_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x00F0, 0x0F00, 0xF000, 0x0000, TDDS_X4R4G4B4_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x0F00, 0x00F0, 0x000F, 0xF000, TDDS_B4G4R4A4_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x0F00, 0x00F0, 0x000F, 0x0000, TDDS_B4G4R4X4_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x000F, 0x00F0, 0x0F00, 0xF000, TDDS_R4G4B4A4_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x000F, 0x00F0, 0x0F00, 0x0000, TDDS_R4G4B4X4_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x7C00, 0x03E0, 0x001F, 0x8000, TDDS_B5G5R5A1_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x7C00, 0x03E0, 0x001F, 0x0000, TDDS_B5G5R5X1_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x001F, 0x03E0, 0x7C00, 0x8000, TDDS_R5G5B5A1_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x001F, 0x03E0, 0x7C00, 0x0000, TDDS_R5G5B5X1_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x003E, 0x07C0, 0xF800, 0x0001, TDDS_A1R5G5B5_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x003E, 0x07C0, 0xF800, 0x0000, TDDS_X1R5G5B5_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xF800, 0x07C0, 0x003E, 0x0001, TDDS_A1B5G5R5_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xF800, 0x07C0, 0x003E, 0x0000, TDDS_X1B5G5R5_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xF800, 0x07E0, 0x001F, 0x0000, TDDS_B5G6R5_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x001F, 0x07E0, 0xF800, 0x0000, TDDS_R5G6B5_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x00FF, 0xFF00, 0x0000, 0x0000, TDDS_R8G8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xFF00, 0x00FF, 0x0000, 0x0000, TDDS_G8R8_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xFFFF, 0x0000, 0x0000, 0x0000, TDDS_R16_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xE0, 0x1C, 0x3, 0xFF00, TDDS_B2G3R3A8_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(24, 0xFF0000, 0x00FF00, 0x0000FF, 0x0, TDDS_B8G8R8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(24, 0x0000FF, 0x00FF00, 0xFF0000, 0x0, TDDS_R8G8B8_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000, TDDS_R8G8B8A8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000, TDDS_R8G8B8X8_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, TDDS_B8G8R8A8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000, TDDS_B8G8R8X8_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF, TDDS_A8B8G8R8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000, TDDS_X8B8G8R8_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF, TDDS_A8R8G8B8_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000, TDDS_X8R8G8B8_UNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000, TDDS_R10G10B10A2_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0xFFC00000, 0x003FF000, 0x00000FFC, 0x00000003, TDDS_A2B10G10R10_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x00000FFC, 0x003FF000, 0xFFC00000, 0x00000003, TDDS_A2R10G10B10_UNORM);
|
||
|
|
||
|
// this is often written incorrectly so we use the most 'common' version
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000, TDDS_B10G10R10A2_UNORM);
|
||
|
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0xFFFF0000, 0x0000FFFF, 0x00000000, 0x00000000, TDDS_G16R16_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000, TDDS_R16G16_UNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, TDDS_R32_UINT);
|
||
|
|
||
|
if (ctx->header.formatRGBBitCount == 8) return TDDS_R8_UINT;
|
||
|
if (ctx->header.formatRGBBitCount == 16) return TDDS_R16_UINT;
|
||
|
if (ctx->header.formatRGBBitCount == 32) return TDDS_R32_UINT;
|
||
|
}
|
||
|
|
||
|
if ((ctx->header.formatFlags & TINYDDS_DDPF_BUMPDUDV) ||
|
||
|
(ctx->header.formatFlags & TINYDDS_DDPF_BUMPLUMINANCE)) {
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0xFF00, 0x00FF, 0x0000, 0x0000, TDDS_G8R8_SNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x00FF, 0xFF00, 0x0000, 0x0000, TDDS_R8G8_SNORM);
|
||
|
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0xFFFF0000, 0x0000FFFF, 0x0000, 0x0, TDDS_G16R16_SNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x0000FFFF, 0xFFFF0000, 0x0000, 0x0, TDDS_R16G16_SNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000, TDDS_R8G8B8A8_SNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000, TDDS_R10G10B10A2_SNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000, TDDS_B10G10R10A2_SNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0x00000FFC, 0x003FF000, 0xFFC00000, 0x00000003, TDDS_A2R10G10B10_SNORM);
|
||
|
TINYDDS_CHK_DDSFORMAT(32, 0xFFC00000, 0x003FF000, 0x00000FFC, 0x00000003, TDDS_A2B10G10R10_SNORM);
|
||
|
|
||
|
if (ctx->header.formatRGBBitCount == 8) return TDDS_R8_SINT;
|
||
|
if (ctx->header.formatRGBBitCount == 16) return TDDS_R16_SINT;
|
||
|
if (ctx->header.formatRGBBitCount == 32) return TDDS_R32_SINT;
|
||
|
}
|
||
|
|
||
|
if (ctx->header.formatFlags & TINYDDS_DDPF_LUMINANCE) {
|
||
|
TINYDDS_CHK_DDSFORMAT(8, 0x0F, 0x00, 0x00, 0xF0, TDDS_R4G4_UNORM); // this is A4L4 aka A4R4 we decode this as R4G4
|
||
|
TINYDDS_CHK_DDSFORMAT(16, 0x00FF, 0x0000, 0x0000, 0xFF00, TDDS_R8G8_UNORM); // this is A8L8 aka A4R8 we decode this as R8G8
|
||
|
|
||
|
if (ctx->header.formatRGBBitCount == 8) return TDDS_R8_UNORM;
|
||
|
if (ctx->header.formatRGBBitCount == 16) return TDDS_R16_UNORM;
|
||
|
if (ctx->header.formatRGBBitCount == 32) return TDDS_R32_UINT;
|
||
|
|
||
|
}
|
||
|
|
||
|
return TDDS_UNDEFINED;
|
||
|
}
|
||
|
#undef TINYDDS_CHK_DDSFORMAT
|
||
|
|
||
|
static uint32_t TinyDDS_MipMapReduce(uint32_t value, uint32_t mipmaplevel) {
|
||
|
|
||
|
// handle 0 being passed in
|
||
|
if (value <= 1)
|
||
|
return 1;
|
||
|
|
||
|
// there are better ways of doing this (log2 etc.) but this doesn't require any
|
||
|
// dependecies and isn't used enough to matter imho
|
||
|
for (uint32_t i = 0u; i < mipmaplevel; ++i) {
|
||
|
if (value <= 1)
|
||
|
return 1;
|
||
|
value = value / 2;
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
bool TinyDDS_ReadHeader(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
|
||
|
ctx->headerPos = ctx->callbacks.tellFn(ctx->user);
|
||
|
if( ctx->callbacks.readFn(ctx->user, &ctx->header, sizeof(TinyDDS_Header)) != sizeof(TinyDDS_Header)) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Could not read DDS header");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// try the easy case of a modern dx10 DDS file
|
||
|
if ((ctx->header.formatFlags & TINYDDS_DDPF_FOURCC) &&
|
||
|
(ctx->header.formatFourCC == TINYDDS_MAKE_RIFFCODE('D', 'X', '1', '0'))) {
|
||
|
ctx->callbacks.readFn(ctx->user, &ctx->headerDx10, sizeof(TinyDDS_HeaderDX10));
|
||
|
|
||
|
if (ctx->headerDx10.DXGIFormat >= TDDS_SYNTHESISED_DXGIFORMATS) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "DX10 Header has an invalid DXGI_FORMAT code");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ctx->format = TinyDDS_DecodeFormat(ctx);
|
||
|
if (ctx->format == TDDS_UNDEFINED) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Could not decode DDS format");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if( (ctx->header.formatFourCC == 0) &&
|
||
|
(ctx->header.formatRGBBitCount != 0) &&
|
||
|
((ctx->header.formatRGBBitCount/8) != TinyDDS_FormatSize(ctx->format))) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Format size mismatch");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// correct for dodgy mipmap levels counts
|
||
|
if(ctx->header.mipMapCount > 1) {
|
||
|
uint32_t w = ctx->header.width;
|
||
|
uint32_t h = ctx->header.height;
|
||
|
|
||
|
for(uint32_t i = 0; i < ctx->header.mipMapCount;++i) {
|
||
|
if (TinyDDS_IsCompressed(ctx->format)) {
|
||
|
if (w <= 4 || h <= 4) {
|
||
|
ctx->header.mipMapCount = i + 1;
|
||
|
break;
|
||
|
}
|
||
|
} else if (w <= 1 || h <= 1) {
|
||
|
ctx->header.mipMapCount = i + 1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
w = w / 2;
|
||
|
h = h / 2;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (TinyDDS_IsCompressed(ctx->format)) {
|
||
|
// compressed images never get asked to make mip maps which is good as
|
||
|
// requires decompress/compress cycle
|
||
|
if(ctx->header.mipMapCount == 0) ctx->header.mipMapCount = 1;
|
||
|
}
|
||
|
|
||
|
if(TinyDDS_IsCLUT(ctx->format)) {
|
||
|
// for now don't ask to generate mipmaps for cluts
|
||
|
if(ctx->header.mipMapCount == 0) ctx->header.mipMapCount = 1;
|
||
|
|
||
|
size_t const clutSize = 256 * sizeof(uint32_t);
|
||
|
|
||
|
ctx->clut = (uint32_t*) ctx->callbacks.allocFn(ctx->user, clutSize);
|
||
|
|
||
|
if( ctx->callbacks.readFn(ctx->user, (void*)ctx->clut, clutSize) != clutSize) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Could not read DDS CLUT");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ctx->firstImagePos = ctx->callbacks.tellFn(ctx->user);
|
||
|
ctx->headerValid = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool TinyDDS_IsCubemap(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return (ctx->header.caps2 & TINYDDS_DDSCAPS2_CUBEMAP);
|
||
|
}
|
||
|
|
||
|
bool TinyDDS_Dimensions(TinyDDS_ContextHandle handle,
|
||
|
uint32_t *width,
|
||
|
uint32_t *height,
|
||
|
uint32_t *depth,
|
||
|
uint32_t *slices) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (width)
|
||
|
*width = ctx->header.width;
|
||
|
if (height)
|
||
|
*height = ctx->header.height;
|
||
|
if (depth)
|
||
|
*depth = ctx->header.depth;
|
||
|
if (slices)
|
||
|
*slices = ctx->headerDx10.arraySize;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
uint32_t TinyDDS_Width(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return 0;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return 0;
|
||
|
}
|
||
|
return ctx->header.width;
|
||
|
}
|
||
|
|
||
|
uint32_t TinyDDS_Height(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return 0;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return 0;
|
||
|
}
|
||
|
return ctx->header.height;
|
||
|
}
|
||
|
|
||
|
uint32_t TinyDDS_Depth(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return 0;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return ctx->header.depth;
|
||
|
}
|
||
|
|
||
|
uint32_t TinyDDS_ArraySlices(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return 0;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return ctx->headerDx10.arraySize;
|
||
|
}
|
||
|
|
||
|
bool TinyDDS_Is1D(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return false;
|
||
|
}
|
||
|
return (ctx->header.height <= 1 && ctx->header.depth <= 1);
|
||
|
}
|
||
|
bool TinyDDS_Is2D(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return false;
|
||
|
}
|
||
|
return (ctx->header.height > 1 && ctx->header.depth <= 1);
|
||
|
}
|
||
|
bool TinyDDS_Is3D(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return (ctx->header.height > 1 && ctx->header.depth > 1);
|
||
|
}
|
||
|
|
||
|
bool TinyDDS_IsArray(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return (ctx->headerDx10.arraySize >= 1);
|
||
|
}
|
||
|
|
||
|
uint32_t TinyDDS_NumberOfMipmaps(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return 0;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return ctx->header.mipMapCount ? ctx->header.mipMapCount : 1;
|
||
|
}
|
||
|
|
||
|
bool TinyDDS_NeedsGenerationOfMipmaps(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return false;
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return ctx->header.mipMapCount == 0;
|
||
|
}
|
||
|
|
||
|
bool TinyDDS_NeedsEndianCorrecting(TinyDDS_ContextHandle handle) {
|
||
|
// TODO should return true if this file is compiled on big endian machines
|
||
|
BASISU_NOTE_UNUSED(handle);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
uint32_t TinyDDS_FaceSize(TinyDDS_ContextHandle handle, uint32_t mipmaplevel) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return 0;
|
||
|
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return 0;
|
||
|
}
|
||
|
uint32_t w = TinyDDS_MipMapReduce(ctx->header.width, mipmaplevel);
|
||
|
uint32_t h = TinyDDS_MipMapReduce(ctx->header.height, mipmaplevel);
|
||
|
uint32_t d = TinyDDS_MipMapReduce(ctx->header.depth, mipmaplevel);
|
||
|
uint32_t s = ctx->headerDx10.arraySize ? ctx->headerDx10.arraySize : 1;
|
||
|
|
||
|
if(d > 1 && s > 1) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Volume textures can't have array slices or be cubemap");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (TinyDDS_IsCompressed(ctx->format)) {
|
||
|
// padd to block boundaries
|
||
|
w = (w + 3) / 4;
|
||
|
h = (h + 3) / 4;
|
||
|
}
|
||
|
// 1 bit special case
|
||
|
if(ctx->format == TDDS_R1_UNORM) {
|
||
|
w = (w + 7) / 8;
|
||
|
}
|
||
|
|
||
|
uint32_t const formatSize = TinyDDS_FormatSize(ctx->format);
|
||
|
return w * h * d * s * formatSize;
|
||
|
}
|
||
|
|
||
|
uint32_t TinyDDS_ImageSize(TinyDDS_ContextHandle handle, uint32_t mipmaplevel) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return 0;
|
||
|
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if( ctx->header.caps2 & TINYDDS_DDSCAPS2_CUBEMAP ||
|
||
|
ctx->headerDx10.miscFlag & TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE ) {
|
||
|
return TinyDDS_FaceSize(handle, mipmaplevel) * 6;
|
||
|
} else {
|
||
|
return TinyDDS_FaceSize(handle, mipmaplevel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void const *TinyDDS_ImageRawData(TinyDDS_ContextHandle handle, uint32_t mipmaplevel) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (mipmaplevel >= (ctx->header.mipMapCount ? ctx->header.mipMapCount : 1) ) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Invalid mipmap level");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (mipmaplevel >= TINYDDS_MAX_MIPMAPLEVELS) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Invalid mipmap level");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (ctx->mipmaps[mipmaplevel] != NULL)
|
||
|
return ctx->mipmaps[mipmaplevel];
|
||
|
|
||
|
if( ctx->header.caps2 & TINYDDS_DDSCAPS2_CUBEMAP ||
|
||
|
ctx->headerDx10.miscFlag & TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE ) {
|
||
|
|
||
|
uint64_t offset = 0;
|
||
|
for(uint32_t i=0;i < mipmaplevel;++i) {
|
||
|
offset += TinyDDS_FaceSize(handle, i);
|
||
|
}
|
||
|
|
||
|
uint32_t mipMapCount = ctx->header.mipMapCount;
|
||
|
if(mipMapCount == 0) mipMapCount = 1;
|
||
|
|
||
|
// at least one cubemap generater has mipMapCount wrong which causes
|
||
|
// image artifacts :(
|
||
|
uint64_t nextFaceOffset = 0;
|
||
|
for(uint32_t i = 0;i < mipMapCount;++i) {
|
||
|
nextFaceOffset += TinyDDS_FaceSize(handle, i);
|
||
|
}
|
||
|
|
||
|
size_t const faceSize = TinyDDS_FaceSize(handle, mipmaplevel);
|
||
|
ctx->mipmaps[mipmaplevel] = (uint8_t const *) ctx->callbacks.allocFn(ctx->user, faceSize * 6);
|
||
|
if(!ctx->mipmaps[mipmaplevel]) return NULL;
|
||
|
|
||
|
uint8_t *dstPtr = (uint8_t*)ctx->mipmaps[mipmaplevel];
|
||
|
for (uint32_t i = 0u;i < 6;++i) {
|
||
|
ctx->callbacks.seekFn(ctx->user, offset + ctx->firstImagePos);
|
||
|
size_t read = ctx->callbacks.readFn(ctx->user, (void *) dstPtr, faceSize);
|
||
|
if(read != faceSize) {
|
||
|
ctx->callbacks.freeFn(ctx->user, (void*)&ctx->mipmaps[mipmaplevel]);
|
||
|
return NULL;
|
||
|
}
|
||
|
dstPtr += faceSize;
|
||
|
offset += nextFaceOffset;
|
||
|
}
|
||
|
return ctx->mipmaps[mipmaplevel];
|
||
|
}
|
||
|
|
||
|
uint64_t offset = 0;
|
||
|
for(uint32_t i=0;i < mipmaplevel;++i) {
|
||
|
offset += TinyDDS_ImageSize(handle, i);
|
||
|
}
|
||
|
|
||
|
uint32_t size = TinyDDS_ImageSize(handle, mipmaplevel);
|
||
|
if (size == 0)
|
||
|
return NULL;
|
||
|
|
||
|
ctx->callbacks.seekFn(ctx->user, offset + ctx->firstImagePos);
|
||
|
|
||
|
ctx->mipmaps[mipmaplevel] = (uint8_t const *) ctx->callbacks.allocFn(ctx->user, size);
|
||
|
if (!ctx->mipmaps[mipmaplevel]) return NULL;
|
||
|
size_t read = ctx->callbacks.readFn(ctx->user, (void *) ctx->mipmaps[mipmaplevel], size);
|
||
|
if(read != size) {
|
||
|
ctx->callbacks.freeFn(ctx->user, (void*)&ctx->mipmaps[mipmaplevel]);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return ctx->mipmaps[mipmaplevel];
|
||
|
}
|
||
|
|
||
|
TinyDDS_Format TinyDDS_GetFormat(TinyDDS_ContextHandle handle) {
|
||
|
TinyDDS_Context *ctx = (TinyDDS_Context *) handle;
|
||
|
if (ctx == NULL)
|
||
|
return TDDS_UNDEFINED;
|
||
|
|
||
|
if (!ctx->headerValid) {
|
||
|
ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid");
|
||
|
return TDDS_UNDEFINED;
|
||
|
}
|
||
|
return ctx->format;
|
||
|
}
|
||
|
|
||
|
#define TDDS_EF(bits, rm, gm, bm, am, fl) \
|
||
|
header->formatRGBBitCount = bits; \
|
||
|
header->formatRBitMask = rm; \
|
||
|
header->formatGBitMask = gm; \
|
||
|
header->formatBBitMask = bm; \
|
||
|
header->formatABitMask = am; \
|
||
|
header->formatFlags = fl; \
|
||
|
header->formatFourCC = 0; \
|
||
|
return true;
|
||
|
|
||
|
#define TDDS_EF_RGB(bits, rm, gm, bm) TDDS_EF(bits, rm, gm, bm, 0, TINYDDS_DDPF_RGB )
|
||
|
#define TDDS_EF_RGBA(bits, rm, gm, bm, am) TDDS_EF(bits, rm, gm, bm, am, TINYDDS_DDPF_RGB | TINYDDS_DDPF_ALPHAPIXELS)
|
||
|
#define TDDS_EF_ALPHA(bits, am) TDDS_EF(bits, 0, 0, 0, am, TINYDDS_DDPF_ALPHA)
|
||
|
|
||
|
#define TDDS_EF_BUMP_RG(bits, rm, gm) TDDS_EF(bits, rm, gm, 0, 0, TINYDDS_DDPF_BUMPDUDV)
|
||
|
#define TDDS_EF_BUMP_RGB(bits, rm, gm, bm) TDDS_EF(bits, rm, gm, bm, 0, TINYDDS_DDPF_BUMPLUMINANCE)
|
||
|
#define TDDS_EF_BUMP_RGBA(bits, rm, gm, bm, am) TDDS_EF(bits, rm, gm, bm, am, TINYDDS_DDPF_BUMPLUMINANCE | TINYDDS_DDPF_ALPHAPIXELS)
|
||
|
|
||
|
static bool TinyDDS_EncodeFormat(TinyDDS_Format fmt, TinyDDS_Header* header, TinyDDS_HeaderDX10* headerDx10) {
|
||
|
// lets start with the easy part. if its real DXGI_FORMAT we can just fill in the Dx10 part
|
||
|
if(fmt < TDDS_SYNTHESISED_DXGIFORMATS) {
|
||
|
headerDx10->DXGIFormat = (TinyImageFormat_DXGI_FORMAT)fmt;
|
||
|
header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','1','0');
|
||
|
header->formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
} else {
|
||
|
headerDx10->DXGIFormat = TIF_DXGI_FORMAT_UNKNOWN;
|
||
|
}
|
||
|
// now lets try synthesising if possible
|
||
|
// if we can reset the DX10 fourCC but leave the format in place
|
||
|
// that way if we have slices which can only be DXGI_FORMAT we can use it
|
||
|
switch(fmt) {
|
||
|
case TDDS_UNDEFINED: break;
|
||
|
|
||
|
case TDDS_R1_UNORM: TDDS_EF_RGB(1, 0x1, 0, 0)
|
||
|
case TDDS_R4G4_UNORM: TDDS_EF_RGB(8, 0x0F, 0xF0, 0)
|
||
|
case TDDS_G4R4_UNORM: TDDS_EF_RGB(8, 0xF0, 0x0F, 0)
|
||
|
case TDDS_B2G3R3_UNORM: TDDS_EF_RGB(8, 0x3, 0x7, 0x7 )
|
||
|
case TDDS_R8_UNORM: TDDS_EF_RGB(8, 0xFF, 0, 0 );
|
||
|
case TDDS_A8_UNORM: TDDS_EF_ALPHA( 8, 0xFF);
|
||
|
|
||
|
case TDDS_R16_UNORM:TDDS_EF_RGB( 16,0x0000FFFF, 0, 0)
|
||
|
case TDDS_A4B4G4R4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0xF000, 0x0F00, 0x00F0, 0x000F);
|
||
|
case TDDS_X4B4G4R4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0xF000, 0x0F00, 0x00F0, 0x0000);
|
||
|
case TDDS_B4G4R4A4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x0F00, 0x00F0, 0x000F, 0xF000);
|
||
|
case TDDS_B4G4R4X4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x0F00, 0x00F0, 0x000F, 0x0000);
|
||
|
case TDDS_A4R4G4B4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x00F0, 0x0F00, 0xF000, 0x000F);
|
||
|
case TDDS_X4R4G4B4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x00F0, 0x0F00, 0xF000, 0x0000);
|
||
|
case TDDS_R4G4B4A4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x000F, 0x00F0, 0x0F00, 0xF000);
|
||
|
case TDDS_R4G4B4X4_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x000F, 0x00F0, 0x0F00, 0x0000);
|
||
|
|
||
|
case TDDS_B5G5R5A1_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x7C00, 0x03E0, 0x001F, 0x8000);
|
||
|
case TDDS_B5G5R5X1_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x7C00, 0x03E0, 0x001F, 0x0000);
|
||
|
|
||
|
case TDDS_R5G5B5A1_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x001F, 0x03E0, 0x7C00, 0x8000);
|
||
|
case TDDS_R5G5B5X1_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x001F, 0x03E0, 0x7C00, 0x0000);
|
||
|
|
||
|
case TDDS_A1R5G5B5_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x003E, 0x07C0, 0xF800, 0x0001);
|
||
|
case TDDS_X1R5G5B5_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0x003E, 0x07C0, 0xF800, 0x0000);
|
||
|
case TDDS_A1B5G5R5_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0xF800, 0x07C0, 0x003E, 0x0001);
|
||
|
case TDDS_X1B5G5R5_UNORM:
|
||
|
TDDS_EF_RGBA(16, 0xF800, 0x07C0, 0x003E, 0x0000);
|
||
|
|
||
|
case TDDS_B5G6R5_UNORM:
|
||
|
TDDS_EF_RGB(16, 0xF800, 0x07E0, 0x001F);
|
||
|
case TDDS_R5G6B5_UNORM:
|
||
|
TDDS_EF_RGB(16, 0x001F, 0x07E0, 0xF800);
|
||
|
|
||
|
case TDDS_R8G8_UNORM:
|
||
|
TDDS_EF_RGB(16, 0x00FF, 0xFF00, 0);
|
||
|
case TDDS_G8R8_UNORM:
|
||
|
TDDS_EF_RGB(16, 0xFF00, 0x00FF, 0);
|
||
|
case TDDS_G8R8_SNORM:
|
||
|
TDDS_EF_BUMP_RG(16, 0xFF00, 0x00FF);
|
||
|
|
||
|
case TDDS_B2G3R3A8_UNORM: TDDS_EF_RGBA(8, 0x3, 0x7, 0x7, 0xFF00 )
|
||
|
|
||
|
case TDDS_R8G8B8_UNORM:
|
||
|
TDDS_EF_RGB( 24,0x000000FF, 0x0000FF00, 0x00FF0000)
|
||
|
case TDDS_B8G8R8_UNORM:
|
||
|
TDDS_EF_RGB( 24,0x00FF0000, 0x0000FF00, 0x000000FF)
|
||
|
|
||
|
case TDDS_R8G8B8A8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000)
|
||
|
case TDDS_R8G8B8X8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)
|
||
|
case TDDS_B8G8R8A8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)
|
||
|
case TDDS_B8G8R8X8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)
|
||
|
case TDDS_A8B8G8R8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF)
|
||
|
case TDDS_X8B8G8R8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000)
|
||
|
case TDDS_A8R8G8B8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF)
|
||
|
case TDDS_X8R8G8B8_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000)
|
||
|
|
||
|
/* A2R10G10B10 is broken via the traditional DDS descriptions, so we
|
||
|
* always use the Dx10 header for those
|
||
|
case TDDS_R10G10B10A2_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)
|
||
|
case TDDS_A2B10G10R10_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0xFFC00000, 0x003FF000, 0x00000FFC, 0x00000003)
|
||
|
case TDDS_A2R10G10B10_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x00000FFC, 0x003FF000, 0xFFC00000, 0x00000003)
|
||
|
case TDDS_B10G10R10A2_UNORM:
|
||
|
TDDS_EF_RGBA( 32,0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)
|
||
|
*/
|
||
|
case TDDS_R10G10B10A2_UNORM:
|
||
|
case TDDS_B10G10R10A2_UNORM:
|
||
|
case TDDS_A2B10G10R10_UNORM:
|
||
|
case TDDS_A2R10G10B10_UNORM:
|
||
|
case TDDS_R10G10B10A2_SNORM:
|
||
|
case TDDS_B10G10R10A2_SNORM:
|
||
|
case TDDS_A2B10G10R10_SNORM:
|
||
|
case TDDS_A2R10G10B10_SNORM:
|
||
|
break;
|
||
|
|
||
|
case TDDS_R16G16_UNORM: TDDS_EF_RGB( 32,0x0000FFFF, 0xFFFF0000, 0)
|
||
|
case TDDS_G16R16_UNORM: TDDS_EF_RGB( 32,0xFFFF0000, 0x0000FFFF, 0)
|
||
|
|
||
|
case TDDS_BC1_RGBA_UNORM_BLOCK:
|
||
|
header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','T','1');
|
||
|
header->formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
return true;
|
||
|
case TDDS_BC2_UNORM_BLOCK:
|
||
|
header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','T','3');
|
||
|
header->formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
return true;
|
||
|
case TDDS_BC3_UNORM_BLOCK:
|
||
|
header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','T','5');
|
||
|
header->formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
return true;
|
||
|
case TDDS_BC4_UNORM_BLOCK:
|
||
|
header->formatFourCC = TINYDDS_MAKE_RIFFCODE('A','T','I','1');
|
||
|
header->formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
return true;
|
||
|
case TDDS_BC5_UNORM_BLOCK:
|
||
|
header->formatFourCC = TINYDDS_MAKE_RIFFCODE('A','T','I','2');
|
||
|
header->formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
return true;
|
||
|
|
||
|
|
||
|
case TDDS_R8_SNORM:
|
||
|
case TDDS_R8G8_SNORM:
|
||
|
case TDDS_R8G8B8A8_SNORM:
|
||
|
case TDDS_R16_SNORM:
|
||
|
case TDDS_R16G16_SNORM:
|
||
|
case TDDS_A8B8G8R8_SNORM:
|
||
|
case TDDS_B8G8R8A8_SNORM:
|
||
|
case TDDS_G16R16_SNORM:
|
||
|
|
||
|
case TDDS_R8_UINT:
|
||
|
case TDDS_R8_SINT:
|
||
|
case TDDS_R8G8_UINT:
|
||
|
case TDDS_R8G8_SINT:
|
||
|
case TDDS_R8G8B8A8_UINT:
|
||
|
case TDDS_R8G8B8A8_SINT:
|
||
|
case TDDS_R8G8B8A8_SRGB:
|
||
|
case TDDS_B8G8R8A8_SRGB:
|
||
|
case TDDS_R9G9B9E5_UFLOAT:
|
||
|
case TDDS_R10G10B10A2_UINT:
|
||
|
case TDDS_R11G11B10_UFLOAT:
|
||
|
case TDDS_R16_UINT:
|
||
|
case TDDS_R16_SINT:
|
||
|
case TDDS_R16_SFLOAT:
|
||
|
case TDDS_R16G16_UINT:
|
||
|
case TDDS_R16G16_SINT:
|
||
|
case TDDS_R16G16_SFLOAT:
|
||
|
case TDDS_R16G16B16A16_UNORM:
|
||
|
case TDDS_R16G16B16A16_SNORM:
|
||
|
case TDDS_R16G16B16A16_UINT:
|
||
|
case TDDS_R16G16B16A16_SINT:
|
||
|
case TDDS_R16G16B16A16_SFLOAT:
|
||
|
case TDDS_R32_UINT:
|
||
|
case TDDS_R32_SINT:
|
||
|
case TDDS_R32_SFLOAT:
|
||
|
case TDDS_R32G32_UINT:
|
||
|
case TDDS_R32G32_SINT:
|
||
|
case TDDS_R32G32_SFLOAT:
|
||
|
case TDDS_R32G32B32_UINT:
|
||
|
case TDDS_R32G32B32_SINT:
|
||
|
case TDDS_R32G32B32_SFLOAT:
|
||
|
case TDDS_R32G32B32A32_UINT:
|
||
|
case TDDS_R32G32B32A32_SINT:
|
||
|
case TDDS_R32G32B32A32_SFLOAT:
|
||
|
case TDDS_BC1_RGBA_SRGB_BLOCK:
|
||
|
case TDDS_BC2_SRGB_BLOCK:
|
||
|
case TDDS_BC3_SRGB_BLOCK:
|
||
|
case TDDS_BC4_SNORM_BLOCK:
|
||
|
case TDDS_BC5_SNORM_BLOCK:
|
||
|
case TDDS_BC6H_UFLOAT_BLOCK:
|
||
|
case TDDS_BC6H_SFLOAT_BLOCK:
|
||
|
case TDDS_BC7_UNORM_BLOCK:
|
||
|
case TDDS_BC7_SRGB_BLOCK:
|
||
|
case TDDS_AYUV:
|
||
|
case TDDS_Y410:
|
||
|
case TDDS_Y416:
|
||
|
case TDDS_NV12:
|
||
|
case TDDS_P010:
|
||
|
case TDDS_P016:
|
||
|
case TDDS_420_OPAQUE:
|
||
|
case TDDS_YUY2:
|
||
|
case TDDS_Y210:
|
||
|
case TDDS_Y216:
|
||
|
case TDDS_NV11:
|
||
|
case TDDS_AI44:
|
||
|
case TDDS_IA44:
|
||
|
case TDDS_P8:
|
||
|
case TDDS_A8P8:
|
||
|
case TDDS_R10G10B10_7E3_A2_FLOAT:
|
||
|
case TDDS_R10G10B10_6E4_A2_FLOAT:
|
||
|
case TDDS_D16_UNORM_S8_UINT:
|
||
|
case TDDS_R16_UNORM_X8_TYPELESS:
|
||
|
case TDDS_X16_TYPELESS_G8_UINT:
|
||
|
case TDDS_P208:
|
||
|
case TDDS_V208:
|
||
|
case TDDS_V408:
|
||
|
case TDDS_R10G10B10_SNORM_A2_UNORM:
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
// these formats can probably be done via dx10 header so check
|
||
|
if(headerDx10->DXGIFormat == TIF_DXGI_FORMAT_UNKNOWN) return false;
|
||
|
else return true;
|
||
|
}
|
||
|
|
||
|
#undef TDDS_EF
|
||
|
#undef TDDS_EF_RGB
|
||
|
#undef TDDS_EF_RGBA
|
||
|
#undef TDDS_EF_ALPHA
|
||
|
|
||
|
bool TinyDDS_WriteImage(TinyDDS_WriteCallbacks const *callbacks,
|
||
|
void *user,
|
||
|
uint32_t width,
|
||
|
uint32_t height,
|
||
|
uint32_t depth, // 3D texture depth
|
||
|
uint32_t slices, // Array slices
|
||
|
uint32_t mipmaplevels,
|
||
|
TinyDDS_Format format,
|
||
|
bool cubemap,
|
||
|
bool preferDx10Format,
|
||
|
uint32_t const *mipmapsizes,
|
||
|
void const **mipmaps) {
|
||
|
TinyDDS_Header header;
|
||
|
TinyDDS_HeaderDX10 headerDX10;
|
||
|
memset(&header, 0, sizeof(header));
|
||
|
memset(&headerDX10, 0, sizeof(headerDX10));
|
||
|
|
||
|
header.magic = TINYDDS_MAKE_RIFFCODE('D', 'D', 'S', ' ');
|
||
|
header.size = 124;
|
||
|
header.formatSize = 32;
|
||
|
|
||
|
header.width = width;
|
||
|
header.height = height;
|
||
|
header.depth = (depth > 1) ? depth : 0;
|
||
|
header.mipMapCount = mipmaplevels;
|
||
|
|
||
|
if(!TinyDDS_EncodeFormat(format, &header, &headerDX10)) return false;
|
||
|
|
||
|
// do we have to force dx10 (for slices)
|
||
|
if (slices > 1) {
|
||
|
if(headerDX10.DXGIFormat == TIF_DXGI_FORMAT_UNKNOWN) {
|
||
|
// DDS doesn't support slices for formats that aren't DXGI compatible
|
||
|
return false;
|
||
|
}
|
||
|
header.formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
header.formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','1','0');
|
||
|
headerDX10.arraySize = slices;
|
||
|
}
|
||
|
header.flags = TINYDDS_DDSD_CAPS | TINYDDS_DDSD_PIXELFORMAT | TINYDDS_DDSD_MIPMAPCOUNT;
|
||
|
header.caps1 = TINYDDS_DDSCAPS_TEXTURE | TINYDDS_DDSCAPS_COMPLEX | TINYDDS_DDSCAPS_MIPMAP;
|
||
|
|
||
|
if(depth > 1) {
|
||
|
headerDX10.resourceDimension = TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE3D;
|
||
|
header.flags |= TINYDDS_DDSD_DEPTH;
|
||
|
header.caps2 |= TINYDDS_DDSCAPS2_VOLUME;
|
||
|
}
|
||
|
else if(height > 1) {
|
||
|
headerDX10.resourceDimension = TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE2D;
|
||
|
header.flags |= TINYDDS_DDSD_HEIGHT;
|
||
|
}
|
||
|
else if(width > 1) {
|
||
|
headerDX10.resourceDimension = TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE1D;
|
||
|
header.flags |= TINYDDS_DDSD_WIDTH;
|
||
|
}
|
||
|
if(cubemap) {
|
||
|
headerDX10.miscFlag |= TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE;
|
||
|
header.caps2 |= TINYDDS_DDSCAPS2_CUBEMAP | TINYDDS_DDSCAPS2_CUBEMAP_ALL;
|
||
|
}
|
||
|
|
||
|
// unclear whether we need to save this or exactly what it should be...
|
||
|
header.pitchOrLinearSize = 0;
|
||
|
if(preferDx10Format && headerDX10.DXGIFormat != TIF_DXGI_FORMAT_UNKNOWN) {
|
||
|
header.formatFlags = TINYDDS_DDPF_FOURCC;
|
||
|
header.formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','1','0');
|
||
|
}
|
||
|
|
||
|
// now write
|
||
|
callbacks->write(user, &header, sizeof(TinyDDS_Header));
|
||
|
if(header.formatFlags & TINYDDS_DDPF_FOURCC &&
|
||
|
header.formatFourCC == TINYDDS_MAKE_RIFFCODE('D','X','1','0')) {
|
||
|
callbacks->write(user, &headerDX10, sizeof(TinyDDS_HeaderDX10));
|
||
|
}
|
||
|
|
||
|
// rg 8/27/2024: The original tinydds.h code is wrong for mipmapped cubemaps.
|
||
|
// I'm going to work around this by having the caller compose the top mip data correctly.
|
||
|
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-file-layout-for-cubic-environment-maps
|
||
|
for (uint32_t mipMapLevel = 0; mipMapLevel < header.mipMapCount; mipMapLevel++)
|
||
|
{
|
||
|
// rg: Adding this check, in case the caller wants to compose all the data themselves.
|
||
|
if (mipmapsizes[mipMapLevel])
|
||
|
{
|
||
|
callbacks->write(user, mipmaps[mipMapLevel], mipmapsizes[mipMapLevel]);
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
#endif // end header
|
||
|
/*
|
||
|
MIT License
|
||
|
|
||
|
Copyright (c) 2019 DeanoC
|
||
|
|
||
|
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.
|
||
|
*/
|
||
|
|