commit
fa8fe30532
20
README.md
20
README.md
@ -11,17 +11,17 @@ by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
|
||||
|
||||
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_image.h](stb_image.h)** | 2.16 | graphics | 7187 | 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_image_write.h](stb_image_write.h)** | 1.07 | graphics | 1458 | image writing to disk: PNG, TGA, BMP
|
||||
**[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.19 | graphics | 7462 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
|
||||
**[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.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_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++
|
||||
**[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++
|
||||
**[stb_textedit.h](stb_textedit.h)** | 1.11 | user interface | 1393 | guts of a text editor for games etc implementing them from scratch
|
||||
**[stb_sprintf.h](stb_sprintf.h)** | 1.05 | utility | 1833 | fast sprintf, snprintf for C/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.12 | user 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 graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
|
||||
**[stb_dxt.h](stb_dxt.h)** | 1.07 | 3D graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor
|
||||
**[stb_dxt.h](stb_dxt.h)** | 1.08b | 3D graphics | 728 | Fabian "ryg" Giesen's real-time DXT compressor
|
||||
**[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D graphics | 316 | revised Perlin noise (3D input, 1D output)
|
||||
**[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D 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 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_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.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
|
||||
|
||||
Total libraries: 20
|
||||
Total lines of C code: 52846
|
||||
Total lines of C code: 53654
|
||||
|
||||
|
||||
FAQ
|
||||
|
281
stb.h
281
stb.h
@ -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
|
||||
|
||||
This is a single header file with a bunch of useful utilities
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
Version History
|
||||
|
||||
2.31 stb_ucharcmp
|
||||
2.30 MinGW fix
|
||||
2.29 attempt to fix use of swprintf()
|
||||
2.28 various new functionality
|
||||
@ -193,6 +194,7 @@ CREDITS
|
||||
Eugene Opalev
|
||||
Tim Sjostrand
|
||||
github:infatum
|
||||
Dave Butler (Croepha)
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
@ -1028,8 +1030,8 @@ stb__wchar *stb__from_utf8(char *str)
|
||||
|
||||
stb__wchar *stb__from_utf8_alt(char *str)
|
||||
{
|
||||
static stb__wchar buffer[64];
|
||||
return stb_from_utf8(buffer, str, 64);
|
||||
static stb__wchar buffer[4096];
|
||||
return stb_from_utf8(buffer, str, 4096);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 q = *(const unsigned char *) ((const char *) b + stb__charcmpoffset);
|
||||
const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset);
|
||||
const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset);
|
||||
return p < q ? -1 : p > q;
|
||||
}
|
||||
|
||||
@ -1599,10 +1601,10 @@ int (*stb_intcmp(int offset))(const void *, const void *)
|
||||
return &stb__intcmp;
|
||||
}
|
||||
|
||||
int (*stb_charcmp(int offset))(const void *, const void *)
|
||||
int (*stb_ucharcmp(int offset))(const void *, const void *)
|
||||
{
|
||||
stb__charcmpoffset = offset;
|
||||
return &stb__charcmp;
|
||||
stb__ucharcmpoffset = offset;
|
||||
return &stb__ucharcmp;
|
||||
}
|
||||
|
||||
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;
|
||||
return &stb__doublecmp;
|
||||
}
|
||||
|
||||
#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_stristr(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 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;
|
||||
}
|
||||
|
||||
char *stb_plural(int n)
|
||||
const char *stb_plural(int n)
|
||||
{
|
||||
return n == 1 ? "" : "s";
|
||||
}
|
||||
@ -3362,7 +3363,7 @@ unsigned int stb_hashlen(char *str, int len)
|
||||
|
||||
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
|
||||
x = stb_rehash(x);
|
||||
@ -3411,7 +3412,7 @@ unsigned int stb_hash_fast(void *p, int len)
|
||||
if (len <= 0 || q == NULL) return 0;
|
||||
|
||||
/* Main loop */
|
||||
if (((int) q & 1) == 0) {
|
||||
if (((int)(size_t) q & 1) == 0) {
|
||||
for (;len > 3; len -= 4) {
|
||||
unsigned int val;
|
||||
hash += stb__get16(q);
|
||||
@ -3737,7 +3738,7 @@ int stb_ischar(char c, char *set)
|
||||
static unsigned char (*tables)[256];
|
||||
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) {
|
||||
int i,k,n,j,f;
|
||||
// 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);
|
||||
memset(tables, 0, sizeof(*tables) * k);
|
||||
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);
|
||||
n = k >> 3;
|
||||
f = bit[k&7];
|
||||
@ -3764,7 +3765,7 @@ int stb_ischar(char c, char *set)
|
||||
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];
|
||||
}
|
||||
@ -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 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) \
|
||||
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
|
||||
|
||||
#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_SDEL ((char *) 1)
|
||||
|
||||
@ -4270,6 +4281,19 @@ int stb_sdict_count(stb_sdict *a)
|
||||
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 *d = stb_sdict_create();
|
||||
@ -5439,15 +5463,62 @@ typedef struct
|
||||
int errors;
|
||||
} 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 *f;
|
||||
char name_full[4096];
|
||||
char temp_full[sizeof(name_full) + 12];
|
||||
int p;
|
||||
#ifdef _MSC_VER
|
||||
int j;
|
||||
#endif
|
||||
|
||||
// @TODO: if the file doesn't exist, we can also use the fastpath here
|
||||
if (mode[0] != 'w' && !strchr(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)
|
||||
return 0;
|
||||
|
||||
// try to generate a temporary file in the same directory
|
||||
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
|
||||
f = stb__open_temp_file(temp_full, name_full, mode);
|
||||
if (f != NULL) {
|
||||
stb__file_data *d = (stb__file_data *) malloc(sizeof(*d));
|
||||
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 (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)
|
||||
if (keep == stb_keep_no) {
|
||||
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->name);
|
||||
@ -7631,14 +7707,14 @@ static stb_ps_hash *stb_ps_makehash(int size, int old_size, void **old_data)
|
||||
h->any_offset = 0;
|
||||
memset(h->table, 0, size * sizeof(h->table[0]));
|
||||
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]);
|
||||
return h;
|
||||
}
|
||||
|
||||
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_bucket: stb_bucket_free(GetBucket(ps)); break;
|
||||
case STB_ps_array : free(GetArray(ps)); break;
|
||||
@ -7650,7 +7726,7 @@ stb_ps *stb_ps_copy(stb_ps *ps)
|
||||
{
|
||||
int i;
|
||||
// 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_bucket: {
|
||||
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 i, code = 3 & (int) ps;
|
||||
assert((3 & (int) value) == STB_ps_direct);
|
||||
int i, code = 3 & (int)(size_t) ps;
|
||||
assert((3 & (int)(size_t) value) == STB_ps_direct);
|
||||
assert(stb_ps_fastlist_valid(value));
|
||||
// not a switch: order based on expected performance/power-law distribution
|
||||
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));
|
||||
#endif
|
||||
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(value != STB_DEL); // STB_DEL is less likely
|
||||
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
if (ps == NULL) return (stb_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;
|
||||
void **t = h->table;
|
||||
// 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;
|
||||
do {
|
||||
n = (n + s) & h->mask;
|
||||
} while (!stb_ps_empty(t[n]));
|
||||
} while (!stb_ps_empty((size_t)t[n]));
|
||||
}
|
||||
if (t[n] == STB_DEL)
|
||||
-- h->count_deletes;
|
||||
@ -7803,9 +7879,9 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value)
|
||||
#ifdef STB_DEBUG
|
||||
assert(stb_ps_find(ps, value));
|
||||
#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
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
return ps == value ? NULL : ps;
|
||||
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]));
|
||||
int i,j=0;
|
||||
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];
|
||||
assert(j == h->count);
|
||||
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)
|
||||
{
|
||||
assert(ps != NULL);
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
*value = ps;
|
||||
return NULL;
|
||||
@ -7919,7 +7995,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
|
||||
stb_ps_hash *h = GetHash(ps);
|
||||
void **t = h->table;
|
||||
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;
|
||||
*value = t[n];
|
||||
h->any_offset = (n+1) & h->mask;
|
||||
@ -7940,7 +8016,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count)
|
||||
{
|
||||
int i,n=0;
|
||||
void **p = NULL;
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
if (ps == NULL) { *count = 0; return NULL; }
|
||||
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);
|
||||
p = (void **) malloc(sizeof(*p) * h->count);
|
||||
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];
|
||||
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 i,n=0;
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
if (ps == NULL || size <= 0) return 0;
|
||||
list[0] = ps;
|
||||
@ -8000,7 +8076,7 @@ int stb_ps_writelist(stb_ps *ps, void **list, int size )
|
||||
stb_ps_hash *h = GetHash(ps);
|
||||
if (size <= 0) return 0;
|
||||
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];
|
||||
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 i;
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
if (ps == NULL) return STB_TRUE;
|
||||
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: {
|
||||
stb_ps_hash *h = GetHash(ps);
|
||||
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))
|
||||
return STB_FALSE;
|
||||
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)
|
||||
{
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
return ps != NULL;
|
||||
case STB_ps_bucket: {
|
||||
@ -8071,7 +8147,7 @@ void ** stb_ps_fastlist(stb_ps *ps, int *count)
|
||||
{
|
||||
static void *storage;
|
||||
|
||||
switch (3 & (int) ps) {
|
||||
switch (3 & (int)(size_t) ps) {
|
||||
case STB_ps_direct:
|
||||
if (ps == NULL) { *count = 0; return NULL; }
|
||||
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)
|
||||
{
|
||||
stb_nfa_edge z = { type, to };
|
||||
stb_nfa_edge z = { (stb_int16)type, (stb_uint16)to };
|
||||
if (matcher->nodes[from].out == NULL)
|
||||
stb_arr_malloc((void **) &matcher->nodes[from].out, matcher);
|
||||
stb_arr_push(matcher->nodes[from].out, z);
|
||||
@ -9831,7 +9907,7 @@ int stb_regex(char *regex, char *str)
|
||||
static char ** regexps;
|
||||
static char ** regexp_cache;
|
||||
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 (strcmp(regex, regexp_cache[(int) 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));
|
||||
mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping));
|
||||
for (i=0; i < stb_arr_len(regexps); ++i)
|
||||
mapping[stb_perfect_hash(&p, (int) regexps[i])] = i;
|
||||
z = stb_perfect_hash(&p, (int) regex);
|
||||
mapping[stb_perfect_hash(&p, (int)(size_t) regexps[i])] = i;
|
||||
z = stb_perfect_hash(&p, (int)(size_t) regex);
|
||||
}
|
||||
return stb_matcher_find(matchers[(int) mapping[z]], str);
|
||||
}
|
||||
@ -10357,7 +10433,7 @@ static void stb__write(unsigned char v)
|
||||
++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)
|
||||
{
|
||||
@ -10620,7 +10696,8 @@ static size_t stb_out_backpatch_id(void)
|
||||
|
||||
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) {
|
||||
memcpy((void *) id, data, 4);
|
||||
} else {
|
||||
|
31
stb_dxt.h
31
stb_dxt.h
@ -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
|
||||
// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation
|
||||
//
|
||||
@ -9,7 +9,8 @@
|
||||
// and "high quality" using mode.
|
||||
//
|
||||
// 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.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);
|
||||
@ -31,11 +32,6 @@
|
||||
#ifndef 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
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -46,15 +42,21 @@ extern "C" {
|
||||
#define STBDDEF extern
|
||||
#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_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);
|
||||
|
||||
#define STB_COMPRESS_DXT_BLOCK
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define STB_COMPRESS_DXT_BLOCK
|
||||
#endif // STB_INCLUDE_STB_DXT_H
|
||||
|
||||
#ifdef STB_DXT_IMPLEMENTATION
|
||||
|
||||
@ -88,7 +90,7 @@ STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *sr
|
||||
|
||||
#ifndef STBD_MEMSET
|
||||
#include <string.h>
|
||||
#define STBD_MEMSET(x) memset(x)
|
||||
#define STBD_MEMSET memset
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned char data[16][4];
|
||||
static int init=1;
|
||||
if (init) {
|
||||
stb__InitDXT();
|
||||
@ -656,8 +659,15 @@ void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int a
|
||||
}
|
||||
|
||||
if (alpha) {
|
||||
int i;
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4);
|
||||
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);
|
||||
@ -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);
|
||||
}
|
||||
#endif // STB_DXT_IMPLEMENTATION
|
||||
#endif // STB_INCLUDE_STB_DXT_H
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
|
545
stb_image.h
545
stb_image.h
@ -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
|
||||
|
||||
Do this:
|
||||
@ -48,6 +48,9 @@ LICENSE
|
||||
|
||||
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.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
|
||||
@ -74,11 +77,11 @@ RECENT REVISION HISTORY:
|
||||
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
|
||||
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
|
||||
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)
|
||||
Jeremy Sawicki (handle all ImageNet JPGs)
|
||||
Optimizations & bugfixes
|
||||
Fabian "ryg" Giesen
|
||||
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
|
||||
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
|
||||
Arseny Kapoulkine
|
||||
John-Mark Allen
|
||||
|
||||
@ -87,16 +90,17 @@ RECENT REVISION HISTORY:
|
||||
Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan
|
||||
Dave Moore Roy Eltham Hayaki Saito Nathan Reed
|
||||
Won Chun Luke Graham Johan Duparc Nick Verigakis
|
||||
the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson
|
||||
Janez Zemva John Bartholomew Michal Cichon github:rlyeh
|
||||
Jonathan Blow Ken Hamada Tero Hanninen github:romigrou
|
||||
Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk
|
||||
Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar
|
||||
Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex
|
||||
Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210
|
||||
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw
|
||||
Blazej Dariusz Roszkowski Gregory Mullen github:phprus
|
||||
Christian Floisand Kevin Schmidt github:poppolopoppo
|
||||
the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh
|
||||
Janez Zemva John Bartholomew Michal Cichon github:romigrou
|
||||
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
|
||||
Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar
|
||||
Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex
|
||||
Ryamond Barbiero Paul Du Bois Engin Manap github:grim210
|
||||
Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw
|
||||
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus
|
||||
Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo
|
||||
Christian Floisand Kevin Schmidt github:darealshinji
|
||||
Blazej Dariusz Roszkowski github:Michaelangel007
|
||||
*/
|
||||
|
||||
#ifndef STBI_INCLUDE_STB_IMAGE_H
|
||||
@ -105,10 +109,8 @@ RECENT REVISION HISTORY:
|
||||
// DOCUMENTATION
|
||||
//
|
||||
// Limitations:
|
||||
// - no 16-bit-per-channel PNG
|
||||
// - no 12-bit-per-channel JPEG
|
||||
// - no JPEGs with arithmetic coding
|
||||
// - no 1-bit BMP
|
||||
// - GIF always returns *comp=4
|
||||
//
|
||||
// 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_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
|
||||
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
|
||||
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_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
|
||||
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_is_16_bit (char const *filename);
|
||||
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
|
||||
#endif
|
||||
|
||||
|
||||
@ -504,7 +513,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
|
||||
#include <limits.h>
|
||||
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
#include <math.h> // ldexp
|
||||
#include <math.h> // ldexp, pow
|
||||
#endif
|
||||
|
||||
#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 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_is16(stbi__context *s);
|
||||
#endif
|
||||
|
||||
#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 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_is16(stbi__context *s);
|
||||
#endif
|
||||
|
||||
#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
|
||||
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__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);
|
||||
#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
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
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) &&
|
||||
stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
|
||||
}
|
||||
#endif
|
||||
|
||||
// mallocs with size overflow checking
|
||||
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);
|
||||
}
|
||||
|
||||
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
|
||||
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;
|
||||
return stbi__malloc(a*b*c*d + add);
|
||||
}
|
||||
#endif
|
||||
|
||||
// stbi__err - error
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
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)
|
||||
{
|
||||
#ifndef STBI_NO_HDR
|
||||
long pos = ftell(f);
|
||||
int res;
|
||||
stbi__context s;
|
||||
stbi__start_file(&s,f);
|
||||
return stbi__hdr_test(&s);
|
||||
res = stbi__hdr_test(&s);
|
||||
fseek(f, pos, SEEK_SET);
|
||||
return res;
|
||||
#else
|
||||
STBI_NOTUSED(f);
|
||||
return 0;
|
||||
@ -1705,7 +1753,8 @@ typedef struct
|
||||
|
||||
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)
|
||||
for (i=0; i < 16; ++i)
|
||||
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) {
|
||||
while (h->size[k] == j)
|
||||
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
|
||||
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 the result is small enough, we can fit it in fast_ac table
|
||||
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)
|
||||
{
|
||||
do {
|
||||
int b = j->nomore ? 0 : stbi__get8(j->s);
|
||||
unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
|
||||
if (b == 0xff) {
|
||||
int c = stbi__get8(j->s);
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
// 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,
|
||||
// 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,
|
||||
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__fsh(x) ((x) << 12)
|
||||
#define stbi__fsh(x) ((x) * 4096)
|
||||
|
||||
// derived from jidctint -- DCT_ISLOW
|
||||
#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
|
||||
// all separate -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;
|
||||
} else {
|
||||
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;
|
||||
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);
|
||||
if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
|
||||
++z->rgb;
|
||||
@ -3093,8 +3142,8 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
|
||||
} else if (stbi__DNL(m)) {
|
||||
int Ld = stbi__get16be(j->s);
|
||||
stbi__uint32 NL = stbi__get16be(j->s);
|
||||
if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG");
|
||||
if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG");
|
||||
if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
|
||||
if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
static int stbi__zlength_base[31] = {
|
||||
static const int stbi__zlength_base[31] = {
|
||||
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,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 };
|
||||
|
||||
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};
|
||||
|
||||
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};
|
||||
|
||||
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 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_uc lencodes[286+32+137];//padding for maximum single op
|
||||
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 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;
|
||||
for (i=0; i < 8; ++i)
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
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_len = (img_width_bytes + 1) * y;
|
||||
|
||||
// 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),
|
||||
// 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)
|
||||
{
|
||||
@ -4912,6 +4963,19 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
p.s = s;
|
||||
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
|
||||
|
||||
// Microsoft/Windows BMP image
|
||||
@ -4963,21 +5027,27 @@ static int stbi__bitcount(unsigned int a)
|
||||
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)
|
||||
{
|
||||
int result;
|
||||
int z=0;
|
||||
|
||||
if (shift < 0) v <<= -shift;
|
||||
else v >>= shift;
|
||||
result = v;
|
||||
|
||||
z = bits;
|
||||
while (z < 8) {
|
||||
result += v >> z;
|
||||
z += bits;
|
||||
}
|
||||
return result;
|
||||
static unsigned int mul_table[9] = {
|
||||
0,
|
||||
0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
|
||||
0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
|
||||
};
|
||||
static unsigned int shift_table[9] = {
|
||||
0, 0,0,1,0,2,4,6,0,
|
||||
};
|
||||
if (shift < 0)
|
||||
v <<= -shift;
|
||||
else
|
||||
v >>= shift;
|
||||
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
|
||||
@ -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");
|
||||
info->bpp = stbi__get16le(s);
|
||||
if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
|
||||
if (hsz != 12) {
|
||||
int compress = stbi__get32le(s);
|
||||
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;
|
||||
}
|
||||
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 { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
|
||||
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 (i=0; i < (int) s->img_x; i += 2) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=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;
|
||||
for (i=0; i < (int) s->img_x; ++i) {
|
||||
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 & mg, gshift, gcount));
|
||||
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)
|
||||
{
|
||||
// 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) {
|
||||
case 8: return STBI_grey;
|
||||
case 16: if(is_grey) return STBI_grey_alpha;
|
||||
// else: fall-through
|
||||
// fallthrough
|
||||
case 15: if(is_rgb16) *is_rgb16 = 1;
|
||||
return STBI_rgb;
|
||||
case 24: // fall-through
|
||||
case 24: // fallthrough
|
||||
case 32: return bits_per_pixel/8;
|
||||
default: return 0;
|
||||
}
|
||||
@ -6038,11 +6125,13 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
int w,h;
|
||||
stbi_uc *out, *old_out; // output buffer (always 4 components)
|
||||
int flags, bgindex, ratio, transparent, eflags, delay;
|
||||
stbi_uc *out; // output buffer (always 4 components)
|
||||
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 lpal[256][4];
|
||||
stbi__gif_lzw codes[4096];
|
||||
stbi__gif_lzw codes[8192];
|
||||
stbi_uc *color_table;
|
||||
int parse, step;
|
||||
int lflags;
|
||||
@ -6050,6 +6139,7 @@ typedef struct
|
||||
int max_x, max_y;
|
||||
int cur_x, cur_y;
|
||||
int line_size;
|
||||
int delay;
|
||||
} stbi__gif;
|
||||
|
||||
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)
|
||||
{
|
||||
stbi_uc *p, *c;
|
||||
int idx;
|
||||
|
||||
// recurse to decode the prefixes, since the linked-list is backwards,
|
||||
// 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;
|
||||
|
||||
p = &g->out[g->cur_x + g->cur_y];
|
||||
c = &g->color_table[g->codes[code].suffix * 4];
|
||||
idx = g->cur_x + g->cur_y;
|
||||
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[1] = c[1];
|
||||
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);
|
||||
return g->out;
|
||||
} 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) {
|
||||
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->first = g->codes[oldcode].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
|
||||
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;
|
||||
stbi_uc *prev_out = 0;
|
||||
int dispose;
|
||||
int first_frame;
|
||||
int pi;
|
||||
int pcount;
|
||||
|
||||
if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
|
||||
return 0; // stbi__g_failure_reason set by stbi__gif_header
|
||||
|
||||
if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))
|
||||
return stbi__errpuc("too large", "GIF too large");
|
||||
|
||||
prev_out = g->out;
|
||||
g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
|
||||
// on first frame, any non-written pixels get the background colour (non-transparent)
|
||||
first_frame = 0;
|
||||
if (g->out == 0) {
|
||||
if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
|
||||
g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
||||
g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
||||
g->history = (stbi_uc *) stbi__malloc(g->w * g->h);
|
||||
if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
|
||||
|
||||
switch ((g->eflags & 0x1C) >> 2) {
|
||||
case 0: // unspecified (also always used on 1st frame)
|
||||
stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);
|
||||
break;
|
||||
case 1: // do not dispose
|
||||
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
|
||||
g->old_out = prev_out;
|
||||
break;
|
||||
case 2: // dispose to background
|
||||
if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
|
||||
stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);
|
||||
break;
|
||||
case 3: // dispose to previous
|
||||
if (g->old_out) {
|
||||
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;
|
||||
// image is treated as "tranparent" at the start - ie, nothing overwrites the current background;
|
||||
// background colour is only used for pixels that are not rendered first frame, after that "background"
|
||||
// color refers to teh color that was there the previous frame.
|
||||
memset( g->out, 0x00, 4 * g->w * g->h );
|
||||
memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent)
|
||||
memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
|
||||
first_frame = 1;
|
||||
} else {
|
||||
// second frame - how do we dispoase of the previous one?
|
||||
dispose = (g->eflags & 0x1C) >> 2;
|
||||
pcount = g->w * g->h;
|
||||
|
||||
if ((dispose == 3) && (two_back == 0)) {
|
||||
dispose = 2; // if I don't have an image to revert back to, default to the old background
|
||||
}
|
||||
|
||||
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 (;;) {
|
||||
switch (stbi__get8(s)) {
|
||||
int tag = stbi__get8(s);
|
||||
switch (tag) {
|
||||
case 0x2C: /* Image Descriptor */
|
||||
{
|
||||
int prev_trans = -1;
|
||||
stbi__int32 x, y, w, h;
|
||||
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);
|
||||
g->color_table = (stbi_uc *) g->lpal;
|
||||
} 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;
|
||||
} else
|
||||
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);
|
||||
if (o == NULL) return NULL;
|
||||
|
||||
if (prev_trans != -1)
|
||||
g->pal[g->transparent][3] = (stbi_uc) prev_trans;
|
||||
// if this was the first frame,
|
||||
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;
|
||||
}
|
||||
@ -6344,19 +6457,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
||||
case 0x21: // Comment Extension.
|
||||
{
|
||||
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);
|
||||
if (len == 4) {
|
||||
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);
|
||||
if (g->transparent >= 0) {
|
||||
g->pal[g->transparent][3] = 0;
|
||||
}
|
||||
} else {
|
||||
// don't need transparent
|
||||
stbi__skip(s, 1);
|
||||
g->transparent = -1;
|
||||
}
|
||||
} else {
|
||||
stbi__skip(s, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((len = stbi__get8(s)) != 0)
|
||||
while ((len = stbi__get8(s)) != 0) {
|
||||
stbi__skip(s, len);
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
stbi_uc *u = 0;
|
||||
stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
|
||||
memset(g, 0, sizeof(*g));
|
||||
STBI_NOTUSED(ri);
|
||||
stbi__gif g;
|
||||
memset(&g, 0, sizeof(g));
|
||||
|
||||
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) {
|
||||
*x = g->w;
|
||||
*y = g->h;
|
||||
*x = g.w;
|
||||
*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)
|
||||
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);
|
||||
STBI_FREE(g);
|
||||
|
||||
// free buffers needed for multiple frame loading;
|
||||
STBI_FREE(g.history);
|
||||
STBI_FREE(g.background);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -6667,7 +6860,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
#ifndef STBI_NO_PSD
|
||||
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 (!y) y = &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);
|
||||
*x = stbi__get32be(s);
|
||||
if (stbi__get16be(s) != 8) {
|
||||
depth = stbi__get16be(s);
|
||||
if (depth != 8 && depth != 16) {
|
||||
stbi__rewind( s );
|
||||
return 0;
|
||||
}
|
||||
@ -6698,6 +6892,33 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
|
||||
*comp = 4;
|
||||
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
|
||||
|
||||
#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");
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
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;
|
||||
STBI_NO_STDIO works again;
|
||||
compilation fixes;
|
||||
|
@ -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
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
@ -10,34 +10,47 @@
|
||||
|
||||
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:
|
||||
|
||||
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.
|
||||
|
||||
The PNG output is not optimal; it is 20-50% larger than the file
|
||||
written by a decent optimizing implementation. This library is designed
|
||||
for source code compactness and simplicity, not optimal image file size
|
||||
or run-time performance.
|
||||
written by a decent optimizing implementation; though providing a custom
|
||||
zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
|
||||
This library is designed for source code compactness and simplicity,
|
||||
not optimal image file size or run-time performance.
|
||||
|
||||
BUILDING:
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
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_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_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_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:
|
||||
|
||||
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:
|
||||
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
|
||||
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.
|
||||
@ -75,6 +94,9 @@ USAGE:
|
||||
writer, both because it is in BGR order and because it may have padding
|
||||
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)
|
||||
data, alpha (if provided) is discarded, and for monochrome data it is
|
||||
replicated across all three channels.
|
||||
@ -88,21 +110,17 @@ USAGE:
|
||||
|
||||
CREDITS:
|
||||
|
||||
PNG/BMP/TGA
|
||||
Sean Barrett
|
||||
HDR
|
||||
Baldur Karlsson
|
||||
TGA monochrome:
|
||||
Jean-Sebastien Guay
|
||||
misc enhancements:
|
||||
Tim Kelsey
|
||||
TGA RLE
|
||||
Alan Hickman
|
||||
initial file IO callback implementation
|
||||
Emmanuel Julien
|
||||
JPEG
|
||||
Jon Olick (original jo_jpeg.cpp code)
|
||||
Daniel Gibson
|
||||
|
||||
Sean Barrett - PNG/BMP/TGA
|
||||
Baldur Karlsson - HDR
|
||||
Jean-Sebastien Guay - TGA monochrome
|
||||
Tim Kelsey - misc enhancements
|
||||
Alan Hickman - TGA RLE
|
||||
Emmanuel Julien - initial file IO callback implementation
|
||||
Jon Olick - original jo_jpeg.cpp code
|
||||
Daniel Gibson - integrate JPEG, allow external zlib
|
||||
Aarni Koskela - allow choosing PNG filter
|
||||
|
||||
bugfixes:
|
||||
github:Chribba
|
||||
Guillaume Chereau
|
||||
@ -114,6 +132,12 @@ CREDITS:
|
||||
Thatcher Ulrich
|
||||
github:poppolopoppo
|
||||
Patrick Boettcher
|
||||
github:xeekworx
|
||||
Cap Petschulat
|
||||
Simon Rodriguez
|
||||
Ivan Tikhonov
|
||||
github:ignotion
|
||||
Adam Schackart
|
||||
|
||||
LICENSE
|
||||
|
||||
@ -124,15 +148,23 @@ LICENSE
|
||||
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||
#define INCLUDE_STB_IMAGE_WRITE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
|
||||
#ifndef STBIWDEF
|
||||
#ifdef STB_IMAGE_WRITE_STATIC
|
||||
#define STBIWDEF static
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
#define STBIWDEF extern "C"
|
||||
#else
|
||||
#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_png_compression_level;
|
||||
extern int stbi_write_force_png_filter;
|
||||
#endif
|
||||
|
||||
#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_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
|
||||
|
||||
#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)
|
||||
|
||||
#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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return f != NULL;
|
||||
}
|
||||
@ -245,12 +298,6 @@ static void stbi__end_write_file(stbi__write_context *s)
|
||||
typedef unsigned int stbiw_uint32;
|
||||
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)
|
||||
{
|
||||
while (*fmt) {
|
||||
@ -341,6 +388,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
|
||||
if (y <= 0)
|
||||
return;
|
||||
|
||||
if (stbi__flip_vertically_on_write)
|
||||
vdir *= -1;
|
||||
|
||||
if (vdir < 0)
|
||||
j_end = -1, j = y-1;
|
||||
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);
|
||||
} else {
|
||||
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);
|
||||
|
||||
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;
|
||||
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";
|
||||
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);
|
||||
#endif
|
||||
s->func(s->context, buffer, len);
|
||||
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
@ -662,6 +726,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
|
||||
// PNG writer
|
||||
//
|
||||
|
||||
#ifndef STBIW_ZLIB_COMPRESS
|
||||
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
|
||||
#define stbiw__sbraw(a) ((int *) (a) - 2)
|
||||
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
|
||||
@ -742,8 +807,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
|
||||
|
||||
#define stbiw__ZHASH 16384
|
||||
|
||||
#endif // STBIW_ZLIB_COMPRESS
|
||||
|
||||
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 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 };
|
||||
@ -752,6 +823,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
||||
int i,j, bitcount=0;
|
||||
unsigned char *out = NULL;
|
||||
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
|
||||
if (hash_table == NULL)
|
||||
return NULL;
|
||||
if (quality < 5) quality = 5;
|
||||
|
||||
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
|
||||
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
|
||||
return (unsigned char *) stbiw__sbraw(out);
|
||||
#endif // STBIW_ZLIB_COMPRESS
|
||||
}
|
||||
|
||||
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
|
||||
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 firstmap[] = { 0,1,0,5,6 };
|
||||
int *mymap = (j != 0) ? mapping : firstmap;
|
||||
int best = 0, bestval = 0x7fffffff;
|
||||
for (p=0; p < 2; ++p) {
|
||||
for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass
|
||||
int type = mymap[k],est=0;
|
||||
unsigned char *z = pixels + stride_bytes*j;
|
||||
for (i=0; i < n; ++i)
|
||||
int *mymap = (y != 0) ? mapping : firstmap;
|
||||
int i;
|
||||
int type = mymap[filter_type];
|
||||
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
|
||||
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
|
||||
for (i = 0; i < n; ++i) {
|
||||
switch (type) {
|
||||
case 0: 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 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
|
||||
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
|
||||
case 2: line_buffer[i] = z[i] - z[i-signed_stride]; 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-signed_stride],0)); break;
|
||||
case 5: 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) {
|
||||
case 0: line_buffer[i] = z[i]; 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 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>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 2: line_buffer[i] = z[i] - z[i-signed_stride]; 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-signed_stride], z[i-signed_stride-n]); 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;
|
||||
}
|
||||
}
|
||||
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]);
|
||||
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
|
||||
filt[j*(x*n+1)] = (unsigned char) best;
|
||||
if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
|
||||
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_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);
|
||||
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;
|
||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||
if (png == NULL) return 0;
|
||||
#ifdef STBI_MSC_SECURE_CRT
|
||||
if (fopen_s(&f, filename, "wb"))
|
||||
f = NULL;
|
||||
#else
|
||||
f = fopen(filename, "wb");
|
||||
#endif
|
||||
if (!f) { STBIW_FREE(png); return 0; }
|
||||
fwrite(png, 1, len, 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];
|
||||
for(row = y, pos = 0; row < y+8; ++row) {
|
||||
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;
|
||||
if(row >= 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
|
||||
|
||||
/* 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)
|
||||
doc fix
|
||||
1.06 (2017-07-23)
|
||||
|
@ -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
|
||||
// http://github.com/nothings/stb
|
||||
//
|
||||
@ -12,6 +12,9 @@
|
||||
// github:d26435
|
||||
// github:trex78
|
||||
// Jari Komppa (SI suffixes)
|
||||
// Rohit Nirmal
|
||||
// Marcin Wojdyr
|
||||
// Leonard Ritter
|
||||
//
|
||||
// LICENSE:
|
||||
//
|
||||
@ -927,7 +930,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
|
||||
fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0;
|
||||
pr = sizeof(void *) * 2;
|
||||
fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros
|
||||
// drop through to X
|
||||
// fall through - to X
|
||||
|
||||
case 'X': // upper hex
|
||||
case 'x': // lower hex
|
||||
@ -1025,11 +1028,11 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
|
||||
n64 = 0;
|
||||
}
|
||||
if ((fl & STBSP__TRIPLET_COMMA) == 0) {
|
||||
while (n) {
|
||||
do {
|
||||
s -= 2;
|
||||
*(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2];
|
||||
n /= 100;
|
||||
}
|
||||
} while (n);
|
||||
}
|
||||
while (n) {
|
||||
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 = f[0];
|
||||
l = 1;
|
||||
fw = pr = fl = 0;
|
||||
fw = fl = 0;
|
||||
lead[0] = 0;
|
||||
tail[0] = 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
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
c.buf = buf;
|
||||
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
|
||||
l = (int)(c.buf - buf);
|
||||
if (l >= count) // should never be greater, only equal (or less) than count
|
||||
l = (int)( c.buf - buf );
|
||||
if ( l >= count ) // should never be greater, only equal (or less) than count
|
||||
l = count - 1;
|
||||
buf[l] = 0;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
@ -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
|
||||
//
|
||||
// This C header file implements the guts of a multi-line text-editing
|
||||
@ -29,6 +29,7 @@
|
||||
//
|
||||
// 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.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
|
||||
// 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)
|
||||
// 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)
|
||||
// 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
|
||||
// state.
|
||||
@ -232,7 +233,9 @@
|
||||
// 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
|
||||
// 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
|
||||
// the STB_TexteditState.
|
||||
@ -711,8 +714,12 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef STB_TEXTEDIT_KEYTYPE
|
||||
#define STB_TEXTEDIT_KEYTYPE int
|
||||
#endif
|
||||
|
||||
// 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:
|
||||
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 (state->undo_rec[k].char_storage >= 0) {
|
||||
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
|
||||
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)
|
||||
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;
|
||||
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
|
||||
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:
|
||||
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
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];
|
||||
|
||||
@ -1278,6 +1288,7 @@ static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
if (r.insert_length) {
|
||||
// easy case: need to insert n characters
|
||||
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;
|
||||
|
@ -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 over = stbte__hittest(x0,y0,x1,y1,id);
|
||||
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));
|
||||
}
|
||||
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 over = !disabled && stbte__hittest(x0,y0,x1,y1,id);
|
||||
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;
|
||||
stbte__draw_textbox(x0,y0,x1,y1, str, off+1,2, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled));
|
||||
}
|
||||
|
381
stb_truetype.h
381
stb_truetype.h
@ -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
|
||||
//
|
||||
// This library processes TrueType files:
|
||||
@ -22,41 +22,35 @@
|
||||
// Mikko Mononen: compound shape support, more cmap formats
|
||||
// Tor Andersson: kerning, subpixel rendering
|
||||
// Dougall Johnson: OpenType / Type 2 font handling
|
||||
// Daniel Ribeiro Maciel: basic GPOS-based kerning
|
||||
//
|
||||
// Misc other:
|
||||
// Ryan Gordon
|
||||
// Simon Glass
|
||||
// github:IntellectualKitty
|
||||
// Imanol Celaya
|
||||
// Daniel Ribeiro Maciel
|
||||
//
|
||||
// Bug/warning reports/fixes:
|
||||
// "Zer" on mollyrocket
|
||||
// Cass Everitt
|
||||
// stoiko (Haemimont Games)
|
||||
// Brian Hook
|
||||
// Walter van Niftrik
|
||||
// David Gow
|
||||
// David Given
|
||||
// Ivan-Assen Ivanov
|
||||
// Anthony Pesch
|
||||
// Johan Duparc
|
||||
// Hou Qiming
|
||||
// Fabian "ryg" Giesen
|
||||
// Martins Mozeiko
|
||||
// Cap Petschulat
|
||||
// Omar Cornut
|
||||
// github:aloucks
|
||||
// Peter LaValle
|
||||
// Sergey Popov
|
||||
// Giumo X. Clanjor
|
||||
// Higor Euripedes
|
||||
// Thomas Fields
|
||||
// Derek Vinyard
|
||||
// Cort Stratton
|
||||
// github:oyvindjam
|
||||
// "Zer" on mollyrocket Fabian "ryg" Giesen
|
||||
// Cass Everitt Martins Mozeiko
|
||||
// stoiko (Haemimont Games) Cap Petschulat
|
||||
// Brian Hook Omar Cornut
|
||||
// Walter van Niftrik github:aloucks
|
||||
// David Gow Peter LaValle
|
||||
// David Given Sergey Popov
|
||||
// Ivan-Assen Ivanov Giumo X. Clanjor
|
||||
// Anthony Pesch Higor Euripedes
|
||||
// Johan Duparc Thomas Fields
|
||||
// Hou Qiming Derek Vinyard
|
||||
// Rob Loach Cort Stratton
|
||||
// Kenney Phillis Jr. github:oyvindjam
|
||||
// Brian Costabile github:vassvik
|
||||
//
|
||||
// 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.16 (2017-07-12) SDF support
|
||||
// 1.15 (2017-03-03) make more arguments const
|
||||
@ -171,7 +165,7 @@
|
||||
// measurement for describing font size, defined as 72 points per inch.
|
||||
// stb_truetype provides a point API for compatibility. However, true
|
||||
// "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
|
||||
// there are 96 pixels per inch, thus making 'inch' measurements have
|
||||
// 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
|
||||
// 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
|
||||
//
|
||||
// Quality:
|
||||
@ -387,7 +414,8 @@ int main(int arg, char **argv)
|
||||
//// INTEGRATION WITH YOUR CODEBASE
|
||||
////
|
||||
//// 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
|
||||
// #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_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
|
||||
#include <math.h>
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#ifndef STBTT_fmod
|
||||
#include <math.h>
|
||||
#define STBTT_fmod(x,y) fmod(x,y)
|
||||
#endif
|
||||
|
||||
#ifndef STBTT_cos
|
||||
#include <math.h>
|
||||
#define STBTT_cos(x) cos(x)
|
||||
@ -427,11 +460,6 @@ int main(int arg, char **argv)
|
||||
#define STBTT_fabs(x) fabs(x)
|
||||
#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
|
||||
#ifndef STBTT_malloc
|
||||
#include <stdlib.h>
|
||||
@ -676,7 +704,7 @@ struct stbtt_fontinfo
|
||||
|
||||
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 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->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // 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)
|
||||
return 0;
|
||||
@ -2172,7 +2201,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
||||
|
||||
// push immediate
|
||||
if (b0 == 255) {
|
||||
f = (float)stbtt__buf_get32(&b) / 0x10000;
|
||||
f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
|
||||
} else {
|
||||
stbtt__buf_skip(&b, -1);
|
||||
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);
|
||||
int r = stbtt__run_charstring(info, glyph_index, &c);
|
||||
if (x0) {
|
||||
*x0 = r ? c.min_x : 0;
|
||||
*y0 = r ? c.min_y : 0;
|
||||
*x1 = r ? c.max_x : 0;
|
||||
*y1 = r ? c.max_y : 0;
|
||||
}
|
||||
if (x0) *x0 = r ? c.min_x : 0;
|
||||
if (y0) *y0 = r ? c.min_y : 0;
|
||||
if (x1) *x1 = r ? c.max_x : 0;
|
||||
if (y1) *y1 = r ? c.max_y : 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_uint32 needle, straw;
|
||||
@ -2269,9 +2296,260 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1,
|
||||
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)
|
||||
{
|
||||
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 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;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (windings) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_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;
|
||||
if (discr > 0.0) {
|
||||
float rcpna = -1 / a;
|
||||
float d = (float) sqrt(discr);
|
||||
float d = (float) STBTT_sqrt(discr);
|
||||
s0 = (b+d) * rcpna;
|
||||
s1 = (b-d) * rcpna;
|
||||
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;
|
||||
|
||||
// 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)
|
||||
y += 0.01f;
|
||||
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
|
||||
//
|
||||
// 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.15 (2017-03-03) make more arguments const
|
||||
// 1.14 (2017-01-16) num-fonts-in-TTC function
|
||||
|
83
stb_vorbis.c
83
stb_vorbis.c
@ -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/
|
||||
//
|
||||
// Original version written by Sean Barrett in 2007.
|
||||
//
|
||||
// Originally sponsored by RAD Game Tools. Seeking sponsored
|
||||
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
|
||||
// Aras Pranckevicius, and Sean Barrett.
|
||||
// Originally sponsored by RAD Game Tools. Seeking implementation
|
||||
// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
|
||||
// Elias Software, Aras Pranckevicius, and Sean Barrett.
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
@ -30,22 +30,26 @@
|
||||
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
|
||||
// Phillip Bennefall Rohit Thiago Goulart
|
||||
// manxorist@github saga musix github:infatum
|
||||
// Timur Gagiev
|
||||
//
|
||||
// Partial history:
|
||||
// 1.11 - 2017/07/23 - fix MinGW compilation
|
||||
// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory
|
||||
// 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)
|
||||
// 1.14 - 2018-02-11 - delete bogus dealloca usage
|
||||
// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)
|
||||
// 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
|
||||
// 1.11 - 2017-07-23 - fix MinGW compilation
|
||||
// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory
|
||||
// 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
|
||||
// fix some inappropriately signed shifts
|
||||
// 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.03 - 2014/08/07 - warning fixes
|
||||
// 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.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
|
||||
// 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.03 - 2014-08-07 - warning fixes
|
||||
// 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.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
|
||||
// (API change) report sample rate for decode-full-file funcs
|
||||
//
|
||||
// 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 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
|
||||
#endif
|
||||
#define temp_alloc_save(f) ((f)->temp_offset)
|
||||
#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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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 c = r->classbook;
|
||||
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 temp_alloc_point = temp_alloc_save(f);
|
||||
#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 we have a valid current loc, and this is final:
|
||||
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
|
||||
if (current_end < f->current_loc + (right_end-left_start)) {
|
||||
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 {
|
||||
*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
|
||||
f->current_loc += *len;
|
||||
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->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);
|
||||
memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1);
|
||||
#ifdef STB_VORBIS_NO_DEFER_FLOOR
|
||||
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);
|
||||
@ -4077,7 +4083,10 @@ static int start_decoder(vorb *f)
|
||||
int i,max_part_read=0;
|
||||
for (i=0; i < f->residue_count; ++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;
|
||||
if (part_read > max_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 *));
|
||||
#endif
|
||||
|
||||
// maximum reasonable partition size is f->blocksize_1
|
||||
|
||||
f->temp_memory_required = classify_mem;
|
||||
if (imdct_mem > f->temp_memory_required)
|
||||
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
|
||||
|
||||
/* Version history
|
||||
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;
|
||||
1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files
|
||||
1.11 - 2017-07-23 - fix MinGW compilation
|
||||
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
|
||||
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
|
||||
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
|
||||
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.03 - 2014/08/07 - Warning fixes
|
||||
1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows
|
||||
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.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.03 - 2014-08-07 - Warning fixes
|
||||
1.02 - 2014-07-09 - Declare qsort compare function _cdecl on windows
|
||||
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
|
||||
(API change) report sample rate for decode-full-file funcs
|
||||
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
|
||||
|
@ -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
|
||||
//
|
||||
// version history:
|
||||
// 1.03 - compile as C++ maybe
|
||||
// 1.02 - tweaks to syntax for no good reason
|
||||
// 1.01 - added a "common uses" documentation section
|
||||
// 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
|
||||
// possible to do this in a generic, type-safe way in C.
|
||||
//
|
||||
// Contributors:
|
||||
//
|
||||
// Timothy Wright (github:ZenToad)
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// 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__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>
|
||||
|
||||
|
@ -4,4 +4,4 @@ CPPFLAGS = -Wno-write-strings -DSTB_DIVIDE_TEST
|
||||
|
||||
all:
|
||||
$(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++
|
||||
|
@ -37,7 +37,8 @@ extern void ods(char *fmt, ...);
|
||||
#define FAST_CHUNK
|
||||
#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,
|
||||
// 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, },
|
||||
|
||||
// 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_cross, 80,80,80,80,80,80 }, // torch
|
||||
{ C_empty }, // fire
|
||||
@ -142,6 +144,7 @@ unsigned char minecraft_info[256][7] =
|
||||
|
||||
// 56
|
||||
{ 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, 60,59,59,59,43,43 },
|
||||
{ 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[10][i] = 63; // emissive lava
|
||||
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
|
||||
|
3305
tests/prerelease/stb_lib.h
Normal file
3305
tests/prerelease/stb_lib.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -66,7 +66,7 @@ LINK32=link.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# 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 /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
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
@ -190,6 +190,34 @@ SOURCE=.\test_c_compilation.c
|
||||
# End 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
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -198,6 +226,10 @@ SOURCE=.\test_vorbis.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\test_voxel.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\textedit_sample.c
|
||||
# End Source File
|
||||
# End Target
|
||||
|
@ -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>
|
||||
|
||||
Package=<5>
|
||||
|
102
tests/stblib.dsp
Normal file
102
tests/stblib.dsp
Normal 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
11
tests/stblib_test.c
Normal 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)
|
||||
{
|
||||
|
||||
}
|
4
tests/stblib_test_companion.c
Normal file
4
tests/stblib_test_companion.c
Normal file
@ -0,0 +1,4 @@
|
||||
//#include "stb_regex.h"
|
||||
//#include "stb_regex.h"
|
||||
#include "prerelease/stb_lib.h"
|
||||
#include "prerelease/stb_lib.h"
|
@ -1,10 +1,8 @@
|
||||
#include "stb_sprintf.h"
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "stb_sprintf.h"
|
||||
|
||||
#define STB_PERLIN_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_DXT_IMPLEMENATION
|
||||
#define STB_C_LEXER_IMPLEMENTATIOn
|
||||
#define STB_DIVIDE_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
@ -14,17 +12,18 @@
|
||||
#define STB_VOXEL_RENDER_IMPLEMENTATION
|
||||
#define STB_EASY_FONT_IMPLEMENTATION
|
||||
|
||||
#include "stb_easy_font.h"
|
||||
#include "stb_herringbone_wang_tile.h"
|
||||
#include "stb_image.h"
|
||||
#include "stb_image_write.h"
|
||||
#include "stb_perlin.h"
|
||||
#include "stb_dxt.h"
|
||||
#include "stb_c_lexer.h"
|
||||
#include "stb_divide.h"
|
||||
#include "stb_image_resize.h"
|
||||
#include "stb_rect_pack.h"
|
||||
|
||||
#define STB_DXT_IMPLEMENTATION
|
||||
#include "stb_dxt.h"
|
||||
|
||||
#define STBVOX_CONFIG_MODE 1
|
||||
#include "stb_voxel_render.h"
|
||||
|
||||
|
1
tests/test_c_lexer.c
Normal file
1
tests/test_c_lexer.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_c_lexer.h"
|
@ -2,9 +2,11 @@
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "stb_sprintf.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_STATIC
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#define STB_PERLIN_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_DXT_IMPLEMENATION
|
||||
#define STB_C_LEXER_IMPLEMENTATIOn
|
||||
#define STB_DIVIDE_IMPLEMENTATION
|
||||
|
1
tests/test_dxt.c
Normal file
1
tests/test_dxt.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_dxt.h"
|
1
tests/test_easyfont.c
Normal file
1
tests/test_easyfont.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_easy_font.h"
|
1
tests/test_image.c
Normal file
1
tests/test_image.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_image.h"
|
1
tests/test_image_write.c
Normal file
1
tests/test_image_write.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_image_write.h"
|
1
tests/test_perlin.c
Normal file
1
tests/test_perlin.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_perlin.h"
|
1
tests/test_sprintf.c
Normal file
1
tests/test_sprintf.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_sprintf.h"
|
@ -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"
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
@ -7,7 +15,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
char ttf_buffer[1<<25];
|
||||
unsigned char ttf_buffer[1 << 25];
|
||||
unsigned char output[512*100];
|
||||
|
||||
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);
|
||||
|
||||
pr[0].chardata_for_range = pdata;
|
||||
pr[0].first_unicode_char_in_range = 32;
|
||||
pr[0].num_chars_in_range = 95;
|
||||
pr[0].array_of_unicode_codepoints = NULL;
|
||||
pr[0].first_unicode_codepoint_in_range = 32;
|
||||
pr[0].num_chars = 95;
|
||||
pr[0].font_size = 20.0f;
|
||||
pr[1].chardata_for_range = pdata+256;
|
||||
pr[1].first_unicode_char_in_range = 0xa0;
|
||||
pr[1].num_chars_in_range = 0x100 - 0xa0;
|
||||
pr[1].array_of_unicode_codepoints = NULL;
|
||||
pr[1].first_unicode_codepoint_in_range = 0xa0;
|
||||
pr[1].num_chars = 0x100 - 0xa0;
|
||||
pr[1].font_size = 20.0f;
|
||||
|
||||
stbtt_PackSetOversampling(&pc, 2, 2);
|
||||
|
1
tests/test_voxel.c
Normal file
1
tests/test_voxel.c
Normal file
@ -0,0 +1 @@
|
||||
#include "stb_voxel_render.h"
|
Loading…
Reference in New Issue
Block a user