Merge branch 'master' into working

Conflicts:
	stb_image.h
This commit is contained in:
Sean Barrett 2018-01-29 04:04:28 -08:00
commit 5db03ef592
21 changed files with 3359 additions and 1245 deletions

View File

@ -11,17 +11,17 @@ by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
library | lastest version | category | LoC | description library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | -------------------------------- --------------------- | ---- | -------- | --- | --------------------------------
**[stb_vorbis.c](stb_vorbis.c)** | 1.10 | audio | 5447 | decode ogg vorbis files from file/memory to float/16-bit signed output **[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.15 | graphics | 7177 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **[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.15 | graphics | 4061 | parse, decode, and rasterize characters from truetype fonts **[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.05 | graphics | 1092 | image writing to disk: PNG, TGA, BMP **[stb_image_write.h](stb_image_write.h)** | 1.07 | graphics | 1458 | image writing to disk: PNG, TGA, BMP
**[stb_image_resize.h](stb_image_resize.h)** | 0.94 | graphics | 2624 | resize images larger/smaller with good quality **[stb_image_resize.h](stb_image_resize.h)** | 0.95 | graphics | 2627 | resize images larger/smaller with good quality
**[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 635 | simple 2D rectangle packer with decent quality **[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 624 | simple 2D rectangle packer with decent quality
**[stb_sprintf.h](stb_sprintf.h)** | 1.02 | utility | 1202 | fast sprintf, snprintf for C/C++ **[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++ **[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&nbsp;interface | 1393 | guts of a text editor for games etc implementing them from scratch **[stb_textedit.h](stb_textedit.h)** | 1.11 | user&nbsp;interface | 1393 | guts of a text editor for games etc implementing them from scratch
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D&nbsp;graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features **[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D&nbsp;graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
**[stb_dxt.h](stb_dxt.h)** | 1.06 | 3D&nbsp;graphics | 687 | Fabian "ryg" Giesen's real-time DXT compressor **[stb_dxt.h](stb_dxt.h)** | 1.07 | 3D&nbsp;graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor
**[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D&nbsp;graphics | 316 | revised Perlin noise (3D input, 1D output) **[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D&nbsp;graphics | 316 | revised Perlin noise (3D input, 1D output)
**[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D&nbsp;graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc **[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D&nbsp;graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game&nbsp;dev | 4172 | embeddable tilemap editor **[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game&nbsp;dev | 4172 | embeddable tilemap editor
@ -29,11 +29,11 @@ library | lastest version | category | LoC | description
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages **[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages
**[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide" **[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide"
**[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids **[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids
**[stb.h](stb.h)** | 2.29 | misc | 14324 | helper functions for C, mostly redundant in C++; basically author's personal stuff **[stb.h](stb.h)** | 2.30 | misc | 14328 | helper functions for C, mostly redundant in C++; basically author's personal stuff
**[stb_leakcheck.h](stb_leakcheck.h)** | 0.3 | misc | 165 | quick-and-dirty malloc/free leak-checking **[stb_leakcheck.h](stb_leakcheck.h)** | 0.4 | misc | 186 | quick-and-dirty malloc/free leak-checking
Total libraries: 20 Total libraries: 20
Total lines of C code: 51304 Total lines of C code: 52846
FAQ FAQ
@ -58,6 +58,22 @@ dual-license for you to choose from.
No, because it's public domain you can freely relicense it to whatever license your new No, because it's public domain you can freely relicense it to whatever license your new
library wants to be. library wants to be.
#### What's the deal with SSE support in GCC-based compilers?
stb_image will either use SSE2 (if you compile with -msse2) or
will not use any SIMD at all, rather than trying to detect the
processor at runtime and handle it correctly. As I understand it,
the approved path in GCC for runtime-detection require
you to use multiple source files, one for each CPU configuration.
Because stb_image is a header-file library that compiles in only
one source file, there's no approved way to build both an
SSE-enabled and a non-SSE-enabled variation.
While we've tried to work around it, we've had multiple issues over
the years due to specific versions of gcc breaking what we're doing,
so we've given up on it. See https://github.com/nothings/stb/issues/280
and https://github.com/nothings/stb/issues/410 for examples.
#### Some of these libraries seem redundant to existing open source libraries. Are they better somehow? #### Some of these libraries seem redundant to existing open source libraries. Are they better somehow?
Generally they're only better in that they're easier to integrate, Generally they're only better in that they're easier to integrate,

96
stb.h
View File

@ -1,4 +1,4 @@
/* stb.h - v2.29 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h /* stb.h - v2.31 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
no warranty is offered or implied; use this code at your own risk no warranty is offered or implied; use this code at your own risk
This is a single header file with a bunch of useful utilities This is a single header file with a bunch of useful utilities
@ -25,6 +25,8 @@
Version History Version History
2.31 stb_ucharcmp
2.30 MinGW fix
2.29 attempt to fix use of swprintf() 2.29 attempt to fix use of swprintf()
2.28 various new functionality 2.28 various new functionality
2.27 test _WIN32 not WIN32 in STB_THREADS 2.27 test _WIN32 not WIN32 in STB_THREADS
@ -185,14 +187,18 @@ CREDITS
Robert Nix Robert Nix
r-lyeh r-lyeh
blackpawn blackpawn
Mojofreem@github github:Mojofreem
Ryan Whitworth Ryan Whitworth
Vincent Isambart Vincent Isambart
Mike Sartain Mike Sartain
Eugene Opalev Eugene Opalev
Tim Sjostrand Tim Sjostrand
github:infatum
Dave Butler (Croepha)
*/ */
#include <stdarg.h>
#ifndef STB__INCLUDE_STB_H #ifndef STB__INCLUDE_STB_H
#define STB__INCLUDE_STB_H #define STB__INCLUDE_STB_H
@ -1544,7 +1550,7 @@ STB_EXTERN int (*stb_doublecmp(int offset))(const void *a, const void *b);
STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b); STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b);
#ifdef STB_DEFINE #ifdef STB_DEFINE
static int stb__intcmpoffset, stb__charcmpoffset, stb__strcmpoffset; static int stb__intcmpoffset, stb__ucharcmpoffset, stb__strcmpoffset;
static int stb__floatcmpoffset, stb__doublecmpoffset; static int stb__floatcmpoffset, stb__doublecmpoffset;
int stb__intcmp(const void *a, const void *b) int stb__intcmp(const void *a, const void *b)
@ -1554,10 +1560,10 @@ int stb__intcmp(const void *a, const void *b)
return p < q ? -1 : p > q; return p < q ? -1 : p > q;
} }
int stb__charcmp(const void *a, const void *b) int stb__ucharcmp(const void *a, const void *b)
{ {
const int p = *(const unsigned char *) ((const char *) a + stb__charcmpoffset); const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset);
const int q = *(const unsigned char *) ((const char *) b + stb__charcmpoffset); const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset);
return p < q ? -1 : p > q; return p < q ? -1 : p > q;
} }
@ -1595,10 +1601,10 @@ int (*stb_intcmp(int offset))(const void *, const void *)
return &stb__intcmp; return &stb__intcmp;
} }
int (*stb_charcmp(int offset))(const void *, const void *) int (*stb_ucharcmp(int offset))(const void *, const void *)
{ {
stb__charcmpoffset = offset; stb__ucharcmpoffset = offset;
return &stb__charcmp; return &stb__ucharcmp;
} }
int (*stb_qsort_strcmp(int offset))(const void *, const void *) int (*stb_qsort_strcmp(int offset))(const void *, const void *)
@ -1624,7 +1630,6 @@ int (*stb_doublecmp(int offset))(const void *, const void *)
stb__doublecmpoffset = offset; stb__doublecmpoffset = offset;
return &stb__doublecmp; return &stb__doublecmp;
} }
#endif #endif
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -1791,7 +1796,7 @@ STB_EXTERN int stb_prefix (char *s, char *t);
STB_EXTERN char * stb_strichr(char *s, char t); STB_EXTERN char * stb_strichr(char *s, char t);
STB_EXTERN char * stb_stristr(char *s, char *t); STB_EXTERN char * stb_stristr(char *s, char *t);
STB_EXTERN int stb_prefix_count(char *s, char *t); STB_EXTERN int stb_prefix_count(char *s, char *t);
STB_EXTERN char * stb_plural(int n); // "s" or "" STB_EXTERN const char * stb_plural(int n); // "s" or ""
STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n); STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n);
STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count);
@ -1818,7 +1823,7 @@ size_t stb_strscpy(char *d, const char *s, size_t n)
return len + 1; return len + 1;
} }
char *stb_plural(int n) const char *stb_plural(int n)
{ {
return n == 1 ? "" : "s"; return n == 1 ? "" : "s";
} }
@ -3358,7 +3363,7 @@ unsigned int stb_hashlen(char *str, int len)
unsigned int stb_hashptr(void *p) unsigned int stb_hashptr(void *p)
{ {
unsigned int x = (unsigned int) p; unsigned int x = (unsigned int)(size_t) p;
// typically lacking in low bits and high bits // typically lacking in low bits and high bits
x = stb_rehash(x); x = stb_rehash(x);
@ -3407,7 +3412,7 @@ unsigned int stb_hash_fast(void *p, int len)
if (len <= 0 || q == NULL) return 0; if (len <= 0 || q == NULL) return 0;
/* Main loop */ /* Main loop */
if (((int) q & 1) == 0) { if (((int)(size_t) q & 1) == 0) {
for (;len > 3; len -= 4) { for (;len > 3; len -= 4) {
unsigned int val; unsigned int val;
hash += stb__get16(q); hash += stb__get16(q);
@ -3733,7 +3738,7 @@ int stb_ischar(char c, char *set)
static unsigned char (*tables)[256]; static unsigned char (*tables)[256];
static char ** sets = NULL; static char ** sets = NULL;
int z = stb_perfect_hash(&p, (int) set); int z = stb_perfect_hash(&p, (int)(size_t) set);
if (z < 0) { if (z < 0) {
int i,k,n,j,f; int i,k,n,j,f;
// special code that means free all existing data // special code that means free all existing data
@ -3752,7 +3757,7 @@ int stb_ischar(char c, char *set)
tables = (unsigned char (*)[256]) realloc(tables, sizeof(*tables) * k); tables = (unsigned char (*)[256]) realloc(tables, sizeof(*tables) * k);
memset(tables, 0, sizeof(*tables) * k); memset(tables, 0, sizeof(*tables) * k);
for (i=0; i < stb_arr_len(sets); ++i) { for (i=0; i < stb_arr_len(sets); ++i) {
k = stb_perfect_hash(&p, (int) sets[i]); k = stb_perfect_hash(&p, (int)(size_t) sets[i]);
assert(k >= 0); assert(k >= 0);
n = k >> 3; n = k >> 3;
f = bit[k&7]; f = bit[k&7];
@ -3760,7 +3765,7 @@ int stb_ischar(char c, char *set)
tables[n][(unsigned char) sets[i][j]] |= f; tables[n][(unsigned char) sets[i][j]] |= f;
} }
} }
z = stb_perfect_hash(&p, (int) set); z = stb_perfect_hash(&p, (int)(size_t) set);
} }
return tables[z >> 3][(unsigned char) c] & bit[z & 7]; return tables[z >> 3][(unsigned char) c] & bit[z & 7];
} }
@ -7679,14 +7684,14 @@ static stb_ps_hash *stb_ps_makehash(int size, int old_size, void **old_data)
h->any_offset = 0; h->any_offset = 0;
memset(h->table, 0, size * sizeof(h->table[0])); memset(h->table, 0, size * sizeof(h->table[0]));
for (i=0; i < old_size; ++i) for (i=0; i < old_size; ++i)
if (!stb_ps_empty(old_data[i])) if (!stb_ps_empty((size_t)old_data[i]))
stb_ps_add(EncodeHash(h), old_data[i]); stb_ps_add(EncodeHash(h), old_data[i]);
return h; return h;
} }
void stb_ps_delete(stb_ps *ps) void stb_ps_delete(stb_ps *ps)
{ {
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: break; case STB_ps_direct: break;
case STB_ps_bucket: stb_bucket_free(GetBucket(ps)); break; case STB_ps_bucket: stb_bucket_free(GetBucket(ps)); break;
case STB_ps_array : free(GetArray(ps)); break; case STB_ps_array : free(GetArray(ps)); break;
@ -7698,7 +7703,7 @@ stb_ps *stb_ps_copy(stb_ps *ps)
{ {
int i; int i;
// not a switch: order based on expected performance/power-law distribution // not a switch: order based on expected performance/power-law distribution
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: return ps; case STB_ps_direct: return ps;
case STB_ps_bucket: { case STB_ps_bucket: {
stb_ps_bucket *n = (stb_ps_bucket *) malloc(sizeof(*n)); stb_ps_bucket *n = (stb_ps_bucket *) malloc(sizeof(*n));
@ -7725,8 +7730,8 @@ stb_ps *stb_ps_copy(stb_ps *ps)
int stb_ps_find(stb_ps *ps, void *value) int stb_ps_find(stb_ps *ps, void *value)
{ {
int i, code = 3 & (int) ps; int i, code = 3 & (int)(size_t) ps;
assert((3 & (int) value) == STB_ps_direct); assert((3 & (int)(size_t) value) == STB_ps_direct);
assert(stb_ps_fastlist_valid(value)); assert(stb_ps_fastlist_valid(value));
// not a switch: order based on expected performance/power-law distribution // not a switch: order based on expected performance/power-law distribution
if (code == STB_ps_direct) if (code == STB_ps_direct)
@ -7767,11 +7772,11 @@ stb_ps * stb_ps_add (stb_ps *ps, void *value)
assert(!stb_ps_find(ps,value)); assert(!stb_ps_find(ps,value));
#endif #endif
if (value == NULL) return ps; // ignore NULL adds to avoid bad breakage if (value == NULL) return ps; // ignore NULL adds to avoid bad breakage
assert((3 & (int) value) == STB_ps_direct); assert((3 & (int)(size_t) value) == STB_ps_direct);
assert(stb_ps_fastlist_valid(value)); assert(stb_ps_fastlist_valid(value));
assert(value != STB_DEL); // STB_DEL is less likely assert(value != STB_DEL); // STB_DEL is less likely
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) return (stb_ps *) value; if (ps == NULL) return (stb_ps *) value;
return EncodeBucket(stb_bucket_create2(ps,value)); return EncodeBucket(stb_bucket_create2(ps,value));
@ -7820,11 +7825,11 @@ stb_ps * stb_ps_add (stb_ps *ps, void *value)
stb_uint32 n = hash & h->mask; stb_uint32 n = hash & h->mask;
void **t = h->table; void **t = h->table;
// find first NULL or STB_DEL entry // find first NULL or STB_DEL entry
if (!stb_ps_empty(t[n])) { if (!stb_ps_empty((size_t)t[n])) {
stb_uint32 s = stb_rehash(hash) | 1; stb_uint32 s = stb_rehash(hash) | 1;
do { do {
n = (n + s) & h->mask; n = (n + s) & h->mask;
} while (!stb_ps_empty(t[n])); } while (!stb_ps_empty((size_t)t[n]));
} }
if (t[n] == STB_DEL) if (t[n] == STB_DEL)
-- h->count_deletes; -- h->count_deletes;
@ -7851,9 +7856,9 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value)
#ifdef STB_DEBUG #ifdef STB_DEBUG
assert(stb_ps_find(ps, value)); assert(stb_ps_find(ps, value));
#endif #endif
assert((3 & (int) value) == STB_ps_direct); assert((3 & (int)(size_t) value) == STB_ps_direct);
if (value == NULL) return ps; // ignore NULL removes to avoid bad breakage if (value == NULL) return ps; // ignore NULL removes to avoid bad breakage
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
return ps == value ? NULL : ps; return ps == value ? NULL : ps;
case STB_ps_bucket: { case STB_ps_bucket: {
@ -7912,7 +7917,7 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value)
stb_ps_array *a = (stb_ps_array *) malloc(sizeof(*a) + (n-1) * sizeof(a->p[0])); stb_ps_array *a = (stb_ps_array *) malloc(sizeof(*a) + (n-1) * sizeof(a->p[0]));
int i,j=0; int i,j=0;
for (i=0; i < h->size; ++i) for (i=0; i < h->size; ++i)
if (!stb_ps_empty(t[i])) if (!stb_ps_empty((size_t)t[i]))
a->p[j++] = t[i]; a->p[j++] = t[i];
assert(j == h->count); assert(j == h->count);
a->count = j; a->count = j;
@ -7934,7 +7939,7 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value)
stb_ps *stb_ps_remove_any(stb_ps *ps, void **value) stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
{ {
assert(ps != NULL); assert(ps != NULL);
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
*value = ps; *value = ps;
return NULL; return NULL;
@ -7967,7 +7972,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
void **t = h->table; void **t = h->table;
stb_uint32 n = h->any_offset; stb_uint32 n = h->any_offset;
while (stb_ps_empty(t[n])) while (stb_ps_empty((size_t)t[n]))
n = (n + 1) & h->mask; n = (n + 1) & h->mask;
*value = t[n]; *value = t[n];
h->any_offset = (n+1) & h->mask; h->any_offset = (n+1) & h->mask;
@ -7988,7 +7993,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count)
{ {
int i,n=0; int i,n=0;
void **p = NULL; void **p = NULL;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) { *count = 0; return NULL; } if (ps == NULL) { *count = 0; return NULL; }
p = (void **) malloc(sizeof(*p) * 1); p = (void **) malloc(sizeof(*p) * 1);
@ -8014,7 +8019,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count)
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
p = (void **) malloc(sizeof(*p) * h->count); p = (void **) malloc(sizeof(*p) * h->count);
for (i=0; i < h->size; ++i) for (i=0; i < h->size; ++i)
if (!stb_ps_empty(h->table[i])) if (!stb_ps_empty((size_t)h->table[i]))
p[n++] = h->table[i]; p[n++] = h->table[i];
break; break;
} }
@ -8026,7 +8031,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count)
int stb_ps_writelist(stb_ps *ps, void **list, int size ) int stb_ps_writelist(stb_ps *ps, void **list, int size )
{ {
int i,n=0; int i,n=0;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL || size <= 0) return 0; if (ps == NULL || size <= 0) return 0;
list[0] = ps; list[0] = ps;
@ -8048,7 +8053,7 @@ int stb_ps_writelist(stb_ps *ps, void **list, int size )
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
if (size <= 0) return 0; if (size <= 0) return 0;
for (i=0; i < h->count; ++i) { for (i=0; i < h->count; ++i) {
if (!stb_ps_empty(h->table[i])) { if (!stb_ps_empty((size_t)h->table[i])) {
list[n++] = h->table[i]; list[n++] = h->table[i];
if (n == size) break; if (n == size) break;
} }
@ -8062,7 +8067,7 @@ int stb_ps_writelist(stb_ps *ps, void **list, int size )
int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data)) int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data))
{ {
int i; int i;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) return STB_TRUE; if (ps == NULL) return STB_TRUE;
return func(ps, data); return func(ps, data);
@ -8084,7 +8089,7 @@ int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data))
case STB_ps_hash: { case STB_ps_hash: {
stb_ps_hash *h = GetHash(ps); stb_ps_hash *h = GetHash(ps);
for (i=0; i < h->count; ++i) for (i=0; i < h->count; ++i)
if (!stb_ps_empty(h->table[i])) if (!stb_ps_empty((size_t)h->table[i]))
if (!func(h->table[i], data)) if (!func(h->table[i], data))
return STB_FALSE; return STB_FALSE;
return STB_TRUE; return STB_TRUE;
@ -8095,7 +8100,7 @@ int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data))
int stb_ps_count (stb_ps *ps) int stb_ps_count (stb_ps *ps)
{ {
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
return ps != NULL; return ps != NULL;
case STB_ps_bucket: { case STB_ps_bucket: {
@ -8119,7 +8124,7 @@ void ** stb_ps_fastlist(stb_ps *ps, int *count)
{ {
static void *storage; static void *storage;
switch (3 & (int) ps) { switch (3 & (int)(size_t) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) { *count = 0; return NULL; } if (ps == NULL) { *count = 0; return NULL; }
storage = ps; storage = ps;
@ -9166,7 +9171,7 @@ static void stb__add_epsilon(stb_matcher *matcher, int from, int to)
static void stb__add_edge(stb_matcher *matcher, int from, int to, int type) static void stb__add_edge(stb_matcher *matcher, int from, int to, int type)
{ {
stb_nfa_edge z = { type, to }; stb_nfa_edge z = { (stb_int16)type, (stb_uint16)to };
if (matcher->nodes[from].out == NULL) if (matcher->nodes[from].out == NULL)
stb_arr_malloc((void **) &matcher->nodes[from].out, matcher); stb_arr_malloc((void **) &matcher->nodes[from].out, matcher);
stb_arr_push(matcher->nodes[from].out, z); stb_arr_push(matcher->nodes[from].out, z);
@ -9879,7 +9884,7 @@ int stb_regex(char *regex, char *str)
static char ** regexps; static char ** regexps;
static char ** regexp_cache; static char ** regexp_cache;
static unsigned short *mapping; static unsigned short *mapping;
int z = stb_perfect_hash(&p, (int) regex); int z = stb_perfect_hash(&p, (int)(size_t) regex);
if (z >= 0) { if (z >= 0) {
if (strcmp(regex, regexp_cache[(int) mapping[z]])) { if (strcmp(regex, regexp_cache[(int) mapping[z]])) {
int i = mapping[z]; int i = mapping[z];
@ -9910,8 +9915,8 @@ int stb_regex(char *regex, char *str)
n = stb_perfect_create(&p, (unsigned int *) (char **) regexps, stb_arr_len(regexps)); n = stb_perfect_create(&p, (unsigned int *) (char **) regexps, stb_arr_len(regexps));
mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping)); mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping));
for (i=0; i < stb_arr_len(regexps); ++i) for (i=0; i < stb_arr_len(regexps); ++i)
mapping[stb_perfect_hash(&p, (int) regexps[i])] = i; mapping[stb_perfect_hash(&p, (int)(size_t) regexps[i])] = i;
z = stb_perfect_hash(&p, (int) regex); z = stb_perfect_hash(&p, (int)(size_t) regex);
} }
return stb_matcher_find(matchers[(int) mapping[z]], str); return stb_matcher_find(matchers[(int) mapping[z]], str);
} }
@ -10405,7 +10410,7 @@ static void stb__write(unsigned char v)
++stb__outbytes; ++stb__outbytes;
} }
#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v))) #define stb_out(v) (stb__out ? (void)(*stb__out++ = (stb_uchar) (v)) : stb__write((stb_uchar) (v)))
static void stb_out2(stb_uint v) static void stb_out2(stb_uint v)
{ {
@ -10668,7 +10673,8 @@ static size_t stb_out_backpatch_id(void)
static void stb_out_backpatch(size_t id, stb_uint value) static void stb_out_backpatch(size_t id, stb_uint value)
{ {
stb_uchar data[4] = { value >> 24, value >> 16, value >> 8, value };
stb_uchar data[4] = { (stb_uchar)(value >> 24), (stb_uchar)(value >> 16), (stb_uchar)(value >> 8), (stb_uchar)(value) };
if (stb__out) { if (stb__out) {
memcpy((void *) id, data, 4); memcpy((void *) id, data, 4);
} else { } else {

View File

@ -1,4 +1,4 @@
// stb_dxt.h - v1.06 - DXT1/DXT5 compressor - public domain // stb_dxt.h - v1.07 - DXT1/DXT5 compressor - public domain
// original by fabian "ryg" giesen - ported to C by stb // original by fabian "ryg" giesen - ported to C by stb
// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation // use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation
// //
@ -9,6 +9,7 @@
// and "high quality" using mode. // and "high quality" using mode.
// //
// version history: // version history:
// v1.07 - bc4; allow not using libc; add STB_DXT_STATIC
// v1.06 - (stb) fix to known-broken 1.05 // v1.06 - (stb) fix to known-broken 1.05
// v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski) // v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski)
// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec); // v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec);
@ -19,6 +20,10 @@
// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom // v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom
// v1.00 - (stb) first release // v1.00 - (stb) first release
// //
// contributors:
// Kevin Schmidt (#defines for "freestanding" compilation)
// github:ppiastucki (BC4 support)
//
// LICENSE // LICENSE
// //
// See end of file for license information. // See end of file for license information.
@ -35,8 +40,15 @@
extern "C" { extern "C" {
#endif #endif
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode); #ifdef STB_DXT_STATIC
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel); #define STBDDEF static
#else
#define STBDDEF extern
#endif
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);
#ifdef __cplusplus #ifdef __cplusplus
} }
@ -61,8 +73,23 @@ void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two
// #define STB_DXT_USE_ROUNDING_BIAS // #define STB_DXT_USE_ROUNDING_BIAS
#include <stdlib.h> #include <stdlib.h>
#if !defined(STBD_ABS) || !defined(STBI_FABS)
#include <math.h> #include <math.h>
#include <string.h> // memset #endif
#ifndef STBD_ABS
#define STBD_ABS(i) abs(i)
#endif
#ifndef STBD_FABS
#define STBD_FABS(x) fabs(x)
#endif
#ifndef STBD_MEMSET
#include <string.h>
#define STBD_MEMSET memset
#endif
static unsigned char stb__Expand5[32]; static unsigned char stb__Expand5[32];
static unsigned char stb__Expand6[64]; static unsigned char stb__Expand6[64];
@ -127,13 +154,13 @@ static void stb__PrepareOptTable(unsigned char *Table,const unsigned char *expan
for (mx=0;mx<size;mx++) { for (mx=0;mx<size;mx++) {
int mine = expand[mn]; int mine = expand[mn];
int maxe = expand[mx]; int maxe = expand[mx];
int err = abs(stb__Lerp13(maxe, mine) - i); int err = STBD_ABS(stb__Lerp13(maxe, mine) - i);
// DX10 spec says that interpolation must be within 3% of "correct" result, // DX10 spec says that interpolation must be within 3% of "correct" result,
// add this as error term. (normally we'd expect a random distribution of // add this as error term. (normally we'd expect a random distribution of
// +-1.5% error, but nowhere in the spec does it say that the error has to be // +-1.5% error, but nowhere in the spec does it say that the error has to be
// unbiased - better safe than sorry). // unbiased - better safe than sorry).
err += abs(maxe - mine) * 3 / 100; err += STBD_ABS(maxe - mine) * 3 / 100;
if(err < bestErr) if(err < bestErr)
{ {
@ -165,7 +192,7 @@ static void stb__DitherBlock(unsigned char *dest, unsigned char *block)
for (ch=0; ch<3; ++ch) { for (ch=0; ch<3; ++ch) {
unsigned char *bp = block+ch, *dp = dest+ch; unsigned char *bp = block+ch, *dp = dest+ch;
unsigned char *quant = (ch == 1) ? stb__QuantGTab+8 : stb__QuantRBTab+8; unsigned char *quant = (ch == 1) ? stb__QuantGTab+8 : stb__QuantRBTab+8;
memset(err, 0, sizeof(err)); STBD_MEMSET(err, 0, sizeof(err));
for(y=0; y<4; ++y) { for(y=0; y<4; ++y) {
dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 4)]; dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 4)];
ep1[0] = bp[ 0] - dp[ 0]; ep1[0] = bp[ 0] - dp[ 0];
@ -349,9 +376,9 @@ static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax1
vfb = b; vfb = b;
} }
magn = fabs(vfr); magn = STBD_FABS(vfr);
if (fabs(vfg) > magn) magn = fabs(vfg); if (STBD_FABS(vfg) > magn) magn = STBD_FABS(vfg);
if (fabs(vfb) > magn) magn = fabs(vfb); if (STBD_FABS(vfb) > magn) magn = STBD_FABS(vfb);
if(magn < 4.0f) { // too small, default to luminance if(magn < 4.0f) { // too small, default to luminance
v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000. v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000.
@ -636,6 +663,11 @@ void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int a
stb__CompressColorBlock(dest,(unsigned char*) src,mode); stb__CompressColorBlock(dest,(unsigned char*) src,mode);
} }
void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src)
{
stb__CompressAlphaBlock(dest,(unsigned char*) src, 1);
}
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src) void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src)
{ {
stb__CompressAlphaBlock(dest,(unsigned char*) src,2); stb__CompressAlphaBlock(dest,(unsigned char*) src,2);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* stb_image_resize - v0.94 - public domain image resizing /* stb_image_resize - v0.95 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014 by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb http://github.com/nothings/stb
@ -156,8 +156,10 @@
Jorge L Rodriguez: Implementation Jorge L Rodriguez: Implementation
Sean Barrett: API design, optimizations Sean Barrett: API design, optimizations
Aras Pranckevicius: bugfix Aras Pranckevicius: bugfix
Nathan Reed: warning fixes
REVISIONS REVISIONS
0.95 (2017-07-23) fixed warnings
0.94 (2017-03-18) fixed warnings 0.94 (2017-03-18) fixed warnings
0.93 (2017-03-03) fixed bug with certain combinations of heights 0.93 (2017-03-03) fixed bug with certain combinations of heights
0.92 (2017-01-02) fix integer overflow on large (>2GB) images 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
@ -393,8 +395,9 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
#ifndef STBIR_MALLOC #ifndef STBIR_MALLOC
#include <stdlib.h> #include <stdlib.h>
#define STBIR_MALLOC(size,c) malloc(size) // use comma operator to evaluate c, to avoid "unused parameter" warnings
#define STBIR_FREE(ptr,c) free(ptr) #define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
#define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
#endif #endif
#ifndef _MSC_VER #ifndef _MSC_VER
@ -983,7 +986,7 @@ static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
return (m); return (m);
} }
return n; // NOTREACHED // NOTREACHED
default: default:
STBIR_ASSERT(!"Unimplemented edge type"); STBIR_ASSERT(!"Unimplemented edge type");

View File

@ -1,5 +1,5 @@
/* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h /* stb_image_write - v1.08 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
Before #including, Before #including,
@ -10,43 +10,64 @@
Will probably not work correctly with strict-aliasing optimizations. Will probably not work correctly with strict-aliasing optimizations.
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
compilation warnings or even errors. To avoid this, also before #including,
#define STBI_MSC_SECURE_CRT
ABOUT: ABOUT:
This header file is a library for writing images to C stdio. It could be This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know. adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed written by a decent optimizing implementation; though providing a custom
for source code compactness and simplicity, not optimal image file size zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
or run-time performance. This library is designed for source code compactness and simplicity,
not optimal image file size or run-time performance.
BUILDING: BUILDING:
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
malloc,realloc,free. malloc,realloc,free.
You can define STBIW_MEMMOVE() to replace memmove() You can #define STBIW_MEMMOVE() to replace memmove()
You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
for PNG compression (instead of the builtin one), it must have the following signature:
unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
The returned data will be freed with STBIW_FREE() (free() by default),
so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
USAGE: USAGE:
There are four functions, one for each image file format: There are five functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data, int quality);
There are also four equivalent functions that use an arbitrary write function. You are void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
There are also five equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these: expected to open/close your file-equivalent before and after calling these:
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
where the callback is: where the callback is:
void stbi_write_func(void *context, void *data, int size); void stbi_write_func(void *context, void *data, int size);
You can configure it with these global variables:
int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
You can define STBI_WRITE_NO_STDIO to disable the file variant of these You can define STBI_WRITE_NO_STDIO to disable the file variant of these
functions, so the library will not use stdio.h at all. However, this will functions, so the library will not use stdio.h at all. However, this will
also disable HDR writing, because it requires stdio for formatted output. also disable HDR writing, because it requires stdio for formatted output.
@ -73,6 +94,9 @@ USAGE:
writer, both because it is in BGR order and because it may have padding writer, both because it is in BGR order and because it may have padding
at the end of the line.) at the end of the line.)
PNG allows you to set the deflate compression level by setting the global
variable 'stbi_write_png_level' (it defaults to 8).
HDR expects linear float data. Since the format is always 32-bit rgb(e) HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels. replicated across all three channels.
@ -80,20 +104,23 @@ USAGE:
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
data, set the global variable 'stbi_write_tga_with_rle' to 0. data, set the global variable 'stbi_write_tga_with_rle' to 0.
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
Higher quality looks better but results in a bigger image.
JPEG baseline (no JPEG progressive).
CREDITS: CREDITS:
PNG/BMP/TGA
Sean Barrett Sean Barrett - PNG/BMP/TGA
HDR Baldur Karlsson - HDR
Baldur Karlsson Jean-Sebastien Guay - TGA monochrome
TGA monochrome: Tim Kelsey - misc enhancements
Jean-Sebastien Guay Alan Hickman - TGA RLE
misc enhancements: Emmanuel Julien - initial file IO callback implementation
Tim Kelsey Jon Olick - original jo_jpeg.cpp code
TGA RLE Daniel Gibson - integrate JPEG, allow external zlib
Alan Hickman Aarni Koskela - allow choosing PNG filter
initial file IO callback implementation
Emmanuel Julien
bugfixes: bugfixes:
github:Chribba github:Chribba
Guillaume Chereau Guillaume Chereau
@ -105,6 +132,7 @@ CREDITS:
Thatcher Ulrich Thatcher Ulrich
github:poppolopoppo github:poppolopoppo
Patrick Boettcher Patrick Boettcher
github:xeekworx
LICENSE LICENSE
@ -123,14 +151,18 @@ extern "C" {
#define STBIWDEF static #define STBIWDEF static
#else #else
#define STBIWDEF extern #define STBIWDEF extern
extern int stbi_write_tga_with_rle;
#endif #endif
STBIWDEF int stbi_write_tga_with_rle;
STBIWDEF int stbi_write_png_comperssion_level;
STBIWDEF int stbi_write_force_png_filter;
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
#endif #endif
typedef void stbi_write_func(void *context, void *data, int size); typedef void stbi_write_func(void *context, void *data, int size);
@ -139,6 +171,9 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w,
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#ifdef __cplusplus #ifdef __cplusplus
} }
@ -197,6 +232,23 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w,
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
STBIWDEF void stbi_flip_vertically_on_write(int flag)
{
stbi__flip_vertically_on_write = flag;
}
typedef struct typedef struct
{ {
stbi_write_func *func; stbi_write_func *func;
@ -219,7 +271,12 @@ static void stbi__stdio_write(void *context, void *data, int size)
static int stbi__start_write_file(stbi__write_context *s, const char *filename) static int stbi__start_write_file(stbi__write_context *s, const char *filename)
{ {
FILE *f = fopen(filename, "wb"); FILE *f;
#ifdef STBI_MSC_SECURE_CRT
fopen_s(&f, filename, "wb");
#else
f = fopen(filename, "wb");
#endif
stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
return f != NULL; return f != NULL;
} }
@ -234,12 +291,6 @@ static void stbi__end_write_file(stbi__write_context *s)
typedef unsigned int stbiw_uint32; typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_tga_with_rle = 1;
#else
int stbi_write_tga_with_rle = 1;
#endif
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
{ {
while (*fmt) { while (*fmt) {
@ -277,6 +328,11 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
va_end(v); va_end(v);
} }
static void stbiw__putc(stbi__write_context *s, unsigned char c)
{
s->func(s->context, &c, 1);
}
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
{ {
unsigned char arr[3]; unsigned char arr[3];
@ -325,6 +381,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
if (y <= 0) if (y <= 0)
return; return;
if (stbi__flip_vertically_on_write)
vdir *= -1;
if (vdir < 0) if (vdir < 0)
j_end = -1, j = y-1; j_end = -1, j = y-1;
else else
@ -396,11 +455,21 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
} else { } else {
int i,j,k; int i,j,k;
int jend, jdir;
stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
for (j = y - 1; j >= 0; --j) { if (stbi__flip_vertically_on_write) {
unsigned char *row = (unsigned char *) data + j * x * comp; 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; int len;
for (i = 0; i < x; i += len) { for (i = 0; i < x; i += len) {
@ -450,7 +519,7 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
return 1; return 1;
} }
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
{ {
stbi__write_context s; stbi__write_context s;
stbi__start_write_callbacks(&s, func, context); stbi__start_write_callbacks(&s, func, context);
@ -458,7 +527,7 @@ int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, i
} }
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{ {
stbi__write_context s; stbi__write_context s;
if (stbi__start_write_file(&s,filename)) { if (stbi__start_write_file(&s,filename)) {
@ -610,17 +679,21 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1); s->func(s->context, header, sizeof(header)-1);
#ifdef STBI_MSC_SECURE_CRT
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif
s->func(s->context, buffer, len); s->func(s->context, buffer, len);
for(i=0; i < y; i++) for(i=0; i < y; i++)
stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x);
STBIW_FREE(scratch); STBIW_FREE(scratch);
return 1; return 1;
} }
} }
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
{ {
stbi__write_context s; stbi__write_context s;
stbi__start_write_callbacks(&s, func, context); stbi__start_write_callbacks(&s, func, context);
@ -628,7 +701,7 @@ int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, i
} }
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{ {
stbi__write_context s; stbi__write_context s;
if (stbi__start_write_file(&s,filename)) { if (stbi__start_write_file(&s,filename)) {
@ -646,6 +719,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
// PNG writer // PNG writer
// //
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2) #define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbm(a) stbiw__sbraw(a)[0]
@ -726,8 +800,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
#define stbiw__ZHASH 16384 #define stbiw__ZHASH 16384
#endif // STBIW_ZLIB_COMPRESS
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{ {
#ifdef STBIW_ZLIB_COMPRESS
// user provided a zlib compress implementation, use that
return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
#else // use builtin
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
@ -829,6 +909,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
// make returned pointer freeable // make returned pointer freeable
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out); return (unsigned char *) stbiw__sbraw(out);
#endif // STBIW_ZLIB_COMPRESS
} }
static unsigned int stbiw__crc32(unsigned char *buffer, int len) static unsigned int stbiw__crc32(unsigned char *buffer, int len)
@ -895,61 +976,87 @@ static unsigned char stbiw__paeth(int a, int b, int c)
} }
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
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)
{
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
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);
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 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
}
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 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;
}
}
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) 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 }; int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib; unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer; signed char *line_buffer;
int i,j,k,p,zlen; int j,zlen;
if (stride_bytes == 0) if (stride_bytes == 0)
stride_bytes = x * n; stride_bytes = x * n;
if (force_filter >= 5) {
force_filter = -1;
}
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; 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; } line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
for (j=0; j < y; ++j) { for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 }; int filter_type;
static int firstmap[] = { 0,1,0,5,6 }; if (force_filter > -1) {
int *mymap = (j != 0) ? mapping : firstmap; filter_type = force_filter;
int best = 0, bestval = 0x7fffffff; stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer);
for (p=0; p < 2; ++p) { } else { // Estimate the best filter by running through all of them:
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 best_filter = 0, best_filter_val = 0x7fffffff, est, i;
int type = mymap[k],est=0; for (filter_type = 0; filter_type < 5; filter_type++) {
unsigned char *z = pixels + stride_bytes*j; stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer);
for (i=0; i < n; ++i)
switch (type) { // Estimate the entropy of the line using this filter; the less, the better.
case 0: line_buffer[i] = z[i]; break; est = 0;
case 1: line_buffer[i] = z[i]; break; for (i = 0; i < x*n; ++i) {
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 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*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 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)
est += abs((signed char) line_buffer[i]); est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; } }
if (est < best_filter_val) {
best_filter_val = est;
best_filter = filter_type;
}
}
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, best contains the filter type, and line_buffer contains the data // when we get here, filter_type contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best; filt[j*(x*n+1)] = (unsigned char) filter_type;
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
} }
STBIW_FREE(line_buffer); STBIW_FREE(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);
STBIW_FREE(filt); STBIW_FREE(filt);
if (!zlib) return 0; if (!zlib) return 0;
@ -994,7 +1101,11 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const
int len; int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (png == NULL) return 0; if (png == NULL) return 0;
#ifdef STBI_MSC_SECURE_CRT
fopen_s(&f, filename, "wb");
#else
f = fopen(filename, "wb"); f = fopen(filename, "wb");
#endif
if (!f) { STBIW_FREE(png); return 0; } if (!f) { STBIW_FREE(png); return 0; }
fwrite(png, 1, len, f); fwrite(png, 1, len, f);
fclose(f); fclose(f);
@ -1013,9 +1124,361 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
return 1; return 1;
} }
/* ***************************************************************************
*
* JPEG writer
*
* This is based on Jon Olick's jo_jpeg.cpp:
* public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
*/
static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,
24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };
static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
int bitBuf = *bitBufP, bitCnt = *bitCntP;
bitCnt += bs[1];
bitBuf |= bs[0] << (24 - bitCnt);
while(bitCnt >= 8) {
unsigned char c = (bitBuf >> 16) & 255;
stbiw__putc(s, c);
if(c == 255) {
stbiw__putc(s, 0);
}
bitBuf <<= 8;
bitCnt -= 8;
}
*bitBufP = bitBuf;
*bitCntP = bitCnt;
}
static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
float z1, z2, z3, z4, z5, z11, z13;
float tmp0 = d0 + d7;
float tmp7 = d0 - d7;
float tmp1 = d1 + d6;
float tmp6 = d1 - d6;
float tmp2 = d2 + d5;
float tmp5 = d2 - d5;
float tmp3 = d3 + d4;
float tmp4 = d3 - d4;
// Even part
float tmp10 = tmp0 + tmp3; // phase 2
float tmp13 = tmp0 - tmp3;
float tmp11 = tmp1 + tmp2;
float tmp12 = tmp1 - tmp2;
d0 = tmp10 + tmp11; // phase 3
d4 = tmp10 - tmp11;
z1 = (tmp12 + tmp13) * 0.707106781f; // c4
d2 = tmp13 + z1; // phase 5
d6 = tmp13 - z1;
// Odd part
tmp10 = tmp4 + tmp5; // phase 2
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
// The rotator is modified from fig 4-8 to avoid extra negations.
z5 = (tmp10 - tmp12) * 0.382683433f; // c6
z2 = tmp10 * 0.541196100f + z5; // c2-c6
z4 = tmp12 * 1.306562965f + z5; // c2+c6
z3 = tmp11 * 0.707106781f; // c4
z11 = tmp7 + z3; // phase 5
z13 = tmp7 - z3;
*d5p = z13 + z2; // phase 6
*d3p = z13 - z2;
*d1p = z11 + z4;
*d7p = z11 - z4;
*d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6;
}
static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
int tmp1 = val < 0 ? -val : val;
val = val < 0 ? val-1 : val;
bits[1] = 1;
while(tmp1 >>= 1) {
++bits[1];
}
bits[0] = val & ((1<<bits[1])-1);
}
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
int dataOff, i, diff, end0pos;
int DU[64];
// DCT rows
for(dataOff=0; dataOff<64; dataOff+=8) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
}
// DCT columns
for(dataOff=0; dataOff<8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);
}
// Quantize/descale/zigzag the coefficients
for(i=0; i<64; ++i) {
float v = CDU[i]*fdtbl[i];
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
}
// Encode DC
diff = DU[0] - DC;
if (diff == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
} else {
unsigned short bits[2];
stbiw__jpg_calcBits(diff, bits);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
}
// Encode ACs
end0pos = 63;
for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {
}
// end0pos = first element in reverse order !=0
if(end0pos == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
return DU[0];
}
for(i = 1; i <= end0pos; ++i) {
int startpos = i;
int nrzeroes;
unsigned short bits[2];
for (; DU[i]==0 && i<=end0pos; ++i) {
}
nrzeroes = i-startpos;
if ( nrzeroes >= 16 ) {
int lng = nrzeroes>>4;
int nrmarker;
for (nrmarker=1; nrmarker <= lng; ++nrmarker)
stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
nrzeroes &= 15;
}
stbiw__jpg_calcBits(DU[i], bits);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
}
if(end0pos != 63) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
}
return DU[0];
}
static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {
// Constants that don't pollute global namespace
static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};
static const unsigned char std_ac_luminance_values[] = {
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
};
static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};
static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};
static const unsigned char std_ac_chrominance_values[] = {
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
};
// Huffman tables
static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};
static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};
static const unsigned short YAC_HT[256][2] = {
{10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},
{2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
};
static const unsigned short UVAC_HT[256][2] = {
{0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},
{1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
};
static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
int row, col, i, k;
float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[64];
if(!data || !width || !height || comp > 4 || comp < 1) {
return 0;
}
quality = quality ? quality : 90;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
for(i = 0; i < 64; ++i) {
int uvti, yti = (YQT[i]*quality+50)/100;
YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);
uvti = (UVQT[i]*quality+50)/100;
UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
}
for(row = 0, k = 0; row < 8; ++row) {
for(col = 0; col < 8; ++col, ++k) {
fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
}
}
// Write Headers
{
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
s->func(s->context, (void*)head0, sizeof(head0));
s->func(s->context, (void*)YTable, sizeof(YTable));
stbiw__putc(s, 1);
s->func(s->context, UVTable, sizeof(UVTable));
s->func(s->context, (void*)head1, sizeof(head1));
s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);
s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));
stbiw__putc(s, 0x10); // HTYACinfo
s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);
s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));
stbiw__putc(s, 1); // HTUDCinfo
s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);
s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
stbiw__putc(s, 0x11); // HTUACinfo
s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);
s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
s->func(s->context, (void*)head2, sizeof(head2));
}
// Encode 8x8 macroblocks
{
static const unsigned short fillBits[] = {0x7F, 7};
const unsigned char *imageData = (const unsigned char *)data;
int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0;
// comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
int x, y, pos;
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
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 = (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);
}
if(col >= width) {
p -= comp*(col+1 - width);
}
r = imageData[p+0];
g = imageData[p+ofsG];
b = imageData[p+ofsB];
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
// Do the bit alignment of the EOI marker
stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
}
// EOI
stbiw__putc(s, 0xFF);
stbiw__putc(s, 0xD9);
return 1;
}
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
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)
writing JPEG (using Jon Olick's code)
1.05 ???
1.04 (2017-03-03) 1.04 (2017-03-03)
monochrome BMP expansion monochrome BMP expansion
1.03 ??? 1.03 ???

View File

@ -1,4 +1,4 @@
// stb_leakcheck.h - v0.3 - quick & dirty malloc leak-checking - public domain // stb_leakcheck.h - v0.4 - quick & dirty malloc leak-checking - public domain
// LICENSE // LICENSE
// //
// See end of file. // See end of file.
@ -22,7 +22,7 @@ typedef struct malloc_info stb_leakcheck_malloc_info;
struct malloc_info struct malloc_info
{ {
char *file; const char *file;
int line; int line;
size_t size; size_t size;
stb_leakcheck_malloc_info *next,*prev; stb_leakcheck_malloc_info *next,*prev;
@ -30,7 +30,7 @@ struct malloc_info
static stb_leakcheck_malloc_info *mi_head; static stb_leakcheck_malloc_info *mi_head;
void *stb_leakcheck_malloc(size_t sz, char *file, int line) void *stb_leakcheck_malloc(size_t sz, const char *file, int line)
{ {
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi)); stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi));
if (mi == NULL) return mi; if (mi == NULL) return mi;
@ -59,10 +59,11 @@ void stb_leakcheck_free(void *ptr)
if (mi->next) if (mi->next)
mi->next->prev = mi->prev; mi->next->prev = mi->prev;
#endif #endif
free(mi);
} }
} }
void *stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line) void *stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line)
{ {
if (ptr == NULL) { if (ptr == NULL) {
return stb_leakcheck_malloc(sz, file, line); return stb_leakcheck_malloc(sz, file, line);
@ -88,11 +89,30 @@ void *stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line)
} }
} }
static void stblkck_internal_print(const char *reason, const char *file, int line, size_t size, void *ptr)
{
#if (defined(_MSC_VER) && _MSC_VER < 1900) /* 1900=VS 2015 */ || defined(__MINGW32__)
// Compilers that use the old MS C runtime library don't have %zd
// and the older ones don't even have %lld either... however, the old compilers
// without "long long" don't support 64-bit targets either, so here's the
// compromise:
#if defined(_MSC_VER) && _MSC_VER < 1400 // before VS 2005
printf("%-6s: %s (%4d): %8d bytes at %p\n", reason, file, line, (int)size, ptr);
#else
printf("%-6s: %s (%4d): %8lld bytes at %p\n", reason, file, line, (long long)size, ptr);
#endif
#else
// Assume we have %zd on other targets.
printf("%-6s: %s (%4d): %zd bytes at %p\n", reason, file, line, size, ptr);
#endif
}
void stb_leakcheck_dumpmem(void) void stb_leakcheck_dumpmem(void)
{ {
stb_leakcheck_malloc_info *mi = mi_head; stb_leakcheck_malloc_info *mi = mi_head;
while (mi) { while (mi) {
if ((ptrdiff_t) mi->size >= 0) if ((ptrdiff_t) mi->size >= 0)
stblkck_internal_print("LEAKED", mi->file, mi->line, mi->size, mi+1);
printf("LEAKED: %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) mi->size, mi+1); printf("LEAKED: %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) mi->size, mi+1);
mi = mi->next; mi = mi->next;
} }
@ -100,6 +120,7 @@ void stb_leakcheck_dumpmem(void)
mi = mi_head; mi = mi_head;
while (mi) { while (mi) {
if ((ptrdiff_t) mi->size < 0) if ((ptrdiff_t) mi->size < 0)
stblkck_internal_print("FREED", mi->file, mi->line, ~mi->size, mi+1);
printf("FREED : %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) ~mi->size, mi+1); printf("FREED : %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) ~mi->size, mi+1);
mi = mi->next; mi = mi->next;
} }
@ -114,8 +135,8 @@ void stb_leakcheck_dumpmem(void)
#define free(p) stb_leakcheck_free(p) #define free(p) stb_leakcheck_free(p)
#define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__) #define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__)
extern void * stb_leakcheck_malloc(size_t sz, char *file, int line); extern void * stb_leakcheck_malloc(size_t sz, const char *file, int line);
extern void * stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line); extern void * stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line);
extern void stb_leakcheck_free(void *ptr); extern void stb_leakcheck_free(void *ptr);
extern void stb_leakcheck_dumpmem(void); extern void stb_leakcheck_dumpmem(void);

