mirror of
https://github.com/nothings/stb
synced 2024-12-15 04:22:35 +03:00
Merge branch 'master' into working
Conflicts: stb_image.h
This commit is contained in:
commit
5db03ef592
38
README.md
38
README.md
@ -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 interface | 1393 | guts of a text editor for games etc implementing them from scratch
|
**[stb_textedit.h](stb_textedit.h)** | 1.11 | user 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 graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
|
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
|
||||||
**[stb_dxt.h](stb_dxt.h)** | 1.06 | 3D graphics | 687 | Fabian "ryg" Giesen's real-time DXT compressor
|
**[stb_dxt.h](stb_dxt.h)** | 1.07 | 3D graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor
|
||||||
**[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D graphics | 316 | revised Perlin noise (3D input, 1D output)
|
**[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D graphics | 316 | revised Perlin noise (3D input, 1D output)
|
||||||
**[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
|
**[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
|
||||||
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game dev | 4172 | embeddable tilemap editor
|
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game dev | 4172 | embeddable tilemap editor
|
||||||
@ -29,11 +29,11 @@ library | lastest version | category | LoC | description
|
|||||||
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages
|
**[stb_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
96
stb.h
@ -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 {
|
||||||
|
52
stb_dxt.h
52
stb_dxt.h
@ -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);
|
||||||
|
729
stb_image.h
729
stb_image.h
File diff suppressed because it is too large
Load Diff
@ -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");
|
||||||
|
@ -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 ???
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
2074
stb_sprintf.h
2074
stb_sprintf.h
File diff suppressed because it is too large
Load Diff
@ -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));
|
||||||
}
|
}
|
||||||
|
586
stb_truetype.h
586
stb_truetype.h
@ -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
|
||||||
|
31
stb_vorbis.c
31
stb_vorbis.c
@ -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;
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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
152
tests/sdf/sdf_test.c
Normal 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;
|
||||||
|
}
|
BIN
tests/sdf/sdf_test_arial_16.png
Normal file
BIN
tests/sdf/sdf_test_arial_16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
BIN
tests/sdf/sdf_test_times_16.png
Normal file
BIN
tests/sdf/sdf_test_times_16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 106 KiB |
BIN
tests/sdf/sdf_test_times_50.png
Normal file
BIN
tests/sdf/sdf_test_times_50.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
@ -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"
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user