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 | |