├── LICENSE ├── README.md ├── dds.c └── dds.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 dfranx 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 | # DDS 2 | This is a simple library for loading `.dds` textures. It supports DXT1, DXT3 & DXT5 compressed formats and most of the uncompressed formats. It loads the data into a RGBA byte array. 3 | It supports 3D textures. 4 | 5 | Example: 6 | ```c 7 | dds_image_t image = dds_load_from_file("texture.dds"); 8 | 9 | // use image->pixels, image->header.width, image->header.width, image->header.depth 10 | 11 | dds_image_free(image); 12 | 13 | ``` -------------------------------------------------------------------------------- /dds.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define FOURCC(str) (dds_uint)(((str)[3] << 24U) | ((str)[2] << 16U) | ((str)[1] << 8U) | (str)[0]) 8 | #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) 9 | #define IMAGE_PITCH(width, block_size) MAX(1, ((width + 3) / 4)) * block_size 10 | 11 | dds_uint dds_calculate_left_shift(dds_uint* right_shift, dds_uint bit_count) 12 | { 13 | if (bit_count >= 8) { 14 | right_shift = right_shift + (bit_count - 8); 15 | return 0; 16 | } 17 | return 8 - bit_count; 18 | } 19 | 20 | void dds_parse_uncompressed(dds_image_t image, const char* data, long data_length) 21 | { 22 | dds_uint img_width = MAX(1, image->header.width); 23 | dds_uint img_height = MAX(1, image->header.height); 24 | dds_uint img_depth = MAX(1, image->header.depth); 25 | 26 | // will this even work? have I envisioned this solution correctly? 27 | dds_uint r_right_shift = 0xFFFFFFFF, g_right_shift = 0xFFFFFFFF, b_right_shift = 0xFFFFFFFF, a_right_shift = 0xFFFFFFFF; 28 | dds_uint r_left_shift = 0, g_left_shift = 0, b_left_shift = 0, a_left_shift = 0; 29 | for (dds_byte i = 0; i < 32; i++) { 30 | if ((image->header.pixel_format.r_bit_mask) >> i & 1) { 31 | if (r_right_shift == 0xFFFFFFFF) 32 | r_right_shift = i; 33 | r_left_shift++; 34 | } 35 | if ((image->header.pixel_format.g_bit_mask) >> i & 1) { 36 | if (g_right_shift == 0xFFFFFFFF) 37 | g_right_shift = i; 38 | g_left_shift++; 39 | } 40 | if ((image->header.pixel_format.b_bit_mask) >> i & 1) { 41 | if (b_right_shift == 0xFFFFFFFF) 42 | b_right_shift = i; 43 | b_left_shift++; 44 | } 45 | if ((image->header.pixel_format.a_bit_mask) >> i & 1) { 46 | if (a_right_shift == 0xFFFFFFFF) 47 | a_right_shift = i; 48 | a_left_shift++; 49 | } 50 | } 51 | 52 | // to avoid undefined behavior: 53 | if (r_right_shift == 0xFFFFFFFF) r_right_shift = 0; 54 | if (g_right_shift == 0xFFFFFFFF) g_right_shift = 0; 55 | if (b_right_shift == 0xFFFFFFFF) b_right_shift = 0; 56 | if (a_right_shift == 0xFFFFFFFF) a_right_shift = 0; 57 | 58 | // fix left/right shift based on the bit count (currently stored in X_left_shift) 59 | r_left_shift = dds_calculate_left_shift(&r_right_shift, r_left_shift); 60 | g_left_shift = dds_calculate_left_shift(&g_right_shift, g_left_shift); 61 | b_left_shift = dds_calculate_left_shift(&b_right_shift, b_left_shift); 62 | a_left_shift = dds_calculate_left_shift(&a_right_shift, a_left_shift); 63 | 64 | dds_byte bytes_per_pixel = image->header.pixel_format.rgb_bit_count / 8; 65 | 66 | data += 128; // skip the header 67 | 68 | // read the actual data 69 | for (dds_uint z = 0; z < img_depth; z++) 70 | for (dds_uint x = 0; x < img_width; x++) 71 | for (dds_uint y = 0; y < img_height; y++) { 72 | dds_uint px_index = (z * img_width * img_height + y * img_width + x) * bytes_per_pixel; 73 | dds_uint data_index = (z * img_width * img_height + (img_height-y-1) * img_width + x) * 4; 74 | 75 | // get the data into uint 76 | dds_uint px = 0; 77 | memcpy(&px, data + px_index, bytes_per_pixel); 78 | 79 | // decode 80 | image->pixels[data_index + 0] = ((px & image->header.pixel_format.r_bit_mask) >> r_right_shift) << r_left_shift; 81 | image->pixels[data_index + 1] = ((px & image->header.pixel_format.g_bit_mask) >> g_right_shift) << g_left_shift; 82 | image->pixels[data_index + 2] = ((px & image->header.pixel_format.b_bit_mask) >> b_right_shift) << b_left_shift; 83 | if (image->header.pixel_format.a_bit_mask == 0) 84 | image->pixels[data_index + 3] = 0xFF; 85 | else 86 | image->pixels[data_index + 3] = ((px & image->header.pixel_format.a_bit_mask) >> a_right_shift) << a_left_shift; 87 | } 88 | } 89 | void dds_parse_dxt1(dds_image_t image, const char* data, long data_length) 90 | { 91 | dds_uint img_width = MAX(1, image->header.width); 92 | dds_uint img_height = MAX(1, image->header.height); 93 | dds_uint img_depth = MAX(1, image->header.depth); 94 | 95 | dds_uint blocks_x = MAX(1, img_width / 4); 96 | dds_uint blocks_y = MAX(1, img_height / 4); 97 | 98 | for (dds_uint z = 0; z < img_depth; z++) { 99 | for (dds_uint x = 0; x < blocks_x; x++) 100 | for (dds_uint y = 0; y < blocks_y; y++) { 101 | unsigned short color0 = 0, color1 = 0; 102 | dds_uint codes = 0; 103 | 104 | // read the block data 105 | dds_uint block_offset = (y * blocks_x + x) * 8; // * 8 == * 64bits cuz blocks are 64 bits (2x shorts, 1x uint) 106 | memcpy(&color0, data + block_offset + 0, 2); 107 | memcpy(&color1, data + block_offset + 2, 2); 108 | memcpy(&codes, data + block_offset + 4, 4); 109 | 110 | // unpack the color data 111 | dds_byte r0 = (color0 & 0b1111100000000000) >> 8; 112 | dds_byte g0 = (color0 & 0b0000011111100000) >> 3; 113 | dds_byte b0 = (color0 & 0b0000000000011111) << 3; 114 | dds_byte r1 = (color1 & 0b1111100000000000) >> 8; 115 | dds_byte g1 = (color1 & 0b0000011111100000) >> 3; 116 | dds_byte b1 = (color1 & 0b0000000000011111) << 3; 117 | 118 | // process the data 119 | for (dds_uint b = 0; b < 16; b++) { 120 | dds_uint px_index = ((z * 4) * img_height * img_width + (img_height - ((y * 4) + b / 4) - 1) * img_width + x * 4 + b % 4) * 4; 121 | 122 | dds_byte code = (codes >> (2 * b)) & 3; 123 | image->pixels[px_index + 3] = 0xFF; 124 | if (code == 0) { 125 | // color0 126 | image->pixels[px_index + 0] = r0; 127 | image->pixels[px_index + 1] = g0; 128 | image->pixels[px_index + 2] = b0; 129 | } else if (code == 1) { 130 | // color1 131 | image->pixels[px_index + 0] = r1; 132 | image->pixels[px_index + 1] = g1; 133 | image->pixels[px_index + 2] = b1; 134 | } else if (code == 2) { 135 | // (2*color0 + color1) / 3 136 | if (color0 > color1) { 137 | image->pixels[px_index + 0] = (2 * r0 + r1) / 3; 138 | image->pixels[px_index + 1] = (2 * g0 + g1) / 3; 139 | image->pixels[px_index + 2] = (2 * b0 + b1) / 3; 140 | } 141 | // (color0 + color1) / 2 142 | else { 143 | image->pixels[px_index + 0] = (r0 + r1) / 2; 144 | image->pixels[px_index + 1] = (g0 + g1) / 2; 145 | image->pixels[px_index + 2] = (b0 + b1) / 2; 146 | } 147 | } else if (code == 3) { 148 | // (color0 + 2*color1) / 3 149 | if (color0 > color1) { 150 | image->pixels[px_index + 0] = (r0 + 2 * r1) / 3; 151 | image->pixels[px_index + 1] = (g0 + 2 * g1) / 3; 152 | image->pixels[px_index + 2] = (b0 + 2 * b1) / 3; 153 | } 154 | // black 155 | else { 156 | image->pixels[px_index + 0] = 0x00; 157 | image->pixels[px_index + 1] = 0x00; 158 | image->pixels[px_index + 2] = 0x00; 159 | } 160 | } 161 | } 162 | } 163 | 164 | // skip this slice 165 | data += blocks_x * blocks_y * 16; 166 | } 167 | } 168 | void dds_parse_dxt3(dds_image_t image, const char* data, long data_length) 169 | { 170 | dds_uint img_width = MAX(1, image->header.width); 171 | dds_uint img_height = MAX(1, image->header.height); 172 | dds_uint img_depth = MAX(1, image->header.depth); 173 | 174 | dds_uint blocks_x = MAX(1, img_width / 4); 175 | dds_uint blocks_y = MAX(1, img_height / 4); 176 | 177 | for (dds_uint z = 0; z < img_depth; z++) { 178 | for (dds_uint x = 0; x < blocks_x; x++) 179 | for (dds_uint y = 0; y < blocks_y; y++) { 180 | unsigned short color0 = 0, color1 = 0; 181 | dds_uint codes = 0; 182 | unsigned long long alpha_data = 0; 183 | 184 | // read the block data 185 | dds_uint block_offset = (y * blocks_x + x) * 16; // 16 == 128bits 186 | memcpy(&alpha_data, data + block_offset, 8); 187 | memcpy(&color0, data + block_offset + 8, 2); 188 | memcpy(&color1, data + block_offset + 10, 2); 189 | memcpy(&codes, data + block_offset + 12, 4); 190 | 191 | // unpack the color data 192 | dds_byte r0 = (color0 & 0b1111100000000000) >> 8; 193 | dds_byte g0 = (color0 & 0b0000011111100000) >> 3; 194 | dds_byte b0 = (color0 & 0b0000000000011111) << 3; 195 | dds_byte r1 = (color1 & 0b1111100000000000) >> 8; 196 | dds_byte g1 = (color1 & 0b0000011111100000) >> 3; 197 | dds_byte b1 = (color1 & 0b0000000000011111) << 3; 198 | 199 | // process the data 200 | for (dds_uint b = 0; b < 16; b++) { 201 | dds_uint px_index = ((z * 4) * img_height * img_width + (img_height - ((y * 4) + b / 4) - 1) * img_width + x * 4 + b % 4) * 4; 202 | dds_byte code = (codes >> (2 * b)) & 0b0011; 203 | 204 | dds_byte alpha = (alpha_data >> (4 * b)) & 0b1111; 205 | image->pixels[px_index + 3] = alpha; 206 | 207 | // color0 208 | if (code == 0) { 209 | image->pixels[px_index + 0] = r0; 210 | image->pixels[px_index + 1] = g0; 211 | image->pixels[px_index + 2] = b0; 212 | } 213 | // color1 214 | else if (code == 1) { 215 | image->pixels[px_index + 0] = r1; 216 | image->pixels[px_index + 1] = g1; 217 | image->pixels[px_index + 2] = b1; 218 | } 219 | // (2*color0 + color1) / 3 220 | else if (code == 2) { 221 | image->pixels[px_index + 0] = (2 * r0 + r1) / 3; 222 | image->pixels[px_index + 1] = (2 * g0 + g1) / 3; 223 | image->pixels[px_index + 2] = (2 * b0 + b1) / 3; 224 | } 225 | // (color0 + 2*color1) / 3 226 | else if (code == 3) { 227 | image->pixels[px_index + 0] = (r0 + 2 * r1) / 3; 228 | image->pixels[px_index + 1] = (g0 + 2 * g1) / 3; 229 | image->pixels[px_index + 2] = (b0 + 2 * b1) / 3; 230 | } 231 | } 232 | } 233 | 234 | // skip this slice 235 | data += blocks_x * blocks_y * 16; 236 | } 237 | } 238 | void dds_parse_dxt5(dds_image_t image, const char* data, long data_length) 239 | { 240 | 241 | dds_uint img_width = MAX(1, image->header.width); 242 | dds_uint img_height = MAX(1, image->header.height); 243 | dds_uint img_depth = MAX(1, image->header.depth); 244 | 245 | dds_uint blocks_x = MAX(1, img_width / 4); 246 | dds_uint blocks_y = MAX(1, img_height / 4); 247 | 248 | for (dds_uint z = 0; z < img_depth; z++) { 249 | for (dds_uint x = 0; x < blocks_x; x++) 250 | for (dds_uint y = 0; y < blocks_y; y++) { 251 | unsigned short color0 = 0, color1 = 0; 252 | dds_uint codes = 0; 253 | unsigned long long alpha_codes = 0; 254 | dds_byte alpha0 = 0, alpha1 = 0; 255 | 256 | // read the block data 257 | dds_uint block_offset = (y * blocks_x + x) * 16; // 16 == 128bits 258 | alpha0 = data[block_offset + 0]; 259 | alpha1 = data[block_offset + 1]; 260 | memcpy(&alpha_codes, data + block_offset + 2, 6); 261 | memcpy(&color0, data + block_offset + 8, 2); 262 | memcpy(&color1, data + block_offset + 10, 2); 263 | memcpy(&codes, data + block_offset + 12, 4); 264 | 265 | // unpack the color data 266 | dds_byte r0 = (color0 & 0b1111100000000000) >> 8; 267 | dds_byte g0 = (color0 & 0b0000011111100000) >> 3; 268 | dds_byte b0 = (color0 & 0b0000000000011111) << 3; 269 | dds_byte r1 = (color1 & 0b1111100000000000) >> 8; 270 | dds_byte g1 = (color1 & 0b0000011111100000) >> 3; 271 | dds_byte b1 = (color1 & 0b0000000000011111) << 3; 272 | 273 | // process the data 274 | for (dds_uint b = 0; b < 16; b++) { 275 | dds_uint px_index = (z * img_height * img_width + (img_height - ((y * 4) + b / 4) - 1) * img_width + x * 4 + b % 4) * 4; 276 | dds_byte code = (codes >> (2 * b)) & 0b0011; 277 | dds_byte alpha_code = (alpha_codes >> (3 * b)) & 0b0111; 278 | 279 | /* COLOR */ 280 | // color0 281 | if (code == 0) { 282 | image->pixels[px_index + 0] = r0; 283 | image->pixels[px_index + 1] = g0; 284 | image->pixels[px_index + 2] = b0; 285 | } 286 | // color1 287 | else if (code == 1) { 288 | image->pixels[px_index + 0] = r1; 289 | image->pixels[px_index + 1] = g1; 290 | image->pixels[px_index + 2] = b1; 291 | } 292 | // (2*color0 + color1) / 3 293 | else if (code == 2) { 294 | image->pixels[px_index + 0] = (2 * r0 + r1) / 3; 295 | image->pixels[px_index + 1] = (2 * g0 + g1) / 3; 296 | image->pixels[px_index + 2] = (2 * b0 + b1) / 3; 297 | } 298 | // (color0 + 2*color1) / 3 299 | else if (code == 3) { 300 | image->pixels[px_index + 0] = (r0 + 2 * r1) / 3; 301 | image->pixels[px_index + 1] = (g0 + 2 * g1) / 3; 302 | image->pixels[px_index + 2] = (b0 + 2 * b1) / 3; 303 | } 304 | 305 | /* ALPHA */ 306 | dds_byte alpha = 0xFF; 307 | if (code == 0) 308 | alpha = alpha0; 309 | else if (code == 1) 310 | alpha = alpha1; 311 | else { 312 | if (alpha0 > alpha1) 313 | alpha = ((8 - alpha_code) * alpha0 + (alpha_code - 1) * alpha1) / 7; 314 | else { 315 | if (alpha_code == 6) 316 | alpha = 0; 317 | else if (alpha_code == 7) 318 | alpha = 255; 319 | else 320 | alpha = ((6 - alpha_code) * alpha0 + (alpha_code - 1) * alpha1) / 5; 321 | } 322 | } 323 | image->pixels[px_index + 3] = alpha; 324 | } 325 | } 326 | 327 | // skip this slice 328 | data += blocks_x * blocks_y * 16; 329 | } 330 | } 331 | 332 | dds_image_t dds_load_from_memory(const char* data, long data_length) 333 | { 334 | const char* data_loc = data; 335 | 336 | dds_uint magic = 0x00; 337 | memcpy(&magic, data_loc, sizeof(magic)); 338 | data_loc += 4; 339 | 340 | if (magic != 0x20534444) // 'DDS ' 341 | return NULL; 342 | 343 | dds_image_t ret = (dds_image_t)malloc(sizeof(struct dds_image)); 344 | 345 | 346 | // read the header 347 | memcpy(&ret->header, data_loc, sizeof(struct dds_header)); 348 | data_loc += sizeof(struct dds_header); 349 | 350 | // check if the dds_header::dwSize (must be equal to 124) 351 | if (ret->header.size != 124) { 352 | dds_image_free(ret); 353 | return NULL; 354 | } 355 | 356 | // check the dds_header::flags (DDSD_CAPS, DDSD_HEIGHT, DDSD_WIDTH, DDSD_PIXELFORMAT must be set) 357 | if (!((ret->header.flags & DDSD_CAPS) && (ret->header.flags & DDSD_HEIGHT) && (ret->header.flags & DDSD_WIDTH) && (ret->header.flags & DDSD_PIXELFORMAT))) { 358 | dds_image_free(ret); 359 | return NULL; 360 | } 361 | 362 | // check the dds_header::caps 363 | if ((ret->header.caps & DDSCAPS_TEXTURE) == 0) { 364 | dds_image_free(ret); 365 | return NULL; 366 | } 367 | 368 | // check if we need to load dds_header_dxt10 369 | if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("DX10")) { 370 | // read the header10 371 | memcpy(&ret->header10, data_loc, sizeof(struct dds_header_dxt10)); 372 | data_loc += sizeof(struct dds_header_dxt10); 373 | } 374 | 375 | // allocate pixel data 376 | dds_uint img_width = MAX(1, ret->header.width); 377 | dds_uint img_height = MAX(1, ret->header.height); 378 | dds_uint img_depth = MAX(1, ret->header.depth); 379 | ret->pixels = (dds_byte*)malloc(img_width * img_height * img_depth * 4); 380 | 381 | // parse/decompress the pixel data 382 | if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("DXT1")) 383 | dds_parse_dxt1(ret, data_loc, data_length - (data_loc - data)); 384 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("DXT2")) 385 | dds_parse_dxt3(ret, data_loc, data_length - (data_loc - data)); 386 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("DXT3")) 387 | dds_parse_dxt3(ret, data_loc, data_length - (data_loc - data)); 388 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("DXT4")) 389 | dds_parse_dxt5(ret, data_loc, data_length - (data_loc - data)); 390 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("DXT5")) 391 | dds_parse_dxt5(ret, data_loc, data_length - (data_loc - data)); 392 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("DX10")) { 393 | // dds_parse_dxt10 394 | } 395 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("ATI1")) { 396 | // dds_parse_ati1 397 | } 398 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("ATI2")) { 399 | // dds_parse_ati2 400 | } 401 | else if ((ret->header.pixel_format.flags & DDPF_FOURCC) && ret->header.pixel_format.four_cc == FOURCC("A2XY")) { 402 | // dds_parse_a2xy 403 | } 404 | else 405 | dds_parse_uncompressed(ret, data, data_length - (data_loc - data)); 406 | 407 | return ret; 408 | } 409 | dds_image_t dds_load_from_file(const char* filename) 410 | { 411 | // open the file 412 | FILE* f = fopen(filename, "rb"); 413 | if (f == NULL) 414 | return NULL; 415 | 416 | // get file size 417 | fseek(f, 0, SEEK_END); 418 | long file_size = ftell(f); 419 | fseek(f, 0, SEEK_SET); 420 | 421 | if (file_size < 128) { 422 | fclose(f); 423 | return NULL; 424 | } 425 | 426 | // read the whole file 427 | char* dds_data = (char*)malloc(file_size); 428 | fread(dds_data, 1, file_size, f); 429 | 430 | // parse the data 431 | dds_image_t ret = dds_load_from_memory(dds_data, file_size); 432 | 433 | // clean up 434 | free(dds_data); 435 | fclose(f); 436 | 437 | return ret; 438 | } 439 | 440 | void dds_image_free(dds_image_t image) 441 | { 442 | free(image->pixels); 443 | free(image); 444 | } 445 | -------------------------------------------------------------------------------- /dds.h: -------------------------------------------------------------------------------- 1 | #ifndef __DFRANX_DDS_H__ 2 | #define __DFRANX_DDS_H__ 3 | 4 | typedef unsigned int dds_uint; 5 | typedef unsigned char dds_byte; 6 | 7 | // dds_header::flags 8 | enum { 9 | DDSD_CAPS = 0x1, 10 | DDSD_HEIGHT = 0x2, 11 | DDSD_WIDTH = 0x4, 12 | DDSD_PITCH = 0x8, 13 | DDSD_PIXELFORMAT = 0x1000, 14 | DDSD_MIPMAPCOUNT = 0x20000, 15 | DDSD_LINEARSIZE = 0x80000, 16 | DDSD_DEPTH = 0x800000 17 | }; 18 | 19 | // dds_header::caps 20 | enum { 21 | DDSCAPS_COMPLEX = 0x8, 22 | DDSCAPS_MIPMAP = 0x400000, 23 | DDSCAPS_TEXTURE = 0x1000 24 | }; 25 | 26 | // dds_header::caps2 27 | enum { 28 | DDSCAPS2_CUBEMAP = 0x200, 29 | DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, 30 | DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, 31 | DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, 32 | DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, 33 | DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, 34 | DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, 35 | DDSCAPS2_VOLUME = 0x200000 36 | }; 37 | 38 | // dds_pixelformat::flags 39 | enum { 40 | DDPF_ALPHAPIXELS = 0x1, 41 | DDPF_ALPHA = 0x2, 42 | DDPF_FOURCC = 0x4, 43 | DDPF_RGB = 0x40, 44 | DDPF_YUV = 0x200, 45 | DDPF_LUMINANCE = 0x20000 46 | }; 47 | 48 | struct dds_pixelformat { 49 | dds_uint size; 50 | dds_uint flags; 51 | dds_uint four_cc; 52 | dds_uint rgb_bit_count; 53 | dds_uint r_bit_mask; 54 | dds_uint g_bit_mask; 55 | dds_uint b_bit_mask; 56 | dds_uint a_bit_mask; 57 | }; 58 | 59 | struct dds_header { 60 | dds_uint size; 61 | dds_uint flags; 62 | dds_uint height; 63 | dds_uint width; 64 | dds_uint pitch_linear_size; 65 | dds_uint depth; 66 | dds_uint mipmap_count; 67 | dds_uint reserved1[11]; 68 | struct dds_pixelformat pixel_format; 69 | dds_uint caps; 70 | dds_uint caps2; 71 | dds_uint caps3; 72 | dds_uint caps4; 73 | dds_uint reserved2; 74 | }; 75 | 76 | struct dds_header_dxt10 77 | { 78 | dds_uint dxgi_format; 79 | dds_uint resource_dimension; 80 | dds_uint misc_flag; 81 | dds_uint array_size; 82 | dds_uint misc_flags2; 83 | }; 84 | 85 | struct dds_image { 86 | struct dds_header header; 87 | struct dds_header_dxt10 header10; 88 | 89 | dds_byte* pixels; // always RGBA; currently no support for mipmaps 90 | }; 91 | typedef struct dds_image* dds_image_t; 92 | 93 | dds_image_t dds_load_from_memory(const char* data, long data_length); 94 | dds_image_t dds_load_from_file(const char* filename); 95 | void dds_image_free(dds_image_t image); 96 | 97 | #endif // __DFRANX_DDS_H__ --------------------------------------------------------------------------------