View File

@ -524,17 +524,6 @@ static int rect_height_compare(const void *a, const void *b)
return (p->w > q->w) ? -1 : (p->w < q->w); return (p->w > q->w) ? -1 : (p->w < q->w);
} }
static int rect_width_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->w > q->w)
return -1;
if (p->w < q->w)
return 1;
return (p->h > q->h) ? -1 : (p->h < q->h);
}
static int rect_original_order(const void *a, const void *b) static int rect_original_order(const void *a, const void *b)
{ {
const stbrp_rect *p = (const stbrp_rect *) a; const stbrp_rect *p = (const stbrp_rect *) a;

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,4 +1,4 @@
// stb_truetype.h - v1.15 - public domain // stb_truetype.h - v1.17 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools // authored from 2009-2016 by Sean Barrett / RAD Game Tools
// //
// This library processes TrueType files: // This library processes TrueType files:
@ -6,6 +6,7 @@
// extract glyph metrics // extract glyph metrics
// extract glyph shapes // extract glyph shapes
// render glyphs to one-channel bitmaps with antialiasing (box filter) // render glyphs to one-channel bitmaps with antialiasing (box filter)
// render glyphs to one-channel SDF bitmaps (signed-distance field/function)
// //
// Todo: // Todo:
// non-MS cmaps // non-MS cmaps
@ -26,34 +27,29 @@
// Ryan Gordon // Ryan Gordon
// Simon Glass // Simon Glass
// github:IntellectualKitty // github:IntellectualKitty
// Imanol Celaya
// //
// Bug/warning reports/fixes: // Bug/warning reports/fixes:
// "Zer" on mollyrocket (with fix) // "Zer" on mollyrocket Fabian "ryg" Giesen
// Cass Everitt // Cass Everitt Martins Mozeiko
// stoiko (Haemimont Games) // stoiko (Haemimont Games) Cap Petschulat
// Brian Hook // Brian Hook Omar Cornut
// Walter van Niftrik // Walter van Niftrik github:aloucks
// David Gow // David Gow Peter LaValle
// David Given // David Given Sergey Popov
// Ivan-Assen Ivanov // Ivan-Assen Ivanov Giumo X. Clanjor
// Anthony Pesch // Anthony Pesch Higor Euripedes
// Johan Duparc // Johan Duparc Thomas Fields
// Hou Qiming // Hou Qiming Derek Vinyard
// Fabian "ryg" Giesen // Rob Loach Cort Stratton
// Martins Mozeiko // Kenney Phillis Jr. github:oyvindjam
// Cap Petschulat //
// Omar Cornut
// github:aloucks
// Peter LaValle
// Sergey Popov
// Giumo X. Clanjor
// Higor Euripedes
// Thomas Fields
// Derek Vinyard
// Cort Stratton
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 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.15 (2017-03-03) make more arguments const
// 1.14 (2017-01-16) num-fonts-in-TTC function // 1.14 (2017-01-16) num-fonts-in-TTC function
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts // 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
@ -92,7 +88,7 @@
// Improved 3D API (more shippable): // Improved 3D API (more shippable):
// #include "stb_rect_pack.h" -- optional, but you really want it // #include "stb_rect_pack.h" -- optional, but you really want it
// stbtt_PackBegin() // stbtt_PackBegin()
// stbtt_PackSetOversample() -- for improved quality on small fonts // stbtt_PackSetOversampling() -- for improved quality on small fonts
// stbtt_PackFontRanges() -- pack and renders // stbtt_PackFontRanges() -- pack and renders
// stbtt_PackEnd() // stbtt_PackEnd()
// stbtt_GetPackedQuad() // stbtt_GetPackedQuad()
@ -110,6 +106,7 @@
// Character advance/positioning // Character advance/positioning
// stbtt_GetCodepointHMetrics() // stbtt_GetCodepointHMetrics()
// stbtt_GetFontVMetrics() // stbtt_GetFontVMetrics()
// stbtt_GetFontVMetricsOS2()
// stbtt_GetCodepointKernAdvance() // stbtt_GetCodepointKernAdvance()
// //
// Starting with version 1.06, the rasterizer was replaced with a new, // Starting with version 1.06, the rasterizer was replaced with a new,
@ -407,6 +404,18 @@ int main(int arg, char **argv)
#ifndef STBTT_sqrt #ifndef STBTT_sqrt
#include <math.h> #include <math.h>
#define STBTT_sqrt(x) sqrt(x) #define STBTT_sqrt(x) sqrt(x)
#define STBTT_pow(x,y) pow(x,y)
#endif
#ifndef STBTT_cos
#include <math.h>
#define STBTT_cos(x) cos(x)
#define STBTT_acos(x) acos(x)
#endif
#ifndef STBTT_fabs
#include <math.h>
#define STBTT_fabs(x) fabs(x)
#endif #endif
#ifndef STBTT_fabs #ifndef STBTT_fabs
@ -432,7 +441,7 @@ int main(int arg, char **argv)
#endif #endif
#ifndef STBTT_memcpy #ifndef STBTT_memcpy
#include <memory.h> #include <string.h>
#define STBTT_memcpy memcpy #define STBTT_memcpy memcpy
#define STBTT_memset memset #define STBTT_memset memset
#endif #endif
@ -548,7 +557,7 @@ STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
#define STBTT_POINT_SIZE(x) (-(x)) #define STBTT_POINT_SIZE(x) (-(x))
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
// Creates character bitmaps from the font_index'th font found in fontdata (use // Creates character bitmaps from the font_index'th font found in fontdata (use
// font_index=0 if you don't know what that is). It creates num_chars_in_range // font_index=0 if you don't know what that is). It creates num_chars_in_range
@ -573,7 +582,7 @@ typedef struct
unsigned char h_oversample, v_oversample; // don't set these, they're used internally unsigned char h_oversample, v_oversample; // don't set these, they're used internally
} stbtt_pack_range; } stbtt_pack_range;
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
// Creates character bitmaps from multiple ranges of characters stored in // Creates character bitmaps from multiple ranges of characters stored in
// ranges. This will usually create a better-packed bitmap than multiple // ranges. This will usually create a better-packed bitmap than multiple
// calls to stbtt_PackFontRange. Note that you can call this multiple // calls to stbtt_PackFontRange. Note that you can call this multiple
@ -715,6 +724,12 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in
// these are expressed in unscaled coordinates, so you must multiply by // these are expressed in unscaled coordinates, so you must multiply by
// the scale factor for a given size // the scale factor for a given size
STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
// table (specific to MS/Windows TTF files).
//
// Returns 1 on success (table present), 0 on failure.
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
// the bounding box around all possible characters // the bounding box around all possible characters
@ -809,6 +824,10 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
// shift for the character // shift for the character
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);
// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
// is performed (see stbtt_PackSetOversampling)
STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
// get the bbox of the bitmap centered around the glyph origin; so the // get the bbox of the bitmap centered around the glyph origin; so the
// bitmap width is ix1-ix0, height is iy1-iy0, and location to place // bitmap width is ix1-ix0, height is iy1-iy0, and location to place
@ -826,6 +845,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float
STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(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 glyph); STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(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 glyph);
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(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 glyph);
STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
@ -848,6 +868,64 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap
int invert, // if non-zero, vertically flip shape int invert, // if non-zero, vertically flip shape
void *userdata); // context for to STBTT_MALLOC void *userdata); // context for to STBTT_MALLOC
//////////////////////////////////////////////////////////////////////////////
//
// Signed Distance Function (or Field) rendering
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
// frees the SDF bitmap allocated below
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
// These functions compute a discretized SDF field for a single character, suitable for storing
// in a single-channel texture, sampling with bilinear filtering, and testing against
// larger than some threshhold to produce scalable fonts.
// info -- the font
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
// glyph/codepoint -- the character to generate the SDF for
// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0),
// which allows effects like bit outlines
// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
// if positive, > onedge_value is inside; if negative, < onedge_value is inside
// width,height -- output height & width of the SDF bitmap (including padding)
// xoff,yoff -- output origin of the character
// return value -- a 2D array of bytes 0..255, width*height in size
//
// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
// optimal use of the limited 0..255 for your application, trading off precision
// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
//
// Example:
// scale = stbtt_ScaleForPixelHeight(22)
// padding = 5
// onedge_value = 180
// pixel_dist_scale = 180/5.0 = 36.0
//
// This will create an SDF bitmap in which the character is about 22 pixels
// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
// shape, sample the SDF at each pixel and fill the pixel if the SDF value
// is greater than or equal to 180/255. (You'll actually want to antialias,
// which is beyond the scope of this example.) Additionally, you can compute
// offset outlines (e.g. to stroke the character border inside & outside,
// or only outside). For example, to fill outside the character up to 3 SDF
// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
// choice of variables maps a range from 5 pixels outside the shape to
// 2 pixels inside the shape to 0..255; this is intended primarily for apply
// outside effects only (the interior range is needed to allow proper
// antialiasing of the font at *smaller* sizes)
//
// The function computes the SDF analytically at each SDF pixel, not by e.g.
// building a higher-res bitmap and approximating it. In theory the quality
// should be as high as possible for an SDF of this size & representation, but
// unclear if this is true in practice (perhaps building a higher-res bitmap
// and computing from that can allow drop-out prevention).
//
// The algorithm has not been optimized at all, so expect it to be slow
// if computing lots of characters or very large sizes.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// Finding the right font... // Finding the right font...
@ -2085,7 +2163,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
// push immediate // push immediate
if (b0 == 255) { if (b0 == 255) {
f = (float)stbtt__buf_get32(&b) / 0x10000; f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
} else { } else {
stbtt__buf_skip(&b, -1); stbtt__buf_skip(&b, -1);
f = (float)(stbtt_int16)stbtt__cff_int(&b); f = (float)(stbtt_int16)stbtt__cff_int(&b);
@ -2123,12 +2201,10 @@ static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, in
{ {
stbtt__csctx c = STBTT__CSCTX_INIT(1); stbtt__csctx c = STBTT__CSCTX_INIT(1);
int r = stbtt__run_charstring(info, glyph_index, &c); int r = stbtt__run_charstring(info, glyph_index, &c);
if (x0) { if (x0) *x0 = r ? c.min_x : 0;
*x0 = r ? c.min_x : 0; if (y0) *y0 = r ? c.min_y : 0;
*y0 = r ? c.min_y : 0; if (x1) *x1 = r ? c.max_x : 0;
*x1 = r ? c.max_x : 0; if (y1) *y1 = r ? c.max_y : 0;
*y1 = r ? c.max_y : 0;
}
return r ? c.num_vertices : 0; return r ? c.num_vertices : 0;
} }
@ -2201,6 +2277,17 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in
if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
} }
STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)
{
int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");
if (!tab)
return 0;
if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68);
if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
return 1;
}
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
{ {
*x0 = ttSHORT(info->data + info->head + 36); *x0 = ttSHORT(info->data + info->head + 36);
@ -2693,19 +2780,18 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
// from the other y segment, and it might ignored as an empty segment. to avoid // from the other y segment, and it might ignored as an empty segment. to avoid
// that, we need to explicitly produce segments based on x positions. // that, we need to explicitly produce segments based on x positions.
// rename variables to clear pairs // rename variables to clearly-defined pairs
float y0 = y_top; float y0 = y_top;
float x1 = (float) (x); float x1 = (float) (x);
float x2 = (float) (x+1); float x2 = (float) (x+1);
float x3 = xb; float x3 = xb;
float y3 = y_bottom; float y3 = y_bottom;
float y1,y2;
// x = e->x + e->dx * (y-y_top) // x = e->x + e->dx * (y-y_top)
// (y-y_top) = (x - e->x) / e->dx // (y-y_top) = (x - e->x) / e->dx
// y = (x - e->x) / e->dx + y_top // y = (x - e->x) / e->dx + y_top
y1 = (x - x0) / dx + y_top; float y1 = (x - x0) / dx + y_top;
y2 = (x+1 - x0) / dx + y_top; float y2 = (x+1 - x0) / dx + y_top;
if (x0 < x1 && x3 > x2) { // three segments descending down-right if (x0 < x1 && x3 > x2) { // three segments descending down-right
stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
@ -3132,8 +3218,9 @@ error:
STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
{ {
float scale = scale_x > scale_y ? scale_y : scale_x; float scale = scale_x > scale_y ? scale_y : scale_x;
int winding_count, *winding_lengths; int winding_count = 0;
int *winding_lengths = NULL;
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
if (windings) { if (windings) {
stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
@ -3221,6 +3308,11 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *
return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
} }
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
{
stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
}
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
{ {
stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
@ -3600,6 +3692,29 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
return k; return k;
} }
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(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 prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
{
stbtt_MakeGlyphBitmapSubpixel(info,
output,
out_w - (prefilter_x - 1),
out_h - (prefilter_y - 1),
out_stride,
scale_x,
scale_y,
shift_x,
shift_y,
glyph);
if (prefilter_x > 1)
stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
if (prefilter_y > 1)
stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
*sub_x = stbtt__oversample_shift(prefilter_x);
*sub_y = stbtt__oversample_shift(prefilter_y);
}
// rects array must be big enough to accommodate all characters in the given ranges // rects array must be big enough to accommodate all characters in the given ranges
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
{ {
@ -3688,7 +3803,7 @@ STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect
stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
} }
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
{ {
stbtt_fontinfo info; stbtt_fontinfo info;
int i,j,n, return_value = 1; int i,j,n, return_value = 1;
@ -3724,7 +3839,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd
return return_value; return return_value;
} }
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
{ {
stbtt_pack_range range; stbtt_pack_range range;
@ -3763,6 +3878,387 @@ STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int
*xpos += b->xadvance; *xpos += b->xadvance;
} }
//////////////////////////////////////////////////////////////////////////////
//
// sdf computation
//
#define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
#define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
{
float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
float roperp = orig[1]*ray[0] - orig[0]*ray[1];
float a = q0perp - 2*q1perp + q2perp;
float b = q1perp - q0perp;
float c = q0perp - roperp;
float s0 = 0., s1 = 0.;
int num_s = 0;
if (a != 0.0) {
float discr = b*b - a*c;
if (discr > 0.0) {
float rcpna = -1 / a;
float d = (float) sqrt(discr);
s0 = (b+d) * rcpna;
s1 = (b-d) * rcpna;
if (s0 >= 0.0 && s0 <= 1.0)
num_s = 1;
if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
if (num_s == 0) s0 = s1;
++num_s;
}
}
} else {
// 2*b*s + c = 0
// s = -c / (2*b)
s0 = c / (-2 * b);
if (s0 >= 0.0 && s0 <= 1.0)
num_s = 1;
}
if (num_s == 0)
return 0;
else {
float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
float q0d = q0[0]*rayn_x + q0[1]*rayn_y;
float q1d = q1[0]*rayn_x + q1[1]*rayn_y;
float q2d = q2[0]*rayn_x + q2[1]*rayn_y;
float rod = orig[0]*rayn_x + orig[1]*rayn_y;
float q10d = q1d - q0d;
float q20d = q2d - q0d;
float q0rd = q0d - rod;
hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
hits[0][1] = a*s0+b;
if (num_s > 1) {
hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
hits[1][1] = a*s1+b;
return 2;
} else {
return 1;
}
}
}
static int equal(float *a, float *b)
{
return (a[0] == b[0] && a[1] == b[1]);
}
static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
{
int i;
float orig[2], ray[2] = { 1, 0 };
float y_frac;
int winding = 0;
orig[0] = x;
orig[1] = y;
// make sure y never passes through a vertex of the shape
y_frac = (float) fmod(y, 1.0f);
if (y_frac < 0.01f)
y += 0.01f;
else if (y_frac > 0.99f)
y -= 0.01f;
orig[1] = y;
// test a ray from (-infinity,y) to (x,y)
for (i=0; i < nverts; ++i) {
if (verts[i].type == STBTT_vline) {
int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x)
winding += (y0 < y1) ? 1 : -1;
}
}
if (verts[i].type == STBTT_vcurve) {
int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy;
int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ;
int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
int by = STBTT_max(y0,STBTT_max(y1,y2));
if (y > ay && y < by && x > ax) {
float q0[2],q1[2],q2[2];
float hits[2][2];
q0[0] = (float)x0;
q0[1] = (float)y0;
q1[0] = (float)x1;
q1[1] = (float)y1;
q2[0] = (float)x2;
q2[1] = (float)y2;
if (equal(q0,q1) || equal(q1,q2)) {
x0 = (int)verts[i-1].x;
y0 = (int)verts[i-1].y;
x1 = (int)verts[i ].x;
y1 = (int)verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x)
winding += (y0 < y1) ? 1 : -1;
}
} else {
int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
if (num_hits >= 1)
if (hits[0][0] < 0)
winding += (hits[0][1] < 0 ? -1 : 1);
if (num_hits >= 2)
if (hits[1][0] < 0)
winding += (hits[1][1] < 0 ? -1 : 1);
}
}
}
}
return winding;
}
static float stbtt__cuberoot( float x )
{
if (x<0)
return -(float) STBTT_pow(-x,1.0f/3.0f);
else
return (float) STBTT_pow( x,1.0f/3.0f);
}
// x^3 + c*x^2 + b*x + a = 0
static int stbtt__solve_cubic(float a, float b, float c, float* r)
{
float s = -a / 3;
float p = b - a*a / 3;
float q = a * (2*a*a - 9*b) / 27 + c;
float p3 = p*p*p;
float d = q*q + 4*p3 / 27;
if (d >= 0) {
float z = (float) STBTT_sqrt(d);
float u = (-q + z) / 2;
float v = (-q - z) / 2;
u = stbtt__cuberoot(u);
v = stbtt__cuberoot(v);
r[0] = s + u + v;
return 1;
} else {
float u = (float) STBTT_sqrt(-p/3);
float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
float m = (float) STBTT_cos(v);
float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
r[0] = s + u * 2 * m;
r[1] = s - u * (m + n);
r[2] = s - u * (m - n);
//STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
//STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
//STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
return 3;
}
}
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
{
float scale_x = scale, scale_y = scale;
int ix0,iy0,ix1,iy1;
int w,h;
unsigned char *data;
// if one scale is 0, use same scale for both
if (scale_x == 0) scale_x = scale_y;
if (scale_y == 0) {
if (scale_x == 0) return NULL; // if both scales are 0, return NULL
scale_y = scale_x;
}
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
// if empty, return NULL
if (ix0 == ix1 || iy0 == iy1)
return NULL;
ix0 -= padding;
iy0 -= padding;
ix1 += padding;
iy1 += padding;
w = (ix1 - ix0);
h = (iy1 - iy0);
if (width ) *width = w;
if (height) *height = h;
if (xoff ) *xoff = ix0;
if (yoff ) *yoff = iy0;
// invert for y-downwards bitmaps
scale_y = -scale_y;
{
int x,y,i,j;
float *precompute;
stbtt_vertex *verts;
int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
for (i=0,j=num_verts-1; i < num_verts; j=i++) {
if (verts[i].type == STBTT_vline) {
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
} else if (verts[i].type == STBTT_vcurve) {
float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
float len2 = bx*bx + by*by;
if (len2 != 0.0f)
precompute[i] = 1.0f / (bx*bx + by*by);
else
precompute[i] = 0.0f;
} else
precompute[i] = 0.0f;
}
for (y=iy0; y < iy1; ++y) {
for (x=ix0; x < ix1; ++x) {
float val;
float min_dist = 999999.0f;
float sx = (float) x + 0.5f;
float sy = (float) y + 0.5f;
float x_gspace = (sx / scale_x);
float y_gspace = (sy / scale_y);
int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
for (i=0; i < num_verts; ++i) {
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
// check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
if (dist2 < min_dist*min_dist)
min_dist = (float) STBTT_sqrt(dist2);
if (verts[i].type == STBTT_vline) {
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
// coarse culling against bbox
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
STBTT_assert(i != 0);
if (dist < min_dist) {
// check position along line
// x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
// minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
float dx = x1-x0, dy = y1-y0;
float px = x0-sx, py = y0-sy;
// minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy
// derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
if (t >= 0.0f && t <= 1.0f)
min_dist = dist;
}
} else if (verts[i].type == STBTT_vcurve) {
float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y;
float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
// coarse culling against bbox to avoid computing cubic unnecessarily
if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
int num=0;
float ax = x1-x0, ay = y1-y0;
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
float mx = x0 - sx, my = y0 - sy;
float res[3],px,py,t,it;
float a_inv = precompute[i];
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
float a = 3*(ax*bx + ay*by);
float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
float c = mx*ax+my*ay;
if (a == 0.0) { // if a is 0, it's linear
if (b != 0.0) {
res[num++] = -c/b;
}
} else {
float discriminant = b*b - 4*a*c;
if (discriminant < 0)
num = 0;
else {
float root = (float) STBTT_sqrt(discriminant);
res[0] = (-b - root)/(2*a);
res[1] = (-b + root)/(2*a);
num = 2; // don't bother distinguishing 1-solution case, as code below will still work
}
}
} else {
float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
float d = (mx*ax+my*ay) * a_inv;
num = stbtt__solve_cubic(b, c, d, res);
}
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
t = res[0], it = 1.0f - t;
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
if (dist2 < min_dist * min_dist)
min_dist = (float) STBTT_sqrt(dist2);
}
if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
t = res[1], it = 1.0f - t;
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
if (dist2 < min_dist * min_dist)
min_dist = (float) STBTT_sqrt(dist2);
}
if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
t = res[2], it = 1.0f - t;
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
if (dist2 < min_dist * min_dist)
min_dist = (float) STBTT_sqrt(dist2);
}
}
}
}
if (winding == 0)
min_dist = -min_dist; // if outside the shape, value is negative
val = onedge_value + pixel_dist_scale * min_dist;
if (val < 0)
val = 0;
else if (val > 255)
val = 255;
data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
}
}
STBTT_free(precompute, info->userdata);
STBTT_free(verts, info->userdata);
}
return data;
}
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
{
return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
}
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
{
STBTT_free(bitmap, userdata);
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -3970,6 +4466,10 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
// FULL VERSION HISTORY // FULL VERSION HISTORY
// //
// 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
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
// 1.11 (2016-04-02) fix unused-variable warning // 1.11 (2016-04-02) fix unused-variable warning
// 1.10 (2016-04-02) allow user-defined fabs() replacement // 1.10 (2016-04-02) allow user-defined fabs() replacement

View File

@ -1,11 +1,11 @@
// Ogg Vorbis audio decoder - v1.10 - public domain // Ogg Vorbis audio decoder - v1.11 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Original version written by Sean Barrett in 2007. // Original version written by Sean Barrett in 2007.
// //
// Originally sponsored by RAD Game Tools. Seeking sponsored // Originally sponsored by RAD Game Tools. Seeking implementation
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software, // sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,
// Aras Pranckevicius, and Sean Barrett. // Elias Software, Aras Pranckevicius, and Sean Barrett.
// //
// LICENSE // LICENSE
// //
@ -29,9 +29,11 @@
// Bernhard Wodo Evan Balster alxprd@github // Bernhard Wodo Evan Balster alxprd@github
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// Phillip Bennefall Rohit Thiago Goulart // Phillip Bennefall Rohit Thiago Goulart
// manxorist@github saga musix // manxorist@github saga musix github:infatum
// //
// Partial history: // Partial history:
// 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.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.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.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame
@ -551,7 +553,7 @@ enum STBVorbisError
#include <math.h> #include <math.h>
// find definition of alloca if it's not in stdlib.h: // find definition of alloca if it's not in stdlib.h:
#ifdef _MSC_VER #if defined(_MSC_VER) || defined(__MINGW32__)
#include <malloc.h> #include <malloc.h>
#endif #endif
#if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__)
@ -576,6 +578,7 @@ enum STBVorbisError
#undef __forceinline #undef __forceinline
#endif #endif
#define __forceinline #define __forceinline
#define alloca __builtin_alloca
#elif !defined(_MSC_VER) #elif !defined(_MSC_VER)
#if __GNUC__ #if __GNUC__
#define __forceinline inline #define __forceinline inline
@ -2040,6 +2043,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in
return TRUE; return TRUE;
} }
// n is 1/2 of the blocksize --
// specification: "Correct per-vector decode length is [n]/2"
static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
{ {
int i,j,pass; int i,j,pass;
@ -2047,7 +2052,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int rtype = f->residue_types[rn]; int rtype = f->residue_types[rn];
int c = r->classbook; int c = r->classbook;
int classwords = f->codebooks[c].dimensions; int classwords = f->codebooks[c].dimensions;
int n_read = r->end - r->begin; unsigned int actual_size = rtype == 2 ? n*2 : n;
unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size);
unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size);
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
int temp_alloc_point = temp_alloc_save(f); int temp_alloc_point = temp_alloc_save(f);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@ -4075,7 +4083,10 @@ static int start_decoder(vorb *f)
int i,max_part_read=0; int i,max_part_read=0;
for (i=0; i < f->residue_count; ++i) { for (i=0; i < f->residue_count; ++i) {
Residue *r = f->residue_config + i; Residue *r = f->residue_config + i;
int n_read = r->end - r->begin; unsigned int actual_size = f->blocksize_1 / 2;
unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size;
unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size;
int n_read = limit_r_end - limit_r_begin;
int part_read = n_read / r->part_size; int part_read = n_read / r->part_size;
if (part_read > max_part_read) if (part_read > max_part_read)
max_part_read = part_read; max_part_read = part_read;
@ -4086,6 +4097,8 @@ static int start_decoder(vorb *f)
classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
#endif #endif
// maximum reasonable partition size is f->blocksize_1
f->temp_memory_required = classify_mem; f->temp_memory_required = classify_mem;
if (imdct_mem > f->temp_memory_required) if (imdct_mem > f->temp_memory_required)
f->temp_memory_required = imdct_mem; f->temp_memory_required = imdct_mem;
@ -5349,6 +5362,8 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
#endif // STB_VORBIS_NO_PULLDATA_API #endif // STB_VORBIS_NO_PULLDATA_API
/* Version history /* Version history
1.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.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.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.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks;

View File

@ -162,6 +162,10 @@
// the main trick is in realizing in the first place that it's // the main trick is in realizing in the first place that it's
// possible to do this in a generic, type-safe way in C. // possible to do this in a generic, type-safe way in C.
// //
// Contributors:
//
// Timothy Wright (github:ZenToad)
//
// LICENSE // LICENSE
// //
// See end of file for license information. // See end of file for license information.
@ -189,7 +193,7 @@
#define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a)) #define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a))
#define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0) #define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0)
#define stb__sbgrow(a,n) ((a) = stb__sbgrowf((a), (n), sizeof(*(a)))) #define stb__sbgrow(a,n) (*((void **)&(a)) = stb__sbgrowf((a), (n), sizeof(*(a))))
#include <stdlib.h> #include <stdlib.h>

View File

@ -3,5 +3,5 @@ CFLAGS = -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DSTB_DIVIDE_TEST
CPPFLAGS = -Wno-write-strings -DSTB_DIVIDE_TEST CPPFLAGS = -Wno-write-strings -DSTB_DIVIDE_TEST
all: all:
$(CC) $(INCLUDES) $(CFLAGS) ../stb_vorbis.c test_c_compilation.c -lm $(CC) $(INCLUDES) $(CFLAGS) ../stb_vorbis.c test_c_compilation.c -lm
$(CC) $(INCLUDES) $(CPPFLAGS) test_cpp_compilation.cpp -lm $(CC) $(INCLUDES) $(CPPFLAGS) test_cpp_compilation.cpp -lm -lstdc++

152
tests/sdf/sdf_test.c Normal file
View File

@ -0,0 +1,152 @@
#define STB_DEFINE
#include "stb.h"
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
// used both to compute SDF and in 'shader'
float sdf_size = 32.0; // the larger this is, the better large font sizes look
float pixel_dist_scale = 64.0; // trades off precision w/ ability to handle *smaller* sizes
int onedge_value = 128;
int padding = 3; // not used in shader
typedef struct
{
float advance;
signed char xoff;
signed char yoff;
unsigned char w,h;
unsigned char *data;
} fontchar;
fontchar fdata[128];
#define BITMAP_W 1200
#define BITMAP_H 800
unsigned char bitmap[BITMAP_H][BITMAP_W][3];
char *sample = "This is goofy text, size %d!";
char *small_sample = "This is goofy text, size %d! Really needs in-shader supersampling to look good.";
void blend_pixel(int x, int y, int color, float alpha)
{
int i;
for (i=0; i < 3; ++i)
bitmap[y][x][i] = (unsigned char) (stb_lerp(alpha, bitmap[y][x][i], color)+0.5); // round
}
void draw_char(float px, float py, char c, float relative_scale)
{
int x,y;
fontchar *fc = &fdata[c];
float fx0 = px + fc->xoff*relative_scale;
float fy0 = py + fc->yoff*relative_scale;
float fx1 = fx0 + fc->w*relative_scale;
float fy1 = fy0 + fc->h*relative_scale;
int ix0 = (int) floor(fx0);
int iy0 = (int) floor(fy0);
int ix1 = (int) ceil(fx1);
int iy1 = (int) ceil(fy1);
// clamp to viewport
if (ix0 < 0) ix0 = 0;
if (iy0 < 0) iy0 = 0;
if (ix1 > BITMAP_W) ix1 = BITMAP_W;
if (iy1 > BITMAP_H) iy1 = BITMAP_H;
for (y=iy0; y < iy1; ++y) {
for (x=ix0; x < ix1; ++x) {
float sdf_dist, pix_dist;
float bmx = stb_linear_remap(x, fx0, fx1, 0, fc->w);
float bmy = stb_linear_remap(y, fy0, fy1, 0, fc->h);
int v00,v01,v10,v11;
float v0,v1,v;
int sx0 = (int) bmx;
int sx1 = sx0+1;
int sy0 = (int) bmy;
int sy1 = sy0+1;
// compute lerp weights
bmx = bmx - sx0;
bmy = bmy - sy0;
// clamp to edge
sx0 = stb_clamp(sx0, 0, fc->w-1);
sx1 = stb_clamp(sx1, 0, fc->w-1);
sy0 = stb_clamp(sy0, 0, fc->h-1);
sy1 = stb_clamp(sy1, 0, fc->h-1);
// bilinear texture sample
v00 = fc->data[sy0*fc->w+sx0];
v01 = fc->data[sy0*fc->w+sx1];
v10 = fc->data[sy1*fc->w+sx0];
v11 = fc->data[sy1*fc->w+sx1];
v0 = stb_lerp(bmx,v00,v01);
v1 = stb_lerp(bmx,v10,v11);
v = stb_lerp(bmy,v0 ,v1 );
#if 0
// non-anti-aliased
if (v > onedge_value)
blend_pixel(x,y,0,1.0);
#else
// Following math can be greatly simplified
// convert distance in SDF value to distance in SDF bitmap
sdf_dist = stb_linear_remap(v, onedge_value, onedge_value+pixel_dist_scale, 0, 1);
// convert distance in SDF bitmap to distance in output bitmap
pix_dist = sdf_dist * relative_scale;
// anti-alias by mapping 1/2 pixel around contour from 0..1 alpha
v = stb_linear_remap(pix_dist, -0.5f, 0.5f, 0, 1);
if (v > 1) v = 1;
if (v > 0)
blend_pixel(x,y,0,v);
#endif
}
}
}
void print_text(float x, float y, char *text, float scale)
{
int i;
for (i=0; text[i]; ++i) {
if (fdata[text[i]].data)
draw_char(x,y,text[i],scale);
x += fdata[text[i]].advance * scale;
}
}
int main(int argc, char **argv)
{
int ch;
float scale, ypos;
stbtt_fontinfo font;
void *data = stb_file("c:/windows/fonts/times.ttf", NULL);
stbtt_InitFont(&font, data, 0);
scale = stbtt_ScaleForPixelHeight(&font, sdf_size);
for (ch=32; ch < 127; ++ch) {
fontchar fc;
int xoff,yoff,w,h, advance;
fc.data = stbtt_GetCodepointSDF(&font, scale, ch, padding, onedge_value, pixel_dist_scale, &w, &h, &xoff, &yoff);
fc.xoff = xoff;
fc.yoff = yoff;
fc.w = w;
fc.h = h;
stbtt_GetCodepointHMetrics(&font, ch, &advance, NULL);
fc.advance = advance * scale;
fdata[ch] = fc;
}
ypos = 60;
memset(bitmap, 255, sizeof(bitmap));
print_text(400, ypos+30, stb_sprintf("sdf bitmap height %d", (int) sdf_size), 30/sdf_size);
ypos += 80;
for (scale = 8.0; scale < 120.0; scale *= 1.33f) {
print_text(80, ypos+scale, stb_sprintf(scale == 8.0 ? small_sample : sample, (int) scale), scale / sdf_size);
ypos += scale*1.05f + 20;
}
stbi_write_png("sdf_test.png", BITMAP_W, BITMAP_H, 3, bitmap, 0);
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -66,7 +66,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GRID_TEST" /FR /FD /GZ /c # ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FR /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"

View File

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

View File

@ -21,6 +21,22 @@ dual-license for you to choose from.
No, because it's public domain you can freely relicense it to whatever license your new No, because it's public domain you can freely relicense it to whatever license your new
library wants to be. library wants to be.
#### What's the deal with SSE support in GCC-based compilers?
stb_image will either use SSE2 (if you compile with -msse2) or
will not use any SIMD at all, rather than trying to detect the
processor at runtime and handle it correctly. As I understand it,
the approved path in GCC for runtime-detection require
you to use multiple source files, one for each CPU configuration.
Because stb_image is a header-file library that compiles in only
one source file, there's no approved way to build both an
SSE-enabled and a non-SSE-enabled variation.
While we've tried to work around it, we've had multiple issues over
the years due to specific versions of gcc breaking what we're doing,
so we've given up on it. See https://github.com/nothings/stb/issues/280
and https://github.com/nothings/stb/issues/410 for examples.
#### Some of these libraries seem redundant to existing open source libraries. Are they better somehow? #### Some of these libraries seem redundant to existing open source libraries. Are they better somehow?
Generally they're only better in that they're easier to integrate, Generally they're only better in that they're easier to integrate,