Merge pull request #1 from nothings/master

Update stb
This commit is contained in:
Mikhail Morozov 2018-02-13 18:01:46 +03:00 committed by GitHub
commit fa8fe30532
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 4786 additions and 488 deletions

View File

@ -11,17 +11,17 @@ by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
library | lastest version | category | LoC | description library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | -------------------------------- --------------------- | ---- | -------- | --- | --------------------------------
**[stb_vorbis.c](stb_vorbis.c)** | 1.11 | audio | 5449 | decode ogg vorbis files from file/memory to float/16-bit signed output **[stb_vorbis.c](stb_vorbis.c)** | 1.14 | audio | 5462 | decode ogg vorbis files from file/memory to float/16-bit signed output
**[stb_image.h](stb_image.h)** | 2.16 | graphics | 7187 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **[stb_image.h](stb_image.h)** | 2.19 | graphics | 7462 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**[stb_truetype.h](stb_truetype.h)** | 1.17 | graphics | 4566 | parse, decode, and rasterize characters from truetype fonts **[stb_truetype.h](stb_truetype.h)** | 1.19 | graphics | 4853 | parse, decode, and rasterize characters from truetype fonts
**[stb_image_write.h](stb_image_write.h)** | 1.07 | graphics | 1458 | image writing to disk: PNG, TGA, BMP **[stb_image_write.h](stb_image_write.h)** | 1.09 | graphics | 1568 | image writing to disk: PNG, TGA, BMP
**[stb_image_resize.h](stb_image_resize.h)** | 0.95 | graphics | 2627 | resize images larger/smaller with good quality **[stb_image_resize.h](stb_image_resize.h)** | 0.95 | graphics | 2627 | resize images larger/smaller with good quality
**[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 624 | simple 2D rectangle packer with decent quality **[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 624 | simple 2D rectangle packer with decent quality
**[stb_sprintf.h](stb_sprintf.h)** | 1.03 | utility | 1812 | fast sprintf, snprintf for C/C++ **[stb_sprintf.h](stb_sprintf.h)** | 1.05 | utility | 1833 | fast sprintf, snprintf for C/C++
**[stretchy_buffer.h](stretchy_buffer.h)** | 1.02 | utility | 257 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ **[stretchy_buffer.h](stretchy_buffer.h)** | 1.03 | utility | 262 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
**[stb_textedit.h](stb_textedit.h)** | 1.11 | user&nbsp;interface | 1393 | guts of a text editor for games etc implementing them from scratch **[stb_textedit.h](stb_textedit.h)** | 1.12 | user&nbsp;interface | 1404 | guts of a text editor for games etc implementing them from scratch
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D&nbsp;graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features **[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D&nbsp;graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
**[stb_dxt.h](stb_dxt.h)** | 1.07 | 3D&nbsp;graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor **[stb_dxt.h](stb_dxt.h)** | 1.08b | 3D&nbsp;graphics | 728 | Fabian "ryg" Giesen's real-time DXT compressor
**[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D&nbsp;graphics | 316 | revised Perlin noise (3D input, 1D output) **[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D&nbsp;graphics | 316 | revised Perlin noise (3D input, 1D output)
**[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D&nbsp;graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc **[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D&nbsp;graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game&nbsp;dev | 4172 | embeddable tilemap editor **[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game&nbsp;dev | 4172 | embeddable tilemap editor
@ -29,11 +29,11 @@ library | lastest version | category | LoC | description
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages **[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages
**[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide" **[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide"
**[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids **[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids
**[stb.h](stb.h)** | 2.30 | misc | 14328 | helper functions for C, mostly redundant in C++; basically author's personal stuff **[stb.h](stb.h)** | 2.31 | misc | 14405 | helper functions for C, mostly redundant in C++; basically author's personal stuff
**[stb_leakcheck.h](stb_leakcheck.h)** | 0.4 | misc | 186 | quick-and-dirty malloc/free leak-checking **[stb_leakcheck.h](stb_leakcheck.h)** | 0.4 | misc | 186 | quick-and-dirty malloc/free leak-checking
Total libraries: 20 Total libraries: 20
Total lines of C code: 52846 Total lines of C code: 53654
FAQ FAQ

281
stb.h
View File

@ -1,4 +1,4 @@
/* stb.h - v2.30 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h /* stb.h - v2.31 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
no warranty is offered or implied; use this code at your own risk no warranty is offered or implied; use this code at your own risk
This is a single header file with a bunch of useful utilities This is a single header file with a bunch of useful utilities
@ -25,6 +25,7 @@
Version History Version History
2.31 stb_ucharcmp
2.30 MinGW fix 2.30 MinGW fix
2.29 attempt to fix use of swprintf() 2.29 attempt to fix use of swprintf()
2.28 various new functionality 2.28 various new functionality
@ -193,6 +194,7 @@ CREDITS
Eugene Opalev Eugene Opalev
Tim Sjostrand Tim Sjostrand
github:infatum github:infatum
Dave Butler (Croepha)
*/ */
#include <stdarg.h> #include <stdarg.h>
@ -1028,8 +1030,8 @@ stb__wchar *stb__from_utf8(char *str)
stb__wchar *stb__from_utf8_alt(char *str) stb__wchar *stb__from_utf8_alt(char *str)
{ {
static stb__wchar buffer[64]; static stb__wchar buffer[4096];
return stb_from_utf8(buffer, str, 64); return stb_from_utf8(buffer, str, 4096);
} }
char *stb__to_utf8(stb__wchar *str) char *stb__to_utf8(stb__wchar *str)
@ -1548,7 +1550,7 @@ STB_EXTERN int (*stb_doublecmp(int offset))(const void *a, const void *b);
STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b); STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b);
#ifdef STB_DEFINE #ifdef STB_DEFINE
static int stb__intcmpoffset, stb__charcmpoffset, stb__strcmpoffset; static int stb__intcmpoffset, stb__ucharcmpoffset, stb__strcmpoffset;
static int stb__floatcmpoffset, stb__doublecmpoffset; static int stb__floatcmpoffset, stb__doublecmpoffset;
int stb__intcmp(const void *a, const void *b) int stb__intcmp(const void *a, const void *b)
@ -1558,10 +1560,10 @@ int stb__intcmp(const void *a, const void *b)
return p < q ? -1 : p > q; return p < q ? -1 : p > q;
} }
int stb__charcmp(const void *a, const void *b) int stb__ucharcmp(const void *a, const void *b)
{ {
const int p = *(const unsigned char *) ((const char *) a + stb__charcmpoffset); const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset);
const int q = *(const unsigned char *) ((const char *) b + stb__charcmpoffset); const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset);
return p < q ? -1 : p > q; return p < q ? -1 : p > q;
} }
@ -1599,10 +1601,10 @@ int (*stb_intcmp(int offset))(const void *, const void *)
return &stb__intcmp; return &stb__intcmp;
} }
int (*stb_charcmp(int offset))(const void *, const void *) int (*stb_ucharcmp(int offset))(const void *, const void *)
{ {
stb__charcmpoffset = offset; stb__ucharcmpoffset = offset;
return &stb__charcmp; return &stb__ucharcmp;
} }
int (*stb_qsort_strcmp(int offset))(const void *, const void *) int (*stb_qsort_strcmp(int offset))(const void *, const void *)
@ -1628,7 +1630,6 @@ int (*stb_doublecmp(int offset))(const void *, const void *)
stb__doublecmpoffset = offset; stb__doublecmpoffset = offset;
return &stb__doublecmp; return &stb__doublecmp;
} }
#endif #endif
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -1795,7 +1796,7 @@ STB_EXTERN int stb_prefix (char *s, char *t);
STB_EXTERN char * stb_strichr(char *s, char t); STB_EXTERN char * stb_strichr(char *s, char t);
STB_EXTERN char * stb_stristr(char *s, char *t); STB_EXTERN char * stb_stristr(char *s, char *t);
STB_EXTERN int stb_prefix_count(char *s, char *t); STB_EXTERN int stb_prefix_count(char *s, char *t);
STB_EXTERN char * stb_plural(int n); // "s" or "" STB_EXTERN const char * stb_plural(int n); // "s" or ""
STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n); STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n);
STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count);
@ -1822,7 +1823,7 @@ size_t stb_strscpy(char *d, const char *s, size_t n)
return len + 1; return len + 1;
} }
char *stb_plural(int n) const char *stb_plural(int n)
{ {
return n == 1 ? "" : "s"; return n == 1 ? "" : "s";
} }
@ -3362,7 +3363,7 @@ unsigned int stb_hashlen(char *str, int len)
unsigned int stb_hashptr(void *p) unsigned int stb_hashptr(void *p)
{ {
unsigned int x = (unsigned int) p; unsigned int x = (unsigned int)(size_t) p;
// typically lacking in low bits and high bits // typically lacking in low bits and high bits
x = stb_rehash(x); x = stb_rehash(x);
@ -3411,7 +3412,7 @@ unsigned int stb_hash_fast(void *p, int len)
if (len <= 0 || q == NULL) return 0; if (len <= 0 || q == NULL) return 0;
/* Main loop */ /* Main loop */
if (((int) q & 1) == 0) { if (((int)(size_t) q & 1) == 0) {
for (;len > 3; len -= 4) { for (;len > 3; len -= 4) {
unsigned int val; unsigned int val;
hash += stb__get16(q); hash += stb__get16(q);
@ -3737,7 +3738,7 @@ int stb_ischar(char c, char *set)
static unsigned char (*tables)[256]; static unsigned char (*tables)[256];
static char ** sets = NULL; static char ** sets = NULL;
int z = stb_perfect_hash(&p, (int) set); int z = stb_perfect_hash(&p, (int)(size_t) set);
if (z < 0) { if (z < 0) {
int i,k,n,j,f; int i,k,n,j,f;
// special code that means free all existing data // special code that means free all existing data
@ -3756,7 +3757,7 @@ int stb_ischar(char c, char *set)
tables = (unsigned char (*)[256]) realloc(tables, sizeof(*tables) * k); tables = (unsigned char (*)[256]) realloc(tables, sizeof(*tables) * k);
memset(tables, 0, sizeof(*tables) * k); memset(tables, 0, sizeof(*tables) * k);
for (i=0; i < stb_arr_len(sets); ++i) { for (i=0; i < stb_arr_len(sets); ++i) {
k = stb_perfect_hash(&p, (int) sets[i]); k = stb_perfect_hash(&p, (int)(size_t) sets[i]);
assert(k >= 0); assert(k >= 0);
n = k >> 3; n = k >> 3;
f = bit[k&7]; f = bit[k&7];
@ -3764,7 +3765,7 @@ int stb_ischar(char c, char *set)
tables[n][(unsigned char) sets[i][j]] |= f; tables[n][(unsigned char) sets[i][j]] |= f;
} }
} }
z = stb_perfect_hash(&p, (int) set); z = stb_perfect_hash(&p, (int)(size_t) set);
} }
return tables[z >> 3][(unsigned char) c] & bit[z & 7]; return tables[z >> 3][(unsigned char) c] & bit[z & 7];
} }
@ -4245,12 +4246,22 @@ STB_EXTERN void stb_sdict_delete(stb_sdict *);
STB_EXTERN void * stb_sdict_change(stb_sdict *, char *str, void *p); STB_EXTERN void * stb_sdict_change(stb_sdict *, char *str, void *p);
STB_EXTERN int stb_sdict_count(stb_sdict *d); STB_EXTERN int stb_sdict_count(stb_sdict *d);
STB_EXTERN int stb_sdict_internal_limit(stb_sdict *d);
STB_EXTERN char * stb_sdict_internal_key(stb_sdict *d, int n);
STB_EXTERN void * stb_sdict_internal_value(stb_sdict *d, int n);
#define stb_sdict_for(d,i,q,z) \ #define stb_sdict_for(d,i,q,z) \
for(i=0; i < (d)->limit ? q=(d)->table[i].k,z=(d)->table[i].v,1 : 0; ++i) \ for(i=0; i < stb_sdict_internal_limit(d) ? (q=stb_sdict_internal_key(d,i),z=stb_sdict_internal_value(d,i),1) : 0; ++i) \
if (q==NULL||q==(void *) 1);else // reversed makes macro friendly if (q==NULL||q==(void *) 1);else // reversed makes macro friendly
#ifdef STB_DEFINE #ifdef STB_DEFINE
// if in same translation unit, for speed, don't call accessors
#undef stb_sdict_for
#define stb_sdict_for(d,i,q,z) \
for(i=0; i < (d)->limit ? (q=(d)->table[i].k,z=(d)->table[i].v,1) : 0; ++i) \
if (q==NULL||q==(void *) 1);else // reversed makes macro friendly
#define STB_DEL ((void *) 1) #define STB_DEL ((void *) 1)
#define STB_SDEL ((char *) 1) #define STB_SDEL ((char *) 1)
@ -4270,6 +4281,19 @@ int stb_sdict_count(stb_sdict *a)
return a->count; return a->count;
} }
int stb_sdict_internal_limit(stb_sdict *a)
{
return a->limit;
}
char* stb_sdict_internal_key(stb_sdict *a, int n)
{
return a->table[n].k;
}
void* stb_sdict_internal_value(stb_sdict *a, int n)
{
return a->table[n].v;
}
stb_sdict * stb_sdict_new(int use_arena) stb_sdict * stb_sdict_new(int use_arena)
{ {
stb_sdict *d = stb_sdict_create(); stb_sdict *d = stb_sdict_create();
@ -5439,15 +5463,62 @@ typedef struct
int errors; int errors;
} stb__file_data; } stb__file_data;
static FILE *stb__open_temp_file(char *temp_name, char *src_name, char *mode)
{
int p;
#ifdef _MSC_VER
int j;
#endif
FILE *f;
// try to generate a temporary file in the same directory
p = strlen(src_name)-1;
while (p > 0 && src_name[p] != '/' && src_name[p] != '\\'
&& src_name[p] != ':' && src_name[p] != '~')
--p;
++p;
memcpy(temp_name, src_name, p);
#ifdef _MSC_VER
// try multiple times to make a temp file... just in
// case some other process makes the name first
for (j=0; j < 32; ++j) {
strcpy(temp_name+p, "stmpXXXXXX");
if (stb_mktemp(temp_name) == NULL)
return 0;
f = fopen(temp_name, mode);
if (f != NULL)
break;
}
#else
{
strcpy(temp_name+p, "stmpXXXXXX");
#ifdef __MINGW32__
int fd = open(mktemp(temp_name), O_RDWR);
#else
int fd = mkstemp(temp_name);
#endif
if (fd == -1) return NULL;
f = fdopen(fd, mode);
if (f == NULL) {
unlink(temp_name);
close(fd);
return NULL;
}
}
#endif
return f;
}
FILE * stb_fopen(char *filename, char *mode) FILE * stb_fopen(char *filename, char *mode)
{ {
FILE *f; FILE *f;
char name_full[4096]; char name_full[4096];
char temp_full[sizeof(name_full) + 12]; char temp_full[sizeof(name_full) + 12];
int p;
#ifdef _MSC_VER // @TODO: if the file doesn't exist, we can also use the fastpath here
int j;
#endif
if (mode[0] != 'w' && !strchr(mode, '+')) if (mode[0] != 'w' && !strchr(mode, '+'))
return stb__fopen(filename, mode); return stb__fopen(filename, mode);
@ -5458,44 +5529,7 @@ FILE * stb_fopen(char *filename, char *mode)
if (stb_fullpath(name_full, sizeof(name_full), filename)==0) if (stb_fullpath(name_full, sizeof(name_full), filename)==0)
return 0; return 0;
// try to generate a temporary file in the same directory f = stb__open_temp_file(temp_full, name_full, mode);
p = strlen(name_full)-1;
while (p > 0 && name_full[p] != '/' && name_full[p] != '\\'
&& name_full[p] != ':' && name_full[p] != '~')
--p;
++p;
memcpy(temp_full, name_full, p);
#ifdef _MSC_VER
// try multiple times to make a temp file... just in
// case some other process makes the name first
for (j=0; j < 32; ++j) {
strcpy(temp_full+p, "stmpXXXXXX");
if (stb_mktemp(temp_full) == NULL)
return 0;
f = fopen(temp_full, mode);
if (f != NULL)
break;
}
#else
{
strcpy(temp_full+p, "stmpXXXXXX");
#ifdef __MINGW32__
int fd = open(mktemp(temp_full), O_RDWR);
#else
int fd = mkstemp(temp_full);
#endif
if (fd == -1) return NULL;
f = fdopen(fd, mode);
if (f == NULL) {
unlink(temp_full);
close(fd);
return NULL;
}
}
#endif
if (f != NULL) { if (f != NULL) {
stb__file_data *d = (stb__file_data *) malloc(sizeof(*d)); stb__file_data *d = (stb__file_data *) malloc(sizeof(*d));
if (!d) { assert(0); /* NOTREACHED */fclose(f); return NULL; } if (!d) { assert(0); /* NOTREACHED */fclose(f); return NULL; }
@ -5538,20 +5572,62 @@ int stb_fclose(FILE *f, int keep)
} }
} }
if (keep != stb_keep_no) { if (keep == stb_keep_no) {
if (stb_fexists(d->name) && remove(d->name)) {
// failed to delete old, so don't keep new
keep = stb_keep_no;
} else {
if (!stb_rename(d->temp_name, d->name))
ok = STB_TRUE;
else
keep=stb_keep_no;
}
}
if (keep == stb_keep_no)
remove(d->temp_name); remove(d->temp_name);
} else {
if (!stb_fexists(d->name)) {
// old file doesn't exist, so just move the new file over it
stb_rename(d->temp_name, d->name);
} else {
// don't delete the old file yet in case there are troubles! First rename it!
char preserved_old_file[4096];
// generate a temp filename in the same directory (also creates it, which we don't need)
FILE *dummy = stb__open_temp_file(preserved_old_file, d->name, "wb");
if (dummy != NULL) {
// we don't actually want the open file
fclose(dummy);
// discard what we just created
remove(preserved_old_file); // if this fails, there's nothing we can do, and following logic handles it as best as possible anyway
// move the existing file to the preserved name
if (0 != stb_rename(d->name, preserved_old_file)) { // 0 on success
// failed, state is:
// filename -> old file
// tempname -> new file
// keep tempname around so we don't lose data
} else {
// state is:
// preserved -> old file
// tempname -> new file
// move the new file to the old name
if (0 == stb_rename(d->temp_name, d->name)) {
// state is:
// preserved -> old file
// filename -> new file
ok = STB_TRUE;
// 'filename -> new file' has always been the goal, so clean up
remove(preserved_old_file); // nothing to be done if it fails
} else {
// couldn't rename, so try renaming preserved file back
// state is:
// preserved -> old file
// tempname -> new file
stb_rename(preserved_old_file, d->name);
// if the rename failed, there's nothing more we can do
}
}
} else {
// we couldn't get a temp filename. do this the naive way; the worst case failure here
// leaves the filename pointing to nothing and the new file as a tempfile
remove(d->name);
stb_rename(d->temp_name, d->name);
}
}
}
free(d->temp_name); free(d->temp_name);
free(d->name); free(d->name);
@ -7631,14 +7707,14 @@ static stb_ps_hash *stb_ps_makehash(int size, int old_size, void **old_data)
h->any_offset = 0; h->any_offset = 0;
memset(h->table, 0, size * sizeof(h->table[0])); memset(h->table, 0, size * sizeof(h->table[0]));
for (i=0; i < old_size; ++i) for (i=0; i < old_size; ++i)
if (!stb_ps_empty(old_data[i])) if (!stb_ps_empty((size_t)old_data[i]))
stb_ps_add(EncodeHash(h), old_data[i]); stb_ps_add(EncodeHash(h), old_data[i]);
return h; return h;
} }
void stb_ps_delete(stb_ps *ps) void stb_ps_delete(stb_ps *ps)
{ {
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: break; case STB_ps_direct: break;
case STB_ps_bucket: stb_bucket_free(GetBucket(ps)); break; case STB_ps_bucket: stb_bucket_free(GetBucket(ps)); break;
case STB_ps_array : free(GetArray(ps)); break; case STB_ps_array : free(GetArray(ps)); break;
@ -7650,7 +7726,7 @@ stb_ps *stb_ps_copy(stb_ps *ps)
{ {
int i; int i;
// not a switch: order based on expected performance/power-law distribution // not a switch: order based on expected performance/power-law distribution
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: return ps; case STB_ps_direct: return ps;
case STB_ps_bucket: { case STB_ps_bucket: {
stb_ps_bucket *n = (stb_ps_bucket *) malloc(sizeof(*n)); stb_ps_bucket *n = (stb_ps_bucket *) malloc(sizeof(*n));
@ -7677,8 +7753,8 @@ stb_ps *stb_ps_copy(stb_ps *ps)
int stb_ps_find(stb_ps *ps, void *value) int stb_ps_find(stb_ps *ps, void *value)
{ {
int i, code = 3 & (int) ps; int i, code = 3 & (int)(size_t) ps;
assert((3 & (int) value) == STB_ps_direct); assert((3 & (int)(size_t) value) == STB_ps_direct);
assert(stb_ps_fastlist_valid(value)); assert(stb_ps_fastlist_valid(value));
// not a switch: order based on expected performance/power-law distribution // not a switch: order based on expected performance/power-law distribution
if (code == STB_ps_direct) if (code == STB_ps_direct)
@ -7719,11 +7795,11 @@ stb_ps * stb_ps_add (stb_ps *ps, void *value)
assert(!stb_ps_find(ps,value)); assert(!stb_ps_find(ps,value));
#endif #endif
if (value == NULL) return ps; // ignore NULL adds to avoid bad breakage if (value == NULL) return ps; // ignore NULL adds to avoid bad breakage
assert((3 & (int) value) == STB_ps_direct); assert((3 & (int)(size_t) value) == STB_ps_direct);
assert(stb_ps_fastlist_valid(value)); assert(stb_ps_fastlist_valid(value));
assert(value != STB_DEL); // STB_DEL is less likely assert(value != STB_DEL); // STB_DEL is less likely
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) return (stb_ps *) value; if (ps == NULL) return (stb_ps *) value;
return EncodeBucket(stb_bucket_create2(ps,value)); return EncodeBucket(stb_bucket_create2(ps,value));
@ -7772,11 +7848,11 @@ stb_ps * stb_ps_add (stb_ps *ps, void *value)
stb_uint32 n = hash & h->mask; stb_uint32 n = hash & h->mask;
void **t = h->table; void **t = h->table;
// find first NULL or STB_DEL entry // find first NULL or STB_DEL entry
if (!stb_ps_empty(t[n])) { if (!stb_ps_empty((size_t)t[n])) {
stb_uint32 s = stb_rehash(hash) | 1; stb_uint32 s = stb_rehash(hash) | 1;
do { do {
n = (n + s) & h->mask; n = (n + s) & h->mask;
} while (!stb_ps_empty(t[n])); } while (!stb_ps_empty((size_t)t[n]));
} }
if (t[n] == STB_DEL) if (t[n] == STB_DEL)
-- h->count_deletes; -- h->count_deletes;
@ -7803,9 +7879,9 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value)
#ifdef STB_DEBUG #ifdef STB_DEBUG
assert(stb_ps_find(ps, value)); assert(stb_ps_find(ps, value));
#endif #endif
assert((3 & (int) value) == STB_ps_direct); assert((3 & (int)(size_t) value) == STB_ps_direct);
if (value == NULL) return ps; // ignore NULL removes to avoid bad breakage if (value == NULL) return ps; // ignore NULL removes to avoid bad breakage
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
return ps == value ? NULL : ps; return ps == value ? NULL : ps;
case STB_ps_bucket: { case STB_ps_bucket: {
@ -7864,7 +7940,7 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value)
stb_ps_array *a = (stb_ps_array *) malloc(sizeof(*a) + (n-1) * sizeof(a->p[0])); stb_ps_array *a = (stb_ps_array *) malloc(sizeof(*a) + (n-1) * sizeof(a->p[0]));
int i,j=0; int i,j=0;
for (i=0; i < h->size; ++i) for (i=0; i < h->size; ++i)
if (!stb_ps_empty(t[i])) if (!stb_ps_empty((size_t)t[i]))
a->p[j++] = t[i]; a->p[j++] = t[i];
assert(j == h->count); assert(j == h->count);
a->count = j; a->count = j;
@ -7886,7 +7962,7 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value)
stb_ps *stb_ps_remove_any(stb_ps *ps, void **value) stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
{ {
assert(ps != NULL); assert(ps != NULL);
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
*value = ps; *value = ps;
return NULL; return NULL;
@ -7919,7 +7995,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
void **t = h->table; void **t = h->table;
stb_uint32 n = h->any_offset; stb_uint32 n = h->any_offset;
while (stb_ps_empty(t[n])) while (stb_ps_empty((size_t)t[n]))
n = (n + 1) & h->mask; n = (n + 1) & h->mask;
*value = t[n]; *value = t[n];
h->any_offset = (n+1) & h->mask; h->any_offset = (n+1) & h->mask;
@ -7940,7 +8016,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count)
{ {
int i,n=0; int i,n=0;
void **p = NULL; void **p = NULL;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) { *count = 0; return NULL; } if (ps == NULL) { *count = 0; return NULL; }
p = (void **) malloc(sizeof(*p) * 1); p = (void **) malloc(sizeof(*p) * 1);
@ -7966,7 +8042,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count)
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
p = (void **) malloc(sizeof(*p) * h->count); p = (void **) malloc(sizeof(*p) * h->count);
for (i=0; i < h->size; ++i) for (i=0; i < h->size; ++i)
if (!stb_ps_empty(h->table[i])) if (!stb_ps_empty((size_t)h->table[i]))
p[n++] = h->table[i]; p[n++] = h->table[i];
break; break;
} }
@ -7978,7 +8054,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count)
int stb_ps_writelist(stb_ps *ps, void **list, int size ) int stb_ps_writelist(stb_ps *ps, void **list, int size )
{ {
int i,n=0; int i,n=0;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL || size <= 0) return 0; if (ps == NULL || size <= 0) return 0;
list[0] = ps; list[0] = ps;
@ -8000,7 +8076,7 @@ int stb_ps_writelist(stb_ps *ps, void **list, int size )
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
if (size <= 0) return 0; if (size <= 0) return 0;
for (i=0; i < h->count; ++i) { for (i=0; i < h->count; ++i) {
if (!stb_ps_empty(h->table[i])) { if (!stb_ps_empty((size_t)h->table[i])) {
list[n++] = h->table[i]; list[n++] = h->table[i];
if (n == size) break; if (n == size) break;
} }
@ -8014,7 +8090,7 @@ int stb_ps_writelist(stb_ps *ps, void **list, int size )
int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data)) int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data))
{ {
int i; int i;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) return STB_TRUE; if (ps == NULL) return STB_TRUE;
return func(ps, data); return func(ps, data);
@ -8036,7 +8112,7 @@ int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data))
case STB_ps_hash: { case STB_ps_hash: {
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
for (i=0; i < h->count; ++i) for (i=0; i < h->count; ++i)
if (!stb_ps_empty(h->table[i])) if (!stb_ps_empty((size_t)h->table[i]))
if (!func(h->table[i], data)) if (!func(h->table[i], data))
return STB_FALSE; return STB_FALSE;
return STB_TRUE; return STB_TRUE;
@ -8047,7 +8123,7 @@ int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data))
int stb_ps_count (stb_ps *ps) int stb_ps_count (stb_ps *ps)
{ {
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
return ps != NULL; return ps != NULL;
case STB_ps_bucket: { case STB_ps_bucket: {
@ -8071,7 +8147,7 @@ void ** stb_ps_fastlist(stb_ps *ps, int *count)
{ {
static void *storage; static void *storage;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) { *count = 0; return NULL; } if (ps == NULL) { *count = 0; return NULL; }
storage = ps; storage = ps;
@ -9118,7 +9194,7 @@ static void stb__add_epsilon(stb_matcher *matcher, int from, int to)
static void stb__add_edge(stb_matcher *matcher, int from, int to, int type) static void stb__add_edge(stb_matcher *matcher, int from, int to, int type)
{ {
stb_nfa_edge z = { type, to }; stb_nfa_edge z = { (stb_int16)type, (stb_uint16)to };
if (matcher->nodes[from].out == NULL) if (matcher->nodes[from].out == NULL)
stb_arr_malloc((void **) &matcher->nodes[from].out, matcher); stb_arr_malloc((void **) &matcher->nodes[from].out, matcher);
stb_arr_push(matcher->nodes[from].out, z); stb_arr_push(matcher->nodes[from].out, z);
@ -9831,7 +9907,7 @@ int stb_regex(char *regex, char *str)
static char ** regexps; static char ** regexps;
static char ** regexp_cache; static char ** regexp_cache;
static unsigned short *mapping; static unsigned short *mapping;
int z = stb_perfect_hash(&p, (int) regex); int z = stb_perfect_hash(&p, (int)(size_t) regex);
if (z >= 0) { if (z >= 0) {
if (strcmp(regex, regexp_cache[(int) mapping[z]])) { if (strcmp(regex, regexp_cache[(int) mapping[z]])) {
int i = mapping[z]; int i = mapping[z];
@ -9862,8 +9938,8 @@ int stb_regex(char *regex, char *str)
n = stb_perfect_create(&p, (unsigned int *) (char **) regexps, stb_arr_len(regexps)); n = stb_perfect_create(&p, (unsigned int *) (char **) regexps, stb_arr_len(regexps));
mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping)); mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping));
for (i=0; i < stb_arr_len(regexps); ++i) for (i=0; i < stb_arr_len(regexps); ++i)
mapping[stb_perfect_hash(&p, (int) regexps[i])] = i; mapping[stb_perfect_hash(&p, (int)(size_t) regexps[i])] = i;
z = stb_perfect_hash(&p, (int) regex); z = stb_perfect_hash(&p, (int)(size_t) regex);
} }
return stb_matcher_find(matchers[(int) mapping[z]], str); return stb_matcher_find(matchers[(int) mapping[z]], str);
} }
@ -10357,7 +10433,7 @@ static void stb__write(unsigned char v)
++stb__outbytes; ++stb__outbytes;
} }
#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v))) #define stb_out(v) (stb__out ? (void)(*stb__out++ = (stb_uchar) (v)) : stb__write((stb_uchar) (v)))
static void stb_out2(stb_uint v) static void stb_out2(stb_uint v)
{ {
@ -10620,7 +10696,8 @@ static size_t stb_out_backpatch_id(void)
static void stb_out_backpatch(size_t id, stb_uint value) static void stb_out_backpatch(size_t id, stb_uint value)
{ {
stb_uchar data[4] = { value >> 24, value >> 16, value >> 8, value };
stb_uchar data[4] = { (stb_uchar)(value >> 24), (stb_uchar)(value >> 16), (stb_uchar)(value >> 8), (stb_uchar)(value) };
if (stb__out) { if (stb__out) {
memcpy((void *) id, data, 4); memcpy((void *) id, data, 4);
} else { } else {

View File

@ -1,4 +1,4 @@
// stb_dxt.h - v1.07 - DXT1/DXT5 compressor - public domain // stb_dxt.h - v1.08b - DXT1/DXT5 compressor - public domain
// original by fabian "ryg" giesen - ported to C by stb // original by fabian "ryg" giesen - ported to C by stb
// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation // use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation
// //
@ -9,7 +9,8 @@
// and "high quality" using mode. // and "high quality" using mode.
// //
// version history: // version history:
// v1.07 - bc4; allow not using libc; add STB_DXT_STATIC // v1.08 - (sbt) fix bug in dxt-with-alpha block
// v1.07 - (stb) bc4; allow not using libc; add STB_DXT_STATIC
// v1.06 - (stb) fix to known-broken 1.05 // v1.06 - (stb) fix to known-broken 1.05
// v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski) // v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski)
// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec); // v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec);
@ -31,11 +32,6 @@
#ifndef STB_INCLUDE_STB_DXT_H #ifndef STB_INCLUDE_STB_DXT_H
#define STB_INCLUDE_STB_DXT_H #define STB_INCLUDE_STB_DXT_H
// compression mode (bitflags)
#define STB_DXT_NORMAL 0
#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like!
#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower.
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -46,15 +42,21 @@ extern "C" {
#define STBDDEF extern #define STBDDEF extern
#endif #endif
// compression mode (bitflags)
#define STB_DXT_NORMAL 0
#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like!
#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower.
STBDDEF void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode); STBDDEF void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode);
STBDDEF void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src_r_one_byte_per_pixel); STBDDEF void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src_r_one_byte_per_pixel);
STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel); STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel);
#define STB_COMPRESS_DXT_BLOCK
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif // STB_INCLUDE_STB_DXT_H
#define STB_COMPRESS_DXT_BLOCK
#ifdef STB_DXT_IMPLEMENTATION #ifdef STB_DXT_IMPLEMENTATION
@ -88,7 +90,7 @@ STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *sr
#ifndef STBD_MEMSET #ifndef STBD_MEMSET
#include <string.h> #include <string.h>
#define STBD_MEMSET(x) memset(x) #define STBD_MEMSET memset
#endif #endif
static unsigned char stb__Expand5[32]; static unsigned char stb__Expand5[32];
@ -649,6 +651,7 @@ static void stb__InitDXT()
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode) void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode)
{ {
unsigned char data[16][4];
static int init=1; static int init=1;
if (init) { if (init) {
stb__InitDXT(); stb__InitDXT();
@ -656,8 +659,15 @@ void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int a
} }
if (alpha) { if (alpha) {
int i;
stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4); stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4);
dest += 8; dest += 8;
// make a new copy of the data in which alpha is opaque,
// because code uses a fast test for color constancy
memcpy(data, src, 4*16);
for (i=0; i < 16; ++i)
data[i][3] = 255;
src = &data[0][0];
} }
stb__CompressColorBlock(dest,(unsigned char*) src,mode); stb__CompressColorBlock(dest,(unsigned char*) src,mode);
@ -674,7 +684,6 @@ void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src)
stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2); stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2);
} }
#endif // STB_DXT_IMPLEMENTATION #endif // STB_DXT_IMPLEMENTATION
#endif // STB_INCLUDE_STB_DXT_H
/* /*
------------------------------------------------------------------------------ ------------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h /* stb_image - v2.19 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@ -48,6 +48,9 @@ LICENSE
RECENT REVISION HISTORY: RECENT REVISION HISTORY:
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
@ -74,11 +77,11 @@ RECENT REVISION HISTORY:
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
github:urraka (animated gif) Junggon Kim (PNM comments) github:urraka (animated gif) Junggon Kim (PNM comments)
Daniel Gibson (16-bit TGA) Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
socks-the-fox (16-bit PNG) socks-the-fox (16-bit PNG)
Jeremy Sawicki (handle all ImageNet JPGs) Jeremy Sawicki (handle all ImageNet JPGs)
Optimizations & bugfixes Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
Fabian "ryg" Giesen Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
Arseny Kapoulkine Arseny Kapoulkine
John-Mark Allen John-Mark Allen
@ -87,16 +90,17 @@ RECENT REVISION HISTORY:
Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan
Dave Moore Roy Eltham Hayaki Saito Nathan Reed Dave Moore Roy Eltham Hayaki Saito Nathan Reed
Won Chun Luke Graham Johan Duparc Nick Verigakis Won Chun Luke Graham Johan Duparc Nick Verigakis
the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh
Janez Zemva John Bartholomew Michal Cichon github:rlyeh Janez Zemva John Bartholomew Michal Cichon github:romigrou
Jonathan Blow Ken Hamada Tero Hanninen github:romigrou Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar
Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex
Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex Ryamond Barbiero Paul Du Bois Engin Manap github:grim210
Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210 Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus
Blazej Dariusz Roszkowski Gregory Mullen github:phprus Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo
Christian Floisand Kevin Schmidt github:poppolopoppo Christian Floisand Kevin Schmidt github:darealshinji
Blazej Dariusz Roszkowski github:Michaelangel007
*/ */
#ifndef STBI_INCLUDE_STB_IMAGE_H #ifndef STBI_INCLUDE_STB_IMAGE_H
@ -105,10 +109,8 @@ RECENT REVISION HISTORY:
// DOCUMENTATION // DOCUMENTATION
// //
// Limitations: // Limitations:
// - no 16-bit-per-channel PNG
// - no 12-bit-per-channel JPEG // - no 12-bit-per-channel JPEG
// - no JPEGs with arithmetic coding // - no JPEGs with arithmetic coding
// - no 1-bit BMP
// - GIF always returns *comp=4 // - GIF always returns *comp=4
// //
// Basic usage (see HDR discussion below for HDR usage): // Basic usage (see HDR discussion below for HDR usage):
@ -353,6 +355,10 @@ typedef struct
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_GIF
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
#endif
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
@ -416,11 +422,14 @@ STBIDEF void stbi_image_free (void *retval_from_stbi_load);
// get image dimensions & components without fully decoding // get image dimensions & components without fully decoding
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit (char const *filename);
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
#endif #endif
@ -504,7 +513,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#include <limits.h> #include <limits.h>
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
#include <math.h> // ldexp #include <math.h> // ldexp, pow
#endif #endif
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
@ -784,6 +793,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__png_test(stbi__context *s); static int stbi__png_test(stbi__context *s);
static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__png_is16(stbi__context *s);
#endif #endif
#ifndef STBI_NO_BMP #ifndef STBI_NO_BMP
@ -802,6 +812,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__psd_test(stbi__context *s); static int stbi__psd_test(stbi__context *s);
static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__psd_is16(stbi__context *s);
#endif #endif
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
@ -819,6 +830,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
#ifndef STBI_NO_GIF #ifndef STBI_NO_GIF
static int stbi__gif_test(stbi__context *s); static int stbi__gif_test(stbi__context *s);
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
#endif #endif
@ -893,11 +905,13 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add)
} }
// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
{ {
return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
} }
#endif
// mallocs with size overflow checking // mallocs with size overflow checking
static void *stbi__malloc_mad2(int a, int b, int add) static void *stbi__malloc_mad2(int a, int b, int add)
@ -912,11 +926,13 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add)
return stbi__malloc(a*b*c + add); return stbi__malloc(a*b*c + add);
} }
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
{ {
if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
return stbi__malloc(a*b*c*d + add); return stbi__malloc(a*b*c*d + add);
} }
#endif
// stbi__err - error // stbi__err - error
// stbi__errpf - error returning pointer to float // stbi__errpf - error returning pointer to float
@ -1054,6 +1070,18 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
} }
} }
static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
{
int slice;
int slice_size = w * h * bytes_per_pixel;
stbi_uc *bytes = (stbi_uc *)image;
for (slice = 0; slice < z; ++slice) {
stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
bytes += slice_size;
}
}
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{ {
stbi__result_info ri; stbi__result_info ri;
@ -1103,7 +1131,7 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
return (stbi__uint16 *) result; return (stbi__uint16 *) result;
} }
#ifndef STBI_NO_HDR #if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR)
static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
{ {
if (stbi__vertically_flip_on_load && result != NULL) { if (stbi__vertically_flip_on_load && result != NULL) {
@ -1205,6 +1233,22 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
} }
#ifndef STBI_NO_GIF
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
{
unsigned char *result;
stbi__context s;
stbi__start_mem(&s,buffer,len);
result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
if (stbi__vertically_flip_on_load) {
stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
}
return result;
}
#endif
#ifndef STBI_NO_LINEAR #ifndef STBI_NO_LINEAR
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{ {
@ -1291,9 +1335,13 @@ STBIDEF int stbi_is_hdr (char const *filename)
STBIDEF int stbi_is_hdr_from_file(FILE *f) STBIDEF int stbi_is_hdr_from_file(FILE *f)
{ {
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
long pos = ftell(f);
int res;
stbi__context s; stbi__context s;
stbi__start_file(&s,f); stbi__start_file(&s,f);
return stbi__hdr_test(&s); res = stbi__hdr_test(&s);
fseek(f, pos, SEEK_SET);
return res;
#else #else
STBI_NOTUSED(f); STBI_NOTUSED(f);
return 0; return 0;
@ -1705,7 +1753,8 @@ typedef struct
static int stbi__build_huffman(stbi__huffman *h, int *count) static int stbi__build_huffman(stbi__huffman *h, int *count)
{ {
int i,j,k=0,code; int i,j,k=0;
unsigned int code;
// build size list for each symbol (from JPEG spec) // build size list for each symbol (from JPEG spec)
for (i=0; i < 16; ++i) for (i=0; i < 16; ++i)
for (j=0; j < count[i]; ++j) for (j=0; j < count[i]; ++j)
@ -1721,7 +1770,7 @@ static int stbi__build_huffman(stbi__huffman *h, int *count)
if (h->size[k] == j) { if (h->size[k] == j) {
while (h->size[k] == j) while (h->size[k] == j)
h->code[k++] = (stbi__uint16) (code++); h->code[k++] = (stbi__uint16) (code++);
if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
} }
// compute largest code + 1 for this size, preshifted as needed later // compute largest code + 1 for this size, preshifted as needed later
h->maxcode[j] = code << (16-j); h->maxcode[j] = code << (16-j);
@ -1765,7 +1814,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
if (k < m) k += (~0U << magbits) + 1; if (k < m) k += (~0U << magbits) + 1;
// if the result is small enough, we can fit it in fast_ac table // if the result is small enough, we can fit it in fast_ac table
if (k >= -128 && k <= 127) if (k >= -128 && k <= 127)
fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
} }
} }
} }
@ -1774,7 +1823,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
static void stbi__grow_buffer_unsafe(stbi__jpeg *j) static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
{ {
do { do {
int b = j->nomore ? 0 : stbi__get8(j->s); unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
if (b == 0xff) { if (b == 0xff) {
int c = stbi__get8(j->s); int c = stbi__get8(j->s);
while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
@ -1790,7 +1839,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
} }
// (1 << n) - 1 // (1 << n) - 1
static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
// decode a jpeg huffman value from the bitstream // decode a jpeg huffman value from the bitstream
stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
@ -1843,7 +1892,7 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
} }
// bias[n] = (-1<<n) + 1 // bias[n] = (-1<<n) + 1
static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767}; static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
// combined JPEG 'receive' and JPEG 'extend', since baseline // combined JPEG 'receive' and JPEG 'extend', since baseline
// always extends everything it receives. // always extends everything it receives.
@ -1886,7 +1935,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
// given a value that's at position X in the zigzag stream, // given a value that's at position X in the zigzag stream,
// where does it appear in the 8x8 matrix coded as row-major? // where does it appear in the 8x8 matrix coded as row-major?
static stbi_uc stbi__jpeg_dezigzag[64+15] = static const stbi_uc stbi__jpeg_dezigzag[64+15] =
{ {
0, 1, 8, 16, 9, 2, 3, 10, 0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5, 17, 24, 32, 25, 18, 11, 4, 5,
@ -2112,7 +2161,7 @@ stbi_inline static stbi_uc stbi__clamp(int x)
} }
#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) #define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
#define stbi__fsh(x) ((x) << 12) #define stbi__fsh(x) ((x) * 4096)
// derived from jidctint -- DCT_ISLOW // derived from jidctint -- DCT_ISLOW
#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ #define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
@ -2167,7 +2216,7 @@ static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
// (1|2|3|4|5|6|7)==0 0 seconds // (1|2|3|4|5|6|7)==0 0 seconds
// all separate -0.047 seconds // all separate -0.047 seconds
// 1 && 2|3 && 4|5 && 6|7: -0.047 seconds // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
int dcterm = d[0] << 2; int dcterm = d[0]*4;
v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
} else { } else {
STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
@ -2968,7 +3017,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
z->rgb = 0; z->rgb = 0;
for (i=0; i < s->img_n; ++i) { for (i=0; i < s->img_n; ++i) {
static unsigned char rgb[3] = { 'R', 'G', 'B' }; static const unsigned char rgb[3] = { 'R', 'G', 'B' };
z->img_comp[i].id = stbi__get8(s); z->img_comp[i].id = stbi__get8(s);
if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
++z->rgb; ++z->rgb;
@ -3093,8 +3142,8 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
} else if (stbi__DNL(m)) { } else if (stbi__DNL(m)) {
int Ld = stbi__get16be(j->s); int Ld = stbi__get16be(j->s);
stbi__uint32 NL = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s);
if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG"); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
} else { } else {
if (!stbi__process_marker(j, m)) return 0; if (!stbi__process_marker(j, m)) return 0;
} }
@ -3912,18 +3961,18 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room
return 1; return 1;
} }
static int stbi__zlength_base[31] = { static const int stbi__zlength_base[31] = {
3,4,5,6,7,8,9,10,11,13, 3,4,5,6,7,8,9,10,11,13,
15,17,19,23,27,31,35,43,51,59, 15,17,19,23,27,31,35,43,51,59,
67,83,99,115,131,163,195,227,258,0,0 }; 67,83,99,115,131,163,195,227,258,0,0 };
static int stbi__zlength_extra[31]= static const int stbi__zlength_extra[31]=
{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
static int stbi__zdist_extra[32] = static const int stbi__zdist_extra[32] =
{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
static int stbi__parse_huffman_block(stbi__zbuf *a) static int stbi__parse_huffman_block(stbi__zbuf *a)
@ -3970,7 +4019,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
static int stbi__compute_huffman_codes(stbi__zbuf *a) static int stbi__compute_huffman_codes(stbi__zbuf *a)
{ {
static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
stbi__zhuffman z_codelength; stbi__zhuffman z_codelength;
stbi_uc lencodes[286+32+137];//padding for maximum single op stbi_uc lencodes[286+32+137];//padding for maximum single op
stbi_uc codelength_sizes[19]; stbi_uc codelength_sizes[19];
@ -4229,7 +4278,7 @@ static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
static int stbi__check_png_header(stbi__context *s) static int stbi__check_png_header(stbi__context *s)
{ {
static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
int i; int i;
for (i=0; i < 8; ++i) for (i=0; i < 8; ++i)
if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
@ -4275,7 +4324,7 @@ static int stbi__paeth(int a, int b, int c)
return c; return c;
} }
static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
// create the png data from post-deflated data // create the png data from post-deflated data
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
@ -4295,8 +4344,10 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
if (!a->out) return stbi__err("outofmem", "Out of memory"); if (!a->out) return stbi__err("outofmem", "Out of memory");
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
img_width_bytes = (((img_n * x * depth) + 7) >> 3); img_width_bytes = (((img_n * x * depth) + 7) >> 3);
img_len = (img_width_bytes + 1) * y; img_len = (img_width_bytes + 1) * y;
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs, // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
// but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
// so just check for raw_len < img_len always. // so just check for raw_len < img_len always.
@ -4675,7 +4726,7 @@ static void stbi__de_iphone(stbi__png *z)
} }
} }
#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) #define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
{ {
@ -4912,6 +4963,19 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
p.s = s; p.s = s;
return stbi__png_info_raw(&p, x, y, comp); return stbi__png_info_raw(&p, x, y, comp);
} }
static int stbi__png_is16(stbi__context *s)
{
stbi__png p;
p.s = s;
if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
return 0;
if (p.depth != 16) {
stbi__rewind(p.s);
return 0;
}
return 1;
}
#endif #endif
// Microsoft/Windows BMP image // Microsoft/Windows BMP image
@ -4963,21 +5027,27 @@ static int stbi__bitcount(unsigned int a)
return a & 0xff; return a & 0xff;
} }
// extract an arbitrarily-aligned N-bit value (N=bits)
// from v, and then make it 8-bits long and fractionally
// extend it to full full range.
static int stbi__shiftsigned(int v, int shift, int bits) static int stbi__shiftsigned(int v, int shift, int bits)
{ {
int result; static unsigned int mul_table[9] = {
int z=0; 0,
0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
if (shift < 0) v <<= -shift; 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
else v >>= shift; };
result = v; static unsigned int shift_table[9] = {
0, 0,0,1,0,2,4,6,0,
z = bits; };
while (z < 8) { if (shift < 0)
result += v >> z; v <<= -shift;
z += bits; else
} v >>= shift;
return result; STBI_ASSERT(v >= 0 && v < 256);
v >>= (8-bits);
STBI_ASSERT(bits >= 0 && bits <= 8);
return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
} }
typedef struct typedef struct
@ -5007,7 +5077,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
} }
if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
info->bpp = stbi__get16le(s); info->bpp = stbi__get16le(s);
if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
if (hsz != 12) { if (hsz != 12) {
int compress = stbi__get32le(s); int compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
@ -5125,10 +5194,27 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
pal[i][3] = 255; pal[i][3] = 255;
} }
stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
if (info.bpp == 4) width = (s->img_x + 1) >> 1; if (info.bpp == 1) width = (s->img_x + 7) >> 3;
else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
else if (info.bpp == 8) width = s->img_x; else if (info.bpp == 8) width = s->img_x;
else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
pad = (-width)&3; pad = (-width)&3;
if (info.bpp == 1) {
for (j=0; j < (int) s->img_y; ++j) {
int bit_offset = 7, v = stbi__get8(s);
for (i=0; i < (int) s->img_x; ++i) {
int color = (v>>bit_offset)&0x1;
out[z++] = pal[color][0];
out[z++] = pal[color][1];
out[z++] = pal[color][2];
if((--bit_offset) < 0) {
bit_offset = 7;
v = stbi__get8(s);
}
}
stbi__skip(s, pad);
}
} else {
for (j=0; j < (int) s->img_y; ++j) { for (j=0; j < (int) s->img_y; ++j) {
for (i=0; i < (int) s->img_x; i += 2) { for (i=0; i < (int) s->img_x; i += 2) {
int v=stbi__get8(s),v2=0; int v=stbi__get8(s),v2=0;
@ -5149,6 +5235,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
} }
stbi__skip(s, pad); stbi__skip(s, pad);
} }
}
} else { } else {
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0; int z = 0;
@ -5188,7 +5275,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
int bpp = info.bpp; int bpp = info.bpp;
for (i=0; i < (int) s->img_x; ++i) { for (i=0; i < (int) s->img_x; ++i) {
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
int a; unsigned int a;
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
@ -5236,14 +5323,14 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
{ {
// only RGB or RGBA (incl. 16bit) or grey allowed // only RGB or RGBA (incl. 16bit) or grey allowed
if(is_rgb16) *is_rgb16 = 0; if (is_rgb16) *is_rgb16 = 0;
switch(bits_per_pixel) { switch(bits_per_pixel) {
case 8: return STBI_grey; case 8: return STBI_grey;
case 16: if(is_grey) return STBI_grey_alpha; case 16: if(is_grey) return STBI_grey_alpha;
// else: fall-through // fallthrough
case 15: if(is_rgb16) *is_rgb16 = 1; case 15: if(is_rgb16) *is_rgb16 = 1;
return STBI_rgb; return STBI_rgb;
case 24: // fall-through case 24: // fallthrough
case 32: return bits_per_pixel/8; case 32: return bits_per_pixel/8;
default: return 0; default: return 0;
} }
@ -6038,11 +6125,13 @@ typedef struct
typedef struct typedef struct
{ {
int w,h; int w,h;
stbi_uc *out, *old_out; // output buffer (always 4 components) stbi_uc *out; // output buffer (always 4 components)
int flags, bgindex, ratio, transparent, eflags, delay; stbi_uc *background; // The current "background" as far as a gif is concerned
stbi_uc *history;
int flags, bgindex, ratio, transparent, eflags;
stbi_uc pal[256][4]; stbi_uc pal[256][4];
stbi_uc lpal[256][4]; stbi_uc lpal[256][4];
stbi__gif_lzw codes[4096]; stbi__gif_lzw codes[8192];
stbi_uc *color_table; stbi_uc *color_table;
int parse, step; int parse, step;
int lflags; int lflags;
@ -6050,6 +6139,7 @@ typedef struct
int max_x, max_y; int max_x, max_y;
int cur_x, cur_y; int cur_x, cur_y;
int line_size; int line_size;
int delay;
} stbi__gif; } stbi__gif;
static int stbi__gif_test_raw(stbi__context *s) static int stbi__gif_test_raw(stbi__context *s)
@ -6125,6 +6215,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
{ {
stbi_uc *p, *c; stbi_uc *p, *c;
int idx;
// recurse to decode the prefixes, since the linked-list is backwards, // recurse to decode the prefixes, since the linked-list is backwards,
// and working backwards through an interleaved image would be nasty // and working backwards through an interleaved image would be nasty
@ -6133,10 +6224,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
if (g->cur_y >= g->max_y) return; if (g->cur_y >= g->max_y) return;
p = &g->out[g->cur_x + g->cur_y]; idx = g->cur_x + g->cur_y;
c = &g->color_table[g->codes[code].suffix * 4]; p = &g->out[idx];
g->history[idx / 4] = 1;
if (c[3] >= 128) { c = &g->color_table[g->codes[code].suffix * 4];
if (c[3] > 128) { // don't render transparent pixels;
p[0] = c[2]; p[0] = c[2];
p[1] = c[1]; p[1] = c[1];
p[2] = c[0]; p[2] = c[0];
@ -6210,11 +6303,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
stbi__skip(s,len); stbi__skip(s,len);
return g->out; return g->out;
} else if (code <= avail) { } else if (code <= avail) {
if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); if (first) {
return stbi__errpuc("no clear code", "Corrupt GIF");
}
if (oldcode >= 0) { if (oldcode >= 0) {
p = &g->codes[avail++]; p = &g->codes[avail++];
if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); if (avail > 8192) {
return stbi__errpuc("too many codes", "Corrupt GIF");
}
p->prefix = (stbi__int16) oldcode; p->prefix = (stbi__int16) oldcode;
p->first = g->codes[oldcode].first; p->first = g->codes[oldcode].first;
p->suffix = (code == avail) ? p->first : g->codes[code].first; p->suffix = (code == avail) ? p->first : g->codes[code].first;
@ -6236,62 +6334,72 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
} }
} }
static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
{
int x, y;
stbi_uc *c = g->pal[g->bgindex];
for (y = y0; y < y1; y += 4 * g->w) {
for (x = x0; x < x1; x += 4) {
stbi_uc *p = &g->out[y + x];
p[0] = c[2];
p[1] = c[1];
p[2] = c[0];
p[3] = 0;
}
}
}
// this function is designed to support animated gifs, although stb_image doesn't support it // this function is designed to support animated gifs, although stb_image doesn't support it
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) // two back is the image from two frames ago, used for a very specific disposal format
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
{ {
int i; int dispose;
stbi_uc *prev_out = 0; int first_frame;
int pi;
int pcount;
if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) // on first frame, any non-written pixels get the background colour (non-transparent)
return 0; // stbi__g_failure_reason set by stbi__gif_header first_frame = 0;
if (g->out == 0) {
if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0)) if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
return stbi__errpuc("too large", "GIF too large"); g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
prev_out = g->out; g->history = (stbi_uc *) stbi__malloc(g->w * g->h);
g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
switch ((g->eflags & 0x1C) >> 2) { // image is treated as "tranparent" at the start - ie, nothing overwrites the current background;
case 0: // unspecified (also always used on 1st frame) // background colour is only used for pixels that are not rendered first frame, after that "background"
stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); // color refers to teh color that was there the previous frame.
break; memset( g->out, 0x00, 4 * g->w * g->h );
case 1: // do not dispose memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent)
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
g->old_out = prev_out; first_frame = 1;
break; } else {
case 2: // dispose to background // second frame - how do we dispoase of the previous one?
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); dispose = (g->eflags & 0x1C) >> 2;
stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); pcount = g->w * g->h;
break;
case 3: // dispose to previous if ((dispose == 3) && (two_back == 0)) {
if (g->old_out) { dispose = 2; // if I don't have an image to revert back to, default to the old background
for (i = g->start_y; i < g->max_y; i += 4 * g->w)
memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
}
break;
} }
if (dispose == 3) { // use previous graphic
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) {
memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
}
}
} else if (dispose == 2) {
// restore what was changed last frame to background before that frame;
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) {
memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
}
}
} else {
// This is a non-disposal case eithe way, so just
// leave the pixels as is, and they will become the new background
// 1: do not dispose
// 0: not specified.
}
// background is what out is after the undoing of the previou frame;
memcpy( g->background, g->out, 4 * g->w * g->h );
}
// clear my history;
memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
for (;;) { for (;;) {
switch (stbi__get8(s)) { int tag = stbi__get8(s);
switch (tag) {
case 0x2C: /* Image Descriptor */ case 0x2C: /* Image Descriptor */
{ {
int prev_trans = -1;
stbi__int32 x, y, w, h; stbi__int32 x, y, w, h;
stbi_uc *o; stbi_uc *o;
@ -6324,10 +6432,6 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
g->color_table = (stbi_uc *) g->lpal; g->color_table = (stbi_uc *) g->lpal;
} else if (g->flags & 0x80) { } else if (g->flags & 0x80) {
if (g->transparent >= 0 && (g->eflags & 0x01)) {
prev_trans = g->pal[g->transparent][3];
g->pal[g->transparent][3] = 0;
}
g->color_table = (stbi_uc *) g->pal; g->color_table = (stbi_uc *) g->pal;
} else } else
return stbi__errpuc("missing color table", "Corrupt GIF"); return stbi__errpuc("missing color table", "Corrupt GIF");
@ -6335,8 +6439,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
o = stbi__process_gif_raster(s, g); o = stbi__process_gif_raster(s, g);
if (o == NULL) return NULL; if (o == NULL) return NULL;
if (prev_trans != -1) // if this was the first frame,
g->pal[g->transparent][3] = (stbi_uc) prev_trans; pcount = g->w * g->h;
if (first_frame && (g->bgindex > 0)) {
// if first frame, any pixel not drawn to gets the background color
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi] == 0) {
g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
}
}
}
return o; return o;
} }
@ -6344,19 +6457,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
case 0x21: // Comment Extension. case 0x21: // Comment Extension.
{ {
int len; int len;
if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. int ext = stbi__get8(s);
if (ext == 0xF9) { // Graphic Control Extension.
len = stbi__get8(s); len = stbi__get8(s);
if (len == 4) { if (len == 4) {
g->eflags = stbi__get8(s); g->eflags = stbi__get8(s);
g->delay = stbi__get16le(s); g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
// unset old transparent
if (g->transparent >= 0) {
g->pal[g->transparent][3] = 255;
}
if (g->eflags & 0x01) {
g->transparent = stbi__get8(s); g->transparent = stbi__get8(s);
if (g->transparent >= 0) {
g->pal[g->transparent][3] = 0;
}
} else {
// don't need transparent
stbi__skip(s, 1);
g->transparent = -1;
}
} else { } else {
stbi__skip(s, len); stbi__skip(s, len);
break; break;
} }
} }
while ((len = stbi__get8(s)) != 0) while ((len = stbi__get8(s)) != 0) {
stbi__skip(s, len); stbi__skip(s, len);
}
break; break;
} }
@ -6367,28 +6496,92 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
return stbi__errpuc("unknown code", "Corrupt GIF"); return stbi__errpuc("unknown code", "Corrupt GIF");
} }
} }
}
STBI_NOTUSED(req_comp); static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
{
if (stbi__gif_test(s)) {
int layers = 0;
stbi_uc *u = 0;
stbi_uc *out = 0;
stbi_uc *two_back = 0;
stbi__gif g;
int stride;
memset(&g, 0, sizeof(g));
if (delays) {
*delays = 0;
}
do {
u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
if (u) {
*x = g.w;
*y = g.h;
++layers;
stride = g.w * g.h * 4;
if (out) {
out = (stbi_uc*) STBI_REALLOC( out, layers * stride );
if (delays) {
*delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers );
}
} else {
out = (stbi_uc*)stbi__malloc( layers * stride );
if (delays) {
*delays = (int*) stbi__malloc( layers * sizeof(int) );
}
}
memcpy( out + ((layers - 1) * stride), u, stride );
if (layers >= 2) {
two_back = out - 2 * stride;
}
if (delays) {
(*delays)[layers - 1U] = g.delay;
}
}
} while (u != 0);
// free temp buffer;
STBI_FREE(g.out);
STBI_FREE(g.history);
STBI_FREE(g.background);
// do the final conversion after loading everything;
if (req_comp && req_comp != 4)
out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
*z = layers;
return out;
} else {
return stbi__errpuc("not GIF", "Image was not as a gif type.");
}
} }
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{ {
stbi_uc *u = 0; stbi_uc *u = 0;
stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); stbi__gif g;
memset(g, 0, sizeof(*g)); memset(&g, 0, sizeof(g));
STBI_NOTUSED(ri);
u = stbi__gif_load_next(s, g, comp, req_comp); u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
if (u) { if (u) {
*x = g->w; *x = g.w;
*y = g->h; *y = g.h;
// moved conversion to after successful load so that the same
// can be done for multiple frames.
if (req_comp && req_comp != 4) if (req_comp && req_comp != 4)
u = stbi__convert_format(u, 4, req_comp, g->w, g->h); u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
} }
else if (g->out)
STBI_FREE(g->out); // free buffers needed for multiple frame loading;
STBI_FREE(g); STBI_FREE(g.history);
STBI_FREE(g.background);
return u; return u;
} }
@ -6667,7 +6860,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
#ifndef STBI_NO_PSD #ifndef STBI_NO_PSD
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int channelCount, dummy; int channelCount, dummy, depth;
if (!x) x = &dummy; if (!x) x = &dummy;
if (!y) y = &dummy; if (!y) y = &dummy;
if (!comp) comp = &dummy; if (!comp) comp = &dummy;
@ -6687,7 +6880,8 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
} }
*y = stbi__get32be(s); *y = stbi__get32be(s);
*x = stbi__get32be(s); *x = stbi__get32be(s);
if (stbi__get16be(s) != 8) { depth = stbi__get16be(s);
if (depth != 8 && depth != 16) {
stbi__rewind( s ); stbi__rewind( s );
return 0; return 0;
} }
@ -6698,6 +6892,33 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
*comp = 4; *comp = 4;
return 1; return 1;
} }
static int stbi__psd_is16(stbi__context *s)
{
int channelCount, depth;
if (stbi__get32be(s) != 0x38425053) {
stbi__rewind( s );
return 0;
}
if (stbi__get16be(s) != 1) {
stbi__rewind( s );
return 0;
}
stbi__skip(s, 6);
channelCount = stbi__get16be(s);
if (channelCount < 0 || channelCount > 16) {
stbi__rewind( s );
return 0;
}
(void) stbi__get32be(s);
(void) stbi__get32be(s);
depth = stbi__get16be(s);
if (depth != 16) {
stbi__rewind( s );
return 0;
}
return 1;
}
#endif #endif
#ifndef STBI_NO_PIC #ifndef STBI_NO_PIC
@ -6928,6 +7149,19 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
return stbi__err("unknown image type", "Image not of any known type, or corrupt"); return stbi__err("unknown image type", "Image not of any known type, or corrupt");
} }
static int stbi__is_16_main(stbi__context *s)
{
#ifndef STBI_NO_PNG
if (stbi__png_is16(s)) return 1;
#endif
#ifndef STBI_NO_PSD
if (stbi__psd_is16(s)) return 1;
#endif
return 0;
}
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
{ {
@ -6949,6 +7183,27 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
fseek(f,pos,SEEK_SET); fseek(f,pos,SEEK_SET);
return r; return r;
} }
STBIDEF int stbi_is_16_bit(char const *filename)
{
FILE *f = stbi__fopen(filename, "rb");
int result;
if (!f) return stbi__err("can't fopen", "Unable to open file");
result = stbi_is_16_bit_from_file(f);
fclose(f);
return result;
}
STBIDEF int stbi_is_16_bit_from_file(FILE *f)
{
int r;
stbi__context s;
long pos = ftell(f);
stbi__start_file(&s, f);
r = stbi__is_16_main(&s);
fseek(f,pos,SEEK_SET);
return r;
}
#endif // !STBI_NO_STDIO #endif // !STBI_NO_STDIO
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
@ -6965,10 +7220,30 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
return stbi__info_main(&s,x,y,comp); return stbi__info_main(&s,x,y,comp);
} }
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
{
stbi__context s;
stbi__start_mem(&s,buffer,len);
return stbi__is_16_main(&s);
}
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
return stbi__is_16_main(&s);
}
#endif // STB_IMAGE_IMPLEMENTATION #endif // STB_IMAGE_IMPLEMENTATION
/* /*
revision history: revision history:
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
1-bit BMP
*_is_16_bit api
avoid warnings
2.16 (2017-07-23) all functions have 16-bit variants; 2.16 (2017-07-23) all functions have 16-bit variants;
STBI_NO_STDIO works again; STBI_NO_STDIO works again;
compilation fixes; compilation fixes;

View File

@ -1,4 +1,4 @@
/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h /* stb_image_write - v1.09 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@ -10,34 +10,47 @@
Will probably not work correctly with strict-aliasing optimizations. Will probably not work correctly with strict-aliasing optimizations.
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
compilation warnings or even errors. To avoid this, also before #including,
#define STBI_MSC_SECURE_CRT
ABOUT: ABOUT:
This header file is a library for writing images to C stdio. It could be This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know. adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed written by a decent optimizing implementation; though providing a custom
for source code compactness and simplicity, not optimal image file size zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
or run-time performance. This library is designed for source code compactness and simplicity,
not optimal image file size or run-time performance.
BUILDING: BUILDING:
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
malloc,realloc,free. malloc,realloc,free.
You can define STBIW_MEMMOVE() to replace memmove() You can #define STBIW_MEMMOVE() to replace memmove()
You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
for PNG compression (instead of the builtin one), it must have the following signature:
unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
The returned data will be freed with STBIW_FREE() (free() by default),
so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
USAGE: USAGE:
There are four functions, one for each image file format: There are five functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data);
There are also four equivalent functions that use an arbitrary write function. You are void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
There are also five equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these: expected to open/close your file-equivalent before and after calling these:
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
@ -49,6 +62,12 @@ USAGE:
where the callback is: where the callback is:
void stbi_write_func(void *context, void *data, int size); void stbi_write_func(void *context, void *data, int size);
You can configure it with these global variables:
int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
You can define STBI_WRITE_NO_STDIO to disable the file variant of these You can define STBI_WRITE_NO_STDIO to disable the file variant of these
functions, so the library will not use stdio.h at all. However, this will functions, so the library will not use stdio.h at all. However, this will
also disable HDR writing, because it requires stdio for formatted output. also disable HDR writing, because it requires stdio for formatted output.
@ -75,6 +94,9 @@ USAGE:
writer, both because it is in BGR order and because it may have padding writer, both because it is in BGR order and because it may have padding
at the end of the line.) at the end of the line.)
PNG allows you to set the deflate compression level by setting the global
variable 'stbi_write_png_compression_level' (it defaults to 8).
HDR expects linear float data. Since the format is always 32-bit rgb(e) HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels. replicated across all three channels.
@ -88,21 +110,17 @@ USAGE:
CREDITS: CREDITS:
PNG/BMP/TGA
Sean Barrett Sean Barrett - PNG/BMP/TGA
HDR Baldur Karlsson - HDR
Baldur Karlsson Jean-Sebastien Guay - TGA monochrome
TGA monochrome: Tim Kelsey - misc enhancements
Jean-Sebastien Guay Alan Hickman - TGA RLE
misc enhancements: Emmanuel Julien - initial file IO callback implementation
Tim Kelsey Jon Olick - original jo_jpeg.cpp code
TGA RLE Daniel Gibson - integrate JPEG, allow external zlib
Alan Hickman Aarni Koskela - allow choosing PNG filter
initial file IO callback implementation
Emmanuel Julien
JPEG
Jon Olick (original jo_jpeg.cpp code)
Daniel Gibson
bugfixes: bugfixes:
github:Chribba github:Chribba
Guillaume Chereau Guillaume Chereau
@ -114,6 +132,12 @@ CREDITS:
Thatcher Ulrich Thatcher Ulrich
github:poppolopoppo github:poppolopoppo
Patrick Boettcher Patrick Boettcher
github:xeekworx
Cap Petschulat
Simon Rodriguez
Ivan Tikhonov
github:ignotion
Adam Schackart
LICENSE LICENSE
@ -124,15 +148,23 @@ LICENSE
#ifndef INCLUDE_STB_IMAGE_WRITE_H #ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H #define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
extern "C" { #ifndef STBIWDEF
#endif
#ifdef STB_IMAGE_WRITE_STATIC #ifdef STB_IMAGE_WRITE_STATIC
#define STBIWDEF static #define STBIWDEF static
#else #else
#ifdef __cplusplus
#define STBIWDEF extern "C"
#else
#define STBIWDEF extern #define STBIWDEF extern
#endif
#endif
#endif
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
extern int stbi_write_tga_with_rle; extern int stbi_write_tga_with_rle;
extern int stbi_write_png_compression_level;
extern int stbi_write_force_png_filter;
#endif #endif
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
@ -151,9 +183,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w,
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
#ifdef __cplusplus STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H #endif//INCLUDE_STB_IMAGE_WRITE_H
@ -208,6 +238,23 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression_level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
STBIWDEF void stbi_flip_vertically_on_write(int flag)
{
stbi__flip_vertically_on_write = flag;
}
typedef struct typedef struct
{ {
stbi_write_func *func; stbi_write_func *func;
@ -230,7 +277,13 @@ static void stbi__stdio_write(void *context, void *data, int size)
static int stbi__start_write_file(stbi__write_context *s, const char *filename) static int stbi__start_write_file(stbi__write_context *s, const char *filename)
{ {
FILE *f = fopen(filename, "wb"); FILE *f;
#ifdef STBI_MSC_SECURE_CRT
if (fopen_s(&f, filename, "wb"))
f = NULL;
#else
f = fopen(filename, "wb");
#endif
stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
return f != NULL; return f != NULL;
} }
@ -245,12 +298,6 @@ static void stbi__end_write_file(stbi__write_context *s)
typedef unsigned int stbiw_uint32; typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_tga_with_rle = 1;
#else
int stbi_write_tga_with_rle = 1;
#endif
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
{ {
while (*fmt) { while (*fmt) {
@ -341,6 +388,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
if (y <= 0) if (y <= 0)
return; return;
if (stbi__flip_vertically_on_write)
vdir *= -1;
if (vdir < 0) if (vdir < 0)
j_end = -1, j = y-1; j_end = -1, j = y-1;
else else
@ -412,10 +462,20 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
} else { } else {
int i,j,k; int i,j,k;
int jend, jdir;
stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
for (j = y - 1; j >= 0; --j) { if (stbi__flip_vertically_on_write) {
j = 0;
jend = y;
jdir = 1;
} else {
j = y-1;
jend = -1;
jdir = -1;
}
for (; j != jend; j += jdir) {
unsigned char *row = (unsigned char *) data + j * x * comp; unsigned char *row = (unsigned char *) data + j * x * comp;
int len; int len;
@ -626,11 +686,15 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1); s->func(s->context, header, sizeof(header)-1);
#ifdef STBI_MSC_SECURE_CRT
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif
s->func(s->context, buffer, len); s->func(s->context, buffer, len);
for(i=0; i < y; i++) for(i=0; i < y; i++)
stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x);
STBIW_FREE(scratch); STBIW_FREE(scratch);
return 1; return 1;
} }
@ -662,6 +726,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
// PNG writer // PNG writer
// //
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2) #define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbm(a) stbiw__sbraw(a)[0]
@ -742,8 +807,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
#define stbiw__ZHASH 16384 #define stbiw__ZHASH 16384
#endif // STBIW_ZLIB_COMPRESS
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{ {
#ifdef STBIW_ZLIB_COMPRESS
// user provided a zlib compress implementation, use that
return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
#else // use builtin
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
@ -752,6 +823,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
int i,j, bitcount=0; int i,j, bitcount=0;
unsigned char *out = NULL; unsigned char *out = NULL;
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
if (hash_table == NULL)
return NULL;
if (quality < 5) quality = 5; if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window stbiw__sbpush(out, 0x78); // DEFLATE 32K window
@ -845,6 +918,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
// make returned pointer freeable // make returned pointer freeable
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out); return (unsigned char *) stbiw__sbraw(out);
#endif // STBIW_ZLIB_COMPRESS
} }
static unsigned int stbiw__crc32(unsigned char *buffer, int len) static unsigned int stbiw__crc32(unsigned char *buffer, int len)
@ -911,61 +985,88 @@ static unsigned char stbiw__paeth(int a, int b, int c)
} }
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)
{ {
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 }; static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 }; static int firstmap[] = { 0,1,0,5,6 };
int *mymap = (j != 0) ? mapping : firstmap; int *mymap = (y != 0) ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff; int i;
for (p=0; p < 2; ++p) { int type = mymap[filter_type];
for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
int type = mymap[k],est=0; int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
unsigned char *z = pixels + stride_bytes*j; for (i = 0; i < n; ++i) {
for (i=0; i < n; ++i)
switch (type) { switch (type) {
case 0: line_buffer[i] = z[i]; break; case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break; case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;
case 5: line_buffer[i] = z[i]; break; case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break; case 6: line_buffer[i] = z[i]; break;
} }
for (i=n; i < x*n; ++i) { }
for (i=n; i < width*n; ++i) {
switch (type) { switch (type) {
case 0: line_buffer[i] = z[i]; break; case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break; case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;
case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
} }
} }
if (p) break; }
for (i=0; i < x*n; ++i)
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int force_filter = stbi_write_force_png_filter;
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int j,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
if (force_filter >= 5) {
force_filter = -1;
}
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
for (j=0; j < y; ++j) {
int filter_type;
if (force_filter > -1) {
filter_type = force_filter;
stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer);
} else { // Estimate the best filter by running through all of them:
int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
for (filter_type = 0; filter_type < 5; filter_type++) {
stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer);
// Estimate the entropy of the line using this filter; the less, the better.
est = 0;
for (i = 0; i < x*n; ++i) {
est += abs((signed char) line_buffer[i]); est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; } }
if (est < best_filter_val) {
best_filter_val = est;
best_filter = filter_type;
} }
} }
// when we get here, best contains the filter type, and line_buffer contains the data if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
filt[j*(x*n+1)] = (unsigned char) best; stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer);
filter_type = best_filter;
}
}
// when we get here, filter_type contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) filter_type;
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
} }
STBIW_FREE(line_buffer); STBIW_FREE(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);
STBIW_FREE(filt); STBIW_FREE(filt);
if (!zlib) return 0; if (!zlib) return 0;
@ -1010,7 +1111,12 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const
int len; int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (png == NULL) return 0; if (png == NULL) return 0;
#ifdef STBI_MSC_SECURE_CRT
if (fopen_s(&f, filename, "wb"))
f = NULL;
#else
f = fopen(filename, "wb"); f = fopen(filename, "wb");
#endif
if (!f) { STBIW_FREE(png); return 0; } if (!f) { STBIW_FREE(png); return 0; }
fwrite(png, 1, len, f); fwrite(png, 1, len, f);
fclose(f); fclose(f);
@ -1318,7 +1424,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
float YDU[64], UDU[64], VDU[64]; float YDU[64], UDU[64], VDU[64];
for(row = y, pos = 0; row < y+8; ++row) { for(row = y, pos = 0; row < y+8; ++row) {
for(col = x; col < x+8; ++col, ++pos) { for(col = x; col < x+8; ++col, ++pos) {
int p = row*width*comp + col*comp; int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp;
float r, g, b; float r, g, b;
if(row >= height) { if(row >= height) {
p -= width*comp*(row+1 - height); p -= width*comp*(row+1 - height);
@ -1377,6 +1483,10 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
1.09 (2018-02-11)
fix typo in zlib quality API, improve STB_I_W_STATIC in C++
1.08 (2018-01-29)
add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
1.07 (2017-07-24) 1.07 (2017-07-24)
doc fix doc fix
1.06 (2017-07-23) 1.06 (2017-07-23)

View File

@ -1,4 +1,4 @@
// stb_sprintf - v1.03 - public domain snprintf() implementation // stb_sprintf - v1.05 - public domain snprintf() implementation
// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 // originally by Jeff Roberts / RAD Game Tools, 2015/10/20
// http://github.com/nothings/stb // http://github.com/nothings/stb
// //
@ -12,6 +12,9 @@
// github:d26435 // github:d26435
// github:trex78 // github:trex78
// Jari Komppa (SI suffixes) // Jari Komppa (SI suffixes)
// Rohit Nirmal
// Marcin Wojdyr
// Leonard Ritter
// //
// LICENSE: // LICENSE:
// //
@ -927,7 +930,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0;
pr = sizeof(void *) * 2; pr = sizeof(void *) * 2;
fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros
// drop through to X // fall through - to X
case 'X': // upper hex case 'X': // upper hex
case 'x': // lower hex case 'x': // lower hex
@ -1025,11 +1028,11 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
n64 = 0; n64 = 0;
} }
if ((fl & STBSP__TRIPLET_COMMA) == 0) { if ((fl & STBSP__TRIPLET_COMMA) == 0) {
while (n) { do {
s -= 2; s -= 2;
*(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2];
n /= 100; n /= 100;
} } while (n);
} }
while (n) { while (n) {
if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
@ -1259,7 +1262,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
s = num + STBSP__NUMSZ - 1; s = num + STBSP__NUMSZ - 1;
*s = f[0]; *s = f[0];
l = 1; l = 1;
fw = pr = fl = 0; fw = fl = 0;
lead[0] = 0; lead[0] = 0;
tail[0] = 0; tail[0] = 0;
pr = 0; pr = 0;
@ -1341,24 +1344,42 @@ static char *stbsp__clamp_callback(char *buf, void *user, int len)
return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can
} }
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va) static char * stbsp__count_clamp_callback( char * buf, void * user, int len )
{
stbsp__context * c = (stbsp__context*)user;
c->count += len;
return c->tmp; // go direct into buffer if you can
}
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va )
{ {
stbsp__context c; stbsp__context c;
int l; int l;
if (count == 0) if ( (count == 0) && !buf )
{
c.count = 0;
STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );
l = c.count;
}
else
{
if ( count == 0 )
return 0; return 0;
c.buf = buf; c.buf = buf;
c.count = count; c.count = count;
STB_SPRINTF_DECORATE(vsprintfcb)(stbsp__clamp_callback, &c, stbsp__clamp_callback(0, &c, 0), fmt, va); STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va );
// zero-terminate // zero-terminate
l = (int)(c.buf - buf); l = (int)( c.buf - buf );
if (l >= count) // should never be greater, only equal (or less) than count if ( l >= count ) // should never be greater, only equal (or less) than count
l = count - 1; l = count - 1;
buf[l] = 0; buf[l] = 0;
}
return l; return l;
} }

View File

@ -1,4 +1,4 @@
// stb_textedit.h - v1.11 - public domain - Sean Barrett // stb_textedit.h - v1.12 - public domain - Sean Barrett
// Development of this library was sponsored by RAD Game Tools // Development of this library was sponsored by RAD Game Tools
// //
// This C header file implements the guts of a multi-line text-editing // This C header file implements the guts of a multi-line text-editing
@ -29,6 +29,7 @@
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual // 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
// 1.9 (2016-08-27) customizable move-by-word // 1.9 (2016-08-27) customizable move-by-word
@ -198,7 +199,7 @@
// void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
// //
// Each of these functions potentially updates the string and updates the // Each of these functions potentially updates the string and updates the
// state. // state.
@ -232,7 +233,9 @@
// inputs, set a high bit to distinguish the two; then you can define the // inputs, set a high bit to distinguish the two; then you can define the
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
// clear. // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
// anything other type you wante before including.
//
// //
// When rendering, you can read the cursor position and selection state from // When rendering, you can read the cursor position and selection state from
// the STB_TexteditState. // the STB_TexteditState.
@ -711,8 +714,12 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
return 0; return 0;
} }
#ifndef STB_TEXTEDIT_KEYTYPE
#define STB_TEXTEDIT_KEYTYPE int
#endif
// API key: process a keyboard input // API key: process a keyboard input
static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
{ {
retry: retry:
switch (key) { switch (key) {
@ -1112,15 +1119,18 @@ static void stb_textedit_discard_redo(StbUndoState *state)
// if the k'th undo state has characters, clean those up // if the k'th undo state has characters, clean those up
if (state->undo_rec[k].char_storage >= 0) { if (state->undo_rec[k].char_storage >= 0) {
int n = state->undo_rec[k].insert_length, i; int n = state->undo_rec[k].insert_length, i;
// delete n characters from all other records // move the remaining redo character data to the end of the buffer
state->redo_char_point = state->redo_char_point + (short) n; // vsnet05 state->redo_char_point = state->redo_char_point + (short) n; // vsnet05
STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
// adjust the position of all the other records to account for above memmove
for (i=state->redo_point; i < k; ++i) for (i=state->redo_point; i < k; ++i)
if (state->undo_rec[i].char_storage >= 0) if (state->undo_rec[i].char_storage >= 0)
state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 state->undo_rec[i].char_storage += (short) n; // vsnet05
} }
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
// now move redo_point to point to the new one
++state->redo_point; ++state->redo_point;
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
} }
} }
@ -1203,11 +1213,11 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// there's definitely room to store the characters eventually // there's definitely room to store the characters eventually
while (s->undo_char_point + u.delete_length > s->redo_char_point) { while (s->undo_char_point + u.delete_length > s->redo_char_point) {
// there's currently not enough room, so discard a redo record
stb_textedit_discard_redo(s);
// should never happen: // should never happen:
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
return; return;
// there's currently not enough room, so discard a redo record
stb_textedit_discard_redo(s);
} }
r = &s->undo_rec[s->redo_point-1]; r = &s->undo_rec[s->redo_point-1];
@ -1278,6 +1288,7 @@ static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
if (r.insert_length) { if (r.insert_length) {
// easy case: need to insert n characters // easy case: need to insert n characters
STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
s->redo_char_point += r.insert_length;
} }
state->cursor = r.where + r.insert_length; state->cursor = r.where + r.insert_length;

View File

@ -1847,7 +1847,7 @@ static int stbte__minibutton(int colormode, int x, int y, int ch, int id)
int x0 = x, y0 = y, x1 = x+8, y1 = y+7; int x0 = x, y0 = y, x1 = x+8, y1 = y+7;
int over = stbte__hittest(x0,y0,x1,y1,id); int over = stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) { if (stbte__ui.event == STBTE__paint) {
char str[2] = { ch,0 }; char str[2] = { (char)ch, 0 };
stbte__draw_textbox(x0,y0,x1,y1, str,1,0,colormode, STBTE__INDEX_FOR_ID(id,0,0)); stbte__draw_textbox(x0,y0,x1,y1, str,1,0,colormode, STBTE__INDEX_FOR_ID(id,0,0));
} }
return stbte__button_core(id); return stbte__button_core(id);
@ -1858,7 +1858,7 @@ static int stbte__layerbutton(int x, int y, int ch, int id, int toggled, int dis
int x0 = x, y0 = y, x1 = x+10, y1 = y+11; int x0 = x, y0 = y, x1 = x+10, y1 = y+11;
int over = !disabled && stbte__hittest(x0,y0,x1,y1,id); int over = !disabled && stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) { if (stbte__ui.event == STBTE__paint) {
char str[2] = { ch,0 }; char str[2] = { (char)ch, 0 };
int off = (9-stbte__get_char_width(ch))/2; int off = (9-stbte__get_char_width(ch))/2;
stbte__draw_textbox(x0,y0,x1,y1, str, off+1,2, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled)); stbte__draw_textbox(x0,y0,x1,y1, str, off+1,2, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled));
} }

View File

@ -1,4 +1,4 @@
// stb_truetype.h - v1.17 - public domain // stb_truetype.h - v1.19 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools // authored from 2009-2016 by Sean Barrett / RAD Game Tools
// //
// This library processes TrueType files: // This library processes TrueType files:
@ -22,41 +22,35 @@
// Mikko Mononen: compound shape support, more cmap formats // Mikko Mononen: compound shape support, more cmap formats
// Tor Andersson: kerning, subpixel rendering // Tor Andersson: kerning, subpixel rendering
// Dougall Johnson: OpenType / Type 2 font handling // Dougall Johnson: OpenType / Type 2 font handling
// Daniel Ribeiro Maciel: basic GPOS-based kerning
// //
// Misc other: // Misc other:
// Ryan Gordon // Ryan Gordon
// Simon Glass // Simon Glass
// github:IntellectualKitty // github:IntellectualKitty
// Imanol Celaya // Imanol Celaya
// Daniel Ribeiro Maciel
// //
// Bug/warning reports/fixes: // Bug/warning reports/fixes:
// "Zer" on mollyrocket // "Zer" on mollyrocket Fabian "ryg" Giesen
// Cass Everitt // Cass Everitt Martins Mozeiko
// stoiko (Haemimont Games) // stoiko (Haemimont Games) Cap Petschulat
// Brian Hook // Brian Hook Omar Cornut
// Walter van Niftrik // Walter van Niftrik github:aloucks
// David Gow // David Gow Peter LaValle
// David Given // David Given Sergey Popov
// Ivan-Assen Ivanov // Ivan-Assen Ivanov Giumo X. Clanjor
// Anthony Pesch // Anthony Pesch Higor Euripedes
// Johan Duparc // Johan Duparc Thomas Fields
// Hou Qiming // Hou Qiming Derek Vinyard
// Fabian "ryg" Giesen // Rob Loach Cort Stratton
// Martins Mozeiko // Kenney Phillis Jr. github:oyvindjam
// Cap Petschulat // Brian Costabile github:vassvik
// Omar Cornut
// github:aloucks
// Peter LaValle
// Sergey Popov
// Giumo X. Clanjor
// Higor Euripedes
// Thomas Fields
// Derek Vinyard
// Cort Stratton
// github:oyvindjam
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
// 1.18 (2018-01-29) add missing function
// 1.17 (2017-07-23) make more arguments const; doc fix // 1.17 (2017-07-23) make more arguments const; doc fix
// 1.16 (2017-07-12) SDF support // 1.16 (2017-07-12) SDF support
// 1.15 (2017-03-03) make more arguments const // 1.15 (2017-03-03) make more arguments const
@ -171,7 +165,7 @@
// measurement for describing font size, defined as 72 points per inch. // measurement for describing font size, defined as 72 points per inch.
// stb_truetype provides a point API for compatibility. However, true // stb_truetype provides a point API for compatibility. However, true
// "per inch" conventions don't make much sense on computer displays // "per inch" conventions don't make much sense on computer displays
// since they different monitors have different number of pixels per // since different monitors have different number of pixels per
// inch. For example, Windows traditionally uses a convention that // inch. For example, Windows traditionally uses a convention that
// there are 96 pixels per inch, thus making 'inch' measurements have // there are 96 pixels per inch, thus making 'inch' measurements have
// nothing to do with inches, and thus effectively defining a point to // nothing to do with inches, and thus effectively defining a point to
@ -181,6 +175,39 @@
// for non-commercial fonts, thus making fonts scaled in points // for non-commercial fonts, thus making fonts scaled in points
// according to the TrueType spec incoherently sized in practice. // according to the TrueType spec incoherently sized in practice.
// //
// DETAILED USAGE:
//
// Scale:
// Select how high you want the font to be, in points or pixels.
// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
// a scale factor SF that will be used by all other functions.
//
// Baseline:
// You need to select a y-coordinate that is the baseline of where
// your text will appear. Call GetFontBoundingBox to get the baseline-relative
// bounding box for all characters. SF*-y0 will be the distance in pixels
// that the worst-case character could extend above the baseline, so if
// you want the top edge of characters to appear at the top of the
// screen where y=0, then you would set the baseline to SF*-y0.
//
// Current point:
// Set the current point where the first character will appear. The
// first character could extend left of the current point; this is font
// dependent. You can either choose a current point that is the leftmost
// point and hope, or add some padding, or check the bounding box or
// left-side-bearing of the first character to be displayed and set
// the current point based on that.
//
// Displaying a character:
// Compute the bounding box of the character. It will contain signed values
// relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
// then the character should be displayed in the rectangle from
// <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
//
// Advancing for the next character:
// Call GlyphHMetrics, and compute 'current_point += SF * advance'.
//
//
// ADVANCED USAGE // ADVANCED USAGE
// //
// Quality: // Quality:
@ -387,7 +414,8 @@ int main(int arg, char **argv)
//// INTEGRATION WITH YOUR CODEBASE //// INTEGRATION WITH YOUR CODEBASE
//// ////
//// The following sections allow you to supply alternate definitions //// The following sections allow you to supply alternate definitions
//// of C library functions used by stb_truetype. //// of C library functions used by stb_truetype, e.g. if you don't
//// link with the C runtime library.
#ifdef STB_TRUETYPE_IMPLEMENTATION #ifdef STB_TRUETYPE_IMPLEMENTATION
// #define your own (u)stbtt_int8/16/32 before including to override this // #define your own (u)stbtt_int8/16/32 before including to override this
@ -403,7 +431,7 @@ int main(int arg, char **argv)
typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
// #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
#ifndef STBTT_ifloor #ifndef STBTT_ifloor
#include <math.h> #include <math.h>
#define STBTT_ifloor(x) ((int) floor(x)) #define STBTT_ifloor(x) ((int) floor(x))
@ -416,6 +444,11 @@ int main(int arg, char **argv)
#define STBTT_pow(x,y) pow(x,y) #define STBTT_pow(x,y) pow(x,y)
#endif #endif
#ifndef STBTT_fmod
#include <math.h>
#define STBTT_fmod(x,y) fmod(x,y)
#endif
#ifndef STBTT_cos #ifndef STBTT_cos
#include <math.h> #include <math.h>
#define STBTT_cos(x) cos(x) #define STBTT_cos(x) cos(x)
@ -427,11 +460,6 @@ int main(int arg, char **argv)
#define STBTT_fabs(x) fabs(x) #define STBTT_fabs(x) fabs(x)
#endif #endif
#ifndef STBTT_fabs
#include <math.h>
#define STBTT_fabs(x) fabs(x)
#endif
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
#ifndef STBTT_malloc #ifndef STBTT_malloc
#include <stdlib.h> #include <stdlib.h>
@ -676,7 +704,7 @@ struct stbtt_fontinfo
int numGlyphs; // number of glyphs, needed for range checking int numGlyphs; // number of glyphs, needed for range checking
int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
int index_map; // a cmap mapping for our chosen character encoding int index_map; // a cmap mapping for our chosen character encoding
int indexToLocFormat; // format needed to map from glyph index to glyph int indexToLocFormat; // format needed to map from glyph index to glyph
@ -1319,6 +1347,7 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
info->kern = stbtt__find_table(data, fontstart, "kern"); // not required info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required
if (!cmap || !info->head || !info->hhea || !info->hmtx) if (!cmap || !info->head || !info->hhea || !info->hmtx)
return 0; return 0;
@ -2172,7 +2201,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
// push immediate // push immediate
if (b0 == 255) { if (b0 == 255) {
f = (float)stbtt__buf_get32(&b) / 0x10000; f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
} else { } else {
stbtt__buf_skip(&b, -1); stbtt__buf_skip(&b, -1);
f = (float)(stbtt_int16)stbtt__cff_int(&b); f = (float)(stbtt_int16)stbtt__cff_int(&b);
@ -2210,12 +2239,10 @@ static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, in
{ {
stbtt__csctx c = STBTT__CSCTX_INIT(1); stbtt__csctx c = STBTT__CSCTX_INIT(1);
int r = stbtt__run_charstring(info, glyph_index, &c); int r = stbtt__run_charstring(info, glyph_index, &c);
if (x0) { if (x0) *x0 = r ? c.min_x : 0;
*x0 = r ? c.min_x : 0; if (y0) *y0 = r ? c.min_y : 0;
*y0 = r ? c.min_y : 0; if (x1) *x1 = r ? c.max_x : 0;
*x1 = r ? c.max_x : 0; if (y1) *y1 = r ? c.max_y : 0;
*y1 = r ? c.max_y : 0;
}
return r ? c.num_vertices : 0; return r ? c.num_vertices : 0;
} }
@ -2239,7 +2266,7 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde
} }
} }
STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
{ {
stbtt_uint8 *data = info->data + info->kern; stbtt_uint8 *data = info->data + info->kern;
stbtt_uint32 needle, straw; stbtt_uint32 needle, straw;
@ -2269,9 +2296,260 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1,
return 0; return 0;
} }
static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
{
stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
switch(coverageFormat) {
case 1: {
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
// Binary search.
stbtt_int32 l=0, r=glyphCount-1, m;
int straw, needle=glyph;
while (l <= r) {
stbtt_uint8 *glyphArray = coverageTable + 4;
stbtt_uint16 glyphID;
m = (l + r) >> 1;
glyphID = ttUSHORT(glyphArray + 2 * m);
straw = glyphID;
if (needle < straw)
r = m - 1;
else if (needle > straw)
l = m + 1;
else {
return m;
}
}
} break;
case 2: {
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
stbtt_uint8 *rangeArray = coverageTable + 4;
// Binary search.
stbtt_int32 l=0, r=rangeCount-1, m;
int strawStart, strawEnd, needle=glyph;
while (l <= r) {
stbtt_uint8 *rangeRecord;
m = (l + r) >> 1;
rangeRecord = rangeArray + 6 * m;
strawStart = ttUSHORT(rangeRecord);
strawEnd = ttUSHORT(rangeRecord + 2);
if (needle < strawStart)
r = m - 1;
else if (needle > strawEnd)
l = m + 1;
else {
stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
return startCoverageIndex + glyph - strawStart;
}
}
} break;
default: {
// There are no other cases.
STBTT_assert(0);
} break;
}
return -1;
}
static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
{
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
switch(classDefFormat)
{
case 1: {
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
classDefTable = classDef1ValueArray + 2 * glyphCount;
} break;
case 2: {
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
stbtt_uint8 *classRangeRecords = classDefTable + 4;
// Binary search.
stbtt_int32 l=0, r=classRangeCount-1, m;
int strawStart, strawEnd, needle=glyph;
while (l <= r) {
stbtt_uint8 *classRangeRecord;
m = (l + r) >> 1;
classRangeRecord = classRangeRecords + 6 * m;
strawStart = ttUSHORT(classRangeRecord);
strawEnd = ttUSHORT(classRangeRecord + 2);
if (needle < strawStart)
r = m - 1;
else if (needle > strawEnd)
l = m + 1;
else
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
}
classDefTable = classRangeRecords + 6 * classRangeCount;
} break;
default: {
// There are no other cases.
STBTT_assert(0);
} break;
}
return -1;
}
// Define to STBTT_assert(x) if you want to break on unimplemented formats.
#define STBTT_GPOS_TODO_assert(x)
static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
{
stbtt_uint16 lookupListOffset;
stbtt_uint8 *lookupList;
stbtt_uint16 lookupCount;
stbtt_uint8 *data;
stbtt_int32 i;
if (!info->gpos) return 0;
data = info->data + info->gpos;
if (ttUSHORT(data+0) != 1) return 0; // Major version 1
if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
lookupListOffset = ttUSHORT(data+8);
lookupList = data + lookupListOffset;
lookupCount = ttUSHORT(lookupList);
for (i=0; i<lookupCount; ++i) {
stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
stbtt_uint8 *lookupTable = lookupList + lookupOffset;
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
stbtt_uint8 *subTableOffsets = lookupTable + 6;
switch(lookupType) {
case 2: { // Pair Adjustment Positioning Subtable
stbtt_int32 sti;
for (sti=0; sti<subTableCount; sti++) {
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
stbtt_uint8 *table = lookupTable + subtableOffset;
stbtt_uint16 posFormat = ttUSHORT(table);
stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
if (coverageIndex == -1) continue;
switch (posFormat) {
case 1: {
stbtt_int32 l, r, m;
int straw, needle;
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
stbtt_int32 valueRecordPairSizeInBytes = 2;
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
stbtt_uint8 *pairValueTable = table + pairPosOffset;
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
stbtt_uint8 *pairValueArray = pairValueTable + 2;
// TODO: Support more formats.
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
if (valueFormat1 != 4) return 0;
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
if (valueFormat2 != 0) return 0;
STBTT_assert(coverageIndex < pairSetCount);
needle=glyph2;
r=pairValueCount-1;
l=0;
// Binary search.
while (l <= r) {
stbtt_uint16 secondGlyph;
stbtt_uint8 *pairValue;
m = (l + r) >> 1;
pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
secondGlyph = ttUSHORT(pairValue);
straw = secondGlyph;
if (needle < straw)
r = m - 1;
else if (needle > straw)
l = m + 1;
else {
stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
return xAdvance;
}
}
} break;
case 2: {
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
stbtt_uint16 class1Count = ttUSHORT(table + 12);
stbtt_uint16 class2Count = ttUSHORT(table + 14);
STBTT_assert(glyph1class < class1Count);
STBTT_assert(glyph2class < class2Count);
// TODO: Support more formats.
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
if (valueFormat1 != 4) return 0;
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
if (valueFormat2 != 0) return 0;
if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
stbtt_uint8 *class1Records = table + 16;
stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
return xAdvance;
}
} break;
default: {
// There are no other cases.
STBTT_assert(0);
break;
};
}
}
break;
};
default:
// TODO: Implement other stuff.
break;
}
}
return 0;
}
STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
{
int xAdvance = 0;
if (info->gpos)
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
if (info->kern)
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
return xAdvance;
}
STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
{ {
if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
return 0; return 0;
return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
} }
@ -2395,7 +2673,7 @@ static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
hh->num_remaining_in_head_chunk = count; hh->num_remaining_in_head_chunk = count;
} }
--hh->num_remaining_in_head_chunk; --hh->num_remaining_in_head_chunk;
return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk; return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
} }
} }
@ -3230,7 +3508,8 @@ error:
STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
{ {
float scale = scale_x > scale_y ? scale_y : scale_x; float scale = scale_x > scale_y ? scale_y : scale_x;
int winding_count, *winding_lengths; int winding_count = 0;
int *winding_lengths = NULL;
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
if (windings) { if (windings) {
stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
@ -3318,6 +3597,11 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *
return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
} }
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
{
stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
}
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
{ {
stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
@ -3909,7 +4193,7 @@ static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2],
float discr = b*b - a*c; float discr = b*b - a*c;
if (discr > 0.0) { if (discr > 0.0) {
float rcpna = -1 / a; float rcpna = -1 / a;
float d = (float) sqrt(discr); float d = (float) STBTT_sqrt(discr);
s0 = (b+d) * rcpna; s0 = (b+d) * rcpna;
s1 = (b-d) * rcpna; s1 = (b-d) * rcpna;
if (s0 >= 0.0 && s0 <= 1.0) if (s0 >= 0.0 && s0 <= 1.0)
@ -3971,7 +4255,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
orig[1] = y; orig[1] = y;
// make sure y never passes through a vertex of the shape // make sure y never passes through a vertex of the shape
y_frac = (float) fmod(y, 1.0f); y_frac = (float) STBTT_fmod(y, 1.0f);
if (y_frac < 0.01f) if (y_frac < 0.01f)
y += 0.01f; y += 0.01f;
else if (y_frac > 0.99f) else if (y_frac > 0.99f)
@ -4471,6 +4755,9 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
// FULL VERSION HISTORY // FULL VERSION HISTORY
// //
// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
// 1.18 (2018-01-29) add missing function
// 1.17 (2017-07-23) make more arguments const; doc fix
// 1.16 (2017-07-12) SDF support // 1.16 (2017-07-12) SDF support
// 1.15 (2017-03-03) make more arguments const // 1.15 (2017-03-03) make more arguments const
// 1.14 (2017-01-16) num-fonts-in-TTC function // 1.14 (2017-01-16) num-fonts-in-TTC function

View File

@ -1,11 +1,11 @@
// Ogg Vorbis audio decoder - v1.11 - public domain // Ogg Vorbis audio decoder - v1.14 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Original version written by Sean Barrett in 2007. // Original version written by Sean Barrett in 2007.
// //
// Originally sponsored by RAD Game Tools. Seeking sponsored // Originally sponsored by RAD Game Tools. Seeking implementation
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software, // sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
// Aras Pranckevicius, and Sean Barrett. // Elias Software, Aras Pranckevicius, and Sean Barrett.
// //
// LICENSE // LICENSE
// //
@ -30,22 +30,26 @@
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// Phillip Bennefall Rohit Thiago Goulart // Phillip Bennefall Rohit Thiago Goulart
// manxorist@github saga musix github:infatum // manxorist@github saga musix github:infatum
// Timur Gagiev
// //
// Partial history: // Partial history:
// 1.11 - 2017/07/23 - fix MinGW compilation // 1.14 - 2018-02-11 - delete bogus dealloca usage
// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory // 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version // 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame // 1.11 - 2017-07-23 - fix MinGW compilation
// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const // 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory
// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) // 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version
// 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame
// 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const
// 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson)
// some crash fixes when out of memory or with corrupt files // some crash fixes when out of memory or with corrupt files
// fix some inappropriately signed shifts // fix some inappropriately signed shifts
// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant // 1.05 - 2015-04-19 - don't define __forceinline if it's redundant
// 1.04 - 2014/08/27 - fix missing const-correct case in API // 1.04 - 2014-08-27 - fix missing const-correct case in API
// 1.03 - 2014/08/07 - warning fixes // 1.03 - 2014-08-07 - warning fixes
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows // 1.02 - 2014-07-09 - declare qsort comparison as explicitly _cdecl in Windows
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct) // 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float (interleaved was correct)
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel; // 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
// (API change) report sample rate for decode-full-file funcs // (API change) report sample rate for decode-full-file funcs
// //
// See end of file for full version history. // See end of file for full version history.
@ -880,11 +884,7 @@ static int error(vorb *f, enum STBVorbisError e)
#define array_size_required(count,size) (count*(sizeof(void *)+(size))) #define array_size_required(count,size) (count*(sizeof(void *)+(size)))
#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) #define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))
#ifdef dealloca
#define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size))
#else
#define temp_free(f,p) 0 #define temp_free(f,p) 0
#endif
#define temp_alloc_save(f) ((f)->temp_offset) #define temp_alloc_save(f) ((f)->temp_offset)
#define temp_alloc_restore(f,p) ((f)->temp_offset = (p)) #define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
@ -2042,6 +2042,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in
return TRUE; return TRUE;
} }
// n is 1/2 of the blocksize --
// specification: "Correct per-vector decode length is [n]/2"
static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
{ {
int i,j,pass; int i,j,pass;
@ -2049,7 +2051,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int rtype = f->residue_types[rn]; int rtype = f->residue_types[rn];
int c = r->classbook; int c = r->classbook;
int classwords = f->codebooks[c].dimensions; int classwords = f->codebooks[c].dimensions;
int n_read = r->end - r->begin; unsigned int actual_size = rtype == 2 ? n*2 : n;
unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size);
unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size);
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
int temp_alloc_point = temp_alloc_save(f); int temp_alloc_point = temp_alloc_save(f);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@ -3391,7 +3396,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->last_seg_which == f->end_seg_with_known_loc) { if (f->last_seg_which == f->end_seg_with_known_loc) {
// if we have a valid current loc, and this is final: // if we have a valid current loc, and this is final:
if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
uint32 current_end = f->known_loc_for_packet - (n-right_end); uint32 current_end = f->known_loc_for_packet;
// then let's infer the size of the (probably) short final frame // then let's infer the size of the (probably) short final frame
if (current_end < f->current_loc + (right_end-left_start)) { if (current_end < f->current_loc + (right_end-left_start)) {
if (current_end < f->current_loc) { if (current_end < f->current_loc) {
@ -3400,7 +3405,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
} else { } else {
*len = current_end - f->current_loc; *len = current_end - f->current_loc;
} }
*len += left_start; *len += left_start; // this doesn't seem right, but has no ill effect on my test files
if (*len > right_end) *len = right_end; // this should never happen if (*len > right_end) *len = right_end; // this should never happen
f->current_loc += *len; f->current_loc += *len;
return TRUE; return TRUE;
@ -4050,6 +4055,7 @@ static int start_decoder(vorb *f)
f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist);
if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem); if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem);
memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1);
#ifdef STB_VORBIS_NO_DEFER_FLOOR #ifdef STB_VORBIS_NO_DEFER_FLOOR
f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem); if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem);
@ -4077,7 +4083,10 @@ static int start_decoder(vorb *f)
int i,max_part_read=0; int i,max_part_read=0;
for (i=0; i < f->residue_count; ++i) { for (i=0; i < f->residue_count; ++i) {
Residue *r = f->residue_config + i; Residue *r = f->residue_config + i;
int n_read = r->end - r->begin; unsigned int actual_size = f->blocksize_1 / 2;
unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size;
unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size;
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
if (part_read > max_part_read) if (part_read > max_part_read)
max_part_read = part_read; max_part_read = part_read;
@ -4088,6 +4097,8 @@ static int start_decoder(vorb *f)
classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
#endif #endif
// maximum reasonable partition size is f->blocksize_1
f->temp_memory_required = classify_mem; f->temp_memory_required = classify_mem;
if (imdct_mem > f->temp_memory_required) if (imdct_mem > f->temp_memory_required)
f->temp_memory_required = imdct_mem; f->temp_memory_required = imdct_mem;
@ -5351,20 +5362,22 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
#endif // STB_VORBIS_NO_PULLDATA_API #endif // STB_VORBIS_NO_PULLDATA_API
/* Version history /* Version history
1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
1.09 - 2016/04/04 - back out 'avoid discarding last frame' fix from previous version 1.11 - 2017-07-23 - fix MinGW compilation
1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks; 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory
1.09 - 2016-04-04 - back out 'avoid discarding last frame' fix from previous version
1.08 - 2016-04-02 - fixed multiple warnings; fix setup memory leaks;
avoid discarding last frame of audio data avoid discarding last frame of audio data
1.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API 1.07 - 2015-01-16 - fixed some warnings, fix mingw, const-correct API
some more crash fixes when out of memory or with corrupt files some more crash fixes when out of memory or with corrupt files
1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson)
some crash fixes when out of memory or with corrupt files some crash fixes when out of memory or with corrupt files
1.05 - 2015/04/19 - don't define __forceinline if it's redundant 1.05 - 2015-04-19 - don't define __forceinline if it's redundant
1.04 - 2014/08/27 - fix missing const-correct case in API 1.04 - 2014-08-27 - fix missing const-correct case in API
1.03 - 2014/08/07 - Warning fixes 1.03 - 2014-08-07 - Warning fixes
1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows 1.02 - 2014-07-09 - Declare qsort compare function _cdecl on windows
1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float
1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in multichannel 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in multichannel
(API change) report sample rate for decode-full-file funcs (API change) report sample rate for decode-full-file funcs
0.99996 - bracket #include <malloc.h> for macintosh compilation by Laurent Gomila 0.99996 - bracket #include <malloc.h> for macintosh compilation by Laurent Gomila
0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem

View File

@ -1,7 +1,8 @@
// stretchy_buffer.h - v1.02 - public domain - nothings.org/stb // stretchy_buffer.h - v1.03 - public domain - nothings.org/stb
// a vector<>-like dynamic array for C // a vector<>-like dynamic array for C
// //
// version history: // version history:
// 1.03 - compile as C++ maybe
// 1.02 - tweaks to syntax for no good reason // 1.02 - tweaks to syntax for no good reason
// 1.01 - added a "common uses" documentation section // 1.01 - added a "common uses" documentation section
// 1.0 - fixed bug in the version I posted prematurely // 1.0 - fixed bug in the version I posted prematurely
@ -162,6 +163,10 @@
// the main trick is in realizing in the first place that it's // the main trick is in realizing in the first place that it's
// possible to do this in a generic, type-safe way in C. // possible to do this in a generic, type-safe way in C.
// //
// Contributors:
//
// Timothy Wright (github:ZenToad)
//
// LICENSE // LICENSE
// //
// See end of file for license information. // See end of file for license information.
@ -189,7 +194,7 @@
#define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a)) #define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a))
#define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0) #define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0)
#define stb__sbgrow(a,n) ((a) = stb__sbgrowf((a), (n), sizeof(*(a)))) #define stb__sbgrow(a,n) (*((void **)&(a)) = stb__sbgrowf((a), (n), sizeof(*(a))))
#include <stdlib.h> #include <stdlib.h>

View File

@ -4,4 +4,4 @@ CPPFLAGS = -Wno-write-strings -DSTB_DIVIDE_TEST
all: all:
$(CC) $(INCLUDES) $(CFLAGS) ../stb_vorbis.c test_c_compilation.c -lm $(CC) $(INCLUDES) $(CFLAGS) ../stb_vorbis.c test_c_compilation.c -lm
$(CC) $(INCLUDES) $(CPPFLAGS) test_cpp_compilation.cpp -lm $(CC) $(INCLUDES) $(CPPFLAGS) test_cpp_compilation.cpp -lm -lstdc++

View File

@ -37,7 +37,8 @@ extern void ods(char *fmt, ...);
#define FAST_CHUNK #define FAST_CHUNK
#define IN_PLACE #define IN_PLACE
#define SKIP_TERRAIN 48 // use to avoid building underground stuff #define SKIP_TERRAIN 0
//#define SKIP_TERRAIN 48 // use to avoid building underground stuff
// allows you to see what perf would be like if underground was efficiently culled, // allows you to see what perf would be like if underground was efficiently culled,
// or if you were making a game without underground // or if you were making a game without underground
@ -131,7 +132,8 @@ unsigned char minecraft_info[256][7] =
{ C_solid, 35,35,35,35,4,4, }, { C_solid, 35,35,35,35,4,4, },
// 48 // 48
{ C_solid, 36,36,36,36,36,36 }, //{ C_solid, 36,36,36,36,36,36 },
{ C_force, 36,36,36,36,36,36 },
{ C_solid, 37,37,37,37,37,37 }, { C_solid, 37,37,37,37,37,37 },
{ C_cross, 80,80,80,80,80,80 }, // torch { C_cross, 80,80,80,80,80,80 }, // torch
{ C_empty }, // fire { C_empty }, // fire
@ -142,6 +144,7 @@ unsigned char minecraft_info[256][7] =
// 56 // 56
{ C_solid, 50,50,50,50,50,50 }, { C_solid, 50,50,50,50,50,50 },
//{ C_force, 50,50,50,50,50,50 },
{ C_solid, 26,26,26,26,26,26 }, { C_solid, 26,26,26,26,26,26 },
{ C_solid, 60,59,59,59,43,43 }, { C_solid, 60,59,59,59,43,43 },
{ C_cross, 95,95,95,95 }, { C_cross, 95,95,95,95 },
@ -831,6 +834,8 @@ void mesh_init(void)
minecraft_color_for_blocktype[161][i] = 37 | 64; // green minecraft_color_for_blocktype[161][i] = 37 | 64; // green
minecraft_color_for_blocktype[10][i] = 63; // emissive lava minecraft_color_for_blocktype[10][i] = 63; // emissive lava
minecraft_color_for_blocktype[11][i] = 63; // emissive minecraft_color_for_blocktype[11][i] = 63; // emissive
//minecraft_color_for_blocktype[56][i] = 63; // emissive diamond
minecraft_color_for_blocktype[48][i] = 63; // emissive dungeon
} }
#ifdef VHEIGHT_TEST #ifdef VHEIGHT_TEST

3305
tests/prerelease/stb_lib.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c # ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FR /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"
@ -190,6 +190,34 @@ SOURCE=.\test_c_compilation.c
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\test_c_lexer.c
# End Source File
# Begin Source File
SOURCE=.\test_dxt.c
# End Source File
# Begin Source File
SOURCE=.\test_easyfont.c
# End Source File
# Begin Source File
SOURCE=.\test_image.c
# End Source File
# Begin Source File
SOURCE=.\test_image_write.c
# End Source File
# Begin Source File
SOURCE=.\test_perlin.c
# End Source File
# Begin Source File
SOURCE=.\test_sprintf.c
# End Source File
# Begin Source File
SOURCE=.\test_truetype.c SOURCE=.\test_truetype.c
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -198,6 +226,10 @@ SOURCE=.\test_vorbis.c
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\test_voxel.c
# End Source File
# Begin Source File
SOURCE=.\textedit_sample.c SOURCE=.\textedit_sample.c
# End Source File # End Source File
# End Target # End Target

View File

@ -123,6 +123,18 @@ Package=<4>
############################################################################### ###############################################################################
Project: "stblib"=.\stblib.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "stretch_test"=.\stretch_test.dsp - Package Owner=<4> Project: "stretch_test"=.\stretch_test.dsp - Package Owner=<4>
Package=<5> Package=<5>

102
tests/stblib.dsp Normal file
View File

@ -0,0 +1,102 @@
# Microsoft Developer Studio Project File - Name="stblib" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=stblib - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "stblib.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "stblib.mak" CFG="stblib - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "stblib - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "stblib - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "stblib - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "stblib - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "stblib - Win32 Release"
# Name "stblib - Win32 Debug"
# Begin Source File
SOURCE=.\prerelease\stb_lib.h
# End Source File
# Begin Source File
SOURCE=..\stb_regex.h
# End Source File
# Begin Source File
SOURCE=.\stblib_test.c
# End Source File
# Begin Source File
SOURCE=.\stblib_test_companion.c
# End Source File
# End Target
# End Project

11
tests/stblib_test.c Normal file
View File

@ -0,0 +1,11 @@
#include "prerelease/stb_lib.h"
#define STB_LIB_IMPLEMENTATION
#include "prerelease/stb_lib.h"
//#define STB_REGEX_IMPLEMENTATION
//#include "stb_regex.h"
int main(int argc, char **argv)
{
}

View File

@ -0,0 +1,4 @@
//#include "stb_regex.h"
//#include "stb_regex.h"
#include "prerelease/stb_lib.h"
#include "prerelease/stb_lib.h"

View File

@ -1,10 +1,8 @@
#include "stb_sprintf.h"
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h" #include "stb_sprintf.h"
#define STB_PERLIN_IMPLEMENTATION #define STB_PERLIN_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_DXT_IMPLEMENATION
#define STB_C_LEXER_IMPLEMENTATIOn #define STB_C_LEXER_IMPLEMENTATIOn
#define STB_DIVIDE_IMPLEMENTATION #define STB_DIVIDE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
@ -14,17 +12,18 @@
#define STB_VOXEL_RENDER_IMPLEMENTATION #define STB_VOXEL_RENDER_IMPLEMENTATION
#define STB_EASY_FONT_IMPLEMENTATION #define STB_EASY_FONT_IMPLEMENTATION
#include "stb_easy_font.h"
#include "stb_herringbone_wang_tile.h" #include "stb_herringbone_wang_tile.h"
#include "stb_image.h" #include "stb_image.h"
#include "stb_image_write.h" #include "stb_image_write.h"
#include "stb_perlin.h" #include "stb_perlin.h"
#include "stb_dxt.h"
#include "stb_c_lexer.h" #include "stb_c_lexer.h"
#include "stb_divide.h" #include "stb_divide.h"
#include "stb_image_resize.h" #include "stb_image_resize.h"
#include "stb_rect_pack.h" #include "stb_rect_pack.h"
#define STB_DXT_IMPLEMENTATION
#include "stb_dxt.h"
#define STBVOX_CONFIG_MODE 1 #define STBVOX_CONFIG_MODE 1
#include "stb_voxel_render.h" #include "stb_voxel_render.h"

1
tests/test_c_lexer.c Normal file
View File

@ -0,0 +1 @@
#include "stb_c_lexer.h"

View File

@ -2,9 +2,11 @@
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h" #include "stb_sprintf.h"
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION
#define STB_PERLIN_IMPLEMENTATION #define STB_PERLIN_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_DXT_IMPLEMENATION #define STB_DXT_IMPLEMENATION
#define STB_C_LEXER_IMPLEMENTATIOn #define STB_C_LEXER_IMPLEMENTATIOn
#define STB_DIVIDE_IMPLEMENTATION #define STB_DIVIDE_IMPLEMENTATION

1
tests/test_dxt.c Normal file
View File

@ -0,0 +1 @@
#include "stb_dxt.h"

1
tests/test_easyfont.c Normal file
View File

@ -0,0 +1 @@
#include "stb_easy_font.h"

1
tests/test_image.c Normal file
View File

@ -0,0 +1 @@
#include "stb_image.h"

1
tests/test_image_write.c Normal file
View File

@ -0,0 +1 @@
#include "stb_image_write.h"

1
tests/test_perlin.c Normal file
View File

@ -0,0 +1 @@
#include "stb_perlin.h"

1
tests/test_sprintf.c Normal file
View File

@ -0,0 +1 @@
#include "stb_sprintf.h"

View File

@ -1,3 +1,11 @@
#ifndef _CRT_SECURE_NO_WARNINGS
// Fixes Compile Errors for Visual Studio 2005 or newer
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h>
// this isn't meant to compile standalone; link with test_c_compilation.c as well
#include "stb_rect_pack.h" #include "stb_rect_pack.h"
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h" #include "stb_truetype.h"
@ -7,7 +15,7 @@
#include <stdio.h> #include <stdio.h>
char ttf_buffer[1<<25]; unsigned char ttf_buffer[1 << 25];
unsigned char output[512*100]; unsigned char output[512*100];
void debug(void) void debug(void)
@ -66,12 +74,14 @@ int main(int argc, char **argv)
stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL);
pr[0].chardata_for_range = pdata; pr[0].chardata_for_range = pdata;
pr[0].first_unicode_char_in_range = 32; pr[0].array_of_unicode_codepoints = NULL;
pr[0].num_chars_in_range = 95; pr[0].first_unicode_codepoint_in_range = 32;
pr[0].num_chars = 95;
pr[0].font_size = 20.0f; pr[0].font_size = 20.0f;
pr[1].chardata_for_range = pdata+256; pr[1].chardata_for_range = pdata+256;
pr[1].first_unicode_char_in_range = 0xa0; pr[1].array_of_unicode_codepoints = NULL;
pr[1].num_chars_in_range = 0x100 - 0xa0; pr[1].first_unicode_codepoint_in_range = 0xa0;
pr[1].num_chars = 0x100 - 0xa0;
pr[1].font_size = 20.0f; pr[1].font_size = 20.0f;
stbtt_PackSetOversampling(&pc, 2, 2); stbtt_PackSetOversampling(&pc, 2, 2);

1
tests/test_voxel.c Normal file
View File

@ -0,0 +1 @@
#include "stb_voxel_render.h"