| 1 | |
| 2 | /// DDS file support, does decoding, _not_ direct uploading |
| 3 | /// (use SOIL for that ;-) |
| 4 | |
| 5 | /// A bunch of DirectDraw Surface structures and flags |
| 6 | typedef struct { |
| 7 | unsigned int dwMagic; |
| 8 | unsigned int dwSize; |
| 9 | unsigned int dwFlags; |
| 10 | unsigned int dwHeight; |
| 11 | unsigned int dwWidth; |
| 12 | unsigned int dwPitchOrLinearSize; |
| 13 | unsigned int dwDepth; |
| 14 | unsigned int dwMipMapCount; |
| 15 | unsigned int dwReserved1[ 11 ]; |
| 16 | |
| 17 | // DDPIXELFORMAT |
| 18 | struct { |
| 19 | unsigned int dwSize; |
| 20 | unsigned int dwFlags; |
| 21 | unsigned int dwFourCC; |
| 22 | unsigned int dwRGBBitCount; |
| 23 | unsigned int dwRBitMask; |
| 24 | unsigned int dwGBitMask; |
| 25 | unsigned int dwBBitMask; |
| 26 | unsigned int dwAlphaBitMask; |
| 27 | } sPixelFormat; |
| 28 | |
| 29 | // DDCAPS2 |
| 30 | struct { |
| 31 | unsigned int dwCaps1; |
| 32 | unsigned int dwCaps2; |
| 33 | unsigned int dwDDSX; |
| 34 | unsigned int dwReserved; |
| 35 | } sCaps; |
| 36 | unsigned int dwReserved2; |
| 37 | } ; |
| 38 | |
| 39 | // the following constants were copied directly off the MSDN website |
| 40 | |
| 41 | // The dwFlags member of the original DDSURFACEDESC2 structure |
| 42 | // can be set to one or more of the following values. |
| 43 | #define DDSD_CAPS 0x00000001 |
| 44 | #define DDSD_HEIGHT 0x00000002 |
| 45 | #define DDSD_WIDTH 0x00000004 |
| 46 | #define DDSD_PITCH 0x00000008 |
| 47 | #define DDSD_PIXELFORMAT 0x00001000 |
| 48 | #define DDSD_MIPMAPCOUNT 0x00020000 |
| 49 | #define DDSD_LINEARSIZE 0x00080000 |
| 50 | #define DDSD_DEPTH 0x00800000 |
| 51 | |
| 52 | // DirectDraw Pixel Format |
| 53 | #define DDPF_ALPHAPIXELS 0x00000001 |
| 54 | #define DDPF_FOURCC 0x00000004 |
| 55 | #define DDPF_RGB 0x00000040 |
| 56 | |
| 57 | // The dwCaps1 member of the DDSCAPS2 structure can be |
| 58 | // set to one or more of the following values. |
| 59 | #define DDSCAPS_COMPLEX 0x00000008 |
| 60 | #define DDSCAPS_TEXTURE 0x00001000 |
| 61 | #define DDSCAPS_MIPMAP 0x00400000 |
| 62 | |
| 63 | // The dwCaps2 member of the DDSCAPS2 structure can be |
| 64 | // set to one or more of the following values. |
| 65 | #define DDSCAPS2_CUBEMAP 0x00000200 |
| 66 | #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 |
| 67 | #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 |
| 68 | #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 |
| 69 | #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 |
| 70 | #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 |
| 71 | #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 |
| 72 | #define DDSCAPS2_VOLUME 0x00200000 |
| 73 | |
| 74 | static int dds_test(stbi *s) |
| 75 | { |
| 76 | // check the magic number |
| 77 | if (get8(s) != 'D') return 0; |
| 78 | if (get8(s) != 'D') return 0; |
| 79 | if (get8(s) != 'S') return 0; |
| 80 | if (get8(s) != ' ') return 0; |
| 81 | // check header size |
| 82 | if (get32le(s) != 124) return 0; |
| 83 | return 1; |
| 84 | } |
| 85 | #ifndef STBI_NO_STDIO |
| 86 | int stbi_dds_test_file (FILE *f) |
| 87 | { |
| 88 | stbi s; |
| 89 | int r,n = ftell(f); |
| 90 | start_file(&s,f); |
| 91 | r = dds_test(&s); |
| 92 | fseek(f,n,SEEK_SET); |
| 93 | return r; |
| 94 | } |
| 95 | #endif |
| 96 | |
| 97 | int stbi_dds_test_memory (stbi_uc const *buffer, int len) |
| 98 | { |
| 99 | stbi s; |
| 100 | start_mem(&s,buffer, len); |
| 101 | return dds_test(&s); |
| 102 | } |
| 103 | |
| 104 | // helper functions |
| 105 | int stbi_convert_bit_range( int c, int from_bits, int to_bits ) |
| 106 | { |
| 107 | int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); |
| 108 | return (b + (b >> from_bits)) >> from_bits; |
| 109 | } |
| 110 | void stbi_rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) |
| 111 | { |
| 112 | *r = stbi_convert_bit_range( (c >> 11) & 31, 5, 8 ); |
| 113 | *g = stbi_convert_bit_range( (c >> 05) & 63, 6, 8 ); |
| 114 | *b = stbi_convert_bit_range( (c >> 00) & 31, 5, 8 ); |
| 115 | } |
| 116 | void stbi_decode_DXT1_block( |
| 117 | unsigned char uncompressed[16*4], |
| 118 | unsigned char compressed[8] ) |
| 119 | { |
| 120 | int next_bit = 4*8; |
| 121 | int i, r, g, b; |
| 122 | int c0, c1; |
| 123 | unsigned char decode_colors[4*4]; |
| 124 | // find the 2 primary colors |
| 125 | c0 = compressed[0] + (compressed[1] << 8); |
| 126 | c1 = compressed[2] + (compressed[3] << 8); |
| 127 | stbi_rgb_888_from_565( c0, &r, &g, &b ); |
| 128 | decode_colors[0] = r; |
| 129 | decode_colors[1] = g; |
| 130 | decode_colors[2] = b; |
| 131 | decode_colors[3] = 255; |
| 132 | stbi_rgb_888_from_565( c1, &r, &g, &b ); |
| 133 | decode_colors[4] = r; |
| 134 | decode_colors[5] = g; |
| 135 | decode_colors[6] = b; |
| 136 | decode_colors[7] = 255; |
| 137 | if( c0 > c1 ) |
| 138 | { |
| 139 | // no alpha, 2 interpolated colors |
| 140 | decode_colors[8] = (2*decode_colors[0] + decode_colors[4]) / 3; |
| 141 | decode_colors[9] = (2*decode_colors[1] + decode_colors[5]) / 3; |
| 142 | decode_colors[10] = (2*decode_colors[2] + decode_colors[6]) / 3; |
| 143 | decode_colors[11] = 255; |
| 144 | decode_colors[12] = (decode_colors[0] + 2*decode_colors[4]) / 3; |
| 145 | decode_colors[13] = (decode_colors[1] + 2*decode_colors[5]) / 3; |
| 146 | decode_colors[14] = (decode_colors[2] + 2*decode_colors[6]) / 3; |
| 147 | decode_colors[15] = 255; |
| 148 | } else |
| 149 | { |
| 150 | // 1 interpolated color, alpha |
| 151 | decode_colors[8] = (decode_colors[0] + decode_colors[4]) / 2; |
| 152 | decode_colors[9] = (decode_colors[1] + decode_colors[5]) / 2; |
| 153 | decode_colors[10] = (decode_colors[2] + decode_colors[6]) / 2; |
| 154 | decode_colors[11] = 255; |
| 155 | decode_colors[12] = 0; |
| 156 | decode_colors[13] = 0; |
| 157 | decode_colors[14] = 0; |
| 158 | decode_colors[15] = 0; |
| 159 | } |
| 160 | // decode the block |
| 161 | for( i = 0; i < 16*4; i += 4 ) |
| 162 | { |
| 163 | int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 4; |
| 164 | next_bit += 2; |
| 165 | uncompressed[i+0] = decode_colors[idx+0]; |
| 166 | uncompressed[i+1] = decode_colors[idx+1]; |
| 167 | uncompressed[i+2] = decode_colors[idx+2]; |
| 168 | uncompressed[i+3] = decode_colors[idx+3]; |
| 169 | } |
| 170 | // done |
| 171 | } |
| 172 | void stbi_decode_DXT23_alpha_block( |
| 173 | unsigned char uncompressed[16*4], |
| 174 | unsigned char compressed[8] ) |
| 175 | { |
| 176 | int i, next_bit = 0; |
| 177 | // each alpha value gets 4 bits |
| 178 | for( i = 3; i < 16*4; i += 4 ) |
| 179 | { |
| 180 | uncompressed[i] = stbi_convert_bit_range( |
| 181 | (compressed[next_bit>>3] >> (next_bit&7)) & 15, |
| 182 | 4, 8 ); |
| 183 | next_bit += 4; |
| 184 | } |
| 185 | } |
| 186 | void stbi_decode_DXT45_alpha_block( |
| 187 | unsigned char uncompressed[16*4], |
| 188 | unsigned char compressed[8] ) |
| 189 | { |
| 190 | int i, next_bit = 8*2; |
| 191 | unsigned char decode_alpha[8]; |
| 192 | // each alpha value gets 3 bits, and the 1st 2 bytes are the range |
| 193 | decode_alpha[0] = compressed[0]; |
| 194 | decode_alpha[1] = compressed[1]; |
| 195 | if( decode_alpha[0] > decode_alpha[1] ) |
| 196 | { |
| 197 | // 6 step intermediate |
| 198 | decode_alpha[2] = (6*decode_alpha[0] + 1*decode_alpha[1]) / 7; |
| 199 | decode_alpha[3] = (5*decode_alpha[0] + 2*decode_alpha[1]) / 7; |
| 200 | decode_alpha[4] = (4*decode_alpha[0] + 3*decode_alpha[1]) / 7; |
| 201 | decode_alpha[5] = (3*decode_alpha[0] + 4*decode_alpha[1]) / 7; |
| 202 | decode_alpha[6] = (2*decode_alpha[0] + 5*decode_alpha[1]) / 7; |
| 203 | decode_alpha[7] = (1*decode_alpha[0] + 6*decode_alpha[1]) / 7; |
| 204 | } else |
| 205 | { |
| 206 | // 4 step intermediate, pluss full and none |
| 207 | decode_alpha[2] = (4*decode_alpha[0] + 1*decode_alpha[1]) / 5; |
| 208 | decode_alpha[3] = (3*decode_alpha[0] + 2*decode_alpha[1]) / 5; |
| 209 | decode_alpha[4] = (2*decode_alpha[0] + 3*decode_alpha[1]) / 5; |
| 210 | decode_alpha[5] = (1*decode_alpha[0] + 4*decode_alpha[1]) / 5; |
| 211 | decode_alpha[6] = 0; |
| 212 | decode_alpha[7] = 255; |
| 213 | } |
| 214 | for( i = 3; i < 16*4; i += 4 ) |
| 215 | { |
| 216 | int idx = 0, bit; |
| 217 | bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; |
| 218 | idx += bit << 0; |
| 219 | ++next_bit; |
| 220 | bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; |
| 221 | idx += bit << 1; |
| 222 | ++next_bit; |
| 223 | bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; |
| 224 | idx += bit << 2; |
| 225 | ++next_bit; |
| 226 | uncompressed[i] = decode_alpha[idx & 7]; |
| 227 | } |
| 228 | // done |
| 229 | } |
| 230 | void stbi_decode_DXT_color_block( |
| 231 | unsigned char uncompressed[16*4], |
| 232 | unsigned char compressed[8] ) |
| 233 | { |
| 234 | int next_bit = 4*8; |
| 235 | int i, r, g, b; |
| 236 | int c0, c1; |
| 237 | unsigned char decode_colors[4*3]; |
| 238 | // find the 2 primary colors |
| 239 | c0 = compressed[0] + (compressed[1] << 8); |
| 240 | c1 = compressed[2] + (compressed[3] << 8); |
| 241 | stbi_rgb_888_from_565( c0, &r, &g, &b ); |
| 242 | decode_colors[0] = r; |
| 243 | decode_colors[1] = g; |
| 244 | decode_colors[2] = b; |
| 245 | stbi_rgb_888_from_565( c1, &r, &g, &b ); |
| 246 | decode_colors[3] = r; |
| 247 | decode_colors[4] = g; |
| 248 | decode_colors[5] = b; |
| 249 | // Like DXT1, but no choicees: |
| 250 | // no alpha, 2 interpolated colors |
| 251 | decode_colors[6] = (2*decode_colors[0] + decode_colors[3]) / 3; |
| 252 | decode_colors[7] = (2*decode_colors[1] + decode_colors[4]) / 3; |
| 253 | decode_colors[8] = (2*decode_colors[2] + decode_colors[5]) / 3; |
| 254 | decode_colors[9] = (decode_colors[0] + 2*decode_colors[3]) / 3; |
| 255 | decode_colors[10] = (decode_colors[1] + 2*decode_colors[4]) / 3; |
| 256 | decode_colors[11] = (decode_colors[2] + 2*decode_colors[5]) / 3; |
| 257 | // decode the block |
| 258 | for( i = 0; i < 16*4; i += 4 ) |
| 259 | { |
| 260 | int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 3; |
| 261 | next_bit += 2; |
| 262 | uncompressed[i+0] = decode_colors[idx+0]; |
| 263 | uncompressed[i+1] = decode_colors[idx+1]; |
| 264 | uncompressed[i+2] = decode_colors[idx+2]; |
| 265 | } |
| 266 | // done |
| 267 | } |
| 268 | static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp) |
| 269 | { |
| 270 | // all variables go up front |
| 271 | stbi_uc *dds_data = NULL; |
| 272 | stbi_uc block[16*4]; |
| 273 | stbi_uc compressed[8]; |
| 274 | int flags, DXT_family; |
| 275 | int has_alpha, has_mipmap; |
| 276 | int is_compressed, cubemap_faces; |
| 277 | int block_pitch, num_blocks; |
| 278 | DDS_header ; |
| 279 | int i, sz, cf; |
| 280 | // load the header |
| 281 | if( sizeof( DDS_header ) != 128 ) |
| 282 | { |
| 283 | return NULL; |
| 284 | } |
| 285 | getn( s, (stbi_uc*)(&header), 128 ); |
| 286 | // and do some checking |
| 287 | if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL; |
| 288 | if( header.dwSize != 124 ) return NULL; |
| 289 | flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; |
| 290 | if( (header.dwFlags & flags) != flags ) return NULL; |
| 291 | /* According to the MSDN spec, the dwFlags should contain |
| 292 | DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if |
| 293 | uncompressed. Some DDS writers do not conform to the |
| 294 | spec, so I need to make my reader more tolerant */ |
| 295 | if( header.sPixelFormat.dwSize != 32 ) return NULL; |
| 296 | flags = DDPF_FOURCC | DDPF_RGB; |
| 297 | if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL; |
| 298 | if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL; |
| 299 | // get the image data |
| 300 | s->img_x = header.dwWidth; |
| 301 | s->img_y = header.dwHeight; |
| 302 | s->img_n = 4; |
| 303 | is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; |
| 304 | has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; |
| 305 | has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1); |
| 306 | cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP; |
| 307 | /* I need cubemaps to have square faces */ |
| 308 | cubemap_faces &= (s->img_x == s->img_y); |
| 309 | cubemap_faces *= 5; |
| 310 | cubemap_faces += 1; |
| 311 | block_pitch = (s->img_x+3) >> 2; |
| 312 | num_blocks = block_pitch * ((s->img_y+3) >> 2); |
| 313 | /* let the user know what's going on */ |
| 314 | *x = s->img_x; |
| 315 | *y = s->img_y; |
| 316 | *comp = s->img_n; |
| 317 | /* is this uncompressed? */ |
| 318 | if( is_compressed ) |
| 319 | { |
| 320 | /* compressed */ |
| 321 | // note: header.sPixelFormat.dwFourCC is something like (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24)) |
| 322 | DXT_family = 1 + (header.sPixelFormat.dwFourCC >> 24) - '1'; |
| 323 | if( (DXT_family < 1) || (DXT_family > 5) ) return NULL; |
| 324 | /* check the expected size...oops, nevermind... |
| 325 | those non-compliant writers leave |
| 326 | dwPitchOrLinearSize == 0 */ |
| 327 | // passed all the tests, get the RAM for decoding |
| 328 | sz = (s->img_x)*(s->img_y)*4*cubemap_faces; |
| 329 | dds_data = (unsigned char*)malloc( sz ); |
| 330 | /* do this once for each face */ |
| 331 | for( cf = 0; cf < cubemap_faces; ++ cf ) |
| 332 | { |
| 333 | // now read and decode all the blocks |
| 334 | for( i = 0; i < num_blocks; ++i ) |
| 335 | { |
| 336 | // where are we? |
| 337 | int bx, by, bw=4, bh=4; |
| 338 | int ref_x = 4 * (i % block_pitch); |
| 339 | int ref_y = 4 * (i / block_pitch); |
| 340 | // get the next block's worth of compressed data, and decompress it |
| 341 | if( DXT_family == 1 ) |
| 342 | { |
| 343 | // DXT1 |
| 344 | getn( s, compressed, 8 ); |
| 345 | stbi_decode_DXT1_block( block, compressed ); |
| 346 | } else if( DXT_family < 4 ) |
| 347 | { |
| 348 | // DXT2/3 |
| 349 | getn( s, compressed, 8 ); |
| 350 | stbi_decode_DXT23_alpha_block ( block, compressed ); |
| 351 | getn( s, compressed, 8 ); |
| 352 | stbi_decode_DXT_color_block ( block, compressed ); |
| 353 | } else |
| 354 | { |
| 355 | // DXT4/5 |
| 356 | getn( s, compressed, 8 ); |
| 357 | stbi_decode_DXT45_alpha_block ( block, compressed ); |
| 358 | getn( s, compressed, 8 ); |
| 359 | stbi_decode_DXT_color_block ( block, compressed ); |
| 360 | } |
| 361 | // is this a partial block? |
| 362 | if( ref_x + 4 > (int)s->img_x ) |
| 363 | { |
| 364 | bw = s->img_x - ref_x; |
| 365 | } |
| 366 | if( ref_y + 4 > (int)s->img_y ) |
| 367 | { |
| 368 | bh = s->img_y - ref_y; |
| 369 | } |
| 370 | // now drop our decompressed data into the buffer |
| 371 | for( by = 0; by < bh; ++by ) |
| 372 | { |
| 373 | int idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x); |
| 374 | for( bx = 0; bx < bw*4; ++bx ) |
| 375 | { |
| 376 | |
| 377 | dds_data[idx+bx] = block[by*16+bx]; |
| 378 | } |
| 379 | } |
| 380 | } |
| 381 | /* done reading and decoding the main image... |
| 382 | skip MIPmaps if present */ |
| 383 | if( has_mipmap ) |
| 384 | { |
| 385 | int block_size = 16; |
| 386 | if( DXT_family == 1 ) |
| 387 | { |
| 388 | block_size = 8; |
| 389 | } |
| 390 | for( i = 1; i < (int)header.dwMipMapCount; ++i ) |
| 391 | { |
| 392 | int mx = s->img_x >> (i + 2); |
| 393 | int my = s->img_y >> (i + 2); |
| 394 | if( mx < 1 ) |
| 395 | { |
| 396 | mx = 1; |
| 397 | } |
| 398 | if( my < 1 ) |
| 399 | { |
| 400 | my = 1; |
| 401 | } |
| 402 | skip( s, mx*my*block_size ); |
| 403 | } |
| 404 | } |
| 405 | }/* per cubemap face */ |
| 406 | } else |
| 407 | { |
| 408 | /* uncompressed */ |
| 409 | DXT_family = 0; |
| 410 | s->img_n = 3; |
| 411 | if( has_alpha ) |
| 412 | { |
| 413 | s->img_n = 4; |
| 414 | } |
| 415 | *comp = s->img_n; |
| 416 | sz = s->img_x*s->img_y*s->img_n*cubemap_faces; |
| 417 | dds_data = (unsigned char*)malloc( sz ); |
| 418 | /* do this once for each face */ |
| 419 | for( cf = 0; cf < cubemap_faces; ++ cf ) |
| 420 | { |
| 421 | /* read the main image for this face */ |
| 422 | getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n ); |
| 423 | /* done reading and decoding the main image... |
| 424 | skip MIPmaps if present */ |
| 425 | if( has_mipmap ) |
| 426 | { |
| 427 | for( i = 1; i < (int)header.dwMipMapCount; ++i ) |
| 428 | { |
| 429 | int mx = s->img_x >> i; |
| 430 | int my = s->img_y >> i; |
| 431 | if( mx < 1 ) |
| 432 | { |
| 433 | mx = 1; |
| 434 | } |
| 435 | if( my < 1 ) |
| 436 | { |
| 437 | my = 1; |
| 438 | } |
| 439 | skip( s, mx*my*s->img_n ); |
| 440 | } |
| 441 | } |
| 442 | } |
| 443 | /* data was BGR, I need it RGB */ |
| 444 | for( i = 0; i < sz; i += s->img_n ) |
| 445 | { |
| 446 | unsigned char temp = dds_data[i]; |
| 447 | dds_data[i] = dds_data[i+2]; |
| 448 | dds_data[i+2] = temp; |
| 449 | } |
| 450 | } |
| 451 | /* finished decompressing into RGBA, |
| 452 | adjust the y size if we have a cubemap |
| 453 | note: sz is already up to date */ |
| 454 | s->img_y *= cubemap_faces; |
| 455 | *y = s->img_y; |
| 456 | // did the user want something else, or |
| 457 | // see if all the alpha values are 255 (i.e. no transparency) |
| 458 | has_alpha = 0; |
| 459 | if( s->img_n == 4) |
| 460 | { |
| 461 | for( i = 3; (i < sz) && (has_alpha == 0); i += 4 ) |
| 462 | { |
| 463 | has_alpha |= (dds_data[i] < 255); |
| 464 | } |
| 465 | } |
| 466 | if( (req_comp <= 4) && (req_comp >= 1) ) |
| 467 | { |
| 468 | // user has some requirements, meet them |
| 469 | if( req_comp != s->img_n ) |
| 470 | { |
| 471 | dds_data = convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y ); |
| 472 | *comp = s->img_n; |
| 473 | } |
| 474 | } else |
| 475 | { |
| 476 | // user had no requirements, only drop to RGB is no alpha |
| 477 | if( (has_alpha == 0) && (s->img_n == 4) ) |
| 478 | { |
| 479 | dds_data = convert_format( dds_data, 4, 3, s->img_x, s->img_y ); |
| 480 | *comp = 3; |
| 481 | } |
| 482 | } |
| 483 | // OK, done |
| 484 | return dds_data; |
| 485 | } |
| 486 | |
| 487 | #ifndef STBI_NO_STDIO |
| 488 | stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) |
| 489 | { |
| 490 | stbi s; |
| 491 | start_file(&s,f); |
| 492 | return dds_load(&s,x,y,comp,req_comp); |
| 493 | } |
| 494 | |
| 495 | stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp) |
| 496 | { |
| 497 | stbi_uc *data; |
| 498 | FILE *f = fopen(filename, "rb" ); |
| 499 | if (!f) return NULL; |
| 500 | data = stbi_dds_load_from_file(f,x,y,comp,req_comp); |
| 501 | fclose(f); |
| 502 | return data; |
| 503 | } |
| 504 | #endif |
| 505 | |
| 506 | stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) |
| 507 | { |
| 508 | stbi s; |
| 509 | start_mem(&s,buffer, len); |
| 510 | return dds_load(&s,x,y,comp,req_comp); |
| 511 | } |
| 512 | |