├── .editorconfig ├── .github └── workflows │ └── push_build.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── tiny_dds │ └── tinydds.h ├── src └── tinydds.c └── tests └── runner.cpp /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*.{c,cpp,h,hpp}] 5 | indent_style = tab 6 | indent_size = 2 7 | -------------------------------------------------------------------------------- /.github/workflows/push_build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | name: Build on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [windows-latest, macos-latest, ubuntu-latest] 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: prepare 16 | run: | 17 | mkdir -p build 18 | cd build 19 | cmake .. 20 | - name: build 21 | run: | 22 | cd build 23 | cmake --build . --config Release -j 8 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12.4) 2 | get_directory_property(hasParent PARENT_DIRECTORY) 3 | if(NOT hasParent) 4 | option(unittests "unittests" OFF) 5 | get_filename_component(_PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) 6 | set_property(GLOBAL PROPERTY GLOBAL_FETCHDEPS_BASE ${_PARENT_DIR}/al2o3 ) 7 | include(FetchContent) 8 | FetchContent_Declare( al2o3 GIT_REPOSITORY https://github.com/DeanoC/al2o3 GIT_TAG master ) 9 | FetchContent_GetProperties(al2o3) 10 | if(NOT al2o3_POPULATED) 11 | FetchContent_Populate(al2o3) 12 | add_subdirectory(${al2o3_SOURCE_DIR} ${al2o3_BINARY_DIR}) 13 | endif() 14 | INIT_AL2O3(${CMAKE_CURRENT_SOURCE_DIR}) 15 | endif () 16 | 17 | SET_MIN_VERSIONS() 18 | set(LibName tiny_dds) 19 | 20 | project(${LibName}) 21 | 22 | set(Interface 23 | tinydds.h 24 | ) 25 | 26 | set(Src 27 | tinydds.c 28 | ) 29 | 30 | set(Deps 31 | al2o3_platform 32 | ) 33 | ADD_LIB(${LibName} "${Interface}" "${Src}" "${Deps}") 34 | 35 | set( Tests 36 | runner.cpp 37 | ) 38 | set( TestDeps 39 | al2o3_catch2 40 | 41 | utils_simple_logmanager) 42 | ADD_LIB_TESTS(${LibName} "${Interface}" "${Tests}" "${TestDeps}") 43 | 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 DeanoC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/DeanoC/tiny_dds/Build/badge.svg) 2 | ![](https://github.com/DeanoC/tiny_dds/Test/badge.svg) 3 | 4 | # tiny_dds 5 | Tiny DDS is a single header DDS loader/saver 6 | 7 | TODO mroe stuff 8 | -------------------------------------------------------------------------------- /include/tiny_dds/tinydds.h: -------------------------------------------------------------------------------- 1 | // MIT license see full LICENSE text at end of file 2 | #pragma once 3 | #ifndef TINY_DDS_TINYDDS_H 4 | #define TINY_DDS_TINYDDS_H 5 | 6 | #ifndef TINYDDS_HAVE_UINTXX_T 7 | #include // for uint32_t and int64_t 8 | #endif 9 | #ifndef TINYDDS_HAVE_BOOL 10 | #include // for bool 11 | #endif 12 | #ifndef TINYDDS_HAVE_SIZE_T 13 | #include // for size_t 14 | #endif 15 | #ifndef TINYDDS_HAVE_MEMCPY 16 | #include // for memcpy 17 | #endif 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #define TINYDDS_MAX_MIPMAPLEVELS 16 24 | 25 | typedef struct TinyDDS_Context *TinyDDS_ContextHandle; 26 | 27 | typedef void *(*TinyDDS_AllocFunc)(void *user, size_t size); 28 | typedef void (*TinyDDS_FreeFunc)(void *user, void *memory); 29 | typedef size_t (*TinyDDS_ReadFunc)(void *user, void *buffer, size_t byteCount); 30 | typedef bool (*TinyDDS_SeekFunc)(void *user, int64_t offset); 31 | typedef int64_t (*TinyDDS_TellFunc)(void *user); 32 | typedef void (*TinyDDS_ErrorFunc)(void *user, char const *msg); 33 | 34 | typedef struct TinyDDS_Callbacks { 35 | TinyDDS_ErrorFunc errorFn; 36 | TinyDDS_AllocFunc allocFn; 37 | TinyDDS_FreeFunc freeFn; 38 | TinyDDS_ReadFunc readFn; 39 | TinyDDS_SeekFunc seekFn; 40 | TinyDDS_TellFunc tellFn; 41 | } TinyDDS_Callbacks; 42 | 43 | TinyDDS_ContextHandle TinyDDS_CreateContext(TinyDDS_Callbacks const *callbacks, void *user); 44 | void TinyDDS_DestroyContext(TinyDDS_ContextHandle handle); 45 | 46 | // reset lets you reuse the context for another file (saves an alloc/free cycle) 47 | void TinyDDS_Reset(TinyDDS_ContextHandle handle); 48 | 49 | // call this to read the header file should already be at the start of the KTX data 50 | bool TinyDDS_ReadHeader(TinyDDS_ContextHandle handle); 51 | 52 | bool TinyDDS_Is1D(TinyDDS_ContextHandle handle); 53 | bool TinyDDS_Is2D(TinyDDS_ContextHandle handle); 54 | bool TinyDDS_Is3D(TinyDDS_ContextHandle handle); 55 | bool TinyDDS_IsCubemap(TinyDDS_ContextHandle handle); 56 | bool TinyDDS_IsArray(TinyDDS_ContextHandle handle); 57 | 58 | bool TinyDDS_Dimensions(TinyDDS_ContextHandle handle, 59 | uint32_t *width, 60 | uint32_t *height, 61 | uint32_t *depth, 62 | uint32_t *slices); 63 | uint32_t TinyDDS_Width(TinyDDS_ContextHandle handle); 64 | uint32_t TinyDDS_Height(TinyDDS_ContextHandle handle); 65 | uint32_t TinyDDS_Depth(TinyDDS_ContextHandle handle); 66 | uint32_t TinyDDS_ArraySlices(TinyDDS_ContextHandle handle); 67 | 68 | bool TinyDDS_NeedsGenerationOfMipmaps(TinyDDS_ContextHandle handle); 69 | bool TinyDDS_NeedsEndianCorrecting(TinyDDS_ContextHandle handle); 70 | 71 | uint32_t TinyDDS_NumberOfMipmaps(TinyDDS_ContextHandle handle); 72 | uint32_t TinyDDS_ImageSize(TinyDDS_ContextHandle handle, uint32_t mipmaplevel); 73 | 74 | // data return by ImageRawData is owned by the context. Don't free it! 75 | void const *TinyDDS_ImageRawData(TinyDDS_ContextHandle handle, uint32_t mipmaplevel); 76 | 77 | typedef void (*TinyDDS_WriteFunc)(void *user, void const *buffer, size_t byteCount); 78 | 79 | typedef struct TinyDDS_WriteCallbacks { 80 | TinyDDS_ErrorFunc error; 81 | TinyDDS_AllocFunc alloc; 82 | TinyDDS_FreeFunc free; 83 | TinyDDS_WriteFunc write; 84 | } TinyDDS_WriteCallbacks; 85 | 86 | #ifndef TINYIMAGEFORMAT_DXGIFORMAT 87 | #define TINYIMAGEFORMAT_DXGIFORMAT 88 | 89 | // early DDS was a direct copy of the Draw Draw surface bits, later on (Dx10) it moved to 90 | // DXGI_FORMAT we use a similar thing to DXGI_FORMAT second form but will synthesis 91 | // the old style when required when saving and vice versa when loading. 92 | typedef enum TinyImageFormat_DXGI_FORMAT { 93 | TIF_DXGI_FORMAT_UNKNOWN = 0, 94 | TIF_DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, 95 | TIF_DXGI_FORMAT_R32G32B32A32_FLOAT = 2, 96 | TIF_DXGI_FORMAT_R32G32B32A32_UINT = 3, 97 | TIF_DXGI_FORMAT_R32G32B32A32_SINT = 4, 98 | TIF_DXGI_FORMAT_R32G32B32_TYPELESS = 5, 99 | TIF_DXGI_FORMAT_R32G32B32_FLOAT = 6, 100 | TIF_DXGI_FORMAT_R32G32B32_UINT = 7, 101 | TIF_DXGI_FORMAT_R32G32B32_SINT = 8, 102 | TIF_DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, 103 | TIF_DXGI_FORMAT_R16G16B16A16_FLOAT = 10, 104 | TIF_DXGI_FORMAT_R16G16B16A16_UNORM = 11, 105 | TIF_DXGI_FORMAT_R16G16B16A16_UINT = 12, 106 | TIF_DXGI_FORMAT_R16G16B16A16_SNORM = 13, 107 | TIF_DXGI_FORMAT_R16G16B16A16_SINT = 14, 108 | TIF_DXGI_FORMAT_R32G32_TYPELESS = 15, 109 | TIF_DXGI_FORMAT_R32G32_FLOAT = 16, 110 | TIF_DXGI_FORMAT_R32G32_UINT = 17, 111 | TIF_DXGI_FORMAT_R32G32_SINT = 18, 112 | TIF_DXGI_FORMAT_R32G8X24_TYPELESS = 19, 113 | TIF_DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, 114 | TIF_DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, 115 | TIF_DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, 116 | TIF_DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, 117 | TIF_DXGI_FORMAT_R10G10B10A2_UNORM = 24, 118 | TIF_DXGI_FORMAT_R10G10B10A2_UINT = 25, 119 | TIF_DXGI_FORMAT_R11G11B10_FLOAT = 26, 120 | TIF_DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, 121 | TIF_DXGI_FORMAT_R8G8B8A8_UNORM = 28, 122 | TIF_DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, 123 | TIF_DXGI_FORMAT_R8G8B8A8_UINT = 30, 124 | TIF_DXGI_FORMAT_R8G8B8A8_SNORM = 31, 125 | TIF_DXGI_FORMAT_R8G8B8A8_SINT = 32, 126 | TIF_DXGI_FORMAT_R16G16_TYPELESS = 33, 127 | TIF_DXGI_FORMAT_R16G16_FLOAT = 34, 128 | TIF_DXGI_FORMAT_R16G16_UNORM = 35, 129 | TIF_DXGI_FORMAT_R16G16_UINT = 36, 130 | TIF_DXGI_FORMAT_R16G16_SNORM = 37, 131 | TIF_DXGI_FORMAT_R16G16_SINT = 38, 132 | TIF_DXGI_FORMAT_R32_TYPELESS = 39, 133 | TIF_DXGI_FORMAT_D32_FLOAT = 40, 134 | TIF_DXGI_FORMAT_R32_FLOAT = 41, 135 | TIF_DXGI_FORMAT_R32_UINT = 42, 136 | TIF_DXGI_FORMAT_R32_SINT = 43, 137 | TIF_DXGI_FORMAT_R24G8_TYPELESS = 44, 138 | TIF_DXGI_FORMAT_D24_UNORM_S8_UINT = 45, 139 | TIF_DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, 140 | TIF_DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, 141 | TIF_DXGI_FORMAT_R8G8_TYPELESS = 48, 142 | TIF_DXGI_FORMAT_R8G8_UNORM = 49, 143 | TIF_DXGI_FORMAT_R8G8_UINT = 50, 144 | TIF_DXGI_FORMAT_R8G8_SNORM = 51, 145 | TIF_DXGI_FORMAT_R8G8_SINT = 52, 146 | TIF_DXGI_FORMAT_R16_TYPELESS = 53, 147 | TIF_DXGI_FORMAT_R16_FLOAT = 54, 148 | TIF_DXGI_FORMAT_D16_UNORM = 55, 149 | TIF_DXGI_FORMAT_R16_UNORM = 56, 150 | TIF_DXGI_FORMAT_R16_UINT = 57, 151 | TIF_DXGI_FORMAT_R16_SNORM = 58, 152 | TIF_DXGI_FORMAT_R16_SINT = 59, 153 | TIF_DXGI_FORMAT_R8_TYPELESS = 60, 154 | TIF_DXGI_FORMAT_R8_UNORM = 61, 155 | TIF_DXGI_FORMAT_R8_UINT = 62, 156 | TIF_DXGI_FORMAT_R8_SNORM = 63, 157 | TIF_DXGI_FORMAT_R8_SINT = 64, 158 | TIF_DXGI_FORMAT_A8_UNORM = 65, 159 | TIF_DXGI_FORMAT_R1_UNORM = 66, 160 | TIF_DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, 161 | TIF_DXGI_FORMAT_R8G8_B8G8_UNORM = 68, 162 | TIF_DXGI_FORMAT_G8R8_G8B8_UNORM = 69, 163 | TIF_DXGI_FORMAT_BC1_TYPELESS = 70, 164 | TIF_DXGI_FORMAT_BC1_UNORM = 71, 165 | TIF_DXGI_FORMAT_BC1_UNORM_SRGB = 72, 166 | TIF_DXGI_FORMAT_BC2_TYPELESS = 73, 167 | TIF_DXGI_FORMAT_BC2_UNORM = 74, 168 | TIF_DXGI_FORMAT_BC2_UNORM_SRGB = 75, 169 | TIF_DXGI_FORMAT_BC3_TYPELESS = 76, 170 | TIF_DXGI_FORMAT_BC3_UNORM = 77, 171 | TIF_DXGI_FORMAT_BC3_UNORM_SRGB = 78, 172 | TIF_DXGI_FORMAT_BC4_TYPELESS = 79, 173 | TIF_DXGI_FORMAT_BC4_UNORM = 80, 174 | TIF_DXGI_FORMAT_BC4_SNORM = 81, 175 | TIF_DXGI_FORMAT_BC5_TYPELESS = 82, 176 | TIF_DXGI_FORMAT_BC5_UNORM = 83, 177 | TIF_DXGI_FORMAT_BC5_SNORM = 84, 178 | TIF_DXGI_FORMAT_B5G6R5_UNORM = 85, 179 | TIF_DXGI_FORMAT_B5G5R5A1_UNORM = 86, 180 | TIF_DXGI_FORMAT_B8G8R8A8_UNORM = 87, 181 | TIF_DXGI_FORMAT_B8G8R8X8_UNORM = 88, 182 | TIF_DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, 183 | TIF_DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, 184 | TIF_DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, 185 | TIF_DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, 186 | TIF_DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, 187 | TIF_DXGI_FORMAT_BC6H_TYPELESS = 94, 188 | TIF_DXGI_FORMAT_BC6H_UF16 = 95, 189 | TIF_DXGI_FORMAT_BC6H_SF16 = 96, 190 | TIF_DXGI_FORMAT_BC7_TYPELESS = 97, 191 | TIF_DXGI_FORMAT_BC7_UNORM = 98, 192 | TIF_DXGI_FORMAT_BC7_UNORM_SRGB = 99, 193 | TIF_DXGI_FORMAT_AYUV = 100, 194 | TIF_DXGI_FORMAT_Y410 = 101, 195 | TIF_DXGI_FORMAT_Y416 = 102, 196 | TIF_DXGI_FORMAT_NV12 = 103, 197 | TIF_DXGI_FORMAT_P010 = 104, 198 | TIF_DXGI_FORMAT_P016 = 105, 199 | TIF_DXGI_FORMAT_420_OPAQUE = 106, 200 | TIF_DXGI_FORMAT_YUY2 = 107, 201 | TIF_DXGI_FORMAT_Y210 = 108, 202 | TIF_DXGI_FORMAT_Y216 = 109, 203 | TIF_DXGI_FORMAT_NV11 = 110, 204 | TIF_DXGI_FORMAT_AI44 = 111, 205 | TIF_DXGI_FORMAT_IA44 = 112, 206 | TIF_DXGI_FORMAT_P8 = 113, 207 | TIF_DXGI_FORMAT_A8P8 = 114, 208 | TIF_DXGI_FORMAT_B4G4R4A4_UNORM = 115, 209 | 210 | // xbox 360 formats 211 | TIF_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT = 116, 212 | TIF_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT = 117, 213 | TIF_DXGI_FORMAT_D16_UNORM_S8_UINT = 118, 214 | TIF_DXGI_FORMAT_R16_UNORM_X8_TYPELESS = 119, 215 | TIF_DXGI_FORMAT_X16_TYPELESS_G8_UINT = 120, 216 | 217 | TIF_DXGI_FORMAT_P208 = 130, 218 | TIF_DXGI_FORMAT_V208 = 131, 219 | TIF_DXGI_FORMAT_V408 = 132, 220 | 221 | // XBox One formats 222 | TIF_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM = 189, 223 | TIF_DXGI_FORMAT_R4G4_UNORM = 190, 224 | 225 | } TinyImageFormat_DXGI_FORMAT; 226 | #endif 227 | 228 | typedef enum TinyDDS_Format { 229 | TDDS_UNDEFINED = TIF_DXGI_FORMAT_UNKNOWN, 230 | TDDS_B5G6R5_UNORM = TIF_DXGI_FORMAT_B5G6R5_UNORM, 231 | TDDS_B5G5R5A1_UNORM = TIF_DXGI_FORMAT_B5G5R5A1_UNORM, 232 | TDDS_R8_UNORM = TIF_DXGI_FORMAT_R8_UNORM, 233 | TDDS_R8_SNORM = TIF_DXGI_FORMAT_R8_SNORM, 234 | TDDS_A8_UNORM = TIF_DXGI_FORMAT_A8_UNORM, 235 | TDDS_R1_UNORM = TIF_DXGI_FORMAT_R1_UNORM, 236 | TDDS_R8_UINT = TIF_DXGI_FORMAT_R8_UINT, 237 | TDDS_R8_SINT = TIF_DXGI_FORMAT_R8_SINT, 238 | TDDS_R8G8_UNORM = TIF_DXGI_FORMAT_R8G8_UNORM, 239 | TDDS_R8G8_SNORM = TIF_DXGI_FORMAT_R8G8_SNORM, 240 | TDDS_R8G8_UINT = TIF_DXGI_FORMAT_R8G8_UINT, 241 | TDDS_R8G8_SINT = TIF_DXGI_FORMAT_R8G8_SINT, 242 | TDDS_R8G8B8A8_UNORM = TIF_DXGI_FORMAT_R8G8B8A8_UNORM, 243 | TDDS_R8G8B8A8_SNORM = TIF_DXGI_FORMAT_R8G8B8A8_SNORM, 244 | TDDS_R8G8B8A8_UINT = TIF_DXGI_FORMAT_R8G8B8A8_UINT, 245 | TDDS_R8G8B8A8_SINT = TIF_DXGI_FORMAT_R8G8B8A8_SINT, 246 | TDDS_R8G8B8A8_SRGB = TIF_DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 247 | TDDS_B8G8R8A8_UNORM = TIF_DXGI_FORMAT_B8G8R8A8_UNORM, 248 | TDDS_B8G8R8A8_SRGB = TIF_DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, 249 | 250 | TDDS_R9G9B9E5_UFLOAT = TIF_DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 251 | TDDS_R10G10B10A2_UNORM = TIF_DXGI_FORMAT_R10G10B10A2_UNORM, 252 | TDDS_R10G10B10A2_UINT = TIF_DXGI_FORMAT_R10G10B10A2_UINT, 253 | TDDS_R11G11B10_UFLOAT = TIF_DXGI_FORMAT_R11G11B10_FLOAT, 254 | 255 | TDDS_R16_UNORM = TIF_DXGI_FORMAT_R16_UNORM, 256 | TDDS_R16_SNORM = TIF_DXGI_FORMAT_R16_SNORM, 257 | TDDS_R16_UINT = TIF_DXGI_FORMAT_R16_UINT, 258 | TDDS_R16_SINT = TIF_DXGI_FORMAT_R16_SINT, 259 | TDDS_R16_SFLOAT = TIF_DXGI_FORMAT_R16_FLOAT, 260 | 261 | TDDS_R16G16_UNORM = TIF_DXGI_FORMAT_R16G16_UNORM, 262 | TDDS_R16G16_SNORM = TIF_DXGI_FORMAT_R16G16_SNORM, 263 | TDDS_R16G16_UINT = TIF_DXGI_FORMAT_R16G16_UINT, 264 | TDDS_R16G16_SINT = TIF_DXGI_FORMAT_R16G16_SINT, 265 | TDDS_R16G16_SFLOAT = TIF_DXGI_FORMAT_R16G16_FLOAT, 266 | 267 | TDDS_R16G16B16A16_UNORM = TIF_DXGI_FORMAT_R16G16B16A16_UNORM, 268 | TDDS_R16G16B16A16_SNORM = TIF_DXGI_FORMAT_R16G16B16A16_SNORM, 269 | TDDS_R16G16B16A16_UINT = TIF_DXGI_FORMAT_R16G16B16A16_UINT, 270 | TDDS_R16G16B16A16_SINT = TIF_DXGI_FORMAT_R16G16B16A16_SINT, 271 | TDDS_R16G16B16A16_SFLOAT = TIF_DXGI_FORMAT_R16G16B16A16_FLOAT, 272 | 273 | TDDS_R32_UINT = TIF_DXGI_FORMAT_R32_UINT, 274 | TDDS_R32_SINT = TIF_DXGI_FORMAT_R32_SINT, 275 | TDDS_R32_SFLOAT = TIF_DXGI_FORMAT_R32_FLOAT, 276 | 277 | TDDS_R32G32_UINT = TIF_DXGI_FORMAT_R32G32_UINT, 278 | TDDS_R32G32_SINT = TIF_DXGI_FORMAT_R32G32_SINT, 279 | TDDS_R32G32_SFLOAT = TIF_DXGI_FORMAT_R32G32_FLOAT, 280 | 281 | TDDS_R32G32B32_UINT = TIF_DXGI_FORMAT_R32G32B32_UINT, 282 | TDDS_R32G32B32_SINT = TIF_DXGI_FORMAT_R32G32B32_SINT, 283 | TDDS_R32G32B32_SFLOAT = TIF_DXGI_FORMAT_R32G32B32_FLOAT, 284 | 285 | TDDS_R32G32B32A32_UINT = TIF_DXGI_FORMAT_R32G32B32A32_UINT, 286 | TDDS_R32G32B32A32_SINT = TIF_DXGI_FORMAT_R32G32B32A32_SINT, 287 | TDDS_R32G32B32A32_SFLOAT = TIF_DXGI_FORMAT_R32G32B32A32_FLOAT, 288 | 289 | TDDS_BC1_RGBA_UNORM_BLOCK = TIF_DXGI_FORMAT_BC1_UNORM, 290 | TDDS_BC1_RGBA_SRGB_BLOCK = TIF_DXGI_FORMAT_BC1_UNORM_SRGB, 291 | TDDS_BC2_UNORM_BLOCK = TIF_DXGI_FORMAT_BC2_UNORM, 292 | TDDS_BC2_SRGB_BLOCK = TIF_DXGI_FORMAT_BC2_UNORM_SRGB, 293 | TDDS_BC3_UNORM_BLOCK = TIF_DXGI_FORMAT_BC3_UNORM, 294 | TDDS_BC3_SRGB_BLOCK = TIF_DXGI_FORMAT_BC3_UNORM_SRGB, 295 | TDDS_BC4_UNORM_BLOCK = TIF_DXGI_FORMAT_BC4_UNORM, 296 | TDDS_BC4_SNORM_BLOCK = TIF_DXGI_FORMAT_BC4_SNORM, 297 | TDDS_BC5_UNORM_BLOCK = TIF_DXGI_FORMAT_BC5_UNORM, 298 | TDDS_BC5_SNORM_BLOCK = TIF_DXGI_FORMAT_BC5_SNORM, 299 | 300 | TDDS_BC6H_UFLOAT_BLOCK = TIF_DXGI_FORMAT_BC6H_UF16, 301 | TDDS_BC6H_SFLOAT_BLOCK = TIF_DXGI_FORMAT_BC6H_SF16, 302 | TDDS_BC7_UNORM_BLOCK = TIF_DXGI_FORMAT_BC7_UNORM, 303 | TDDS_BC7_SRGB_BLOCK = TIF_DXGI_FORMAT_BC7_UNORM_SRGB, 304 | 305 | TDDS_AYUV = TIF_DXGI_FORMAT_AYUV, 306 | TDDS_Y410 = TIF_DXGI_FORMAT_Y410, 307 | TDDS_Y416 = TIF_DXGI_FORMAT_Y416, 308 | TDDS_NV12 = TIF_DXGI_FORMAT_NV12, 309 | TDDS_P010 = TIF_DXGI_FORMAT_P010, 310 | TDDS_P016 = TIF_DXGI_FORMAT_P016, 311 | TDDS_420_OPAQUE = TIF_DXGI_FORMAT_420_OPAQUE, 312 | TDDS_YUY2 = TIF_DXGI_FORMAT_YUY2, 313 | TDDS_Y210 = TIF_DXGI_FORMAT_Y210, 314 | TDDS_Y216 = TIF_DXGI_FORMAT_Y216, 315 | TDDS_NV11 = TIF_DXGI_FORMAT_NV11, 316 | TDDS_AI44 = TIF_DXGI_FORMAT_AI44, 317 | TDDS_IA44 = TIF_DXGI_FORMAT_IA44, 318 | TDDS_P8 = TIF_DXGI_FORMAT_P8, 319 | TDDS_A8P8 = TIF_DXGI_FORMAT_A8P8, 320 | TDDS_B4G4R4A4_UNORM = TIF_DXGI_FORMAT_B4G4R4A4_UNORM, 321 | TDDS_R10G10B10_7E3_A2_FLOAT = TIF_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT, 322 | TDDS_R10G10B10_6E4_A2_FLOAT = TIF_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT, 323 | TDDS_D16_UNORM_S8_UINT = TIF_DXGI_FORMAT_D16_UNORM_S8_UINT, 324 | TDDS_R16_UNORM_X8_TYPELESS = TIF_DXGI_FORMAT_R16_UNORM_X8_TYPELESS, 325 | TDDS_X16_TYPELESS_G8_UINT = TIF_DXGI_FORMAT_X16_TYPELESS_G8_UINT, 326 | TDDS_P208 = TIF_DXGI_FORMAT_P208, 327 | TDDS_V208 = TIF_DXGI_FORMAT_V208, 328 | TDDS_V408 = TIF_DXGI_FORMAT_V408, 329 | TDDS_R10G10B10_SNORM_A2_UNORM = TIF_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM, 330 | TDDS_R4G4_UNORM = TIF_DXGI_FORMAT_R4G4_UNORM, 331 | 332 | TDDS_SYNTHESISED_DXGIFORMATS = 0xFFFF, 333 | TDDS_G4R4_UNORM = TDDS_SYNTHESISED_DXGIFORMATS, 334 | 335 | TDDS_A4B4G4R4_UNORM, 336 | TDDS_X4B4G4R4_UNORM, 337 | 338 | TDDS_A4R4G4B4_UNORM, 339 | TDDS_X4R4G4B4_UNORM, 340 | 341 | TDDS_B4G4R4X4_UNORM, 342 | 343 | TDDS_R4G4B4A4_UNORM, 344 | TDDS_R4G4B4X4_UNORM, 345 | 346 | TDDS_B5G5R5X1_UNORM, 347 | 348 | TDDS_R5G5B5A1_UNORM, 349 | TDDS_R5G5B5X1_UNORM, 350 | 351 | TDDS_A1R5G5B5_UNORM, 352 | TDDS_X1R5G5B5_UNORM, 353 | 354 | TDDS_A1B5G5R5_UNORM, 355 | TDDS_X1B5G5R5_UNORM, 356 | 357 | TDDS_R5G6B5_UNORM, 358 | 359 | TDDS_B2G3R3_UNORM, 360 | TDDS_B2G3R3A8_UNORM, 361 | 362 | TDDS_G8R8_UNORM, 363 | TDDS_G8R8_SNORM, 364 | 365 | TDDS_R8G8B8_UNORM, 366 | TDDS_B8G8R8_UNORM, 367 | 368 | TDDS_A8B8G8R8_SNORM, 369 | TDDS_B8G8R8A8_SNORM, 370 | 371 | TDDS_R8G8B8X8_UNORM, 372 | TDDS_B8G8R8X8_UNORM, 373 | TDDS_A8B8G8R8_UNORM, 374 | TDDS_X8B8G8R8_UNORM, 375 | TDDS_A8R8G8B8_UNORM, 376 | TDDS_X8R8G8B8_UNORM, 377 | 378 | TDDS_R10G10B10A2_SNORM, 379 | TDDS_B10G10R10A2_UNORM, 380 | TDDS_B10G10R10A2_SNORM, 381 | TDDS_A2B10G10R10_UNORM, 382 | TDDS_A2B10G10R10_SNORM, 383 | TDDS_A2R10G10B10_UNORM, 384 | TDDS_A2R10G10B10_SNORM, 385 | 386 | TDDS_G16R16_UNORM, 387 | TDDS_G16R16_SNORM, 388 | 389 | } TinyDDS_Format; 390 | 391 | // tiny_imageformat/format needs included before tinydds.h for this functionality 392 | #ifdef TINYIMAGEFORMAT_BASE_H_ 393 | 394 | static TinyImageFormat TinyImageFormat_FromTinyDDSFormat(TinyDDS_Format fmt) { 395 | switch (fmt) { 396 | case TDDS_UNDEFINED: return TinyImageFormat_UNDEFINED; 397 | 398 | case TDDS_R32G32B32A32_SFLOAT: return TinyImageFormat_R32G32B32A32_SFLOAT; 399 | case TDDS_R32G32B32A32_UINT: return TinyImageFormat_R32G32B32A32_UINT; 400 | case TDDS_R32G32B32A32_SINT: return TinyImageFormat_R32G32B32A32_SINT; 401 | case TDDS_R32G32B32_SFLOAT: return TinyImageFormat_R32G32B32_SFLOAT; 402 | case TDDS_R32G32B32_UINT: return TinyImageFormat_R32G32B32_UINT; 403 | case TDDS_R32G32B32_SINT: return TinyImageFormat_R32G32B32_SINT; 404 | case TDDS_R16G16B16A16_SFLOAT: return TinyImageFormat_R16G16B16A16_SFLOAT; 405 | case TDDS_R16G16B16A16_UNORM: return TinyImageFormat_R16G16B16A16_UNORM; 406 | case TDDS_R16G16B16A16_UINT: return TinyImageFormat_R16G16B16A16_UINT; 407 | case TDDS_R16G16B16A16_SNORM: return TinyImageFormat_R16G16B16A16_SNORM; 408 | case TDDS_R16G16B16A16_SINT: return TinyImageFormat_R16G16B16A16_SINT; 409 | case TDDS_R32G32_SFLOAT: return TinyImageFormat_R32G32_SFLOAT; 410 | case TDDS_R32G32_UINT: return TinyImageFormat_R32G32_UINT; 411 | case TDDS_R32G32_SINT: return TinyImageFormat_R32G32_SINT; 412 | case TDDS_R8G8B8A8_UNORM: return TinyImageFormat_R8G8B8A8_UNORM; 413 | case TDDS_R8G8B8A8_SRGB: return TinyImageFormat_R8G8B8A8_SRGB; 414 | case TDDS_R8G8B8A8_UINT: return TinyImageFormat_R8G8B8A8_UINT; 415 | case TDDS_R8G8B8A8_SNORM: return TinyImageFormat_R8G8B8A8_SNORM; 416 | case TDDS_R8G8B8A8_SINT: return TinyImageFormat_R8G8B8A8_SINT; 417 | case TDDS_R16G16_SFLOAT: return TinyImageFormat_R16G16_SFLOAT; 418 | case TDDS_R16G16_UNORM: return TinyImageFormat_R16G16_UNORM; 419 | case TDDS_R16G16_UINT: return TinyImageFormat_R16G16_UINT; 420 | case TDDS_R16G16_SNORM: return TinyImageFormat_R16G16_SNORM; 421 | case TDDS_R16G16_SINT: return TinyImageFormat_R16G16_SINT; 422 | case TDDS_R32_SFLOAT: return TinyImageFormat_R32_SFLOAT; 423 | case TDDS_R32_UINT: return TinyImageFormat_R32_UINT; 424 | case TDDS_R32_SINT: return TinyImageFormat_R32_SINT; 425 | 426 | case TDDS_R8G8_UNORM: return TinyImageFormat_R8G8_UNORM; 427 | case TDDS_R8G8_UINT: return TinyImageFormat_R8G8_UINT; 428 | case TDDS_R8G8_SNORM: return TinyImageFormat_R8G8_SNORM; 429 | case TDDS_R8G8_SINT: return TinyImageFormat_R8G8_SINT; 430 | case TDDS_G8R8_UNORM: return TinyImageFormat_G8R8_UNORM; 431 | case TDDS_G8R8_SNORM: return TinyImageFormat_G8R8_SNORM; 432 | 433 | case TDDS_R16_SFLOAT: return TinyImageFormat_R16_SFLOAT; 434 | case TDDS_R16_UNORM: return TinyImageFormat_R16_UNORM; 435 | case TDDS_R16_UINT: return TinyImageFormat_R16_UINT; 436 | case TDDS_R16_SNORM: return TinyImageFormat_R16_SNORM; 437 | case TDDS_R16_SINT: return TinyImageFormat_R16_SINT; 438 | case TDDS_R8_UNORM: return TinyImageFormat_R8_UNORM; 439 | case TDDS_R8_UINT: return TinyImageFormat_R8_UINT; 440 | case TDDS_R8_SNORM: return TinyImageFormat_R8_SNORM; 441 | case TDDS_R8_SINT: return TinyImageFormat_R8_SINT; 442 | case TDDS_A8_UNORM: return TinyImageFormat_A8_UNORM; 443 | case TDDS_BC1_RGBA_UNORM_BLOCK: return TinyImageFormat_DXBC1_RGBA_UNORM; 444 | case TDDS_BC1_RGBA_SRGB_BLOCK: return TinyImageFormat_DXBC1_RGBA_SRGB; 445 | case TDDS_BC2_UNORM_BLOCK: return TinyImageFormat_DXBC2_UNORM; 446 | case TDDS_BC2_SRGB_BLOCK: return TinyImageFormat_DXBC2_SRGB; 447 | case TDDS_BC3_UNORM_BLOCK: return TinyImageFormat_DXBC3_UNORM; 448 | case TDDS_BC3_SRGB_BLOCK: return TinyImageFormat_DXBC3_SRGB; 449 | case TDDS_BC4_UNORM_BLOCK: return TinyImageFormat_DXBC4_UNORM; 450 | case TDDS_BC4_SNORM_BLOCK: return TinyImageFormat_DXBC4_SNORM; 451 | case TDDS_BC5_UNORM_BLOCK: return TinyImageFormat_DXBC5_UNORM; 452 | case TDDS_BC5_SNORM_BLOCK: return TinyImageFormat_DXBC5_SNORM; 453 | case TDDS_BC6H_UFLOAT_BLOCK: return TinyImageFormat_DXBC6H_UFLOAT; 454 | case TDDS_BC6H_SFLOAT_BLOCK: return TinyImageFormat_DXBC6H_SFLOAT; 455 | case TDDS_BC7_UNORM_BLOCK: return TinyImageFormat_DXBC7_UNORM; 456 | case TDDS_BC7_SRGB_BLOCK: return TinyImageFormat_DXBC7_SRGB; 457 | case TDDS_B8G8R8A8_UNORM: return TinyImageFormat_B8G8R8A8_UNORM; 458 | case TDDS_B8G8R8A8_SRGB: return TinyImageFormat_B8G8R8A8_SRGB; 459 | 460 | case TDDS_B2G3R3A8_UNORM: return TinyImageFormat_B2G3R3A8_UNORM; 461 | case TDDS_B2G3R3_UNORM: return TinyImageFormat_B2G3R3_UNORM; 462 | case TDDS_R4G4_UNORM: return TinyImageFormat_R4G4_UNORM; 463 | 464 | case TDDS_R8G8B8_UNORM: return TinyImageFormat_R8G8B8_UNORM; 465 | case TDDS_B8G8R8_UNORM: return TinyImageFormat_B8G8R8_UNORM; 466 | case TDDS_B8G8R8A8_SNORM: return TinyImageFormat_B8G8R8A8_SNORM; 467 | 468 | case TDDS_R9G9B9E5_UFLOAT: return TinyImageFormat_E5B9G9R9_UFLOAT; 469 | case TDDS_R11G11B10_UFLOAT: return TinyImageFormat_B10G11R11_UFLOAT; 470 | case TDDS_G4R4_UNORM: return TinyImageFormat_G4R4_UNORM; 471 | 472 | case TDDS_R5G6B5_UNORM: return TinyImageFormat_R5G6B5_UNORM; 473 | case TDDS_B5G6R5_UNORM: return TinyImageFormat_B5G6R5_UNORM; 474 | 475 | case TDDS_B5G5R5A1_UNORM: return TinyImageFormat_B5G5R5A1_UNORM; 476 | case TDDS_B5G5R5X1_UNORM: return TinyImageFormat_B5G5R5X1_UNORM; 477 | 478 | case TDDS_R5G5B5A1_UNORM: return TinyImageFormat_R5G5B5A1_UNORM; 479 | case TDDS_R5G5B5X1_UNORM: return TinyImageFormat_R5G5B5X1_UNORM; 480 | 481 | case TDDS_A1R5G5B5_UNORM: return TinyImageFormat_A1R5G5B5_UNORM; 482 | case TDDS_X1R5G5B5_UNORM: return TinyImageFormat_X1R5G5B5_UNORM; 483 | 484 | case TDDS_X1B5G5R5_UNORM: return TinyImageFormat_X1B5G5R5_UNORM; 485 | case TDDS_A1B5G5R5_UNORM: return TinyImageFormat_A1B5G5R5_UNORM; 486 | 487 | case TDDS_X4B4G4R4_UNORM: return TinyImageFormat_X4B4G4R4_UNORM; 488 | case TDDS_X4R4G4B4_UNORM: return TinyImageFormat_X4R4G4B4_UNORM; 489 | case TDDS_A4R4G4B4_UNORM: return TinyImageFormat_A4R4G4B4_UNORM; 490 | case TDDS_B4G4R4A4_UNORM: return TinyImageFormat_B4G4R4A4_UNORM; 491 | case TDDS_A4B4G4R4_UNORM: return TinyImageFormat_A4B4G4R4_UNORM; 492 | case TDDS_B4G4R4X4_UNORM: return TinyImageFormat_B4G4R4X4_UNORM; 493 | case TDDS_R4G4B4A4_UNORM: return TinyImageFormat_R4G4B4A4_UNORM; 494 | case TDDS_R4G4B4X4_UNORM: return TinyImageFormat_R4G4B4X4_UNORM; 495 | 496 | case TDDS_R8G8B8X8_UNORM: return TinyImageFormat_R8G8B8X8_UNORM; 497 | 498 | // DDS A2R10B10G10 support is basically broken historically so expect channels to need swapping 499 | case TDDS_A2B10G10R10_UNORM: return TinyImageFormat_A2B10G10R10_UNORM; 500 | case TDDS_A2B10G10R10_SNORM: return TinyImageFormat_A2B10G10R10_SNORM; 501 | case TDDS_A2R10G10B10_UNORM: return TinyImageFormat_A2R10G10B10_UNORM; 502 | case TDDS_A2R10G10B10_SNORM: return TinyImageFormat_A2R10G10B10_SNORM; 503 | case TDDS_B10G10R10A2_UNORM: return TinyImageFormat_R10G10B10A2_UNORM; 504 | case TDDS_B10G10R10A2_SNORM: return TinyImageFormat_R10G10B10A2_SNORM; 505 | case TDDS_R10G10B10A2_UNORM: return TinyImageFormat_B10G10R10A2_UNORM; 506 | case TDDS_R10G10B10A2_SNORM: return TinyImageFormat_B10G10R10A2_SNORM; 507 | case TDDS_R10G10B10A2_UINT: return TinyImageFormat_B10G10R10A2_UINT; 508 | 509 | case TDDS_B8G8R8X8_UNORM: return TinyImageFormat_B8G8R8X8_UNORM; 510 | 511 | case TDDS_G16R16_UNORM: return TinyImageFormat_G16R16_UNORM; 512 | case TDDS_G16R16_SNORM: return TinyImageFormat_G16R16_SNORM; 513 | case TDDS_X8B8G8R8_UNORM: return TinyImageFormat_R8G8B8X8_UNORM; 514 | case TDDS_X8R8G8B8_UNORM: return TinyImageFormat_B8G8R8X8_UNORM; 515 | case TDDS_A8B8G8R8_UNORM: return TinyImageFormat_R8G8B8A8_UNORM; 516 | case TDDS_A8R8G8B8_UNORM: return TinyImageFormat_B8G8R8A8_UNORM; 517 | case TDDS_A8B8G8R8_SNORM: return TinyImageFormat_R8G8B8X8_UNORM; 518 | case TDDS_P8: return TinyImageFormat_CLUT_P8; 519 | case TDDS_A8P8: return TinyImageFormat_CLUT_P8A8; 520 | case TDDS_R1_UNORM: return TinyImageFormat_R1_UNORM; 521 | 522 | case TDDS_AYUV:break; 523 | case TDDS_Y410:break; 524 | case TDDS_Y416:break; 525 | case TDDS_NV12:break; 526 | case TDDS_P010:break; 527 | case TDDS_P016:break; 528 | case TDDS_420_OPAQUE:break; 529 | case TDDS_YUY2:break; 530 | case TDDS_Y210:break; 531 | case TDDS_Y216:break; 532 | case TDDS_NV11:break; 533 | case TDDS_AI44:break; 534 | case TDDS_IA44:break; 535 | case TDDS_R10G10B10_7E3_A2_FLOAT:break; 536 | case TDDS_R10G10B10_6E4_A2_FLOAT:break; 537 | case TDDS_D16_UNORM_S8_UINT:break; 538 | case TDDS_R16_UNORM_X8_TYPELESS:break; 539 | case TDDS_X16_TYPELESS_G8_UINT:break; 540 | case TDDS_P208:break; 541 | case TDDS_V208:break; 542 | case TDDS_V408:break; 543 | case TDDS_R10G10B10_SNORM_A2_UNORM:break; 544 | } 545 | 546 | return TinyImageFormat_UNDEFINED; 547 | } 548 | 549 | static TinyDDS_Format TinyImageFormat_ToTinyDDSFormat(TinyImageFormat fmt) { 550 | switch (fmt) { 551 | case TinyImageFormat_R4G4_UNORM: return TDDS_R4G4_UNORM; 552 | case TinyImageFormat_G4R4_UNORM: return TDDS_G4R4_UNORM; 553 | 554 | case TinyImageFormat_A4R4G4B4_UNORM: return TDDS_A4R4G4B4_UNORM; 555 | case TinyImageFormat_B4G4R4A4_UNORM: return TDDS_B4G4R4A4_UNORM; 556 | case TinyImageFormat_A4B4G4R4_UNORM: return TDDS_A4B4G4R4_UNORM; 557 | case TinyImageFormat_X4R4G4B4_UNORM: return TDDS_X4R4G4B4_UNORM; 558 | case TinyImageFormat_X4B4G4R4_UNORM: return TDDS_X4B4G4R4_UNORM; 559 | case TinyImageFormat_R4G4B4A4_UNORM: return TDDS_R4G4B4A4_UNORM; 560 | case TinyImageFormat_R4G4B4X4_UNORM: return TDDS_R4G4B4X4_UNORM; 561 | 562 | case TinyImageFormat_A1B5G5R5_UNORM: return TDDS_A1B5G5R5_UNORM; 563 | case TinyImageFormat_X1B5G5R5_UNORM: return TDDS_X1B5G5R5_UNORM; 564 | 565 | case TinyImageFormat_A1R5G5B5_UNORM: return TDDS_A1R5G5B5_UNORM; 566 | case TinyImageFormat_X1R5G5B5_UNORM: return TDDS_X1R5G5B5_UNORM; 567 | 568 | case TinyImageFormat_B5G5R5A1_UNORM: return TDDS_B5G5R5A1_UNORM; 569 | case TinyImageFormat_B5G5R5X1_UNORM: return TDDS_B5G5R5X1_UNORM; 570 | 571 | case TinyImageFormat_R5G5B5A1_UNORM: return TDDS_R5G5B5A1_UNORM; 572 | case TinyImageFormat_R5G5B5X1_UNORM: return TDDS_R5G5B5X1_UNORM; 573 | 574 | case TinyImageFormat_R5G6B5_UNORM: return TDDS_R5G6B5_UNORM; 575 | case TinyImageFormat_B5G6R5_UNORM: return TDDS_B5G6R5_UNORM; 576 | 577 | case TinyImageFormat_A2B10G10R10_UNORM: return TDDS_A2B10G10R10_UNORM; 578 | case TinyImageFormat_A2B10G10R10_SNORM: return TDDS_A2B10G10R10_SNORM; 579 | case TinyImageFormat_A2R10G10B10_UNORM: return TDDS_A2R10G10B10_UNORM; 580 | case TinyImageFormat_A2R10G10B10_SNORM: return TDDS_A2R10G10B10_SNORM; 581 | case TinyImageFormat_R10G10B10A2_UNORM: return TDDS_B10G10R10A2_UNORM; 582 | case TinyImageFormat_R10G10B10A2_SNORM: return TDDS_B10G10R10A2_SNORM; 583 | case TinyImageFormat_B10G10R10A2_UNORM: return TDDS_R10G10B10A2_UNORM; 584 | case TinyImageFormat_B10G10R10A2_SNORM: return TDDS_R10G10B10A2_SNORM; 585 | case TinyImageFormat_B10G10R10A2_UINT: return TDDS_R10G10B10A2_UINT; 586 | 587 | case TinyImageFormat_E5B9G9R9_UFLOAT: return TDDS_R9G9B9E5_UFLOAT; 588 | case TinyImageFormat_B10G11R11_UFLOAT: return TDDS_R11G11B10_UFLOAT; 589 | 590 | case TinyImageFormat_R8_UNORM: return TDDS_R8_UNORM; 591 | case TinyImageFormat_R8_SNORM: return TDDS_R8_SNORM; 592 | case TinyImageFormat_R8_UINT: return TDDS_R8_UINT; 593 | case TinyImageFormat_R8_SINT: return TDDS_R8_SINT; 594 | case TinyImageFormat_A8_UNORM: return TDDS_A8_UNORM; 595 | case TinyImageFormat_B2G3R3_UNORM: return TDDS_B2G3R3_UNORM; 596 | 597 | case TinyImageFormat_B2G3R3A8_UNORM: return TDDS_B2G3R3A8_UNORM; 598 | case TinyImageFormat_R8G8_UNORM: return TDDS_R8G8_UNORM; 599 | case TinyImageFormat_R8G8_SNORM: return TDDS_R8G8_SNORM; 600 | case TinyImageFormat_R8G8_UINT: return TDDS_R8G8_UINT; 601 | case TinyImageFormat_R8G8_SINT: return TDDS_R8G8_SINT; 602 | case TinyImageFormat_G8R8_UNORM: return TDDS_G8R8_UNORM; 603 | case TinyImageFormat_G8R8_SNORM: return TDDS_G8R8_SNORM; 604 | 605 | case TinyImageFormat_R8G8B8_UNORM: return TDDS_R8G8B8_UNORM; 606 | case TinyImageFormat_B8G8R8_UNORM: return TDDS_B8G8R8_UNORM; 607 | 608 | case TinyImageFormat_R8G8B8A8_UNORM: return TDDS_R8G8B8A8_UNORM; 609 | case TinyImageFormat_R8G8B8A8_SNORM: return TDDS_R8G8B8A8_SNORM; 610 | case TinyImageFormat_R8G8B8A8_UINT: return TDDS_R8G8B8A8_UINT; 611 | case TinyImageFormat_R8G8B8A8_SINT: return TDDS_R8G8B8A8_SINT; 612 | case TinyImageFormat_R8G8B8A8_SRGB: return TDDS_R8G8B8A8_SRGB; 613 | case TinyImageFormat_B8G8R8A8_UNORM: return TDDS_B8G8R8A8_UNORM; 614 | case TinyImageFormat_B8G8R8A8_SRGB: return TDDS_B8G8R8A8_SRGB; 615 | 616 | case TinyImageFormat_R16_UNORM: return TDDS_R16_UNORM; 617 | case TinyImageFormat_R16_SNORM: return TDDS_R16_SNORM; 618 | case TinyImageFormat_R16_UINT: return TDDS_R16_UINT; 619 | case TinyImageFormat_R16_SINT: return TDDS_R16_SINT; 620 | case TinyImageFormat_R16_SFLOAT: return TDDS_R16_SFLOAT; 621 | 622 | case TinyImageFormat_R16G16_UNORM: return TDDS_R16G16_UNORM; 623 | case TinyImageFormat_R16G16_SNORM: return TDDS_R16G16_SNORM; 624 | case TinyImageFormat_R16G16_UINT: return TDDS_R16G16_UINT; 625 | case TinyImageFormat_R16G16_SINT: return TDDS_R16G16_SINT; 626 | case TinyImageFormat_R16G16_SFLOAT: return TDDS_R16G16_SFLOAT; 627 | 628 | case TinyImageFormat_G16R16_UNORM: return TDDS_G16R16_UNORM; 629 | case TinyImageFormat_G16R16_SNORM: return TDDS_G16R16_SNORM; 630 | 631 | case TinyImageFormat_R16G16B16A16_UNORM: return TDDS_R16G16B16A16_UNORM; 632 | case TinyImageFormat_R16G16B16A16_SNORM: return TDDS_R16G16B16A16_SNORM; 633 | case TinyImageFormat_R16G16B16A16_UINT: return TDDS_R16G16B16A16_UINT; 634 | case TinyImageFormat_R16G16B16A16_SINT: return TDDS_R16G16B16A16_SINT; 635 | case TinyImageFormat_R16G16B16A16_SFLOAT: return TDDS_R16G16B16A16_SFLOAT; 636 | 637 | case TinyImageFormat_R32_UINT: return TDDS_R32_UINT; 638 | case TinyImageFormat_R32_SINT: return TDDS_R32_SINT; 639 | case TinyImageFormat_R32_SFLOAT: return TDDS_R32_SFLOAT; 640 | 641 | case TinyImageFormat_R32G32_UINT: return TDDS_R32G32_UINT; 642 | case TinyImageFormat_R32G32_SINT: return TDDS_R32G32_SINT; 643 | case TinyImageFormat_R32G32_SFLOAT: return TDDS_R32G32_SFLOAT; 644 | 645 | case TinyImageFormat_R32G32B32_UINT: return TDDS_R32G32B32_UINT; 646 | case TinyImageFormat_R32G32B32_SINT: return TDDS_R32G32B32_SINT; 647 | case TinyImageFormat_R32G32B32_SFLOAT:return TDDS_R32G32B32_SFLOAT; 648 | 649 | case TinyImageFormat_R32G32B32A32_UINT: return TDDS_R32G32B32A32_UINT; 650 | case TinyImageFormat_R32G32B32A32_SINT: return TDDS_R32G32B32A32_SINT; 651 | case TinyImageFormat_R32G32B32A32_SFLOAT: return TDDS_R32G32B32A32_SFLOAT; 652 | 653 | case TinyImageFormat_D16_UNORM: return TDDS_R16_UNORM; 654 | case TinyImageFormat_D32_SFLOAT: return TDDS_R32_SFLOAT; 655 | case TinyImageFormat_S8_UINT: return TDDS_R8_UINT; 656 | case TinyImageFormat_DXBC1_RGB_UNORM: return TDDS_BC1_RGBA_UNORM_BLOCK; 657 | case TinyImageFormat_DXBC1_RGB_SRGB: return TDDS_BC1_RGBA_SRGB_BLOCK; 658 | case TinyImageFormat_DXBC1_RGBA_UNORM: return TDDS_BC1_RGBA_UNORM_BLOCK; 659 | case TinyImageFormat_DXBC1_RGBA_SRGB: return TDDS_BC1_RGBA_SRGB_BLOCK; 660 | case TinyImageFormat_DXBC2_UNORM: return TDDS_BC2_UNORM_BLOCK; 661 | case TinyImageFormat_DXBC2_SRGB: return TDDS_BC2_SRGB_BLOCK; 662 | case TinyImageFormat_DXBC3_UNORM: return TDDS_BC3_UNORM_BLOCK; 663 | case TinyImageFormat_DXBC3_SRGB: return TDDS_BC3_SRGB_BLOCK; 664 | case TinyImageFormat_DXBC4_UNORM: return TDDS_BC4_UNORM_BLOCK; 665 | case TinyImageFormat_DXBC4_SNORM: return TDDS_BC4_SNORM_BLOCK; 666 | case TinyImageFormat_DXBC5_UNORM: return TDDS_BC5_UNORM_BLOCK; 667 | case TinyImageFormat_DXBC5_SNORM: return TDDS_BC5_SNORM_BLOCK; 668 | case TinyImageFormat_DXBC6H_UFLOAT: return TDDS_BC6H_UFLOAT_BLOCK; 669 | case TinyImageFormat_DXBC6H_SFLOAT: return TDDS_BC6H_SFLOAT_BLOCK; 670 | case TinyImageFormat_DXBC7_UNORM: return TDDS_BC7_UNORM_BLOCK; 671 | case TinyImageFormat_DXBC7_SRGB: return TDDS_BC7_SRGB_BLOCK; 672 | 673 | case TinyImageFormat_CLUT_P8: return TDDS_P8; 674 | case TinyImageFormat_CLUT_P8A8: return TDDS_A8P8; 675 | case TinyImageFormat_R1_UNORM: return TDDS_R1_UNORM; 676 | 677 | // unsupported 678 | // TODO Some of these can be via Dx10/4CC codes I think 679 | default: return TDDS_UNDEFINED; 680 | } 681 | 682 | return TDDS_UNDEFINED; 683 | } 684 | #endif 685 | 686 | TinyDDS_Format TinyDDS_GetFormat(TinyDDS_ContextHandle handle); 687 | bool TinyDDS_WriteImage(TinyDDS_WriteCallbacks const *callbacks, 688 | void *user, 689 | uint32_t width, 690 | uint32_t height, 691 | uint32_t depth, 692 | uint32_t slices, 693 | uint32_t mipmaplevels, 694 | TinyDDS_Format format, 695 | bool cubemap, 696 | bool preferDx10Format, 697 | uint32_t const *mipmapsizes, 698 | void const **mipmaps); 699 | 700 | #ifdef TINYDDS_IMPLEMENTATION 701 | 702 | #define TINYDDS_DDSD_CAPS 0x00000001 703 | #define TINYDDS_DDSD_HEIGHT 0x00000002 704 | #define TINYDDS_DDSD_WIDTH 0x00000004 705 | #define TINYDDS_DDSD_PITCH 0x00000008 706 | #define TINYDDS_DDSD_PIXELFORMAT 0x00001000 707 | #define TINYDDS_DDSD_MIPMAPCOUNT 0x00020000 708 | #define TINYDDS_DDSD_LINEARSIZE 0x00080000 709 | #define TINYDDS_DDSD_DEPTH 0x00800000 710 | #define TINYDDS_DDSCAPS_COMPLEX 0x00000008 711 | #define TINYDDS_DDSCAPS_TEXTURE 0x00001000 712 | #define TINYDDS_DDSCAPS_MIPMAP 0x00400000 713 | #define TINYDDS_DDSCAPS2_CUBEMAP 0x00000200 714 | #define TINYDDS_DDSCAPS2_VOLUME 0x00200000 715 | #define TINYDDS_DDSCAPS2_CUBEMAP_ALL 0x0000FC000 716 | #define TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE 0x4 717 | #define TINYDDS_D3D10_RESOURCE_DIMENSION_BUFFER 1 718 | #define TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE1D 2 719 | #define TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE2D 3 720 | #define TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE3D 4 721 | #define TINYDDS_DDPF_ALPHAPIXELS 0x00000001l 722 | #define TINYDDS_DDPF_ALPHA 0x00000002l 723 | #define TINYDDS_DDPF_FOURCC 0x00000004l 724 | #define TINYDDS_DDPF_PALETTEINDEXED4 0x00000008l 725 | #define TINYDDS_DDPF_PALETTEINDEXEDTO8 0x00000010l 726 | #define TINYDDS_DDPF_PALETTEINDEXED8 0x00000020l 727 | #define TINYDDS_DDPF_RGB 0x00000040l 728 | #define TINYDDS_DDPF_LUMINANCE 0x00020000l 729 | #define TINYDDS_DDPF_BUMPLUMINANCE 0x00040000l 730 | #define TINYDDS_DDPF_BUMPDUDV 0x00080000l 731 | 732 | // some of these get stuck in unofficial DDS v9 FourCC code 733 | typedef enum TINYDDS_D3DFORMAT { 734 | TINYDDS_D3DFMT_UNKNOWN = 0, 735 | TINYDDS_D3DFMT_R8G8B8 = 20, 736 | TINYDDS_D3DFMT_A8R8G8B8 = 21, 737 | TINYDDS_D3DFMT_X8R8G8B8 = 22, 738 | TINYDDS_D3DFMT_R5G6B5 = 23, 739 | TINYDDS_D3DFMT_X1R5G5B5 = 24, 740 | TINYDDS_D3DFMT_A1R5G5B5 = 25, 741 | TINYDDS_D3DFMT_A4R4G4B4 = 26, 742 | TINYDDS_D3DFMT_R3G3B2 = 27, 743 | TINYDDS_D3DFMT_A8 = 28, 744 | TINYDDS_D3DFMT_A8R3G3B2 = 29, 745 | TINYDDS_D3DFMT_X4R4G4B4 = 30, 746 | TINYDDS_D3DFMT_A2B10G10R10 = 31, 747 | TINYDDS_D3DFMT_A8B8G8R8 = 32, 748 | TINYDDS_D3DFMT_X8B8G8R8 = 33, 749 | TINYDDS_D3DFMT_G16R16 = 34, 750 | TINYDDS_D3DFMT_A2R10G10B10 = 35, 751 | TINYDDS_D3DFMT_A16B16G16R16 = 36, 752 | TINYDDS_D3DFMT_A8P8 = 40, 753 | TINYDDS_D3DFMT_P8 = 41, 754 | TINYDDS_D3DFMT_L8 = 50, 755 | TINYDDS_D3DFMT_A8L8 = 51, 756 | TINYDDS_D3DFMT_A4L4 = 52, 757 | TINYDDS_D3DFMT_V8U8 = 60, 758 | TINYDDS_D3DFMT_L6V5U5 = 61, 759 | TINYDDS_D3DFMT_X8L8V8U8 = 62, 760 | TINYDDS_D3DFMT_Q8W8V8U8 = 63, 761 | TINYDDS_D3DFMT_V16U16 = 64, 762 | TINYDDS_D3DFMT_A2W10V10U10 = 67, 763 | TINYDDS_D3DFMT_L16 = 81, 764 | TINYDDS_D3DFMT_Q16W16V16U16 = 110, 765 | TINYDDS_D3DFMT_R16F = 111, 766 | TINYDDS_D3DFMT_G16R16F = 112, 767 | TINYDDS_D3DFMT_A16B16G16R16F = 113, 768 | TINYDDS_D3DFMT_R32F = 114, 769 | TINYDDS_D3DFMT_G32R32F = 115, 770 | TINYDDS_D3DFMT_A32B32G32R32F = 116, 771 | TINYDDS_D3DFMT_CxV8U8 = 117, 772 | TINYDDS_D3DFMT_A1 = 118, 773 | TINYDDS_D3DFMT_A2B10G10R10_XR_BIAS = 119, 774 | } TINYDDS_D3DFORMAT; 775 | 776 | typedef struct TinyDDS_Header { 777 | uint32_t magic; 778 | uint32_t size; 779 | uint32_t flags; 780 | uint32_t height; 781 | uint32_t width; 782 | uint32_t pitchOrLinearSize; 783 | uint32_t depth; 784 | uint32_t mipMapCount; 785 | uint32_t reserved0[11]; 786 | 787 | uint32_t formatSize; 788 | uint32_t formatFlags; 789 | uint32_t formatFourCC; 790 | uint32_t formatRGBBitCount; 791 | uint32_t formatRBitMask; 792 | uint32_t formatGBitMask; 793 | uint32_t formatBBitMask; 794 | uint32_t formatABitMask; 795 | 796 | uint32_t caps1; 797 | uint32_t caps2; 798 | uint32_t caps3; // not used? 799 | uint32_t caps4; // not used? 800 | 801 | uint32_t reserved1; 802 | } TinyDDS_Header; 803 | 804 | typedef struct TinyDDS_HeaderDX10 { 805 | uint32_t DXGIFormat; 806 | uint32_t resourceDimension; 807 | uint32_t miscFlag; 808 | uint32_t arraySize; 809 | uint32_t reserved; 810 | } TinyDDS_HeaderDX10; 811 | 812 | typedef struct TinyDDS_Context { 813 | TinyDDS_Callbacks callbacks; 814 | void *user; 815 | uint64_t headerPos; 816 | uint64_t firstImagePos; 817 | 818 | TinyDDS_Header header; 819 | TinyDDS_HeaderDX10 headerDx10; 820 | TinyDDS_Format format; 821 | 822 | bool headerValid; 823 | uint8_t const *mipmaps[TINYDDS_MAX_MIPMAPLEVELS]; 824 | uint32_t const *clut; 825 | 826 | } TinyDDS_Context; 827 | 828 | #define TINYDDS_MAKE_RIFFCODE(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24)) 829 | 830 | static uint32_t TinyDDS_fileIdentifier = TINYDDS_MAKE_RIFFCODE('D', 'D', 'S', ' '); 831 | 832 | static void TinyDDS_NullErrorFunc(void *user, char const *msg) {} 833 | 834 | TinyDDS_ContextHandle TinyDDS_CreateContext(TinyDDS_Callbacks const *callbacks, void *user) { 835 | TinyDDS_Context *ctx = (TinyDDS_Context *) callbacks->allocFn(user, sizeof(TinyDDS_Context)); 836 | if (ctx == NULL) 837 | return NULL; 838 | 839 | memset(ctx, 0, sizeof(TinyDDS_Context)); 840 | memcpy(&ctx->callbacks, callbacks, sizeof(TinyDDS_Callbacks)); 841 | ctx->user = user; 842 | if (ctx->callbacks.errorFn == NULL) { 843 | ctx->callbacks.errorFn = &TinyDDS_NullErrorFunc; 844 | } 845 | 846 | if (ctx->callbacks.readFn == NULL) { 847 | ctx->callbacks.errorFn(user, "TinyDDS must have read callback"); 848 | return NULL; 849 | } 850 | if (ctx->callbacks.allocFn == NULL) { 851 | ctx->callbacks.errorFn(user, "TinyDDS must have alloc callback"); 852 | return NULL; 853 | } 854 | if (ctx->callbacks.freeFn == NULL) { 855 | ctx->callbacks.errorFn(user, "TinyDDS must have free callback"); 856 | return NULL; 857 | } 858 | if (ctx->callbacks.seekFn == NULL) { 859 | ctx->callbacks.errorFn(user, "TinyDDS must have seek callback"); 860 | return NULL; 861 | } 862 | if (ctx->callbacks.tellFn == NULL) { 863 | ctx->callbacks.errorFn(user, "TinyDDS must have tell callback"); 864 | return NULL; 865 | } 866 | 867 | TinyDDS_Reset(ctx); 868 | 869 | return ctx; 870 | } 871 | 872 | void TinyDDS_DestroyContext(TinyDDS_ContextHandle handle) { 873 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 874 | if (ctx == NULL) 875 | return; 876 | TinyDDS_Reset(handle); 877 | 878 | ctx->callbacks.freeFn(ctx->user, ctx); 879 | } 880 | 881 | void TinyDDS_Reset(TinyDDS_ContextHandle handle) { 882 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 883 | if (ctx == NULL) 884 | return; 885 | 886 | // backup user provided callbacks and data 887 | TinyDDS_Callbacks callbacks; 888 | memcpy(&callbacks, &ctx->callbacks, sizeof(TinyDDS_Callbacks)); 889 | void *user = ctx->user; 890 | 891 | for (int i = 0; i < TINYDDS_MAX_MIPMAPLEVELS; ++i) { 892 | if (ctx->mipmaps[i] != NULL) { 893 | callbacks.freeFn(user, (void *) ctx->mipmaps[i]); 894 | } 895 | } 896 | 897 | if(ctx->clut) { 898 | callbacks.freeFn(user, (void *) ctx->clut); 899 | ctx->clut = NULL; 900 | } 901 | 902 | // reset to default state 903 | memset(ctx, 0, sizeof(TinyDDS_Context)); 904 | memcpy(&ctx->callbacks, &callbacks, sizeof(TinyDDS_Callbacks)); 905 | ctx->user = user; 906 | 907 | } 908 | 909 | static bool TinyDDS_IsCLUT(TinyDDS_Format fmt) { 910 | switch (fmt) { 911 | case TDDS_P8: 912 | case TDDS_A8P8: 913 | return true; 914 | default: return false; 915 | } 916 | } 917 | 918 | static bool TinyDDS_IsCompressed(TinyDDS_Format fmt) { 919 | switch (fmt) { 920 | case TDDS_BC1_RGBA_UNORM_BLOCK: 921 | case TDDS_BC1_RGBA_SRGB_BLOCK: 922 | case TDDS_BC2_UNORM_BLOCK: 923 | case TDDS_BC2_SRGB_BLOCK: 924 | case TDDS_BC3_UNORM_BLOCK: 925 | case TDDS_BC3_SRGB_BLOCK: 926 | case TDDS_BC4_UNORM_BLOCK: 927 | case TDDS_BC4_SNORM_BLOCK: 928 | case TDDS_BC5_UNORM_BLOCK: 929 | case TDDS_BC5_SNORM_BLOCK: 930 | case TDDS_BC6H_UFLOAT_BLOCK: 931 | case TDDS_BC6H_SFLOAT_BLOCK: 932 | case TDDS_BC7_UNORM_BLOCK: 933 | case TDDS_BC7_SRGB_BLOCK: return true; 934 | default: return false; 935 | } 936 | } 937 | 938 | // the size is per pixel (except R1) for uncompressed and per block of 16 pixels for compressed 939 | static uint32_t TinyDDS_FormatSize(TinyDDS_Format fmt) { 940 | switch(fmt) { 941 | // 8 pixels at 1 bits each 942 | case TDDS_R1_UNORM: 943 | return 1; 944 | // 2 * 4 bits 945 | case TDDS_R4G4_UNORM: 946 | case TDDS_G4R4_UNORM: 947 | // 1 * 8 bits 948 | case TDDS_P8:; 949 | case TDDS_R8_UNORM: 950 | case TDDS_R8_SNORM: 951 | case TDDS_R8_UINT: 952 | case TDDS_R8_SINT: 953 | case TDDS_A8_UNORM: 954 | // 2 + 2 * 3 bits 955 | case TDDS_B2G3R3_UNORM: 956 | return 1; 957 | 958 | // 2 + 2 * 3 +8 bits 959 | case TDDS_B2G3R3A8_UNORM: 960 | // 4 * 4 bits 961 | case TDDS_B4G4R4A4_UNORM: 962 | case TDDS_A4B4G4R4_UNORM: 963 | case TDDS_X4B4G4R4_UNORM: 964 | case TDDS_A4R4G4B4_UNORM: 965 | case TDDS_X4R4G4B4_UNORM: 966 | case TDDS_B4G4R4X4_UNORM: 967 | case TDDS_R4G4B4A4_UNORM: 968 | case TDDS_R4G4B4X4_UNORM: 969 | 970 | // 3 * 5 bits + 1 bit 971 | case TDDS_B5G5R5A1_UNORM: 972 | case TDDS_B5G5R5X1_UNORM: 973 | case TDDS_R5G5B5A1_UNORM: 974 | case TDDS_R5G5B5X1_UNORM: 975 | case TDDS_A1R5G5B5_UNORM: 976 | case TDDS_X1R5G5B5_UNORM: 977 | case TDDS_A1B5G5R5_UNORM: 978 | case TDDS_X1B5G5R5_UNORM: 979 | 980 | // 1 * 6 bit + 2 * 5 bits 981 | case TDDS_R5G6B5_UNORM: 982 | case TDDS_B5G6R5_UNORM: 983 | // 2 x 8 bits 984 | case TDDS_A8P8: 985 | case TDDS_R8G8_UNORM: 986 | case TDDS_R8G8_SNORM: 987 | case TDDS_G8R8_UNORM: 988 | case TDDS_G8R8_SNORM: 989 | case TDDS_R8G8_UINT: 990 | case TDDS_R8G8_SINT: 991 | // 1 * 16 bits 992 | case TDDS_R16_UNORM: 993 | case TDDS_R16_SNORM: 994 | case TDDS_R16_UINT: 995 | case TDDS_R16_SINT: 996 | case TDDS_R16_SFLOAT: 997 | return 2; 998 | 999 | // 3 * 8 bits 1000 | case TDDS_R8G8B8_UNORM: 1001 | case TDDS_B8G8R8_UNORM: 1002 | return 3; 1003 | // 4 * 8 bits 1004 | case TDDS_A8B8G8R8_SNORM: 1005 | case TDDS_R8G8B8A8_SNORM: 1006 | case TDDS_R8G8B8A8_UINT: 1007 | case TDDS_R8G8B8A8_SINT: 1008 | case TDDS_R8G8B8A8_SRGB: 1009 | case TDDS_B8G8R8A8_SRGB: 1010 | case TDDS_B8G8R8A8_SNORM: 1011 | 1012 | case TDDS_R8G8B8A8_UNORM: 1013 | case TDDS_R8G8B8X8_UNORM: 1014 | case TDDS_B8G8R8A8_UNORM: 1015 | case TDDS_B8G8R8X8_UNORM: 1016 | case TDDS_A8B8G8R8_UNORM: 1017 | case TDDS_X8B8G8R8_UNORM: 1018 | case TDDS_A8R8G8B8_UNORM: 1019 | case TDDS_X8R8G8B8_UNORM: 1020 | 1021 | // 3 * 9 bits + 5 bits 1022 | case TDDS_R9G9B9E5_UFLOAT: 1023 | // 3 * 10 bits + 2 bits 1024 | case TDDS_R10G10B10_7E3_A2_FLOAT: 1025 | case TDDS_R10G10B10_6E4_A2_FLOAT: 1026 | case TDDS_R10G10B10_SNORM_A2_UNORM: 1027 | 1028 | case TDDS_B10G10R10A2_UNORM: 1029 | case TDDS_B10G10R10A2_SNORM: 1030 | case TDDS_A2B10G10R10_UNORM: 1031 | case TDDS_A2B10G10R10_SNORM: 1032 | case TDDS_A2R10G10B10_UNORM: 1033 | case TDDS_A2R10G10B10_SNORM: 1034 | case TDDS_R10G10B10A2_UNORM: 1035 | case TDDS_R10G10B10A2_SNORM: 1036 | case TDDS_R10G10B10A2_UINT: 1037 | 1038 | // 2 * 11 bits + 10 bits 1039 | case TDDS_R11G11B10_UFLOAT: 1040 | // 2 * 16 bits 1041 | case TDDS_R16G16_UNORM: 1042 | case TDDS_R16G16_SNORM: 1043 | case TDDS_R16G16_UINT: 1044 | case TDDS_R16G16_SINT: 1045 | case TDDS_R16G16_SFLOAT: 1046 | case TDDS_G16R16_UNORM: 1047 | case TDDS_G16R16_SNORM: 1048 | // 1 * 32 bits 1049 | case TDDS_R32_UINT: 1050 | case TDDS_R32_SINT: 1051 | case TDDS_R32_SFLOAT: 1052 | return 4; 1053 | // 4 * 16 bits 1054 | case TDDS_R16G16B16A16_UNORM: 1055 | case TDDS_R16G16B16A16_SNORM: 1056 | case TDDS_R16G16B16A16_UINT: 1057 | case TDDS_R16G16B16A16_SINT: 1058 | case TDDS_R16G16B16A16_SFLOAT: 1059 | // 2 * 32 bits 1060 | case TDDS_R32G32_UINT: 1061 | case TDDS_R32G32_SINT: 1062 | case TDDS_R32G32_SFLOAT: 1063 | return 8; 1064 | // 3 * 32 bits 1065 | case TDDS_R32G32B32_UINT: 1066 | case TDDS_R32G32B32_SINT: 1067 | case TDDS_R32G32B32_SFLOAT: 1068 | return 12; 1069 | // 4 * 32 bits 1070 | case TDDS_R32G32B32A32_UINT: 1071 | case TDDS_R32G32B32A32_SINT: 1072 | case TDDS_R32G32B32A32_SFLOAT: 1073 | return 16; 1074 | // block formats 1075 | case TDDS_BC1_RGBA_UNORM_BLOCK: 1076 | case TDDS_BC1_RGBA_SRGB_BLOCK: 1077 | case TDDS_BC4_UNORM_BLOCK: 1078 | case TDDS_BC4_SNORM_BLOCK: 1079 | return 8; 1080 | 1081 | case TDDS_BC2_UNORM_BLOCK: 1082 | case TDDS_BC2_SRGB_BLOCK: 1083 | case TDDS_BC3_UNORM_BLOCK: 1084 | case TDDS_BC3_SRGB_BLOCK: 1085 | case TDDS_BC5_UNORM_BLOCK: 1086 | case TDDS_BC5_SNORM_BLOCK: 1087 | case TDDS_BC6H_UFLOAT_BLOCK: 1088 | case TDDS_BC6H_SFLOAT_BLOCK: 1089 | case TDDS_BC7_UNORM_BLOCK: 1090 | case TDDS_BC7_SRGB_BLOCK: 1091 | return 16; 1092 | 1093 | case TDDS_UNDEFINED: return 0; 1094 | // default: return 0; 1095 | case TDDS_AYUV:break; 1096 | case TDDS_Y410:break; 1097 | case TDDS_Y416:break; 1098 | case TDDS_NV12:break; 1099 | case TDDS_P010:break; 1100 | case TDDS_P016:break; 1101 | case TDDS_420_OPAQUE:break; 1102 | case TDDS_YUY2:break; 1103 | case TDDS_Y210:break; 1104 | case TDDS_Y216:break; 1105 | case TDDS_NV11:break; 1106 | case TDDS_AI44:break; 1107 | case TDDS_IA44:break; 1108 | case TDDS_D16_UNORM_S8_UINT:break; 1109 | case TDDS_R16_UNORM_X8_TYPELESS:break; 1110 | case TDDS_X16_TYPELESS_G8_UINT:break; 1111 | case TDDS_P208:break; 1112 | case TDDS_V208:break; 1113 | case TDDS_V408:break; 1114 | } 1115 | return 0; 1116 | } 1117 | 1118 | #define TINYDDS_CHK_DDSFORMAT(bits, rm, gm, bm, am, fmt) \ 1119 | if ((ctx->header.formatRGBBitCount == bits) && \ 1120 | (ctx->header.formatRBitMask == rm) && \ 1121 | (ctx->header.formatGBitMask == gm) && \ 1122 | (ctx->header.formatBBitMask == bm) && \ 1123 | (ctx->header.formatABitMask == am)) { return fmt; } 1124 | 1125 | static TinyDDS_Format TinyDDS_DecodeFormat(TinyDDS_Context *ctx) { 1126 | if (ctx->header.formatFlags & TINYDDS_DDPF_FOURCC) { 1127 | if (ctx->headerDx10.DXGIFormat != TIF_DXGI_FORMAT_UNKNOWN) { 1128 | return (TinyDDS_Format) ctx->headerDx10.DXGIFormat; 1129 | } 1130 | 1131 | // check fourCC and some special numbers.. 1132 | // unofficially during the dx9 timeline, D3D_FORMAT were stuck directly into 1133 | // formatFourCC field we handle FourCC and these < 119 codes here 1134 | // its unclear if this was only for formats that couldn't be exposed via 1135 | // Direct Draw Surfaces (like floats etc.) so I decode most of them anyway 1136 | switch (ctx->header.formatFourCC) { 1137 | case TINYDDS_D3DFMT_R8G8B8: return TDDS_R8G8B8_UNORM; 1138 | case TINYDDS_D3DFMT_A8R8G8B8: return TDDS_A8R8G8B8_UNORM; 1139 | case TINYDDS_D3DFMT_X8R8G8B8: return TDDS_X8R8G8B8_UNORM; 1140 | case TINYDDS_D3DFMT_R5G6B5: return TDDS_R5G6B5_UNORM; 1141 | case TINYDDS_D3DFMT_X1R5G5B5: return TDDS_X1R5G5B5_UNORM; 1142 | case TINYDDS_D3DFMT_A1R5G5B5: return TDDS_A1R5G5B5_UNORM; 1143 | case TINYDDS_D3DFMT_A4R4G4B4: return TDDS_A4R4G4B4_UNORM; 1144 | case TINYDDS_D3DFMT_R3G3B2: return TDDS_B2G3R3_UNORM; 1145 | case TINYDDS_D3DFMT_A8: return TDDS_A8_UNORM; 1146 | case TINYDDS_D3DFMT_A8R3G3B2: return TDDS_B2G3R3A8_UNORM; 1147 | case TINYDDS_D3DFMT_X4R4G4B4: return TDDS_A4R4G4B4_UNORM; 1148 | case TINYDDS_D3DFMT_A2B10G10R10: return TDDS_A2B10G10R10_UNORM; 1149 | case TINYDDS_D3DFMT_A8B8G8R8: return TDDS_A8B8G8R8_UNORM; 1150 | case TINYDDS_D3DFMT_X8B8G8R8: return TDDS_A8B8G8R8_UNORM; 1151 | case TINYDDS_D3DFMT_A2R10G10B10: return TDDS_A2R10G10B10_UNORM; 1152 | case TINYDDS_D3DFMT_G16R16: return TDDS_R16G16_UNORM; 1153 | case TINYDDS_D3DFMT_A16B16G16R16: return TDDS_R16G16B16A16_UNORM; 1154 | case TINYDDS_D3DFMT_R16F: return TDDS_R16_SFLOAT; 1155 | case TINYDDS_D3DFMT_G16R16F: return TDDS_R16G16_SFLOAT; 1156 | case TINYDDS_D3DFMT_A16B16G16R16F: return TDDS_R16G16B16A16_SFLOAT; 1157 | case TINYDDS_D3DFMT_A8P8: return TDDS_A8P8; 1158 | case TINYDDS_D3DFMT_P8: return TDDS_P8; 1159 | case TINYDDS_D3DFMT_L8: return TDDS_R8_UNORM; 1160 | case TINYDDS_D3DFMT_A8L8: return TDDS_R8G8_UNORM; 1161 | case TINYDDS_D3DFMT_A4L4: return TDDS_R4G4_UNORM; 1162 | case TINYDDS_D3DFMT_V8U8: return TDDS_G8R8_SNORM; 1163 | case TINYDDS_D3DFMT_L6V5U5: return TDDS_UNDEFINED; // TODO TDDS_R5G6B5_SNORM_PACK16; 1164 | case TINYDDS_D3DFMT_X8L8V8U8: return TDDS_R8G8B8A8_SNORM; 1165 | case TINYDDS_D3DFMT_Q8W8V8U8: return TDDS_R8G8B8A8_SNORM; 1166 | case TINYDDS_D3DFMT_V16U16: return TDDS_R16G16_SNORM; 1167 | case TINYDDS_D3DFMT_A2W10V10U10: return TDDS_A2B10G10R10_SNORM; 1168 | case TINYDDS_D3DFMT_L16: return TDDS_R16_UNORM; 1169 | case TINYDDS_D3DFMT_Q16W16V16U16: return TDDS_R16G16B16A16_SNORM; 1170 | case TINYDDS_D3DFMT_R32F: return TDDS_R32_SFLOAT; 1171 | case TINYDDS_D3DFMT_G32R32F: return TDDS_R32G32_SFLOAT; 1172 | case TINYDDS_D3DFMT_A32B32G32R32F: return TDDS_R32G32B32A32_SFLOAT; 1173 | case TINYDDS_D3DFMT_CxV8U8: return TDDS_UNDEFINED; 1174 | case TINYDDS_D3DFMT_A1: return TDDS_R1_UNORM; 1175 | case TINYDDS_D3DFMT_A2B10G10R10_XR_BIAS: return TDDS_UNDEFINED; 1176 | 1177 | // real 4CC no exotics yet just the block compression ones 1178 | case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '1'): return TDDS_BC1_RGBA_UNORM_BLOCK; 1179 | case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '2'): return TDDS_BC2_UNORM_BLOCK; 1180 | case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '3'): return TDDS_BC2_UNORM_BLOCK; 1181 | case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '4'): return TDDS_BC3_UNORM_BLOCK; 1182 | case TINYDDS_MAKE_RIFFCODE('D', 'X', 'T', '5'): return TDDS_BC3_UNORM_BLOCK; 1183 | case TINYDDS_MAKE_RIFFCODE('A', 'T', 'I', '1'): return TDDS_BC4_UNORM_BLOCK; 1184 | case TINYDDS_MAKE_RIFFCODE('A', 'T', 'I', '2'): return TDDS_BC5_UNORM_BLOCK; 1185 | case TINYDDS_MAKE_RIFFCODE('B', 'C', '4', 'U'): return TDDS_BC4_UNORM_BLOCK; 1186 | case TINYDDS_MAKE_RIFFCODE('B', 'C', '4', 'S'): return TDDS_BC4_SNORM_BLOCK; 1187 | case TINYDDS_MAKE_RIFFCODE('B', 'C', '5', 'U'): return TDDS_BC5_UNORM_BLOCK; 1188 | case TINYDDS_MAKE_RIFFCODE('B', 'C', '5', 'S'): return TDDS_BC5_SNORM_BLOCK; 1189 | } 1190 | } 1191 | 1192 | // okay back to direct draw surface bit fields to try and work format out. 1193 | // TODO this could be better i'm sure 1194 | 1195 | if ((ctx->header.formatFlags & TINYDDS_DDPF_PALETTEINDEXED4)) { 1196 | return TDDS_UNDEFINED; // TODO 4 bit CLUTs 1197 | } 1198 | 1199 | if ((ctx->header.formatFlags & TINYDDS_DDPF_PALETTEINDEXED8)) { 1200 | if(ctx->header.formatRGBBitCount != 8) return TDDS_UNDEFINED; 1201 | if(ctx->header.formatFlags & TINYDDS_DDPF_ALPHA) { 1202 | return TDDS_A8P8; 1203 | } else { 1204 | return TDDS_P8; 1205 | } 1206 | } 1207 | // what is this? TINYDDS_DDPF_PALETTEINDEXEDTO8 1208 | 1209 | // most have RGB data and/or alpha 1210 | if ((ctx->header.formatFlags & TINYDDS_DDPF_RGB) || 1211 | (ctx->header.formatFlags & TINYDDS_DDPF_ALPHA)) { 1212 | 1213 | TINYDDS_CHK_DDSFORMAT(1, 0x1, 0x0, 0, 0, TDDS_R1_UNORM); 1214 | 1215 | TINYDDS_CHK_DDSFORMAT(8, 0xF0, 0x0F, 0, 0, TDDS_G4R4_UNORM); 1216 | TINYDDS_CHK_DDSFORMAT(8, 0x0F, 0xF0, 0, 0, TDDS_R4G4_UNORM); 1217 | TINYDDS_CHK_DDSFORMAT(8, 0xFF, 0, 0, 0, TDDS_R8_UNORM); 1218 | TINYDDS_CHK_DDSFORMAT(8, 0, 0, 0, 0xFF, TDDS_A8_UNORM); 1219 | TINYDDS_CHK_DDSFORMAT(8, 0xE0, 0x1C, 0x3, 0, TDDS_B2G3R3_UNORM); 1220 | 1221 | TINYDDS_CHK_DDSFORMAT(16, 0xF000, 0x0F00, 0x00F0, 0x000F, TDDS_A4B4G4R4_UNORM); 1222 | TINYDDS_CHK_DDSFORMAT(16, 0xF000, 0x0F00, 0x00F0, 0x0000, TDDS_X4B4G4R4_UNORM); 1223 | 1224 | TINYDDS_CHK_DDSFORMAT(16, 0x00F0, 0x0F00, 0xF000, 0x000F, TDDS_A4R4G4B4_UNORM); 1225 | TINYDDS_CHK_DDSFORMAT(16, 0x00F0, 0x0F00, 0xF000, 0x0000, TDDS_X4R4G4B4_UNORM); 1226 | 1227 | TINYDDS_CHK_DDSFORMAT(16, 0x0F00, 0x00F0, 0x000F, 0xF000, TDDS_B4G4R4A4_UNORM); 1228 | TINYDDS_CHK_DDSFORMAT(16, 0x0F00, 0x00F0, 0x000F, 0x0000, TDDS_B4G4R4X4_UNORM); 1229 | 1230 | TINYDDS_CHK_DDSFORMAT(16, 0x000F, 0x00F0, 0x0F00, 0xF000, TDDS_R4G4B4A4_UNORM); 1231 | TINYDDS_CHK_DDSFORMAT(16, 0x000F, 0x00F0, 0x0F00, 0x0000, TDDS_R4G4B4X4_UNORM); 1232 | 1233 | TINYDDS_CHK_DDSFORMAT(16, 0x7C00, 0x03E0, 0x001F, 0x8000, TDDS_B5G5R5A1_UNORM); 1234 | TINYDDS_CHK_DDSFORMAT(16, 0x7C00, 0x03E0, 0x001F, 0x0000, TDDS_B5G5R5X1_UNORM); 1235 | 1236 | TINYDDS_CHK_DDSFORMAT(16, 0x001F, 0x03E0, 0x7C00, 0x8000, TDDS_R5G5B5A1_UNORM); 1237 | TINYDDS_CHK_DDSFORMAT(16, 0x001F, 0x03E0, 0x7C00, 0x0000, TDDS_R5G5B5X1_UNORM); 1238 | 1239 | TINYDDS_CHK_DDSFORMAT(16, 0x003E, 0x07C0, 0xF800, 0x0001, TDDS_A1R5G5B5_UNORM); 1240 | TINYDDS_CHK_DDSFORMAT(16, 0x003E, 0x07C0, 0xF800, 0x0000, TDDS_X1R5G5B5_UNORM); 1241 | 1242 | TINYDDS_CHK_DDSFORMAT(16, 0xF800, 0x07C0, 0x003E, 0x0001, TDDS_A1B5G5R5_UNORM); 1243 | TINYDDS_CHK_DDSFORMAT(16, 0xF800, 0x07C0, 0x003E, 0x0000, TDDS_X1B5G5R5_UNORM); 1244 | 1245 | TINYDDS_CHK_DDSFORMAT(16, 0xF800, 0x07E0, 0x001F, 0x0000, TDDS_B5G6R5_UNORM); 1246 | TINYDDS_CHK_DDSFORMAT(16, 0x001F, 0x07E0, 0xF800, 0x0000, TDDS_R5G6B5_UNORM); 1247 | 1248 | TINYDDS_CHK_DDSFORMAT(16, 0x00FF, 0xFF00, 0x0000, 0x0000, TDDS_R8G8_UNORM); 1249 | TINYDDS_CHK_DDSFORMAT(16, 0xFF00, 0x00FF, 0x0000, 0x0000, TDDS_G8R8_UNORM); 1250 | 1251 | TINYDDS_CHK_DDSFORMAT(16, 0xFFFF, 0x0000, 0x0000, 0x0000, TDDS_R16_UNORM); 1252 | 1253 | TINYDDS_CHK_DDSFORMAT(16, 0xE0, 0x1C, 0x3, 0xFF00, TDDS_B2G3R3A8_UNORM); 1254 | 1255 | TINYDDS_CHK_DDSFORMAT(24, 0xFF0000, 0x00FF00, 0x0000FF, 0x0, TDDS_B8G8R8_UNORM); 1256 | TINYDDS_CHK_DDSFORMAT(24, 0x0000FF, 0x00FF00, 0xFF0000, 0x0, TDDS_R8G8B8_UNORM); 1257 | 1258 | TINYDDS_CHK_DDSFORMAT(32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000, TDDS_R8G8B8A8_UNORM); 1259 | TINYDDS_CHK_DDSFORMAT(32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000, TDDS_R8G8B8X8_UNORM); 1260 | 1261 | TINYDDS_CHK_DDSFORMAT(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, TDDS_B8G8R8A8_UNORM); 1262 | TINYDDS_CHK_DDSFORMAT(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000, TDDS_B8G8R8X8_UNORM); 1263 | 1264 | TINYDDS_CHK_DDSFORMAT(32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF, TDDS_A8B8G8R8_UNORM); 1265 | TINYDDS_CHK_DDSFORMAT(32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000, TDDS_X8B8G8R8_UNORM); 1266 | 1267 | TINYDDS_CHK_DDSFORMAT(32, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF, TDDS_A8R8G8B8_UNORM); 1268 | TINYDDS_CHK_DDSFORMAT(32, 0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000, TDDS_X8R8G8B8_UNORM); 1269 | 1270 | TINYDDS_CHK_DDSFORMAT(32, 0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000, TDDS_R10G10B10A2_UNORM); 1271 | TINYDDS_CHK_DDSFORMAT(32, 0xFFC00000, 0x003FF000, 0x00000FFC, 0x00000003, TDDS_A2B10G10R10_UNORM); 1272 | TINYDDS_CHK_DDSFORMAT(32, 0x00000FFC, 0x003FF000, 0xFFC00000, 0x00000003, TDDS_A2R10G10B10_UNORM); 1273 | 1274 | // this is often written incorrectly so we use the most 'common' version 1275 | TINYDDS_CHK_DDSFORMAT(32, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000, TDDS_B10G10R10A2_UNORM); 1276 | 1277 | 1278 | TINYDDS_CHK_DDSFORMAT(32, 0xFFFF0000, 0x0000FFFF, 0x00000000, 0x00000000, TDDS_G16R16_UNORM); 1279 | TINYDDS_CHK_DDSFORMAT(32, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000, TDDS_R16G16_UNORM); 1280 | TINYDDS_CHK_DDSFORMAT(32, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, TDDS_R32_UINT); 1281 | 1282 | if (ctx->header.formatRGBBitCount == 8) return TDDS_R8_UINT; 1283 | if (ctx->header.formatRGBBitCount == 16) return TDDS_R16_UINT; 1284 | if (ctx->header.formatRGBBitCount == 32) return TDDS_R32_UINT; 1285 | } 1286 | 1287 | if ((ctx->header.formatFlags & TINYDDS_DDPF_BUMPDUDV) || 1288 | (ctx->header.formatFlags & TINYDDS_DDPF_BUMPLUMINANCE)) { 1289 | TINYDDS_CHK_DDSFORMAT(16, 0xFF00, 0x00FF, 0x0000, 0x0000, TDDS_G8R8_SNORM); 1290 | TINYDDS_CHK_DDSFORMAT(16, 0x00FF, 0xFF00, 0x0000, 0x0000, TDDS_R8G8_SNORM); 1291 | 1292 | TINYDDS_CHK_DDSFORMAT(32, 0xFFFF0000, 0x0000FFFF, 0x0000, 0x0, TDDS_G16R16_SNORM); 1293 | TINYDDS_CHK_DDSFORMAT(32, 0x0000FFFF, 0xFFFF0000, 0x0000, 0x0, TDDS_R16G16_SNORM); 1294 | TINYDDS_CHK_DDSFORMAT(32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000, TDDS_R8G8B8A8_SNORM); 1295 | TINYDDS_CHK_DDSFORMAT(32, 0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000, TDDS_R10G10B10A2_SNORM); 1296 | TINYDDS_CHK_DDSFORMAT(32, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000, TDDS_B10G10R10A2_SNORM); 1297 | TINYDDS_CHK_DDSFORMAT(32, 0x00000FFC, 0x003FF000, 0xFFC00000, 0x00000003, TDDS_A2R10G10B10_SNORM); 1298 | TINYDDS_CHK_DDSFORMAT(32, 0xFFC00000, 0x003FF000, 0x00000FFC, 0x00000003, TDDS_A2B10G10R10_SNORM); 1299 | 1300 | if (ctx->header.formatRGBBitCount == 8) return TDDS_R8_SINT; 1301 | if (ctx->header.formatRGBBitCount == 16) return TDDS_R16_SINT; 1302 | if (ctx->header.formatRGBBitCount == 32) return TDDS_R32_SINT; 1303 | } 1304 | 1305 | if (ctx->header.formatFlags & TINYDDS_DDPF_LUMINANCE) { 1306 | TINYDDS_CHK_DDSFORMAT(8, 0x0F, 0x00, 0x00, 0xF0, TDDS_R4G4_UNORM); // this is A4L4 aka A4R4 we decode this as R4G4 1307 | TINYDDS_CHK_DDSFORMAT(16, 0x00FF, 0x0000, 0x0000, 0xFF00, TDDS_R8G8_UNORM); // this is A8L8 aka A4R8 we decode this as R8G8 1308 | 1309 | if (ctx->header.formatRGBBitCount == 8) return TDDS_R8_UNORM; 1310 | if (ctx->header.formatRGBBitCount == 16) return TDDS_R16_UNORM; 1311 | if (ctx->header.formatRGBBitCount == 32) return TDDS_R32_UINT; 1312 | 1313 | } 1314 | 1315 | return TDDS_UNDEFINED; 1316 | } 1317 | #undef TINYDDS_CHK_DDSFORMAT 1318 | 1319 | static uint32_t TinyDDS_MipMapReduce(uint32_t value, uint32_t mipmaplevel) { 1320 | 1321 | // handle 0 being passed in 1322 | if (value <= 1) 1323 | return 1; 1324 | 1325 | // there are better ways of doing this (log2 etc.) but this doesn't require any 1326 | // dependecies and isn't used enough to matter imho 1327 | for (uint32_t i = 0u; i < mipmaplevel; ++i) { 1328 | if (value <= 1) 1329 | return 1; 1330 | value = value / 2; 1331 | } 1332 | return value; 1333 | } 1334 | 1335 | bool TinyDDS_ReadHeader(TinyDDS_ContextHandle handle) { 1336 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1337 | if (ctx == NULL) 1338 | return false; 1339 | 1340 | ctx->headerPos = ctx->callbacks.tellFn(ctx->user); 1341 | if( ctx->callbacks.readFn(ctx->user, &ctx->header, sizeof(TinyDDS_Header)) != sizeof(TinyDDS_Header)) { 1342 | ctx->callbacks.errorFn(ctx->user, "Could not read DDS header"); 1343 | return false; 1344 | } 1345 | 1346 | // try the easy case of a modern dx10 DDS file 1347 | if ((ctx->header.formatFlags & TINYDDS_DDPF_FOURCC) && 1348 | (ctx->header.formatFourCC == TINYDDS_MAKE_RIFFCODE('D', 'X', '1', '0'))) { 1349 | ctx->callbacks.readFn(ctx->user, &ctx->headerDx10, sizeof(TinyDDS_HeaderDX10)); 1350 | 1351 | if (ctx->headerDx10.DXGIFormat >= TDDS_SYNTHESISED_DXGIFORMATS) { 1352 | ctx->callbacks.errorFn(ctx->user, "DX10 Header has an invalid DXGI_FORMAT code"); 1353 | return false; 1354 | } 1355 | } 1356 | 1357 | ctx->format = TinyDDS_DecodeFormat(ctx); 1358 | if (ctx->format == TDDS_UNDEFINED) { 1359 | ctx->callbacks.errorFn(ctx->user, "Could not decode DDS format"); 1360 | return false; 1361 | } 1362 | 1363 | if( (ctx->header.formatFourCC == 0) && 1364 | (ctx->header.formatRGBBitCount != 0) && 1365 | ((ctx->header.formatRGBBitCount/8) != TinyDDS_FormatSize(ctx->format))) { 1366 | ctx->callbacks.errorFn(ctx->user, "Format size mismatch"); 1367 | return false; 1368 | } 1369 | 1370 | // correct for dodgy mipmap levels counts 1371 | if(ctx->header.mipMapCount > 1) { 1372 | uint32_t w = ctx->header.width; 1373 | uint32_t h = ctx->header.height; 1374 | 1375 | for(uint32_t i = 0; i < ctx->header.mipMapCount;++i) { 1376 | if (TinyDDS_IsCompressed(ctx->format)) { 1377 | if (w <= 4 || h <= 4) { 1378 | ctx->header.mipMapCount = i + 1; 1379 | break; 1380 | } 1381 | } else if (w <= 1 || h <= 1) { 1382 | ctx->header.mipMapCount = i + 1; 1383 | break; 1384 | } 1385 | 1386 | 1387 | w = w / 2; 1388 | h = h / 2; 1389 | } 1390 | 1391 | } 1392 | 1393 | if (TinyDDS_IsCompressed(ctx->format)) { 1394 | // compressed images never get asked to make mip maps which is good as 1395 | // requires decompress/compress cycle 1396 | if(ctx->header.mipMapCount == 0) ctx->header.mipMapCount = 1; 1397 | } 1398 | 1399 | if(TinyDDS_IsCLUT(ctx->format)) { 1400 | // for now don't ask to generate mipmaps for cluts 1401 | if(ctx->header.mipMapCount == 0) ctx->header.mipMapCount = 1; 1402 | 1403 | size_t const clutSize = 256 * sizeof(uint32_t); 1404 | 1405 | ctx->clut = (uint32_t*) ctx->callbacks.allocFn(ctx->user, clutSize); 1406 | 1407 | if( ctx->callbacks.readFn(ctx->user, (void*)ctx->clut, clutSize) != clutSize) { 1408 | ctx->callbacks.errorFn(ctx->user, "Could not read DDS CLUT"); 1409 | return false; 1410 | } 1411 | } 1412 | 1413 | ctx->firstImagePos = ctx->callbacks.tellFn(ctx->user); 1414 | ctx->headerValid = true; 1415 | return true; 1416 | } 1417 | 1418 | bool TinyDDS_IsCubemap(TinyDDS_ContextHandle handle) { 1419 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1420 | if (ctx == NULL) 1421 | return false; 1422 | if (!ctx->headerValid) { 1423 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1424 | return false; 1425 | } 1426 | 1427 | return (ctx->header.caps2 & TINYDDS_DDSCAPS2_CUBEMAP); 1428 | } 1429 | 1430 | bool TinyDDS_Dimensions(TinyDDS_ContextHandle handle, 1431 | uint32_t *width, 1432 | uint32_t *height, 1433 | uint32_t *depth, 1434 | uint32_t *slices) { 1435 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1436 | if (ctx == NULL) 1437 | return false; 1438 | if (!ctx->headerValid) { 1439 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1440 | return false; 1441 | } 1442 | 1443 | if (width) 1444 | *width = ctx->header.width; 1445 | if (height) 1446 | *height = ctx->header.height; 1447 | if (depth) 1448 | *depth = ctx->header.depth; 1449 | if (slices) 1450 | *slices = ctx->headerDx10.arraySize; 1451 | return true; 1452 | } 1453 | 1454 | uint32_t TinyDDS_Width(TinyDDS_ContextHandle handle) { 1455 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1456 | if (ctx == NULL) 1457 | return 0; 1458 | if (!ctx->headerValid) { 1459 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1460 | return 0; 1461 | } 1462 | return ctx->header.width; 1463 | } 1464 | 1465 | uint32_t TinyDDS_Height(TinyDDS_ContextHandle handle) { 1466 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1467 | if (ctx == NULL) 1468 | return 0; 1469 | if (!ctx->headerValid) { 1470 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1471 | return 0; 1472 | } 1473 | return ctx->header.height; 1474 | } 1475 | 1476 | uint32_t TinyDDS_Depth(TinyDDS_ContextHandle handle) { 1477 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1478 | if (ctx == NULL) 1479 | return 0; 1480 | if (!ctx->headerValid) { 1481 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1482 | return 0; 1483 | } 1484 | 1485 | return ctx->header.depth; 1486 | } 1487 | 1488 | uint32_t TinyDDS_ArraySlices(TinyDDS_ContextHandle handle) { 1489 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1490 | if (ctx == NULL) 1491 | return 0; 1492 | if (!ctx->headerValid) { 1493 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1494 | return 0; 1495 | } 1496 | 1497 | return ctx->headerDx10.arraySize; 1498 | } 1499 | 1500 | bool TinyDDS_Is1D(TinyDDS_ContextHandle handle) { 1501 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1502 | if (ctx == NULL) 1503 | return false; 1504 | if (!ctx->headerValid) { 1505 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1506 | return false; 1507 | } 1508 | return (ctx->header.height <= 1 && ctx->header.depth <= 1); 1509 | } 1510 | bool TinyDDS_Is2D(TinyDDS_ContextHandle handle) { 1511 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1512 | if (ctx == NULL) 1513 | return false; 1514 | if (!ctx->headerValid) { 1515 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1516 | return false; 1517 | } 1518 | return (ctx->header.height > 1 && ctx->header.depth <= 1); 1519 | } 1520 | bool TinyDDS_Is3D(TinyDDS_ContextHandle handle) { 1521 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1522 | if (ctx == NULL) 1523 | return false; 1524 | if (!ctx->headerValid) { 1525 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1526 | return false; 1527 | } 1528 | 1529 | return (ctx->header.height > 1 && ctx->header.depth > 1); 1530 | } 1531 | 1532 | bool TinyDDS_IsArray(TinyDDS_ContextHandle handle) { 1533 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1534 | if (ctx == NULL) 1535 | return false; 1536 | if (!ctx->headerValid) { 1537 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1538 | return false; 1539 | } 1540 | 1541 | return (ctx->headerDx10.arraySize >= 1); 1542 | } 1543 | 1544 | uint32_t TinyDDS_NumberOfMipmaps(TinyDDS_ContextHandle handle) { 1545 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1546 | if (ctx == NULL) 1547 | return 0; 1548 | if (!ctx->headerValid) { 1549 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1550 | return 0; 1551 | } 1552 | 1553 | return ctx->header.mipMapCount ? ctx->header.mipMapCount : 1; 1554 | } 1555 | 1556 | bool TinyDDS_NeedsGenerationOfMipmaps(TinyDDS_ContextHandle handle) { 1557 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1558 | if (ctx == NULL) 1559 | return false; 1560 | if (!ctx->headerValid) { 1561 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1562 | return false; 1563 | } 1564 | 1565 | return ctx->header.mipMapCount == 0; 1566 | } 1567 | 1568 | bool TinyDDS_NeedsEndianCorrecting(TinyDDS_ContextHandle handle) { 1569 | // TODO should return true if this file is compiled on big endian machines 1570 | return false; 1571 | } 1572 | 1573 | uint32_t TinyDDS_FaceSize(TinyDDS_ContextHandle handle, uint32_t mipmaplevel) { 1574 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1575 | if (ctx == NULL) 1576 | return 0; 1577 | 1578 | if (!ctx->headerValid) { 1579 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1580 | return 0; 1581 | } 1582 | uint32_t w = TinyDDS_MipMapReduce(ctx->header.width, mipmaplevel); 1583 | uint32_t h = TinyDDS_MipMapReduce(ctx->header.height, mipmaplevel); 1584 | uint32_t d = TinyDDS_MipMapReduce(ctx->header.depth, mipmaplevel); 1585 | uint32_t s = ctx->headerDx10.arraySize ? ctx->headerDx10.arraySize : 1; 1586 | 1587 | if(d > 1 && s > 1) { 1588 | ctx->callbacks.errorFn(ctx->user, "Volume textures can't have array slices or be cubemap"); 1589 | return 0; 1590 | } 1591 | 1592 | if (TinyDDS_IsCompressed(ctx->format)) { 1593 | // padd to block boundaries 1594 | w = (w + 3) / 4; 1595 | h = (h + 3) / 4; 1596 | } 1597 | // 1 bit special case 1598 | if(ctx->format == TDDS_R1_UNORM) { 1599 | w = (w + 7) / 8; 1600 | } 1601 | 1602 | uint32_t const formatSize = TinyDDS_FormatSize(ctx->format); 1603 | return w * h * d * s * formatSize; 1604 | } 1605 | 1606 | uint32_t TinyDDS_ImageSize(TinyDDS_ContextHandle handle, uint32_t mipmaplevel) { 1607 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1608 | if (ctx == NULL) 1609 | return 0; 1610 | 1611 | if (!ctx->headerValid) { 1612 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1613 | return 0; 1614 | } 1615 | 1616 | if( ctx->header.caps2 & TINYDDS_DDSCAPS2_CUBEMAP || 1617 | ctx->headerDx10.miscFlag & TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE ) { 1618 | return TinyDDS_FaceSize(handle, mipmaplevel) * 6; 1619 | } else { 1620 | return TinyDDS_FaceSize(handle, mipmaplevel); 1621 | } 1622 | } 1623 | 1624 | void const *TinyDDS_ImageRawData(TinyDDS_ContextHandle handle, uint32_t mipmaplevel) { 1625 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1626 | if (ctx == NULL) 1627 | return NULL; 1628 | 1629 | if (!ctx->headerValid) { 1630 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1631 | return NULL; 1632 | } 1633 | 1634 | if (mipmaplevel >= (ctx->header.mipMapCount ? ctx->header.mipMapCount : 1) ) { 1635 | ctx->callbacks.errorFn(ctx->user, "Invalid mipmap level"); 1636 | return NULL; 1637 | } 1638 | 1639 | if (mipmaplevel >= TINYDDS_MAX_MIPMAPLEVELS) { 1640 | ctx->callbacks.errorFn(ctx->user, "Invalid mipmap level"); 1641 | return NULL; 1642 | } 1643 | 1644 | if (ctx->mipmaps[mipmaplevel] != NULL) 1645 | return ctx->mipmaps[mipmaplevel]; 1646 | 1647 | if( ctx->header.caps2 & TINYDDS_DDSCAPS2_CUBEMAP || 1648 | ctx->headerDx10.miscFlag & TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE ) { 1649 | 1650 | uint64_t offset = 0; 1651 | for(uint32_t i=0;i < mipmaplevel;++i) { 1652 | offset += TinyDDS_FaceSize(handle, i); 1653 | } 1654 | 1655 | uint32_t mipMapCount = ctx->header.mipMapCount; 1656 | if(mipMapCount == 0) mipMapCount = 1; 1657 | 1658 | // at least one cubemap generater has mipMapCount wrong which causes 1659 | // image artifacts :( 1660 | uint64_t nextFaceOffset = 0; 1661 | for(uint32_t i = 0;i < mipMapCount;++i) { 1662 | nextFaceOffset += TinyDDS_FaceSize(handle, i); 1663 | } 1664 | 1665 | size_t const faceSize = TinyDDS_FaceSize(handle, mipmaplevel); 1666 | ctx->mipmaps[mipmaplevel] = (uint8_t const *) ctx->callbacks.allocFn(ctx->user, faceSize * 6); 1667 | if(!ctx->mipmaps[mipmaplevel]) return NULL; 1668 | 1669 | uint8_t *dstPtr = (uint8_t*)ctx->mipmaps[mipmaplevel]; 1670 | for (uint32_t i = 0u;i < 6;++i) { 1671 | ctx->callbacks.seekFn(ctx->user, offset + ctx->firstImagePos); 1672 | size_t read = ctx->callbacks.readFn(ctx->user, (void *) dstPtr, faceSize); 1673 | if(read != faceSize) { 1674 | ctx->callbacks.freeFn(ctx->user, (void*)&ctx->mipmaps[mipmaplevel]); 1675 | return NULL; 1676 | } 1677 | dstPtr += faceSize; 1678 | offset += nextFaceOffset; 1679 | } 1680 | return ctx->mipmaps[mipmaplevel]; 1681 | } 1682 | 1683 | uint64_t offset = 0; 1684 | for(uint32_t i=0;i < mipmaplevel;++i) { 1685 | offset += TinyDDS_ImageSize(handle, i); 1686 | } 1687 | 1688 | uint32_t size = TinyDDS_ImageSize(handle, mipmaplevel); 1689 | if (size == 0) 1690 | return NULL; 1691 | 1692 | ctx->callbacks.seekFn(ctx->user, offset + ctx->firstImagePos); 1693 | 1694 | ctx->mipmaps[mipmaplevel] = (uint8_t const *) ctx->callbacks.allocFn(ctx->user, size); 1695 | if (!ctx->mipmaps[mipmaplevel]) return NULL; 1696 | size_t read = ctx->callbacks.readFn(ctx->user, (void *) ctx->mipmaps[mipmaplevel], size); 1697 | if(read != size) { 1698 | ctx->callbacks.freeFn(ctx->user, (void*)&ctx->mipmaps[mipmaplevel]); 1699 | return NULL; 1700 | } 1701 | 1702 | return ctx->mipmaps[mipmaplevel]; 1703 | } 1704 | 1705 | TinyDDS_Format TinyDDS_GetFormat(TinyDDS_ContextHandle handle) { 1706 | TinyDDS_Context *ctx = (TinyDDS_Context *) handle; 1707 | if (ctx == NULL) 1708 | return TDDS_UNDEFINED; 1709 | 1710 | if (!ctx->headerValid) { 1711 | ctx->callbacks.errorFn(ctx->user, "Header data hasn't been read yet or its invalid"); 1712 | return TDDS_UNDEFINED; 1713 | } 1714 | return ctx->format; 1715 | } 1716 | 1717 | #define TDDS_EF(bits, rm, gm, bm, am, fl) \ 1718 | header->formatRGBBitCount = bits; \ 1719 | header->formatRBitMask = rm; \ 1720 | header->formatGBitMask = gm; \ 1721 | header->formatBBitMask = bm; \ 1722 | header->formatABitMask = am; \ 1723 | header->formatFlags = fl; \ 1724 | header->formatFourCC = 0; \ 1725 | return true; 1726 | 1727 | #define TDDS_EF_RGB(bits, rm, gm, bm) TDDS_EF(bits, rm, gm, bm, 0, TINYDDS_DDPF_RGB ) 1728 | #define TDDS_EF_RGBA(bits, rm, gm, bm, am) TDDS_EF(bits, rm, gm, bm, am, TINYDDS_DDPF_RGB | TINYDDS_DDPF_ALPHAPIXELS) 1729 | #define TDDS_EF_ALPHA(bits, am) TDDS_EF(bits, 0, 0, 0, am, TINYDDS_DDPF_ALPHA) 1730 | 1731 | #define TDDS_EF_BUMP_RG(bits, rm, gm) TDDS_EF(bits, rm, gm, 0, 0, TINYDDS_DDPF_BUMPDUDV) 1732 | #define TDDS_EF_BUMP_RGB(bits, rm, gm, bm) TDDS_EF(bits, rm, gm, bm, 0, TINYDDS_DDPF_BUMPLUMINANCE) 1733 | #define TDDS_EF_BUMP_RGBA(bits, rm, gm, bm, am) TDDS_EF(bits, rm, gm, bm, am, TINYDDS_DDPF_BUMPLUMINANCE | TINYDDS_DDPF_ALPHAPIXELS) 1734 | 1735 | static bool TinyDDS_EncodeFormat(TinyDDS_Format fmt, TinyDDS_Header* header, TinyDDS_HeaderDX10* headerDx10) { 1736 | // lets start with the easy part. if its real DXGI_FORMAT we can just fill in the Dx10 part 1737 | if(fmt < TDDS_SYNTHESISED_DXGIFORMATS) { 1738 | headerDx10->DXGIFormat = (TinyImageFormat_DXGI_FORMAT)fmt; 1739 | header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','1','0'); 1740 | header->formatFlags = TINYDDS_DDPF_FOURCC; 1741 | } else { 1742 | headerDx10->DXGIFormat = TIF_DXGI_FORMAT_UNKNOWN; 1743 | } 1744 | // now lets try synthesising if possible 1745 | // if we can reset the DX10 fourCC but leave the format in place 1746 | // that way if we have slices which can only be DXGI_FORMAT we can use it 1747 | switch(fmt) { 1748 | case TDDS_UNDEFINED: break; 1749 | 1750 | case TDDS_R1_UNORM: TDDS_EF_RGB(1, 0x1, 0, 0) 1751 | case TDDS_R4G4_UNORM: TDDS_EF_RGB(8, 0x0F, 0xF0, 0) 1752 | case TDDS_G4R4_UNORM: TDDS_EF_RGB(8, 0xF0, 0x0F, 0) 1753 | case TDDS_B2G3R3_UNORM: TDDS_EF_RGB(8, 0x3, 0x7, 0x7 ) 1754 | case TDDS_R8_UNORM: TDDS_EF_RGB(8, 0xFF, 0, 0 ); 1755 | case TDDS_A8_UNORM: TDDS_EF_ALPHA( 8, 0xFF); 1756 | 1757 | case TDDS_R16_UNORM:TDDS_EF_RGB( 16,0x0000FFFF, 0, 0) 1758 | case TDDS_A4B4G4R4_UNORM: 1759 | TDDS_EF_RGBA(16, 0xF000, 0x0F00, 0x00F0, 0x000F); 1760 | case TDDS_X4B4G4R4_UNORM: 1761 | TDDS_EF_RGBA(16, 0xF000, 0x0F00, 0x00F0, 0x0000); 1762 | case TDDS_B4G4R4A4_UNORM: 1763 | TDDS_EF_RGBA(16, 0x0F00, 0x00F0, 0x000F, 0xF000); 1764 | case TDDS_B4G4R4X4_UNORM: 1765 | TDDS_EF_RGBA(16, 0x0F00, 0x00F0, 0x000F, 0x0000); 1766 | case TDDS_A4R4G4B4_UNORM: 1767 | TDDS_EF_RGBA(16, 0x00F0, 0x0F00, 0xF000, 0x000F); 1768 | case TDDS_X4R4G4B4_UNORM: 1769 | TDDS_EF_RGBA(16, 0x00F0, 0x0F00, 0xF000, 0x0000); 1770 | case TDDS_R4G4B4A4_UNORM: 1771 | TDDS_EF_RGBA(16, 0x000F, 0x00F0, 0x0F00, 0xF000); 1772 | case TDDS_R4G4B4X4_UNORM: 1773 | TDDS_EF_RGBA(16, 0x000F, 0x00F0, 0x0F00, 0x0000); 1774 | 1775 | case TDDS_B5G5R5A1_UNORM: 1776 | TDDS_EF_RGBA(16, 0x7C00, 0x03E0, 0x001F, 0x8000); 1777 | case TDDS_B5G5R5X1_UNORM: 1778 | TDDS_EF_RGBA(16, 0x7C00, 0x03E0, 0x001F, 0x0000); 1779 | 1780 | case TDDS_R5G5B5A1_UNORM: 1781 | TDDS_EF_RGBA(16, 0x001F, 0x03E0, 0x7C00, 0x8000); 1782 | case TDDS_R5G5B5X1_UNORM: 1783 | TDDS_EF_RGBA(16, 0x001F, 0x03E0, 0x7C00, 0x0000); 1784 | 1785 | case TDDS_A1R5G5B5_UNORM: 1786 | TDDS_EF_RGBA(16, 0x003E, 0x07C0, 0xF800, 0x0001); 1787 | case TDDS_X1R5G5B5_UNORM: 1788 | TDDS_EF_RGBA(16, 0x003E, 0x07C0, 0xF800, 0x0000); 1789 | case TDDS_A1B5G5R5_UNORM: 1790 | TDDS_EF_RGBA(16, 0xF800, 0x07C0, 0x003E, 0x0001); 1791 | case TDDS_X1B5G5R5_UNORM: 1792 | TDDS_EF_RGBA(16, 0xF800, 0x07C0, 0x003E, 0x0000); 1793 | 1794 | case TDDS_B5G6R5_UNORM: 1795 | TDDS_EF_RGB(16, 0xF800, 0x07E0, 0x001F); 1796 | case TDDS_R5G6B5_UNORM: 1797 | TDDS_EF_RGB(16, 0x001F, 0x07E0, 0xF800); 1798 | 1799 | case TDDS_R8G8_UNORM: 1800 | TDDS_EF_RGB(16, 0x00FF, 0xFF00, 0); 1801 | case TDDS_G8R8_UNORM: 1802 | TDDS_EF_RGB(16, 0xFF00, 0x00FF, 0); 1803 | case TDDS_G8R8_SNORM: 1804 | TDDS_EF_BUMP_RG(16, 0xFF00, 0x00FF); 1805 | 1806 | case TDDS_B2G3R3A8_UNORM: TDDS_EF_RGBA(8, 0x3, 0x7, 0x7, 0xFF00 ) 1807 | 1808 | case TDDS_R8G8B8_UNORM: 1809 | TDDS_EF_RGB( 24,0x000000FF, 0x0000FF00, 0x00FF0000) 1810 | case TDDS_B8G8R8_UNORM: 1811 | TDDS_EF_RGB( 24,0x00FF0000, 0x0000FF00, 0x000000FF) 1812 | 1813 | case TDDS_R8G8B8A8_UNORM: 1814 | TDDS_EF_RGBA( 32,0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000) 1815 | case TDDS_R8G8B8X8_UNORM: 1816 | TDDS_EF_RGBA( 32,0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000) 1817 | case TDDS_B8G8R8A8_UNORM: 1818 | TDDS_EF_RGBA( 32,0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000) 1819 | case TDDS_B8G8R8X8_UNORM: 1820 | TDDS_EF_RGBA( 32,0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000) 1821 | case TDDS_A8B8G8R8_UNORM: 1822 | TDDS_EF_RGBA( 32,0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF) 1823 | case TDDS_X8B8G8R8_UNORM: 1824 | TDDS_EF_RGBA( 32,0xFF000000, 0x00FF0000, 0x0000FF00, 0x00000000) 1825 | case TDDS_A8R8G8B8_UNORM: 1826 | TDDS_EF_RGBA( 32,0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF) 1827 | case TDDS_X8R8G8B8_UNORM: 1828 | TDDS_EF_RGBA( 32,0x0000FF00, 0x00FF0000, 0xFF000000, 0x00000000) 1829 | 1830 | /* A2R10G10B10 is broken via the traditional DDS descriptions, so we 1831 | * always use the Dx10 header for those 1832 | case TDDS_R10G10B10A2_UNORM: 1833 | TDDS_EF_RGBA( 32,0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000) 1834 | case TDDS_A2B10G10R10_UNORM: 1835 | TDDS_EF_RGBA( 32,0xFFC00000, 0x003FF000, 0x00000FFC, 0x00000003) 1836 | case TDDS_A2R10G10B10_UNORM: 1837 | TDDS_EF_RGBA( 32,0x00000FFC, 0x003FF000, 0xFFC00000, 0x00000003) 1838 | case TDDS_B10G10R10A2_UNORM: 1839 | TDDS_EF_RGBA( 32,0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000) 1840 | */ 1841 | case TDDS_R10G10B10A2_UNORM: 1842 | case TDDS_B10G10R10A2_UNORM: 1843 | case TDDS_A2B10G10R10_UNORM: 1844 | case TDDS_A2R10G10B10_UNORM: 1845 | case TDDS_R10G10B10A2_SNORM: 1846 | case TDDS_B10G10R10A2_SNORM: 1847 | case TDDS_A2B10G10R10_SNORM: 1848 | case TDDS_A2R10G10B10_SNORM: 1849 | break; 1850 | 1851 | case TDDS_R16G16_UNORM: TDDS_EF_RGB( 32,0x0000FFFF, 0xFFFF0000, 0) 1852 | case TDDS_G16R16_UNORM: TDDS_EF_RGB( 32,0xFFFF0000, 0x0000FFFF, 0) 1853 | 1854 | case TDDS_BC1_RGBA_UNORM_BLOCK: 1855 | header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','T','1'); 1856 | header->formatFlags = TINYDDS_DDPF_FOURCC; 1857 | return true; 1858 | case TDDS_BC2_UNORM_BLOCK: 1859 | header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','T','3'); 1860 | header->formatFlags = TINYDDS_DDPF_FOURCC; 1861 | return true; 1862 | case TDDS_BC3_UNORM_BLOCK: 1863 | header->formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','T','5'); 1864 | header->formatFlags = TINYDDS_DDPF_FOURCC; 1865 | return true; 1866 | case TDDS_BC4_UNORM_BLOCK: 1867 | header->formatFourCC = TINYDDS_MAKE_RIFFCODE('A','T','I','1'); 1868 | header->formatFlags = TINYDDS_DDPF_FOURCC; 1869 | return true; 1870 | case TDDS_BC5_UNORM_BLOCK: 1871 | header->formatFourCC = TINYDDS_MAKE_RIFFCODE('A','T','I','2'); 1872 | header->formatFlags = TINYDDS_DDPF_FOURCC; 1873 | return true; 1874 | 1875 | 1876 | case TDDS_R8_SNORM: 1877 | case TDDS_R8G8_SNORM: 1878 | case TDDS_R8G8B8A8_SNORM: 1879 | case TDDS_R16_SNORM: 1880 | case TDDS_R16G16_SNORM: 1881 | case TDDS_A8B8G8R8_SNORM: 1882 | case TDDS_B8G8R8A8_SNORM: 1883 | case TDDS_G16R16_SNORM: 1884 | 1885 | case TDDS_R8_UINT: 1886 | case TDDS_R8_SINT: 1887 | case TDDS_R8G8_UINT: 1888 | case TDDS_R8G8_SINT: 1889 | case TDDS_R8G8B8A8_UINT: 1890 | case TDDS_R8G8B8A8_SINT: 1891 | case TDDS_R8G8B8A8_SRGB: 1892 | case TDDS_B8G8R8A8_SRGB: 1893 | case TDDS_R9G9B9E5_UFLOAT: 1894 | case TDDS_R10G10B10A2_UINT: 1895 | case TDDS_R11G11B10_UFLOAT: 1896 | case TDDS_R16_UINT: 1897 | case TDDS_R16_SINT: 1898 | case TDDS_R16_SFLOAT: 1899 | case TDDS_R16G16_UINT: 1900 | case TDDS_R16G16_SINT: 1901 | case TDDS_R16G16_SFLOAT: 1902 | case TDDS_R16G16B16A16_UNORM: 1903 | case TDDS_R16G16B16A16_SNORM: 1904 | case TDDS_R16G16B16A16_UINT: 1905 | case TDDS_R16G16B16A16_SINT: 1906 | case TDDS_R16G16B16A16_SFLOAT: 1907 | case TDDS_R32_UINT: 1908 | case TDDS_R32_SINT: 1909 | case TDDS_R32_SFLOAT: 1910 | case TDDS_R32G32_UINT: 1911 | case TDDS_R32G32_SINT: 1912 | case TDDS_R32G32_SFLOAT: 1913 | case TDDS_R32G32B32_UINT: 1914 | case TDDS_R32G32B32_SINT: 1915 | case TDDS_R32G32B32_SFLOAT: 1916 | case TDDS_R32G32B32A32_UINT: 1917 | case TDDS_R32G32B32A32_SINT: 1918 | case TDDS_R32G32B32A32_SFLOAT: 1919 | case TDDS_BC1_RGBA_SRGB_BLOCK: 1920 | case TDDS_BC2_SRGB_BLOCK: 1921 | case TDDS_BC3_SRGB_BLOCK: 1922 | case TDDS_BC4_SNORM_BLOCK: 1923 | case TDDS_BC5_SNORM_BLOCK: 1924 | case TDDS_BC6H_UFLOAT_BLOCK: 1925 | case TDDS_BC6H_SFLOAT_BLOCK: 1926 | case TDDS_BC7_UNORM_BLOCK: 1927 | case TDDS_BC7_SRGB_BLOCK: 1928 | case TDDS_AYUV: 1929 | case TDDS_Y410: 1930 | case TDDS_Y416: 1931 | case TDDS_NV12: 1932 | case TDDS_P010: 1933 | case TDDS_P016: 1934 | case TDDS_420_OPAQUE: 1935 | case TDDS_YUY2: 1936 | case TDDS_Y210: 1937 | case TDDS_Y216: 1938 | case TDDS_NV11: 1939 | case TDDS_AI44: 1940 | case TDDS_IA44: 1941 | case TDDS_P8: 1942 | case TDDS_A8P8: 1943 | case TDDS_R10G10B10_7E3_A2_FLOAT: 1944 | case TDDS_R10G10B10_6E4_A2_FLOAT: 1945 | case TDDS_D16_UNORM_S8_UINT: 1946 | case TDDS_R16_UNORM_X8_TYPELESS: 1947 | case TDDS_X16_TYPELESS_G8_UINT: 1948 | case TDDS_P208: 1949 | case TDDS_V208: 1950 | case TDDS_V408: 1951 | case TDDS_R10G10B10_SNORM_A2_UNORM: 1952 | break; 1953 | 1954 | } 1955 | // these formats can probably be done via dx10 header so check 1956 | if(headerDx10->DXGIFormat == TIF_DXGI_FORMAT_UNKNOWN) return false; 1957 | else return true; 1958 | } 1959 | 1960 | #undef TDDS_EF 1961 | #undef TDDS_EF_RGB 1962 | #undef TDDS_EF_RGBA 1963 | #undef TDDS_EF_ALPHA 1964 | 1965 | bool TinyDDS_WriteImage(TinyDDS_WriteCallbacks const *callbacks, 1966 | void *user, 1967 | uint32_t width, 1968 | uint32_t height, 1969 | uint32_t depth, 1970 | uint32_t slices, 1971 | uint32_t mipmaplevels, 1972 | TinyDDS_Format format, 1973 | bool cubemap, 1974 | bool preferDx10Format, 1975 | uint32_t const *mipmapsizes, 1976 | void const **mipmaps) { 1977 | TinyDDS_Header header; 1978 | TinyDDS_HeaderDX10 headerDX10; 1979 | memset(&header, 0, sizeof(header)); 1980 | memset(&headerDX10, 0, sizeof(headerDX10)); 1981 | 1982 | header.magic = TINYDDS_MAKE_RIFFCODE('D', 'D', 'S', ' '); 1983 | header.size = 124; 1984 | header.formatSize = 32; 1985 | 1986 | header.width = width; 1987 | header.height = height; 1988 | header.depth = (depth > 1) ? depth : 0; 1989 | header.mipMapCount = mipmaplevels; 1990 | 1991 | if(!TinyDDS_EncodeFormat(format, &header, &headerDX10)) return false; 1992 | 1993 | // do we have to force dx10 (for slices) 1994 | if (slices > 1) { 1995 | if(headerDX10.DXGIFormat == TIF_DXGI_FORMAT_UNKNOWN) { 1996 | // DDS doesn't support slices for formats that aren't DXGI compatible 1997 | return false; 1998 | } 1999 | header.formatFlags = TINYDDS_DDPF_FOURCC; 2000 | header.formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','1','0'); 2001 | headerDX10.arraySize = slices; 2002 | } 2003 | header.flags = TINYDDS_DDSD_CAPS | TINYDDS_DDSD_PIXELFORMAT | TINYDDS_DDSD_MIPMAPCOUNT; 2004 | header.caps1 = TINYDDS_DDSCAPS_TEXTURE | TINYDDS_DDSCAPS_COMPLEX | TINYDDS_DDSCAPS_MIPMAP; 2005 | 2006 | if(depth > 1) { 2007 | headerDX10.resourceDimension = TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE3D; 2008 | header.flags |= TINYDDS_DDSD_DEPTH; 2009 | header.caps2 |= TINYDDS_DDSCAPS2_VOLUME; 2010 | } 2011 | else if(height > 1) { 2012 | headerDX10.resourceDimension = TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE2D; 2013 | header.flags |= TINYDDS_DDSD_HEIGHT; 2014 | } 2015 | else if(width > 1) { 2016 | headerDX10.resourceDimension = TINYDDS_D3D10_RESOURCE_DIMENSION_TEXTURE1D; 2017 | header.flags |= TINYDDS_DDSD_WIDTH; 2018 | } 2019 | if(cubemap) { 2020 | headerDX10.miscFlag |= TINYDDS_D3D10_RESOURCE_MISC_TEXTURECUBE; 2021 | header.caps2 |= TINYDDS_DDSCAPS2_CUBEMAP | TINYDDS_DDSCAPS2_CUBEMAP_ALL; 2022 | } 2023 | 2024 | // unclear whether we need to save this or exactly what it should be... 2025 | header.pitchOrLinearSize = 0; 2026 | if(preferDx10Format && headerDX10.DXGIFormat != TIF_DXGI_FORMAT_UNKNOWN) { 2027 | header.formatFlags = TINYDDS_DDPF_FOURCC; 2028 | header.formatFourCC = TINYDDS_MAKE_RIFFCODE('D','X','1','0'); 2029 | } 2030 | 2031 | // now write 2032 | callbacks->write(user, &header, sizeof(TinyDDS_Header)); 2033 | if(header.formatFlags & TINYDDS_DDPF_FOURCC && 2034 | header.formatFourCC == TINYDDS_MAKE_RIFFCODE('D','X','1','0')) { 2035 | callbacks->write(user, &headerDX10, sizeof(TinyDDS_HeaderDX10)); 2036 | } 2037 | 2038 | for (uint32_t mipMapLevel = 0; mipMapLevel < header.mipMapCount; mipMapLevel++) { 2039 | callbacks->write(user, mipmaps[mipMapLevel], mipmapsizes[mipMapLevel]); 2040 | } 2041 | return true; 2042 | } 2043 | 2044 | #endif 2045 | 2046 | #ifdef __cplusplus 2047 | }; 2048 | #endif 2049 | 2050 | #endif // end header 2051 | /* 2052 | MIT License 2053 | 2054 | Copyright (c) 2019 DeanoC 2055 | 2056 | Permission is hereby granted, free of charge, to any person obtaining a copy 2057 | of this software and associated documentation files (the "Software"), to deal 2058 | in the Software without restriction, including without limitation the rights 2059 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2060 | copies of the Software, and to permit persons to whom the Software is 2061 | furnished to do so, subject to the following conditions: 2062 | 2063 | The above copyright notice and this permission notice shall be included in all 2064 | copies or substantial portions of the Software. 2065 | 2066 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2067 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2068 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2069 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2070 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2071 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2072 | SOFTWARE. 2073 | */ 2074 | -------------------------------------------------------------------------------- /src/tinydds.c: -------------------------------------------------------------------------------- 1 | #define TINYDDS_IMPLEMENTATION 2 | #include "tiny_dds/tinydds.h" 3 | -------------------------------------------------------------------------------- /tests/runner.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_RUNNER 2 | #include "al2o3_catch2/catch2.hpp" 3 | #include "utils_simple_logmanager/logmanager.h" 4 | 5 | int main(int argc, char const *argv[]) { 6 | auto logger = SimpleLogManager_Alloc(); 7 | 8 | auto ret = Catch::Session().run(argc, (char **) argv); 9 | 10 | SimpleLogManager_Free(logger); 11 | 12 | return ret; 13 | } 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------