FS#127 - Make image loading thread-safe

git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1205 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
LaurentGom 2009-08-18 07:31:15 +00:00
parent 3cfbc8409b
commit 0093952872
6 changed files with 1383 additions and 998 deletions

View File

@ -13,18 +13,6 @@
* everybody at gamedev.net * everybody at gamedev.net
*/ */
#define SOIL_CHECK_FOR_GL_ERRORS 0
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wingdi.h>
#elif defined(__APPLE__) || defined(__APPLE_CC__)
/* I can't test this Apple stuff! */
#define APIENTRY
#else
#endif
#include "SOIL.h" #include "SOIL.h"
#include "stb_image_aug.h" #include "stb_image_aug.h"
#include "image_DXT.h" #include "image_DXT.h"
@ -35,7 +23,6 @@
/* error reporting */ /* error reporting */
char *result_string_pointer = "SOIL initialized"; char *result_string_pointer = "SOIL initialized";
unsigned char* unsigned char*
SOIL_load_image SOIL_load_image
( (
@ -44,7 +31,7 @@ unsigned char*
int force_channels int force_channels
) )
{ {
unsigned char *result = stbi_load( (char*)filename, unsigned char *result = stbi_load( filename,
width, height, channels, force_channels ); width, height, channels, force_channels );
if( result == NULL ) if( result == NULL )
{ {
@ -66,7 +53,7 @@ unsigned char*
) )
{ {
unsigned char *result = stbi_load_from_memory( unsigned char *result = stbi_load_from_memory(
(stbi_uc *)buffer, buffer_length, buffer, buffer_length,
width, height, channels, width, height, channels,
force_channels ); force_channels );
if( result == NULL ) if( result == NULL )
@ -100,17 +87,17 @@ int
} }
if( image_type == SOIL_SAVE_TYPE_BMP ) if( image_type == SOIL_SAVE_TYPE_BMP )
{ {
save_result = stbi_write_bmp( (char*)filename, save_result = stbi_write_bmp( filename,
width, height, channels, (void*)data ); width, height, channels, (void*)data );
} else } else
if( image_type == SOIL_SAVE_TYPE_TGA ) if( image_type == SOIL_SAVE_TYPE_TGA )
{ {
save_result = stbi_write_tga( (char*)filename, save_result = stbi_write_tga( filename,
width, height, channels, (void*)data ); width, height, channels, (void*)data );
} else } else
if( image_type == SOIL_SAVE_TYPE_DDS ) if( image_type == SOIL_SAVE_TYPE_DDS )
{ {
save_result = save_image_as_DDS( (const char*)filename, save_result = save_image_as_DDS( filename,
width, height, channels, (const unsigned char *const)data ); width, height, channels, (const unsigned char *const)data );
} else } else
{ {

View File

@ -73,7 +73,6 @@ enum
SOIL_SAVE_TYPE_BMP = 1, SOIL_SAVE_TYPE_BMP = 1,
SOIL_SAVE_TYPE_DDS = 2 SOIL_SAVE_TYPE_DDS = 2
}; };
/** /**
Loads an image from disk into an array of unsigned chars. Loads an image from disk into an array of unsigned chars.
Note that *channels return the original channel count of the Note that *channels return the original channel count of the

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* stbi-1.08 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c /* stbi-1.18 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
when you control the images you're loading when you control the images you're loading
QUICK NOTES: QUICK NOTES:
@ -6,18 +6,30 @@
avoid problematic images and only need the trivial interface avoid problematic images and only need the trivial interface
JPEG baseline (no JPEG progressive, no oddball channel decimations) JPEG baseline (no JPEG progressive, no oddball channel decimations)
PNG non-interlaced PNG 8-bit only
BMP non-1bpp, non-RLE BMP non-1bpp, non-RLE
TGA (not sure what subset, if a subset) TGA (not sure what subset, if a subset)
PSD (composite view only, no extra channels) PSD (composited view only, no extra channels)
HDR (radiance rgbE format) HDR (radiance rgbE format)
writes BMP,TGA (define STBI_NO_WRITE to remove code) writes BMP,TGA (define STBI_NO_WRITE to remove code)
decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code) decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code)
supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
TODO: TODO:
stbi_info_* stbi_info_*
history: history:
1.18 fix a threading bug (local mutable static)
1.17 support interlaced PNG
1.16 major bugfix - convert_format converted one too many pixels
1.15 initialize some fields for thread safety
1.14 fix threadsafe conversion bug; header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
1.13 threadsafe
1.12 const qualifiers in the API
1.11 Support installable IDCT, colorspace conversion routines
1.10 Fixes for 64-bit (don't use "unsigned long")
optimized upsampling by Fabian "ryg" Giesen
1.09 Fix format-conversion for PSD code (bad global variables!)
1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
1.07 attempt to fix C++ warning/errors again 1.07 attempt to fix C++ warning/errors again
1.06 attempt to fix C++ warning/errors again 1.06 attempt to fix C++ warning/errors again
@ -53,8 +65,9 @@
on 'test' only check type, not whether we support this variant on 'test' only check type, not whether we support this variant
*/ */
#ifndef HEADER_STB_IMAGE_AUGMENTED
#define HEADER_STB_IMAGE_AUGMENTED #ifndef STBI_INCLUDE_STB_IMAGE_H
#define STBI_INCLUDE_STB_IMAGE_H
//// begin header file //////////////////////////////////////////////////// //// begin header file ////////////////////////////////////////////////////
// //
@ -144,15 +157,11 @@
// //
// stbi_is_hdr(char *filename); // stbi_is_hdr(char *filename);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
#include <stdio.h> #include <stdio.h>
#endif #endif
#ifndef STBI_NO_HDR #define STBI_VERSION 1
#include <math.h> // ldexp
#include <string.h> // strcmp
#endif
enum enum
{ {
@ -176,27 +185,27 @@ extern "C" {
// write a BMP/TGA file given tightly packed 'comp' channels (no padding, nor bmp-stride-padding) // write a BMP/TGA file given tightly packed 'comp' channels (no padding, nor bmp-stride-padding)
// (you must include the appropriate extension in the filename). // (you must include the appropriate extension in the filename).
// returns TRUE on success, FALSE if couldn't open file, error writing file // returns TRUE on success, FALSE if couldn't open file, error writing file
extern int stbi_write_bmp (char *filename, int x, int y, int comp, void *data); extern int stbi_write_bmp (char const *filename, int x, int y, int comp, void *data);
extern int stbi_write_tga (char *filename, int x, int y, int comp, void *data); extern int stbi_write_tga (char const *filename, int x, int y, int comp, void *data);
#endif #endif
// PRIMARY API - works on images of any type // PRIMARY API - works on images of any type
// load image by filename, open file, or memory buffer // load image by filename, open file, or memory buffer
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern stbi_uc *stbi_load (char *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
#endif #endif
extern stbi_uc *stbi_load_from_memory(stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
// for stbi_load_from_file, file pointer is left pointing immediately after image // for stbi_load_from_file, file pointer is left pointing immediately after image
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern float *stbi_loadf (char *filename, int *x, int *y, int *comp, int req_comp); extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp);
extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
#endif #endif
extern float *stbi_loadf_from_memory(stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
extern void stbi_hdr_to_ldr_gamma(float gamma); extern void stbi_hdr_to_ldr_gamma(float gamma);
extern void stbi_hdr_to_ldr_scale(float scale); extern void stbi_hdr_to_ldr_scale(float scale);
@ -207,96 +216,96 @@ extern void stbi_ldr_to_hdr_scale(float scale);
#endif // STBI_NO_HDR #endif // STBI_NO_HDR
// get a VERY brief reason for failure // get a VERY brief reason for failure
// NOT THREADSAFE
extern char *stbi_failure_reason (void); extern char *stbi_failure_reason (void);
// free the loaded image -- this is just free() // free the loaded image -- this is just free()
extern void stbi_image_free (void *retval_from_stbi_load); extern void stbi_image_free (void *retval_from_stbi_load);
// get image dimensions & components without fully decoding // get image dimensions & components without fully decoding
extern int stbi_info_from_memory(stbi_uc *buffer, int len, int *x, int *y, int *comp); extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
extern int stbi_is_hdr_from_memory(stbi_uc *buffer, int len); extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern int stbi_info (char *filename, int *x, int *y, int *comp); extern int stbi_info (char const *filename, int *x, int *y, int *comp);
extern int stbi_is_hdr (char *filename); extern int stbi_is_hdr (char const *filename);
extern int stbi_is_hdr_from_file(FILE *f); extern int stbi_is_hdr_from_file(FILE *f);
#endif #endif
// ZLIB client - used by PNG, available for other purposes // ZLIB client - used by PNG, available for other purposes
extern char *stbi_zlib_decode_malloc_guesssize(int initial_size, int *outlen); extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
extern char *stbi_zlib_decode_malloc(char *buffer, int len, int *outlen); extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
extern int stbi_zlib_decode_buffer(char *obuffer, int olen, char *ibuffer, int ilen); extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
extern char *stbi_zlib_decode_noheader_malloc(char *buffer, int len, int *outlen);
extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, char *ibuffer, int ilen);
extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
// TYPE-SPECIFIC ACCESS // TYPE-SPECIFIC ACCESS
// is it a jpeg? // is it a jpeg?
extern int stbi_jpeg_test_memory (stbi_uc *buffer, int len); extern int stbi_jpeg_test_memory (stbi_uc const *buffer, int len);
extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
extern int stbi_jpeg_info_from_memory(stbi_uc *buffer, int len, int *x, int *y, int *comp); extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern stbi_uc *stbi_jpeg_load (char *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp);
extern int stbi_jpeg_test_file (FILE *f); extern int stbi_jpeg_test_file (FILE *f);
extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
extern int stbi_jpeg_info (char *filename, int *x, int *y, int *comp); extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp);
extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp);
#endif #endif
extern int stbi_jpeg_dc_only; // only decode DC component
// is it a png? // is it a png?
extern int stbi_png_test_memory (stbi_uc *buffer, int len); extern int stbi_png_test_memory (stbi_uc const *buffer, int len);
extern stbi_uc *stbi_png_load_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
extern int stbi_png_info_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp); extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern stbi_uc *stbi_png_load (char *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp);
extern int stbi_png_info (char *filename, int *x, int *y, int *comp); extern int stbi_png_info (char const *filename, int *x, int *y, int *comp);
extern int stbi_png_test_file (FILE *f); extern int stbi_png_test_file (FILE *f);
extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp);
#endif #endif
// is it a bmp? // is it a bmp?
extern int stbi_bmp_test_memory (stbi_uc *buffer, int len); extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len);
extern stbi_uc *stbi_bmp_load (char *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern int stbi_bmp_test_file (FILE *f); extern int stbi_bmp_test_file (FILE *f);
extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
#endif #endif
// is it a tga? // is it a tga?
extern int stbi_tga_test_memory (stbi_uc *buffer, int len); extern int stbi_tga_test_memory (stbi_uc const *buffer, int len);
extern stbi_uc *stbi_tga_load (char *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi_tga_load_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern int stbi_tga_test_file (FILE *f); extern int stbi_tga_test_file (FILE *f);
extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
#endif #endif
// is it a psd? // is it a psd?
extern int stbi_psd_test_memory (stbi_uc *buffer, int len); extern int stbi_psd_test_memory (stbi_uc const *buffer, int len);
extern stbi_uc *stbi_psd_load (char *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi_psd_load_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern int stbi_psd_test_file (FILE *f); extern int stbi_psd_test_file (FILE *f);
extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
#endif #endif
// is it an hdr? // is it an hdr?
extern int stbi_hdr_test_memory (stbi_uc *buffer, int len); extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len);
extern float * stbi_hdr_load (char *filename, int *x, int *y, int *comp, int req_comp); extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp);
extern float * stbi_hdr_load_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi_hdr_load_rgbe (char const *filename, int *x, int *y, int *comp, int req_comp);
extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern int stbi_hdr_test_file (FILE *f); extern int stbi_hdr_test_file (FILE *f);
extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
@ -305,8 +314,8 @@ extern float * stbi_hdr_load_from_file (FILE *f, int *x, int
// define new loaders // define new loaders
typedef struct typedef struct
{ {
int (*test_memory)(stbi_uc *buffer, int len); int (*test_memory)(stbi_uc const *buffer, int len);
stbi_uc * (*load_from_memory)(stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); stbi_uc * (*load_from_memory)(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
int (*test_file)(FILE *f); int (*test_file)(FILE *f);
stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp); stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp);
@ -315,8 +324,28 @@ typedef struct
// register a loader by filling out the above structure (you must defined ALL functions) // register a loader by filling out the above structure (you must defined ALL functions)
// returns 1 if added or already added, 0 if not added (too many loaders) // returns 1 if added or already added, 0 if not added (too many loaders)
// NOT THREADSAFE
extern int stbi_register_loader(stbi_loader *loader); extern int stbi_register_loader(stbi_loader *loader);
// define faster low-level operations (typically SIMD support)
#if STBI_SIMD
typedef void (*stbi_idct_8x8)(uint8 *out, int out_stride, short data[64], unsigned short *dequantize);
// compute an integer IDCT on "input"
// input[x] = data[x] * dequantize[x]
// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride'
// CLAMP results to 0..255
typedef void (*stbi_YCbCr_to_RGB_run)(uint8 *output, uint8 const *y, uint8 const *cb, uint8 const *cr, int count, int step);
// compute a conversion from YCbCr to RGB
// 'count' pixels
// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B
// y: Y input channel
// cb: Cb input channel; scale/biased to be 0..255
// cr: Cr input channel; scale/biased to be 0..255
extern void stbi_install_idct(stbi_idct_8x8 func);
extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func);
#endif // STBI_SIMD
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@ -324,6 +353,5 @@ extern int stbi_register_loader(stbi_loader *loader);
// //
// //
//// end header file ///////////////////////////////////////////////////// //// end header file /////////////////////////////////////////////////////
#endif // STBI_INCLUDE_STB_IMAGE_H
#endif

View File

@ -6,10 +6,10 @@
#define HEADER_STB_IMAGE_DDS_AUGMENTATION #define HEADER_STB_IMAGE_DDS_AUGMENTATION
// is it a DDS file? // is it a DDS file?
extern int stbi_dds_test_memory (stbi_uc *buffer, int len); extern int stbi_dds_test_memory (stbi_uc const *buffer, int len);
extern stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp);
extern stbi_uc *stbi_dds_load_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern int stbi_dds_test_file (FILE *f); extern int stbi_dds_test_file (FILE *f);
extern stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);

View File

@ -71,32 +71,34 @@ typedef struct {
#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
#define DDSCAPS2_VOLUME 0x00200000 #define DDSCAPS2_VOLUME 0x00200000
static int dds_test(void) static int dds_test(stbi *s)
{ {
// check the magic number // check the magic number
if (get8() != 'D') return 0; if (get8(s) != 'D') return 0;
if (get8() != 'D') return 0; if (get8(s) != 'D') return 0;
if (get8() != 'S') return 0; if (get8(s) != 'S') return 0;
if (get8() != ' ') return 0; if (get8(s) != ' ') return 0;
// check header size // check header size
if (get32le() != 124) return 0; if (get32le(s) != 124) return 0;
return 1; return 1;
} }
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
int stbi_dds_test_file (FILE *f) int stbi_dds_test_file (FILE *f)
{ {
stbi s;
int r,n = ftell(f); int r,n = ftell(f);
start_file(f); start_file(&s,f);
r = dds_test(); r = dds_test(&s);
fseek(f,n,SEEK_SET); fseek(f,n,SEEK_SET);
return r; return r;
} }
#endif #endif
int stbi_dds_test_memory (stbi_uc *buffer, int len) int stbi_dds_test_memory (stbi_uc const *buffer, int len)
{ {
start_mem(buffer, len); stbi s;
return dds_test(); start_mem(&s,buffer, len);
return dds_test(&s);
} }
// helper functions // helper functions
@ -263,7 +265,7 @@ void stbi_decode_DXT_color_block(
} }
// done // done
} }
static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp) static stbi_uc *dds_load(stbi *s, int *x, int *y, int *comp, int req_comp)
{ {
// all variables go up front // all variables go up front
stbi_uc *dds_data = NULL; stbi_uc *dds_data = NULL;
@ -280,7 +282,7 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
{ {
return NULL; return NULL;
} }
getn( (stbi_uc*)(&header), 128 ); getn( s, (stbi_uc*)(&header), 128 );
// and do some checking // and do some checking
if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL; if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL;
if( header.dwSize != 124 ) return NULL; if( header.dwSize != 124 ) return NULL;
@ -295,23 +297,23 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL; if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL;
if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL; if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL;
// get the image data // get the image data
img_x = header.dwWidth; s->img_x = header.dwWidth;
img_y = header.dwHeight; s->img_y = header.dwHeight;
img_n = 4; s->img_n = 4;
is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;
has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS;
has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1); has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1);
cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP; cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP;
/* I need cubemaps to have square faces */ /* I need cubemaps to have square faces */
cubemap_faces &= (img_x == img_y); cubemap_faces &= (s->img_x == s->img_y);
cubemap_faces *= 5; cubemap_faces *= 5;
cubemap_faces += 1; cubemap_faces += 1;
block_pitch = (img_x+3) >> 2; block_pitch = (s->img_x+3) >> 2;
num_blocks = block_pitch * ((img_y+3) >> 2); num_blocks = block_pitch * ((s->img_y+3) >> 2);
/* let the user know what's going on */ /* let the user know what's going on */
*x = img_x; *x = s->img_x;
*y = img_y; *y = s->img_y;
*comp = img_n; *comp = s->img_n;
/* is this uncompressed? */ /* is this uncompressed? */
if( is_compressed ) if( is_compressed )
{ {
@ -323,7 +325,7 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
those non-compliant writers leave those non-compliant writers leave
dwPitchOrLinearSize == 0 */ dwPitchOrLinearSize == 0 */
// passed all the tests, get the RAM for decoding // passed all the tests, get the RAM for decoding
sz = (img_x)*(img_y)*4*cubemap_faces; sz = (s->img_x)*(s->img_y)*4*cubemap_faces;
dds_data = (unsigned char*)malloc( sz ); dds_data = (unsigned char*)malloc( sz );
/* do this once for each face */ /* do this once for each face */
for( cf = 0; cf < cubemap_faces; ++ cf ) for( cf = 0; cf < cubemap_faces; ++ cf )
@ -339,36 +341,36 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
if( DXT_family == 1 ) if( DXT_family == 1 )
{ {
// DXT1 // DXT1
getn( compressed, 8 ); getn( s, compressed, 8 );
stbi_decode_DXT1_block( block, compressed ); stbi_decode_DXT1_block( block, compressed );
} else if( DXT_family < 4 ) } else if( DXT_family < 4 )
{ {
// DXT2/3 // DXT2/3
getn( compressed, 8 ); getn( s, compressed, 8 );
stbi_decode_DXT23_alpha_block ( block, compressed ); stbi_decode_DXT23_alpha_block ( block, compressed );
getn( compressed, 8 ); getn( s, compressed, 8 );
stbi_decode_DXT_color_block ( block, compressed ); stbi_decode_DXT_color_block ( block, compressed );
} else } else
{ {
// DXT4/5 // DXT4/5
getn( compressed, 8 ); getn( s, compressed, 8 );
stbi_decode_DXT45_alpha_block ( block, compressed ); stbi_decode_DXT45_alpha_block ( block, compressed );
getn( compressed, 8 ); getn( s, compressed, 8 );
stbi_decode_DXT_color_block ( block, compressed ); stbi_decode_DXT_color_block ( block, compressed );
} }
// is this a partial block? // is this a partial block?
if( ref_x + 4 > img_x ) if( ref_x + 4 > s->img_x )
{ {
bw = img_x - ref_x; bw = s->img_x - ref_x;
} }
if( ref_y + 4 > img_y ) if( ref_y + 4 > s->img_y )
{ {
bh = img_y - ref_y; bh = s->img_y - ref_y;
} }
// now drop our decompressed data into the buffer // now drop our decompressed data into the buffer
for( by = 0; by < bh; ++by ) for( by = 0; by < bh; ++by )
{ {
int idx = 4*((ref_y+by+cf*img_x)*img_x + ref_x); int idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x);
for( bx = 0; bx < bw*4; ++bx ) for( bx = 0; bx < bw*4; ++bx )
{ {
@ -387,8 +389,8 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
} }
for( i = 1; i < header.dwMipMapCount; ++i ) for( i = 1; i < header.dwMipMapCount; ++i )
{ {
int mx = img_x >> (i + 2); int mx = s->img_x >> (i + 2);
int my = img_y >> (i + 2); int my = s->img_y >> (i + 2);
if( mx < 1 ) if( mx < 1 )
{ {
mx = 1; mx = 1;
@ -397,7 +399,7 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
{ {
my = 1; my = 1;
} }
skip( mx*my*block_size ); skip( s, mx*my*block_size );
} }
} }
}/* per cubemap face */ }/* per cubemap face */
@ -405,27 +407,27 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
{ {
/* uncompressed */ /* uncompressed */
DXT_family = 0; DXT_family = 0;
img_n = 3; s->img_n = 3;
if( has_alpha ) if( has_alpha )
{ {
img_n = 4; s->img_n = 4;
} }
*comp = img_n; *comp = s->img_n;
sz = img_x*img_y*img_n*cubemap_faces; sz = s->img_x*s->img_y*s->img_n*cubemap_faces;
dds_data = (unsigned char*)malloc( sz ); dds_data = (unsigned char*)malloc( sz );
/* do this once for each face */ /* do this once for each face */
for( cf = 0; cf < cubemap_faces; ++ cf ) for( cf = 0; cf < cubemap_faces; ++ cf )
{ {
/* read the main image for this face */ /* read the main image for this face */
getn( &dds_data[cf*img_x*img_y*img_n], img_x*img_y*img_n ); getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n );
/* done reading and decoding the main image... /* done reading and decoding the main image...
skip MIPmaps if present */ skip MIPmaps if present */
if( has_mipmap ) if( has_mipmap )
{ {
for( i = 1; i < header.dwMipMapCount; ++i ) for( i = 1; i < header.dwMipMapCount; ++i )
{ {
int mx = img_x >> i; int mx = s->img_x >> i;
int my = img_y >> i; int my = s->img_y >> i;
if( mx < 1 ) if( mx < 1 )
{ {
mx = 1; mx = 1;
@ -434,12 +436,12 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
{ {
my = 1; my = 1;
} }
skip( mx*my*img_n ); skip( s, mx*my*s->img_n );
} }
} }
} }
/* data was BGR, I need it RGB */ /* data was BGR, I need it RGB */
for( i = 0; i < sz; i += img_n ) for( i = 0; i < sz; i += s->img_n )
{ {
unsigned char temp = dds_data[i]; unsigned char temp = dds_data[i];
dds_data[i] = dds_data[i+2]; dds_data[i] = dds_data[i+2];
@ -449,12 +451,12 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
/* finished decompressing into RGBA, /* finished decompressing into RGBA,
adjust the y size if we have a cubemap adjust the y size if we have a cubemap
note: sz is already up to date */ note: sz is already up to date */
img_y *= cubemap_faces; s->img_y *= cubemap_faces;
*y = img_y; *y = s->img_y;
// did the user want something else, or // did the user want something else, or
// see if all the alpha values are 255 (i.e. no transparency) // see if all the alpha values are 255 (i.e. no transparency)
has_alpha = 0; has_alpha = 0;
if( img_n == 4) if( s->img_n == 4)
{ {
for( i = 3; (i < sz) && (has_alpha == 0); i += 4 ) for( i = 3; (i < sz) && (has_alpha == 0); i += 4 )
{ {
@ -464,17 +466,17 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
if( (req_comp <= 4) && (req_comp >= 1) ) if( (req_comp <= 4) && (req_comp >= 1) )
{ {
// user has some requirements, meet them // user has some requirements, meet them
if( req_comp != img_n ) if( req_comp != s->img_n )
{ {
dds_data = convert_format( dds_data, img_n, req_comp ); dds_data = convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y );
*comp = img_n; *comp = s->img_n;
} }
} else } else
{ {
// user had no requirements, only drop to RGB is no alpha // user had no requirements, only drop to RGB is no alpha
if( (has_alpha == 0) && (img_n == 4) ) if( (has_alpha == 0) && (s->img_n == 4) )
{ {
dds_data = convert_format( dds_data, 4, 3 ); dds_data = convert_format( dds_data, 4, 3, s->img_x, s->img_y );
*comp = 3; *comp = 3;
} }
} }
@ -483,25 +485,27 @@ static stbi_uc *dds_load(int *x, int *y, int *comp, int req_comp)
} }
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp)
{
stbi s;
start_file(&s,f);
return dds_load(&s,x,y,comp,req_comp);
}
stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp) stbi_uc *stbi_dds_load (char *filename, int *x, int *y, int *comp, int req_comp)
{ {
stbi_uc *data; stbi_uc *data;
FILE *f = fopen(filename, "rb"); FILE *f = fopen(filename, "rb");
if (!f) return NULL; if (!f) return NULL;
data = dds_load(x,y,comp,req_comp); data = stbi_dds_load_from_file(f,x,y,comp,req_comp);
fclose(f); fclose(f);
return data; return data;
} }
stbi_uc *stbi_dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp)
{
start_file(f);
return dds_load(x,y,comp,req_comp);
}
#endif #endif
stbi_uc *stbi_dds_load_from_memory (stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp) stbi_uc *stbi_dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
{ {
start_mem(buffer, len); stbi s;
return dds_load(x,y,comp,req_comp); start_mem(&s,buffer, len);
return dds_load(&s,x,y,comp,req_comp);
} }