Merge branch 'master' into sdf

Conflicts:
	stb_truetype.h
This commit is contained in:
Sean Barrett 2017-07-12 06:42:02 -07:00
commit fa98e4f6cf
54 changed files with 10388 additions and 2039 deletions

28
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,28 @@
Pull Requests and Issues are both welcome.
# Responsiveness
General priority order is:
* Crashes
* Bugs
* Warnings
* Enhancements (new features, performance improvement, etc)
Pull requests get priority over Issues. Some pull requests I take
as written; some I modify myself; some I will request changes before
accepting them. Because I've ended up supporting a lot of libraries
(20 as I write this, with more on the way), I am somewhat slow to
address things. Many issues have been around for a long time.
# Pull requests
* Do NOT update the version number in the file. (This just causes conflicts.)
* Do add your name to the list of contributors. (Don't worry about the formatting.) I'll try to remember to add it if you don't, but I sometimes forget as it's an extra step.
# Specific libraries
I generally do not want new file formats for stb_image because
we are trying to improve its security, so increasing its attack
surface is counter-productive.

6
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,6 @@
* Delete this list before clicking CREATE PULL REQUEST
* Make sure you're using a special branch just for this pull request. (Sometimes people unknowingly use a default branch, then later update that branch, which updates the pull request with the other changes if it hasn't been merged yet.)
* Do NOT update the version number in the file. (This just causes conflicts.)
* Do add your name to the list of contributors. (Don't worry about the formatting.) I'll try to remember to add it if you don't, but I sometimes forget as it's an extra step.
If you get something above wrong, don't fret it, it's not the end of the world.

5
.travis.yml Normal file
View File

@ -0,0 +1,5 @@
language: C
install: true
script:
- cd tests
- make all

View File

@ -3,31 +3,37 @@
stb
===
single-file public domain libraries for C/C++
single-file public domain (or MIT licensed) libraries for C/C++ <a name="stb_libs"></a>
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | --------------------------------
**stb_vorbis.c** | 1.05 | audio | 5445 | decode ogg vorbis files from file/memory to float/16-bit signed output
**stb_image.h** | 2.06 | graphics | 6437 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**stb_truetype.h** | 1.06 | graphics | 2632 | parse, decode, and rasterize characters from truetype fonts
**stb_image_write.h** | 0.98 | graphics | 730 | image writing to disk: PNG, TGA, BMP
**stb_image_resize.h** | 0.90 | graphics | 2585 | resize images larger/smaller with good quality
**stb_rect_pack.h** | 0.06 | graphics | 560 | simple 2D rectangle packer with decent quality
**stretchy_buffer.h** | 1.02 | utility | 210 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
**stb_textedit.h** | 1.6 | UI | 1290 | guts of a text editor for games etc implementing them from scratch
**stb_voxel_render.h** | 0.81 | 3D&nbsp;graphics | 3644 | Minecraft-esque voxel rendering "engine" with many more features
**stb_dxt.h** | 1.04 | 3D&nbsp;graphics | 624 | Fabian "ryg" Giesen's real-time DXT compressor
**stb_perlin.h** | 0.2 | 3D&nbsp;graphics | 175 | revised Perlin noise (3D input, 1D output)
**stb_easy_font.h** | 0.5 | 3D&nbsp;graphics | 220 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
**stb_tilemap_editor.h** | 0.35 | game&nbsp;dev | 4120 | embeddable tilemap editor
**stb_herringbone_wa...** | 0.6 | game&nbsp;dev | 1217 | herringbone Wang tile map generator
**stb_c_lexer.h** | 0.06 | parsing | 809 | simplify writing parsers for C-like languages
**stb_divide.h** | 0.91 | math | 373 | more useful 32-bit modulus e.g. "euclidean divide"
**stb.h** | 2.24 | misc | 14086 | helper functions for C, mostly redundant in C++; basically author's personal stuff
**stb_leakcheck.h** | 0.2 | misc | 117 | quick-and-dirty malloc/free leak-checking
**[stb_vorbis.c](stb_vorbis.c)** | 1.10 | audio | 5447 | 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_truetype.h](stb_truetype.h)** | 1.15 | graphics | 4061 | 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_resize.h](stb_image_resize.h)** | 0.94 | graphics | 2624 | 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_sprintf.h](stb_sprintf.h)** | 1.02 | utility | 1202 | fast sprintf, snprintf for C/C++
**[stretchy_buffer.h](stretchy_buffer.h)** | 1.02 | utility | 257 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
**[stb_textedit.h](stb_textedit.h)** | 1.11 | user&nbsp;interface | 1393 | guts of a text editor for games etc implementing them from scratch
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D&nbsp;graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
**[stb_dxt.h](stb_dxt.h)** | 1.06 | 3D&nbsp;graphics | 687 | Fabian "ryg" Giesen's real-time DXT compressor
**[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D&nbsp;graphics | 316 | revised Perlin noise (3D input, 1D output)
**[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D&nbsp;graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game&nbsp;dev | 4172 | embeddable tilemap editor
**[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.6 | game&nbsp;dev | 1220 | herringbone Wang tile map generator
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages
**[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide"
**[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids
**[stb.h](stb.h)** | 2.29 | misc | 14324 | 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
Total libraries: 18
Total lines of C code: 45274
Total libraries: 20
Total lines of C code: 51304
FAQ
@ -35,15 +41,40 @@ FAQ
#### What's the license?
These libraries are in the public domain (or the equivalent where that is not
possible). You can do anything you want with them. You have no legal obligation
These libraries are in the public domain. You can do anything you
want with them. You have no legal obligation
to do anything else, although I appreciate attribution.
#### If I wrap an stb library in a new library, does the new library have to be public domain?
They are also licensed under the MIT open source license, if you have lawyers
who are unhappy with public domain. Every source file includes an explicit
dual-license for you to choose from.
No.
#### <a name="other_libs"></a> Are there other single-file public-domain/open source libraries with minimal dependencies out there?
#### A lot of these libraries seem redundant to existing open source libraries. Are they better somehow?
[Yes.](https://github.com/nothings/single_file_libs)
#### If I wrap an stb library in a new library, does the new library have to be public domain/MIT?
No, because it's public domain you can freely relicense it to whatever license your new
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?
Generally they're only better in that they're easier to integrate,
easier to use, and easier to release (single file; good API; no
@ -51,6 +82,10 @@ attribution requirement). They may be less featureful, slower,
and/or use more memory. If you're already using an equivalent
library, there's probably no good reason to switch.
#### Can I link directly to the table of stb libraries?
You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list.
#### Why do you list "lines of code"? It's a terrible metric.
Just to give you some idea of the internal complexity of the library,
@ -88,10 +123,10 @@ remember to attach *two* files, etc.
#### Why "stb"? Is this something to do with Set-Top Boxes?
No, they are just the initials for my name, Sean T. Barrett.
This was not chosen out of egomania, but as a semi-robust
This was not chosen out of egomania, but as a moderately sane
way of namespacing the filenames and source function names.
#### Will you add more image types to stb_image.c?
#### Will you add more image types to stb_image.h?
If people submit them, I generally add them, but the goal of stb_image
is less for applications like image viewer apps (which need to support
@ -99,10 +134,6 @@ every type of image under the sun) and more for things like games which
can choose what images to use, so I may decline to add them if they're
too rare or if the size of implementation vs. apparent benefit is too low.
#### Are there other single-file public-domain libraries out there?
Yes. I'll put a list here when people remind me what they are.
#### Do you have any advice on how to create my own single-file library?
Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt

BIN
data/map_01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
data/map_02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
data/map_03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

1055
deprecated/rrsprintf.h Normal file

File diff suppressed because it is too large Load Diff

1
docs/other_libs.md Normal file
View File

@ -0,0 +1 @@
Moved to https://github.com/nothings/single_file_libs

View File

@ -165,9 +165,9 @@ public domain declarations aren't necessary recognized
in the USA and some other locations. For that reason,
I recommend a declaration along these lines:
// This software is in the public domain. Where that dedication is not
// recognized, you are granted a perpetual, irrevocable license to copy
// and modify this file as you see fit.
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
I typically place this declaration at the end of the initial
comment block of the file and just say 'public domain'

View File

@ -95,9 +95,9 @@ public domain declarations aren't necessary recognized
in the USA and some other locations. For that reason,
I recommend a declaration along these lines:
// This software is in the public domain. Where that dedication is not
// recognized, you are granted a perpetual, irrevocable license to copy
// and modify this file as you see fit.
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
I typically place this declaration at the end of the initial
comment block of the file and just say 'public domain'

388
stb.h
View File

@ -1,4 +1,4 @@
/* stb.h - v2.24 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
/* stb.h - v2.29 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
no warranty is offered or implied; use this code at your own risk
This is a single header file with a bunch of useful utilities
@ -25,6 +25,11 @@
Version History
2.29 attempt to fix use of swprintf()
2.28 various new functionality
2.27 test _WIN32 not WIN32 in STB_THREADS
2.26 various warning & bugfixes
2.25 various warning & bugfixes
2.24 various warning & bugfixes
2.23 fix 2.22
2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name
@ -166,6 +171,26 @@ Version History
(stb_array), (stb_arena)
Parenthesized items have since been removed.
LICENSE
See end of file for license information.
CREDITS
Written by Sean Barrett.
Fixes:
Philipp Wiesemann
Robert Nix
r-lyeh
blackpawn
Mojofreem@github
Ryan Whitworth
Vincent Isambart
Mike Sartain
Eugene Opalev
Tim Sjostrand
*/
#ifndef STB__INCLUDE_STB_H
@ -186,10 +211,28 @@ Parenthesized items have since been removed.
#endif
#endif
#if defined(_WIN32) && !defined(__MINGW32__)
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#endif
#ifndef _CRT_NON_CONFORMING_SWPRINTFS
#define _CRT_NON_CONFORMING_SWPRINTFS
#endif
#if !defined(_MSC_VER) || _MSC_VER > 1700
#include <intrin.h> // _BitScanReverse
#endif
#endif
#include <stdlib.h> // stdlib could have min/max
#include <stdio.h> // need FILE
#include <string.h> // stb_define_hash needs memcpy/memset
#include <time.h> // stb_dirtree
#ifdef __MINGW32__
#include <fcntl.h> // O_RDWR
#endif
#ifdef STB_PERSONAL
typedef int Bool;
@ -323,7 +366,7 @@ typedef char stb__testsize2_64[sizeof(stb_uint64)==8 ? 1 : -1];
// add platform-specific ways of checking for sizeof(char*) == 8,
// and make those define STB_PTR64
#if defined(_WIN64) || defined(__x86_64__) || defined(__ia64__)
#if defined(_WIN64) || defined(__x86_64__) || defined(__ia64__) || defined(__LP64__)
#define STB_PTR64
#endif
@ -682,20 +725,42 @@ STB_EXTERN char * stb_sstrdup(char *s);
STB_EXTERN void stbprint(const char *fmt, ...);
STB_EXTERN char *stb_sprintf(const char *fmt, ...);
STB_EXTERN char *stb_mprintf(const char *fmt, ...);
STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...);
STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v);
#ifdef STB_DEFINE
int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v)
{
int res;
#ifdef _WIN32
// Could use "_vsnprintf_s(s, n, _TRUNCATE, fmt, v)" ?
res = _vsnprintf(s,n,fmt,v);
#else
res = vsnprintf(s,n,fmt,v);
#endif
if (n) s[n-1] = 0;
// Unix returns length output would require, Windows returns negative when truncated.
return (res >= (int) n || res < 0) ? -1 : res;
}
int stb_snprintf(char *s, size_t n, const char *fmt, ...)
{
int res;
va_list v;
va_start(v,fmt);
res = stb_vsnprintf(s, n, fmt, v);
va_end(v);
return res;
}
char *stb_sprintf(const char *fmt, ...)
{
static char buffer[1024];
va_list v;
va_start(v,fmt);
#ifdef _WIN32
_vsnprintf(buffer, 1024, fmt, v);
#else
vsnprintf(buffer, 1024, fmt, v);
#endif
stb_vsnprintf(buffer,1024,fmt,v);
va_end(v);
buffer[1023] = 0;
return buffer;
}
@ -704,13 +769,8 @@ char *stb_mprintf(const char *fmt, ...)
static char buffer[1024];
va_list v;
va_start(v,fmt);
#ifdef _WIN32
_vsnprintf(buffer, 1024, fmt, v);
#else
vsnprintf(buffer, 1024, fmt, v);
#endif
stb_vsnprintf(buffer,1024,fmt,v);
va_end(v);
buffer[1023] = 0;
return strdup(buffer);
}
@ -810,9 +870,8 @@ void stbprint(const char *fmt, ...)
va_list v;
va_start(v,fmt);
res = _vsnprintf(buffer, sizeof(buffer), fmt, v);
res = stb_vsnprintf(buffer, sizeof(buffer), fmt, v);
va_end(v);
buffer[sizeof(buffer)-1] = 0;
if (res < 0) {
tbuf = (char *) malloc(16384);
@ -1021,9 +1080,15 @@ void stb_fatal(char *s, ...)
vfprintf(stderr, s, a);
va_end(a);
fputs("\n", stderr);
#ifdef _WIN32
#ifdef STB_DEBUG
#ifdef _MSC_VER
#ifndef STB_PTR64
__asm int 3; // trap to debugger!
#else
__debugbreak();
#endif
#else
__builtin_trap();
#endif
#endif
exit(1);
@ -1395,13 +1460,13 @@ int stb_is_pow2(unsigned int n)
// tricky use of 4-bit table to identify 5 bit positions (note the '-1')
// 3-bit table would require another tree level; 5-bit table wouldn't save one
#ifdef _WIN32
#if defined(_WIN32) && !defined(__MINGW32__)
#pragma warning(push)
#pragma warning(disable: 4035) // disable warning about no return value
int stb_log2_floor(unsigned int n)
{
#if _MSC_VER > 1700
DWORD i;
unsigned long i;
_BitScanReverse(&i, n);
return i != 0 ? i : -1;
#else
@ -1727,6 +1792,7 @@ STB_EXTERN char * stb_strichr(char *s, char t);
STB_EXTERN char * stb_stristr(char *s, char *t);
STB_EXTERN int stb_prefix_count(char *s, char *t);
STB_EXTERN char * stb_plural(int n); // "s" or ""
STB_EXTERN 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_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out);
@ -1741,6 +1807,17 @@ STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count);
#ifdef STB_DEFINE
size_t stb_strscpy(char *d, const char *s, size_t n)
{
size_t len = strlen(s);
if (len >= n) {
if (n) d[0] = 0;
return 0;
}
strcpy(d,s);
return len + 1;
}
char *stb_plural(int n)
{
return n == 1 ? "" : "s";
@ -2561,7 +2638,8 @@ void stb_malloc_validate(void *p, void *parent)
static void * stb__try_chunk(stb__chunk *c, int size, int align, int pre_align)
{
char *memblock = (char *) (c+1), *q;
int iq, start_offset;
stb_inta iq;
int start_offset;
// we going to allocate at the end of the chunk, not the start. confusing,
// but it means we don't need both a 'limit' and a 'cur', just a 'cur'.
@ -2973,8 +3051,8 @@ typedef struct
#define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature)
#define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature)
#else
#define stb_arr_check(a) 0
#define stb_arr_check2(a) 0
#define stb_arr_check(a) ((void) 0)
#define stb_arr_check2(a) ((void) 0)
#endif
// ARRAY LENGTH
@ -3023,7 +3101,7 @@ typedef struct
#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n))
// insert an element at i
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n), ((a)[i] = v))
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v))
// delete N elements from the middle starting at index 'i'
#define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n))
@ -3209,7 +3287,7 @@ void stb__arr_insertn_(void **pp, int size, int i, int n STB__PARAMS)
}
z = stb_arr_len2(p);
stb__arr_addlen_(&p, size, i STB__ARGS);
stb__arr_addlen_(&p, size, n STB__ARGS);
memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i));
}
*pp = p;
@ -3219,7 +3297,7 @@ void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS)
{
void *p = *pp;
if (n) {
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-i));
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n)));
stb_arrhead2(p)->len -= n;
}
*pp = p;
@ -3297,7 +3375,7 @@ unsigned int stb_hashptr(void *p)
unsigned int stb_rehash_improved(unsigned int v)
{
return stb_hashptr((void *) v);
return stb_hashptr((void *)(size_t) v);
}
unsigned int stb_hash2(char *str, unsigned int *hash2_ptr)
@ -5049,7 +5127,7 @@ void stb_fwrite32(FILE *f, stb_uint32 x)
fwrite(&x, 4, 1, f);
}
#ifdef _MSC_VER
#if defined(_MSC_VER) || defined(__MINGW32__)
#define stb__stat _stat
#else
#define stb__stat stat
@ -5112,7 +5190,18 @@ int stb_filewrite(char *filename, void *data, size_t length)
{
FILE *f = stb_fopen(filename, "wb");
if (f) {
fwrite(data, 1, length, f);
unsigned char *data_ptr = (unsigned char *) data;
size_t remaining = length;
while (remaining > 0) {
size_t len2 = remaining > 65536 ? 65536 : remaining;
size_t len3 = fwrite(data_ptr, 1, len2, f);
if (len2 != len3) {
fprintf(stderr, "Failed while writing %s\n", filename);
break;
}
remaining -= len2;
data_ptr += len2;
}
stb_fclose(f, stb_keep_if_different);
}
return f != NULL;
@ -5389,7 +5478,11 @@ FILE * stb_fopen(char *filename, char *mode)
#else
{
strcpy(temp_full+p, "stmpXXXXXX");
int fd = mkstemp(temp_full);
#ifdef __MINGW32__
int fd = open(mktemp(temp_full), O_RDWR);
#else
int fd = mkstemp(temp_full);
#endif
if (fd == -1) return NULL;
f = fdopen(fd, mode);
if (f == NULL) {
@ -5708,6 +5801,19 @@ char *stb_strip_final_slash(char *t)
}
return t;
}
char *stb_strip_final_slash_regardless(char *t)
{
if (t[0]) {
char *z = t + strlen(t) - 1;
// *z is the last character
if (*z == '\\' || *z == '/')
*z = 0;
if (*z == '\\')
*z = '/'; // canonicalize to make sure it matches db
}
return t;
}
#endif
//////////////////////////////////////////////////////////////////////////////
@ -5820,42 +5926,57 @@ void stb_readdir_free(char **files)
stb_arr_free(f2);
}
static int isdotdirname(char *name)
{
if (name[0] == '.')
return (name[1] == '.') ? !name[2] : !name[1];
return 0;
}
STB_EXTERN int stb_wildmatchi(char *expr, char *candidate);
static char **readdir_raw(char *dir, int return_subdirs, char *mask)
{
char **results = NULL;
char buffer[512], with_slash[512];
int n;
char buffer[4096], with_slash[4096];
size_t n;
#ifdef _MSC_VER
stb__wchar *ws;
struct _wfinddata_t data;
#ifdef _WIN64
const intptr_t none = -1;
intptr_t z;
#else
const long none = -1;
long z;
#else
#endif
#else // !_MSC_VER
const DIR *none = NULL;
DIR *z;
#endif
strcpy(buffer,dir);
n = stb_strscpy(buffer,dir,sizeof(buffer));
if (!n || n >= sizeof(buffer))
return NULL;
stb_fixpath(buffer);
n = strlen(buffer);
n--;
if (n > 0 && (buffer[n-1] != '/')) {
buffer[n++] = '/';
}
buffer[n] = 0;
strcpy(with_slash, buffer);
if (!stb_strscpy(with_slash,buffer,sizeof(with_slash)))
return NULL;
#ifdef _MSC_VER
strcpy(buffer+n, "*.*");
if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n))
return NULL;
ws = stb__from_utf8(buffer);
z = _wfindfirst((const wchar_t *)ws, &data);
#else
z = opendir(dir);
#endif
if (z != none) {
int nonempty = STB_TRUE;
#ifndef _MSC_VER
@ -5876,17 +5997,18 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
is_subdir = !!(data.attrib & _A_SUBDIR);
#else
char *name = data->d_name;
strcpy(buffer+n,name);
DIR *y = opendir(buffer);
is_subdir = (y != NULL);
if (y != NULL) closedir(y);
if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n))
break;
// Could follow DT_LNK, but would need to check for recursive links.
is_subdir = !!(data->d_type & DT_DIR);
#endif
if (is_subdir == return_subdirs) {
if (!is_subdir || name[0] != '.') {
if (!is_subdir || !isdotdirname(name)) {
if (!mask || stb_wildmatchi(mask, name)) {
char buffer[512],*p=buffer;
sprintf(buffer, "%s%s", with_slash, name);
char buffer[4096],*p=buffer;
if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 )
break;
if (buffer[0] == '.' && buffer[1] == '/')
p = buffer+2;
stb_arr_push(results, strdup(p));
@ -6649,14 +6771,16 @@ typedef struct
char * path; // full path from passed-in root
time_t last_modified;
int num_files;
int flag;
} stb_dirtree_dir;
typedef struct
{
char *name; // name relative to path
int dir; // index into dirs[] array
unsigned long size; // size, max 4GB
stb_int64 size; // size, max 4GB
time_t last_modified;
int flag;
} stb_dirtree_file;
typedef struct
@ -6684,6 +6808,14 @@ extern stb_dirtree *stb_dirtree_get_with_file ( char *dir, char *cache_file);
// do a call to stb_dirtree_get() with the same cache file at about the same
// time, but I _think_ it might just work.
// i needed to build an identical data structure representing the state of
// a mirrored copy WITHOUT bothering to rescan it (i.e. we're mirroring to
// it WITHOUT scanning it, e.g. it's over the net), so this requires access
// to all of the innards.
extern void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last);
extern void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last);
extern void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir);
extern void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir);
#ifdef STB_DEFINE
static void stb__dirtree_add_dir(char *path, time_t last, stb_dirtree *active)
@ -6695,7 +6827,7 @@ static void stb__dirtree_add_dir(char *path, time_t last, stb_dirtree *active)
stb_arr_push(active->dirs, d);
}
static void stb__dirtree_add_file(char *name, int dir, unsigned long size, time_t last, stb_dirtree *active)
static void stb__dirtree_add_file(char *name, int dir, stb_int64 size, time_t last, stb_dirtree *active)
{
stb_dirtree_file f;
f.dir = dir;
@ -6706,23 +6838,25 @@ static void stb__dirtree_add_file(char *name, int dir, unsigned long size, time_
stb_arr_push(active->files, f);
}
static char stb__signature[12] = { 's', 'T', 'b', 'D', 'i', 'R', 't', 'R', 'e', 'E', '0', '1' };
// version 02 supports > 4GB files
static char stb__signature[12] = { 's', 'T', 'b', 'D', 'i', 'R', 't', 'R', 'e', 'E', '0', '2' };
static void stb__dirtree_save_db(char *filename, stb_dirtree *data, char *root)
{
int i, num_dirs_final=0, num_files_final;
char *info = root ? root : "";
int *remap;
FILE *f = fopen(filename, "wb");
if (!f) return;
fwrite(stb__signature, sizeof(stb__signature), 1, f);
fwrite(root, strlen(root)+1, 1, f);
fwrite(info, strlen(info)+1, 1, f);
// need to be slightly tricky and not write out NULLed directories, nor the root
// build remapping table of all dirs we'll be writing out
remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(data->dirs));
for (i=0; i < stb_arr_len(data->dirs); ++i) {
if (data->dirs[i].path == NULL || 0==stb_stricmp(data->dirs[i].path, root)) {
if (data->dirs[i].path == NULL || (root && 0==stb_stricmp(data->dirs[i].path, root))) {
remap[i] = -1;
} else {
remap[i] = num_dirs_final++;
@ -6739,14 +6873,14 @@ static void stb__dirtree_save_db(char *filename, stb_dirtree *data, char *root)
num_files_final = 0;
for (i=0; i < stb_arr_len(data->files); ++i)
if (remap[data->files[i].dir] >= 0)
if (remap[data->files[i].dir] >= 0 && data->files[i].name)
++num_files_final;
fwrite(&num_files_final, 4, 1, f);
for (i=0; i < stb_arr_len(data->files); ++i) {
if (remap[data->files[i].dir] >= 0) {
if (remap[data->files[i].dir] >= 0 && data->files[i].name) {
stb_fput_ranged(f, remap[data->files[i].dir], 0, num_dirs_final);
stb_fput_varlenu(f, data->files[i].size);
stb_fput_varlen64(f, data->files[i].size);
fwrite(&data->files[i].last_modified, 4, 1, f);
stb_fput_string(f, data->files[i].name);
}
@ -6783,7 +6917,7 @@ static void stb__dirtree_load_db(char *filename, stb_dirtree *data, char *dir)
stb_arr_setlen(data->files, n);
for (i=0; i < stb_arr_len(data->files); ++i) {
data->files[i].dir = stb_fget_ranged(f, 0, stb_arr_len(data->dirs));
data->files[i].size = stb_fget_varlenu(f);
data->files[i].size = stb_fget_varlen64(f);
fread(&data->files[i].last_modified, 4, 1, f);
data->files[i].name = stb_fget_string(f, data->string_pool);
if (data->files[i].name == NULL) goto bail;
@ -6797,6 +6931,7 @@ static void stb__dirtree_load_db(char *filename, stb_dirtree *data, char *dir)
fclose(f);
}
static int stb__dircount, stb__dircount_mask, stb__showfile;
static void stb__dirtree_scandir(char *path, time_t last_time, stb_dirtree *active)
{
// this is dumb depth first; theoretically it might be faster
@ -6805,48 +6940,75 @@ static void stb__dirtree_scandir(char *path, time_t last_time, stb_dirtree *acti
int n;
struct _wfinddata_t c_file;
struct _wfinddatai64_t c_file;
long hFile;
stb__wchar full_path[1024];
int has_slash;
if (stb__showfile) printf("<");
has_slash = (path[0] && path[strlen(path)-1] == '/');
// @TODO: do this concatenation without using swprintf to avoid this mess:
#if defined(_MSC_VER) && _MSC_VER < 1400
if (has_slash)
swprintf((wchar_t *)full_path, L"%s*", stb__from_utf8(path));
swprintf(full_path, L"%s*", stb__from_utf8(path));
else
swprintf((wchar_t *)full_path, L"%s/*", stb__from_utf8(path));
swprintf(full_path, L"%s/*", stb__from_utf8(path));
#else
if (has_slash)
swprintf(full_path, 1024, L"%s*", stb__from_utf8(path));
else
swprintf(full_path, 1024, L"%s/*", stb__from_utf8(path));
#endif
// it's possible this directory is already present: that means it was in the
// cache, but its parent wasn't... in that case, we're done with it
if (stb__showfile) printf("C[%d]", stb_arr_len(active->dirs));
for (n=0; n < stb_arr_len(active->dirs); ++n)
if (0 == stb_stricmp(active->dirs[n].path, path))
if (0 == stb_stricmp(active->dirs[n].path, path)) {
if (stb__showfile) printf("D");
return;
}
if (stb__showfile) printf("E");
// otherwise, we need to add it
stb__dirtree_add_dir(path, last_time, active);
n = stb_arr_lastn(active->dirs);
if( (hFile = _wfindfirst((const wchar_t *)full_path, &c_file )) != -1L ) {
if (stb__showfile) printf("[");
if( (hFile = _wfindfirsti64( full_path, &c_file )) != -1L ) {
do {
if (stb__showfile) printf(")");
if (c_file.attrib & _A_SUBDIR) {
// ignore subdirectories starting with '.', e.g. "." and ".."
if (c_file.name[0] != '.') {
char *new_path = (char *) full_path;
char *temp = stb__to_utf8((stb__wchar *)c_file.name);
char *temp = stb__to_utf8(c_file.name);
if (has_slash)
sprintf(new_path, "%s%s", path, temp);
else
sprintf(new_path, "%s/%s", path, temp);
if (stb__dircount_mask) {
++stb__dircount;
if (!(stb__dircount & stb__dircount_mask)) {
printf("%s\r", new_path);
}
}
stb__dirtree_scandir(new_path, c_file.time_write, active);
}
} else {
char *temp = stb__to_utf8((stb__wchar *)c_file.name);
char *temp = stb__to_utf8(c_file.name);
stb__dirtree_add_file(temp, n, c_file.size, c_file.time_write, active);
}
} while( _wfindnext( hFile, &c_file ) == 0 );
if (stb__showfile) printf("(");
} while( _wfindnexti64( hFile, &c_file ) == 0 );
if (stb__showfile) printf("]");
_findclose( hFile );
}
if (stb__showfile) printf(">\n");
}
// scan the database and see if it's all valid
@ -6862,13 +7024,21 @@ static int stb__dirtree_update_db(stb_dirtree *db, stb_dirtree *active)
for (i=0; i < stb_arr_len(db->dirs); ++i) {
struct _stat info;
if (stb__dircount_mask) {
++stb__dircount;
if (!(stb__dircount & stb__dircount_mask)) {
printf(".");
}
}
if (0 == _stat(db->dirs[i].path, &info)) {
if (info.st_mode & _S_IFDIR) {
// it's still a directory, as expected
if (info.st_mtime > db->dirs[i].last_modified) {
int n = abs(info.st_mtime - db->dirs[i].last_modified);
if (n > 1 && n != 3600) { // the 3600 is a hack because sometimes this jumps for no apparent reason, even when no time zone or DST issues are at play
// it's changed! force a rescan
// we don't want to scan it until we've stat()d its
// subdirs, though, so we queue it
if (stb__showfile) printf("Changed: %s - %08x:%08x\n", db->dirs[i].path, db->dirs[i].last_modified, info.st_mtime);
stb_arr_push(rescan, i);
// update the last_mod time
db->dirs[i].last_modified = info.st_mtime;
@ -6946,6 +7116,8 @@ stb_dirtree *stb_dirtree_get_with_file(char *dir, char *cache_file)
if (cache_file != NULL)
stb__dirtree_load_db(cache_file, &db, stripped_dir);
else if (stb__showfile)
printf("No cache file\n");
active.files = NULL;
active.dirs = NULL;
@ -6960,6 +7132,9 @@ stb_dirtree *stb_dirtree_get_with_file(char *dir, char *cache_file)
stb__dirtree_scandir(stripped_dir, 0, &active); // no last_modified time available for root
if (stb__dircount_mask)
printf(" \r");
// done with the DB; write it back out if any changes, i.e. either
// 1. any inconsistency found between cached information and actual disk
// or 2. if scanning the root found any new directories--which we detect because
@ -7022,6 +7197,32 @@ void stb_dirtree_free(stb_dirtree *d)
stb__dirtree_free_raw(d);
free(d);
}
void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last)
{
stb__dirtree_add_dir(path, last, active);
}
void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last)
{
stb__dirtree_add_file(name, dir, size, last, active);
}
void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir)
{
char *s = stb_strip_final_slash(strdup(dir));
target->dirs = 0;
target->files = 0;
target->string_pool = 0;
stb__dirtree_load_db(filename, target, s);
free(s);
}
void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir)
{
stb__dirtree_save_db(filename, target, 0); // don't strip out any directories
}
#endif // STB_DEFINE
#endif // _WIN32
@ -7338,7 +7539,7 @@ STB_EXTERN void ** stb_ps_fastlist(stb_ps *ps, int *count);
// but some entries of the list may be invalid;
// test with 'stb_ps_fastlist_valid(x)'
#define stb_ps_fastlist_valid(x) ((unsigned int) (x) > 1)
#define stb_ps_fastlist_valid(x) ((stb_uinta) (x) > 1)
#ifdef STB_DEFINE
@ -7359,8 +7560,6 @@ typedef struct
#define GetBucket(p) ((stb_ps_bucket *) ((char *) (p) - STB_ps_bucket))
#define EncodeBucket(p) ((stb_ps *) ((char *) (p) + STB_ps_bucket))
typedef char stb__verify_bucket_heap_size[sizeof(stb_ps_bucket) == 16];
static void stb_bucket_free(stb_ps_bucket *b)
{
free(b);
@ -7736,7 +7935,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
void ** stb_ps_getlist(stb_ps *ps, int *count)
{
int i,n=0;
void **p;
void **p = NULL;
switch (3 & (int) ps) {
case STB_ps_direct:
if (ps == NULL) { *count = 0; return NULL; }
@ -10058,7 +10257,7 @@ char *stb_decompress_fromfile(char *filename, unsigned int *len)
if (p == NULL) return NULL;
if (p[0] != 0x57 || p[1] != 0xBc || p[2] || p[3]) { free(p); return NULL; }
q = (char *) malloc(stb_decompress_length(p)+1);
if (!q) { free(p); free(p); return NULL; }
if (!q) { free(p); return NULL; }
*len = stb_decompress((unsigned char *) q, p, n);
if (*len) q[*len] = 0;
free(p);
@ -10407,15 +10606,15 @@ int stb_compress_intofile(FILE *f, char *input, unsigned int length)
////////////////////// streaming I/O version /////////////////////
static stb_uint stb_out_backpatch_id(void)
static size_t stb_out_backpatch_id(void)
{
if (stb__out)
return (stb_uint) stb__out;
return (size_t) stb__out;
else
return ftell(stb__outfile);
}
static void stb_out_backpatch(stb_uint 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 };
if (stb__out) {
@ -11107,7 +11306,7 @@ int stb_arith_decode_byte(stb_arith *a)
// Threads
//
#ifndef WIN32
#ifndef _WIN32
#ifdef STB_THREADS
#error "threads not implemented except for Windows"
#endif
@ -14077,10 +14276,49 @@ void stua_run_script(char *s)
stua_gc(1);
}
#endif // STB_DEFINE
#endif // STB_STUA
#undef STB_EXTERN
#endif // STB_INCLUDE_STB_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,4 +1,4 @@
// stb_c_lexer.h - v0.06 - public domain Sean Barrett 2013
// stb_c_lexer.h - v0.09 - public domain Sean Barrett 2013
// lexer for making little C-like languages with recursive-descent parsers
//
// This file provides both the interface and the implementation.
@ -10,6 +10,9 @@
// suffixes on integer constants are not handled (you can override this).
//
// History:
// 0.09 hex floats, no-stdlib fixes
// 0.08 fix bad pointer comparison
// 0.07 fix mishandling of hexadecimal constants parsed by strtol
// 0.06 fix missing next character after ending quote mark (Andreas Fredriksson)
// 0.05 refixed get_location because github version had lost the fix
// 0.04 fix octal parsing bug
@ -28,6 +31,14 @@
// - haven't implemented octal/hex character constants
// - haven't implemented support for unicode CLEX_char
// - need to expand error reporting so you don't just get "CLEX_parse_error"
//
// Contributors:
// Arpad Goretity (bugfix)
// Alan Hickman (hex floats)
//
// LICENSE
//
// See end of file for license information.
#ifndef STB_C_LEXER_DEFINITIONS
// to change the default parsing rules, copy the following lines
@ -38,7 +49,8 @@
#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit
#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit
#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit
#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE]-?[0-9]+)?) CLEX_floatlit
#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit
#define STB_C_LEX_C99_HEX_FLOATS N // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit
#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id
#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring
#define STB_C_LEX_C_SQ_STRINGS N // single-quote-delimited strings with escapes CLEX_ssstring
@ -77,7 +89,7 @@
#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess
// still have #line, #pragma, etc)
//#define STB_C_LEX_ISWHITE(str) ... // return length in bytes of first character if it is whitespace
//#define STB_C_LEX_ISWHITE(str) ... // return length in bytes of whitespace characters if first char is whitespace
#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions
// --END--
@ -164,11 +176,6 @@ extern void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where,
#define Y(x) 1
#define N(x) 0
#if STB_C_LEX_USE_STDLIB(x)
#define STB__CLEX_use_stdlib
#include <stdlib.h>
#endif
#if STB_C_LEX_INTEGERS_AS_DOUBLES(x)
typedef double stb__clex_int;
#define intfield real_number
@ -193,6 +200,10 @@ typedef long stb__clex_int;
#define STB__clex_define_shifts
#endif
#if STB_C_LEX_C99_HEX_FLOATS(x)
#define STB__clex_hex_floats
#endif
#if STB_C_LEX_C_HEX_INTS(x)
#define STB__clex_hex_ints
#endif
@ -213,6 +224,11 @@ typedef long stb__clex_int;
#define STB__clex_discard_preprocessor
#endif
#if STB_C_LEX_USE_STDLIB(x) && (!defined(STB__clex_hex_floats) || __STDC_VERSION__ >= 199901L)
#define STB__CLEX_use_stdlib
#include <stdlib.h>
#endif
// Now pick a definition of Y/N that's conducive to
// defining the enum of token names.
#if STB_C_LEX_DEFINE_ALL_TOKEN_NAMES(x) || defined(STB_C_LEXER_SELF_TEST)
@ -357,34 +373,95 @@ static int stb__clex_parse_suffixes(stb_lexer *lexer, long tokenid, char *start,
}
#ifndef STB__CLEX_use_stdlib
static double stb__clex_pow(double base, unsigned int exponent)
{
double value=1;
for ( ; exponent; exponent >>= 1) {
if (exponent & 1)
value *= base;
base *= base;
}
return value;
}
static double stb__clex_parse_float(char *p, char **q)
{
char *s = p;
double value=0;
while (*p >= '0' && *p <= '9')
value = value*10 + (*p++ - '0');
if (*p == '.') {
double powten=1, addend = 0;
++p;
while (*p >= '0' && *p <= '9') {
addend = addend + 10*(*p++ - '0');
powten *= 10;
int base=10;
int exponent=0;
#ifdef STB__clex_hex_floats
if (*p == '0') {
if (p[1] == 'x' || p[1] == 'X') {
base=16;
p += 2;
}
value += addend / powten;
}
if (*p == 'e' || *p == 'E') {
#endif
for (;;) {
if (*p >= '0' && *p <= '9')
value = value*base + (*p++ - '0');
#ifdef STB__clex_hex_floats
else if (base == 16 && *p >= 'a' && *p <= 'f')
value = value*base + 10 + (*p++ - 'a');
else if (base == 16 && *p >= 'A' && *p <= 'F')
value = value*base + 10 + (*p++ - 'A');
#endif
else
break;
}
if (*p == '.') {
double pow, addend = 0;
++p;
for (pow=1; ; pow*=base) {
if (*p >= '0' && *p <= '9')
addend = addend*base + (*p++ - '0');
#ifdef STB__clex_hex_floats
else if (base == 16 && *p >= 'a' && *p <= 'f')
addend = addend*base + 10 + (*p++ - 'a');
else if (base == 16 && *p >= 'A' && *p <= 'F')
addend = addend*base + 10 + (*p++ - 'A');
#endif
else
break;
}
value += addend / pow;
}
#ifdef STB__clex_hex_floats
if (base == 16) {
// exponent required for hex float literal
if (*p != 'p' && *p != 'P') {
*q = s;
return 0;
}
exponent = 1;
} else
#endif
exponent = (*p == 'e' || *p == 'E');
if (exponent) {
int sign = p[1] == '-';
int exponent=0;
double pow10=1;
p += 1+sign;
unsigned int exponent=0;
double power=1;
++p;
if (*p == '-' || *p == '+')
++p;
while (*p >= '0' && *p <= '9')
exponent = exponent*10 + (*p++ - '0');
// can't use pow() from stdlib, so do it slow way
while (exponent-- > 0)
pow10 *= 10;
if (sign)
value /= pow10;
#ifdef STB__clex_hex_floats
if (base == 16)
power = stb__clex_pow(2, exponent);
else
value *= pow10;
#endif
power = stb__clex_pow(10, exponent);
if (sign)
value /= power;
else
value *= power;
}
*q = p;
return value;
@ -452,7 +529,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
int n;
n = STB_C_LEX_ISWHITE(p);
if (n == 0) break;
if (lexer->eof && lexer+n > lexer->eof)
if (lexer->eof && lexer->eof - lexer->parse_point < n)
return stb__clex_token(tok, CLEX_parse_error, p,lexer->eof-1);
p += n;
}
@ -623,33 +700,57 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
goto single_char;
case '0':
#ifdef STB__clex_hex_ints
#if defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
if (p+1 != lexer->eof) {
if (p[1] == 'x' || p[1] == 'X') {
char *q = p+2;
#ifdef STB__CLEX_use_stdlib
lexer->int_number = strtol((char *) p, (char **) q, 16);
#else
stb__clex_int n=0;
while (q != lexer->eof) {
if (*q >= '0' && *q <= '9')
n = n*16 + (*q - '0');
else if (*q >= 'a' && *q <= 'f')
n = n*16 + (*q - 'a') + 10;
else if (*q >= 'A' && *q <= 'F')
n = n*16 + (*q - 'A') + 10;
else
break;
++q;
char *q;
#ifdef STB__clex_hex_floats
for (q=p+2;
q != lexer->eof && ((*q >= '0' && *q <= '9') || (*q >= 'a' && *q <= 'f') || (*q >= 'A' && *q <= 'F'));
++q);
if (q != lexer->eof) {
if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'p' || *q == 'P')) {
#ifdef STB__CLEX_use_stdlib
lexer->real_number = strtod((char *) p, (char**) &q);
#else
lexer->real_number = stb__clex_parse_float(p, &q);
#endif
if (p == q)
return stb__clex_token(lexer, CLEX_parse_error, p,q);
return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES);
}
}
#endif // STB__CLEX_hex_floats
#ifdef STB__clex_hex_ints
#ifdef STB__CLEX_use_stdlib
lexer->int_number = strtol((char *) p, (char **) &q, 16);
#else
{
stb__clex_int n=0;
for (q=p+2; q != lexer->eof; ++q) {
if (*q >= '0' && *q <= '9')
n = n*16 + (*q - '0');
else if (*q >= 'a' && *q <= 'f')
n = n*16 + (*q - 'a') + 10;
else if (*q >= 'A' && *q <= 'F')
n = n*16 + (*q - 'A') + 10;
else
break;
}
lexer->int_number = n;
}
lexer->int_field = n; // int_field is macro that expands to real_number/int_number depending on type of n
#endif
if (q == p+2)
return stb__clex_token(lexer, CLEX_parse_error, p-2,p-1);
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_HEX_SUFFIXES);
#endif
}
}
#endif // STB__clex_hex_ints
#endif // defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
// can't test for octal because we might parse '0.0' as float or as '0' '.' '0',
// so have to do float first
@ -685,14 +786,14 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
stb__clex_int n=0;
while (q != lexer->eof) {
if (*q >= '0' && *q <= '7')
n = n*8 + (q - '0');
n = n*8 + (*q - '0');
else
break;
++q;
}
if (q != lexer->eof && (*q == '8' || *q=='9'))
return stb__clex_token(tok, CLEX_parse_error, p, q);
lexer->int_field = n;
return stb__clex_token(lexer, CLEX_parse_error, p, q);
lexer->int_number = n;
#endif
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
}
@ -707,12 +808,12 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
stb__clex_int n=0;
while (q != lexer->eof) {
if (*q >= '0' && *q <= '9')
n = n*10 + (q - '0');
n = n*10 + (*q - '0');
else
break;
++q;
}
lexer->int_field = n;
lexer->int_number = n;
#endif
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
}
@ -725,6 +826,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
#ifdef STB_C_LEXER_SELF_TEST
#include <stdio.h>
#include <stdlib.h>
static void print_token(stb_lexer *lexer)
{
@ -780,7 +882,15 @@ multiline comments */
void dummy(void)
{
printf("test",1); // https://github.com/nothings/stb/issues/13
double some_floats[] = {
1.0501, -10.4e12, 5E+10,
#if 0 // not support in C++ or C-pre-99, so don't try to compile it
0x1.0p+24, 0xff.FP-8, 0x1p-23,
#endif
4.
};
printf("test %d",1); // https://github.com/nothings/stb/issues/13
}
int main(int argc, char **argv)
@ -791,11 +901,13 @@ int main(int argc, char **argv)
stb_lexer lex;
if (len < 0) {
fprintf(stderr, "Error opening file\n");
free(text);
fclose(f);
return 1;
}
fclose(f);
stb_c_lexer_init(&lex, text, text+len, (char *) malloc(1<<16), 1<<16);
stb_c_lexer_init(&lex, text, text+len, (char *) malloc(0x10000), 0x10000);
while (stb_c_lexer_get_token(&lex)) {
if (lex.token == CLEX_parse_error) {
printf("\n<<<PARSE ERROR>>>\n");
@ -807,3 +919,44 @@ int main(int argc, char **argv)
return 0;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

1045
stb_connected_components.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -75,6 +75,10 @@
// by the euclidean division operator we define, so it's possibly not
// always true. If any such platform turns up, we can add more cases.
// (Possibly only stb_div_trunc currently relies on property (b).)
//
// LICENSE
//
// See end of file for license information.
#ifndef INCLUDE_STB_DIVIDE_H
@ -371,3 +375,45 @@ int main(int argc, char **argv)
#endif // STB_DIVIDE_TEST
#endif // STB_DIVIDE_IMPLEMENTATION
#endif // INCLUDE_STB_DIVIDE_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,4 +1,4 @@
// stb_dxt.h - v1.04 - DXT1/DXT5 compressor - public domain
// stb_dxt.h - v1.06 - DXT1/DXT5 compressor - public domain
// original by fabian "ryg" giesen - ported to C by stb
// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation
//
@ -9,6 +9,8 @@
// and "high quality" using mode.
//
// version history:
// v1.06 - (stb) fix to known-broken 1.05
// v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski)
// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec);
// single color match fix (allow for inexact color interpolation);
// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps.
@ -16,6 +18,10 @@
// v1.02 - (stb) fix alpha encoding bug
// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom
// v1.00 - (stb) first release
//
// LICENSE
//
// See end of file for license information.
#ifndef STB_INCLUDE_STB_DXT_H
#define STB_INCLUDE_STB_DXT_H
@ -25,7 +31,17 @@
#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like!
#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower.
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode);
#ifdef __cplusplus
extern "C" {
#endif
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode);
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel);
#ifdef __cplusplus
}
#endif
#define STB_COMPRESS_DXT_BLOCK
#ifdef STB_DXT_IMPLEMENTATION
@ -532,18 +548,18 @@ static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, i
}
// Alpha block compression (this is easy for a change)
static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int mode)
static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src, int stride)
{
int i,dist,bias,dist4,dist2,bits,mask;
// find min/max color
int mn,mx;
mn = mx = src[3];
mn = mx = src[0];
for (i=1;i<16;i++)
{
if (src[i*4+3] < mn) mn = src[i*4+3];
else if (src[i*4+3] > mx) mx = src[i*4+3];
if (src[i*stride] < mn) mn = src[i*stride];
else if (src[i*stride] > mx) mx = src[i*stride];
}
// encode them
@ -562,7 +578,7 @@ static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int m
bits = 0,mask=0;
for (i=0;i<16;i++) {
int a = src[i*4+3]*7 + bias;
int a = src[i*stride]*7 + bias;
int ind,t;
// select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max).
@ -613,12 +629,59 @@ void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int a
}
if (alpha) {
stb__CompressAlphaBlock(dest,(unsigned char*) src,mode);
stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4);
dest += 8;
}
stb__CompressColorBlock(dest,(unsigned char*) src,mode);
}
#endif // STB_DXT_IMPLEMENTATION
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src)
{
stb__CompressAlphaBlock(dest,(unsigned char*) src,2);
stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2);
}
#endif // STB_DXT_IMPLEMENTATION
#endif // STB_INCLUDE_STB_DXT_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,4 +1,4 @@
// stb_easy_font.h - v0.5 - bitmap font for 3D rendering - public domain
// stb_easy_font.h - v1.0 - bitmap font for 3D rendering - public domain
// Sean Barrett, Feb 2015
//
// Easy-to-deploy,
@ -16,8 +16,10 @@
// DOCUMENTATION:
//
// int stb_easy_font_width(char *text)
// int stb_easy_font_height(char *text)
//
// Takes a string without newlines and returns the horizontal size.
// Takes a string and returns the horizontal size and the
// vertical size (which can vary if 'text' has newlines).
//
// int stb_easy_font_print(float x, float y,
// char *text, unsigned char color[4],
@ -40,7 +42,7 @@
//
// You can ignore z and color if you get them from elsewhere
// This format was chosen in the hopes it would make it
// easier for you to reuse existing buffer-drawing code.
// easier for you to reuse existing vertex-buffer-drawing code.
//
// If you pass in NULL for color, it becomes 255,255,255,255.
//
@ -63,12 +65,27 @@
// compact to me; -0.5 is a reasonable compromise as long as
// you're scaling the font up.
//
// LICENSE
//
// See end of file for license information.
//
// VERSION HISTORY
//
// (2017-01-15) 1.0 space character takes same space as numbers; fix bad spacing of 'f'
// (2016-01-22) 0.7 width() supports multiline text; add height()
// (2015-09-13) 0.6 #include <math.h>; updated license
// (2015-02-01) 0.5 First release
//
// CONTRIBUTORS
//
// github:vassvik -- bug report
#if 0
// SAMPLE CODE:
//
// Here's sample code for old OpenGL; it's a lot more complicated
// to make work on modern APIs, and that's your problem.
//
#if 0
void print_string(float x, float y, char *text, float r, float g, float b)
{
static char buffer[99999]; // ~500 chars
@ -88,13 +105,14 @@ void print_string(float x, float y, char *text, float r, float g, float b)
#define INCLUDE_STB_EASY_FONT_H
#include <stdlib.h>
#include <math.h>
struct {
struct stb_easy_font_info_struct {
unsigned char advance;
unsigned char h_seg;
unsigned char v_seg;
} stb_easy_font_charinfo[96] = {
{ 5, 0, 0 }, { 3, 0, 0 }, { 5, 1, 1 }, { 7, 1, 4 },
{ 6, 0, 0 }, { 3, 0, 0 }, { 5, 1, 1 }, { 7, 1, 4 },
{ 7, 3, 7 }, { 7, 6, 12 }, { 7, 8, 19 }, { 4, 16, 21 },
{ 4, 17, 22 }, { 4, 19, 23 }, { 23, 21, 24 }, { 23, 22, 31 },
{ 20, 23, 34 }, { 22, 23, 36 }, { 19, 24, 36 }, { 21, 25, 36 },
@ -111,7 +129,7 @@ struct {
{ 7,109,165 }, { 7,118,167 }, { 6,118,172 }, { 4,120,176 },
{ 6,122,177 }, { 4,122,181 }, { 23,124,182 }, { 22,129,182 },
{ 4,130,182 }, { 22,131,183 }, { 6,133,187 }, { 22,135,191 },
{ 6,137,192 }, { 22,139,196 }, { 5,144,197 }, { 22,147,198 },
{ 6,137,192 }, { 22,139,196 }, { 6,144,197 }, { 22,147,198 },
{ 6,150,202 }, { 19,151,206 }, { 21,152,207 }, { 6,155,209 },
{ 3,160,210 }, { 23,160,211 }, { 22,164,216 }, { 22,165,220 },
{ 22,167,224 }, { 22,169,228 }, { 21,171,232 }, { 21,173,233 },
@ -210,11 +228,76 @@ static int stb_easy_font_print(float x, float y, char *text, unsigned char color
static int stb_easy_font_width(char *text)
{
float len = 0;
float max_len = 0;
while (*text) {
len += stb_easy_font_charinfo[*text-32].advance & 15;
len += stb_easy_font_spacing_val;
if (*text == '\n') {
if (len > max_len) max_len = len;
len = 0;
} else {
len += stb_easy_font_charinfo[*text-32].advance & 15;
len += stb_easy_font_spacing_val;
}
++text;
}
return (int) ceil(len);
if (len > max_len) max_len = len;
return (int) ceil(max_len);
}
static int stb_easy_font_height(char *text)
{
float y = 0;
int nonempty_line=0;
while (*text) {
if (*text == '\n') {
y += 12;
nonempty_line = 0;
} else {
nonempty_line = 1;
}
++text;
}
return (int) ceil(y + (nonempty_line ? 12 : 0));
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,8 +1,11 @@
/* stbhw - v0.6 - http://nothings.org/gamedev/herringbone
Herringbone Wang Tile Generator - Sean Barrett 2014 - public domain
This file is in the public domain. In case that declaration is ineffective,
you are also granted a license to use and modify it without restriction.
== LICENSE ==============================
This software is dual-licensed to the public domain and under the following
license: you are granted a perpetual, irrevocable license to copy, modify,
publish, and distribute this file as you see fit.
== WHAT IT IS ===========================

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* stb_image_resize - v0.90 - public domain image resizing
/* stb_image_resize - v0.94 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb
@ -107,8 +107,8 @@
industry, it is still uncommon in the videogame/real-time world.
If you linearly filter non-premultiplied alpha, strange effects
occur. (For example, the average of 1% opaque bright green
and 99% opaque black produces 50% transparent dark green when
occur. (For example, the 50/50 average of 99% transparent bright green
and 1% transparent black produces 50% transparent dark green when
non-premultiplied, whereas premultiplied it produces 50%
transparent near-black. The former introduces green energy
that doesn't exist in the source image.)
@ -152,16 +152,20 @@
(For example, graphics hardware does not apply sRGB conversion
to the alpha channel.)
ADDITIONAL CONTRIBUTORS
CONTRIBUTORS
Jorge L Rodriguez: Implementation
Sean Barrett: API design, optimizations
Aras Pranckevicius: bugfix
REVISIONS
0.94 (2017-03-18) fixed warnings
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.91 (2016-04-02) fix warnings; fix handling of subpixel regions
0.90 (2014-09-17) first released version
LICENSE
This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy
and modify this file as you see fit.
See end of file for license information.
TODO
Don't decode all of the image data when only processing a partial tile
@ -382,15 +386,6 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
#define STBIR_ASSERT(x) assert(x)
#endif
#ifdef STBIR_DEBUG
#define STBIR__DEBUG_ASSERT STBIR_ASSERT
#else
#define STBIR__DEBUG_ASSERT
#endif
// If you hit this it means I haven't done it yet.
#define STBIR__UNIMPLEMENTED(x) STBIR_ASSERT(!(x))
// For memset
#include <string.h>
@ -538,10 +533,11 @@ typedef struct
int horizontal_num_contributors;
int vertical_num_contributors;
int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
int ring_buffer_num_entries; // Total number of entries in the ring buffer.
int ring_buffer_first_scanline;
int ring_buffer_last_scanline;
int ring_buffer_begin_index;
int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
float* ring_buffer;
float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
@ -556,16 +552,17 @@ typedef struct
int encode_buffer_size;
} stbir__info;
static const float stbir__max_uint8_as_float = 255.0f;
static const float stbir__max_uint16_as_float = 65535.0f;
static const double stbir__max_uint32_as_float = 4294967295.0;
static stbir__inline int stbir__min(int a, int b)
{
return a < b ? a : b;
}
static stbir__inline int stbir__max(int a, int b)
{
return a > b ? a : b;
}
static stbir__inline float stbir__saturate(float x)
{
if (x < 0)
@ -757,7 +754,7 @@ static float stbir__filter_trapezoid(float x, float scale)
{
float halfscale = scale / 2;
float t = 0.5f + halfscale;
STBIR__DEBUG_ASSERT(scale <= 1);
STBIR_ASSERT(scale <= 1);
x = (float)fabs(x);
@ -775,7 +772,7 @@ static float stbir__filter_trapezoid(float x, float scale)
static float stbir__support_trapezoid(float scale)
{
STBIR__DEBUG_ASSERT(scale <= 1);
STBIR_ASSERT(scale <= 1);
return 0.5f + scale / 2;
}
@ -989,7 +986,7 @@ static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
return n; // NOTREACHED
default:
STBIR__UNIMPLEMENTED("Unimplemented edge type");
STBIR_ASSERT(!"Unimplemented edge type");
return 0;
}
}
@ -1032,18 +1029,18 @@ static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radi
*out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
}
static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
{
int i;
float total_filter = 0;
float filter_scale;
STBIR__DEBUG_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
contributor->n0 = in_first_pixel;
contributor->n1 = in_last_pixel;
STBIR__DEBUG_ASSERT(contributor->n1 >= contributor->n0);
STBIR_ASSERT(contributor->n1 >= contributor->n0);
for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
{
@ -1061,10 +1058,10 @@ static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbi
total_filter += coefficient_group[i];
}
STBIR__DEBUG_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
STBIR__DEBUG_ASSERT(total_filter > 0.9);
STBIR__DEBUG_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
STBIR_ASSERT(total_filter > 0.9);
STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
// Make sure the sum of all coefficients is 1.
filter_scale = 1 / total_filter;
@ -1082,16 +1079,16 @@ static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbi
}
}
static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
{
int i;
STBIR__DEBUG_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
contributor->n0 = out_first_pixel;
contributor->n1 = out_last_pixel;
STBIR__DEBUG_ASSERT(contributor->n1 >= contributor->n0);
STBIR_ASSERT(contributor->n1 >= contributor->n0);
for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
{
@ -1100,7 +1097,7 @@ static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, st
coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
}
STBIR__DEBUG_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
{
@ -1112,7 +1109,7 @@ static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, st
}
}
static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
{
int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
@ -1135,8 +1132,8 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, st
break;
}
STBIR__DEBUG_ASSERT(total > 0.9f);
STBIR__DEBUG_ASSERT(total < 1.1f);
STBIR_ASSERT(total > 0.9f);
STBIR_ASSERT(total < 1.1f);
scale = 1 / total;
@ -1189,7 +1186,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, st
// Each scan line uses the same kernel values so we should calculate the kernel
// values once and then we can use them for every scan line.
static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
{
int n;
int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
@ -1206,7 +1203,7 @@ static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributor
stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
stbir__calculate_coefficients_upsample(stbir_info, filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
}
}
else
@ -1222,10 +1219,10 @@ static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributor
stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
stbir__calculate_coefficients_downsample(stbir_info, filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
}
stbir__normalize_downsample_coefficients(stbir_info, contributors, coefficients, filter, scale_ratio, shift, input_size, output_size);
stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
}
}
@ -1246,11 +1243,11 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int type = stbir_info->type;
int colorspace = stbir_info->colorspace;
int input_w = stbir_info->input_w;
int input_stride_bytes = stbir_info->input_stride_bytes;
size_t input_stride_bytes = stbir_info->input_stride_bytes;
float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir_edge edge_horizontal = stbir_info->edge_horizontal;
stbir_edge edge_vertical = stbir_info->edge_vertical;
int in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
int decode = STBIR__DECODE(type, colorspace);
@ -1275,7 +1272,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / 255;
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
}
break;
@ -1288,7 +1285,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / 255;
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
}
break;
@ -1298,7 +1295,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535;
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
}
break;
@ -1308,10 +1305,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535);
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / 65535;
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
}
break;
@ -1321,7 +1318,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295);
decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
}
break;
@ -1331,10 +1328,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++)
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295));
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / 4294967295);
decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
}
break;
@ -1363,7 +1360,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
break;
default:
STBIR__UNIMPLEMENTED("Unknown type/colorspace/channels combination.");
STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
break;
}
@ -1416,6 +1413,8 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
int ring_buffer_index;
float* ring_buffer;
stbir_info->ring_buffer_last_scanline = n;
if (stbir_info->ring_buffer_begin_index < 0)
{
ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
@ -1423,24 +1422,21 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
}
else
{
ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline) + 1) % stbir_info->vertical_filter_pixel_width;
STBIR__DEBUG_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
}
ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
stbir_info->ring_buffer_last_scanline = n;
return ring_buffer;
}
static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n, float* output_buffer)
static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
{
int x, k;
int output_w = stbir_info->output_w;
int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
int channels = stbir_info->channels;
float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
@ -1456,11 +1452,11 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
int coefficient_group = coefficient_width * x;
int coefficient_counter = 0;
STBIR__DEBUG_ASSERT(n1 >= n0);
STBIR__DEBUG_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
STBIR__DEBUG_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
STBIR__DEBUG_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
STBIR__DEBUG_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
STBIR_ASSERT(n1 >= n0);
STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
switch (channels) {
case 1:
@ -1468,7 +1464,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
{
int in_pixel_index = k * 1;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
}
break;
@ -1477,7 +1473,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
{
int in_pixel_index = k * 2;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
}
@ -1487,7 +1483,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
{
int in_pixel_index = k * 3;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
@ -1498,7 +1494,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
{
int in_pixel_index = k * 4;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
@ -1511,7 +1507,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
int in_pixel_index = k * channels;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
int c;
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
for (c = 0; c < channels; c++)
output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
}
@ -1520,12 +1516,10 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
}
}
static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n, float* output_buffer)
static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
{
int x, k;
int input_w = stbir_info->input_w;
int output_w = stbir_info->output_w;
int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
int channels = stbir_info->channels;
float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
@ -1534,7 +1528,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
int max_x = input_w + filter_pixel_margin * 2;
STBIR__DEBUG_ASSERT(!stbir__use_width_upsampling(stbir_info));
STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
switch (channels) {
case 1:
@ -1552,7 +1546,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
{
int out_pixel_index = k * 1;
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
}
}
@ -1573,7 +1567,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
{
int out_pixel_index = k * 2;
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
}
@ -1595,7 +1589,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
{
int out_pixel_index = k * 3;
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
@ -1618,7 +1612,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
{
int out_pixel_index = k * 4;
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
@ -1643,7 +1637,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
int c;
int out_pixel_index = k * channels;
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
STBIR__DEBUG_ASSERT(coefficient != 0);
STBIR_ASSERT(coefficient != 0);
for (c = 0; c < channels; c++)
output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
}
@ -1659,9 +1653,9 @@ static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
// Now resample it into the ring buffer.
if (stbir__use_width_upsampling(stbir_info))
stbir__resample_horizontal_upsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n));
stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
else
stbir__resample_horizontal_downsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n));
stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
// Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
}
@ -1675,17 +1669,17 @@ static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n
// Now resample it into the horizontal buffer.
if (stbir__use_width_upsampling(stbir_info))
stbir__resample_horizontal_upsample(stbir_info, n, stbir_info->horizontal_buffer);
stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
else
stbir__resample_horizontal_downsample(stbir_info, n, stbir_info->horizontal_buffer);
stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
// Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
}
// Get the specified scan line from the ring buffer.
static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_size, int ring_buffer_length)
static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
{
int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_size;
int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
}
@ -1720,19 +1714,23 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
// build a table of all channels that need colorspace correction, so
// we don't perform colorspace correction on channels that don't need it.
for (x=0, num_nonalpha=0; x < channels; ++x)
for (x = 0, num_nonalpha = 0; x < channels; ++x)
{
if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
nonalpha[num_nonalpha++] = x;
{
nonalpha[num_nonalpha++] = (stbir_uint16)x;
}
}
#define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
#define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
#ifdef STBIR__SATURATE_INT
#define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * 255 ))
#define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * 65535))
#define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
#define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
#else
#define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * 255 )
#define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * 65535)
#define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
#define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
#endif
switch (decode)
@ -1787,7 +1785,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < num_nonalpha; n++)
{
int index = pixel_index + nonalpha[n];
((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535);
((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
}
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
@ -1804,7 +1802,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < channels; n++)
{
int index = pixel_index + n;
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * 4294967295);
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
}
}
break;
@ -1817,11 +1815,11 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for (n = 0; n < num_nonalpha; n++)
{
int index = pixel_index + nonalpha[n];
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295);
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
}
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295);
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
}
break;
@ -1855,12 +1853,12 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
break;
default:
STBIR__UNIMPLEMENTED("Unknown type/colorspace/channels combination.");
STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
break;
}
}
static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out)
static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
{
int x, k;
int output_w = stbir_info->output_w;
@ -1870,7 +1868,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
int alpha_channel = stbir_info->alpha_channel;
int type = stbir_info->type;
int colorspace = stbir_info->colorspace;
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
void* output_data = stbir_info->output_data;
float* encode_buffer = stbir_info->encode_buffer;
int decode = STBIR__DECODE(type, colorspace);
@ -1881,7 +1879,6 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
float* ring_buffer = stbir_info->ring_buffer;
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
int n0,n1, output_row_start;
@ -1892,7 +1889,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
output_row_start = n * stbir_info->output_stride_bytes;
STBIR__DEBUG_ASSERT(stbir__use_height_upsampling(stbir_info));
STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
memset(encode_buffer, 0, output_w * sizeof(float) * channels);
@ -1905,7 +1902,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1918,7 +1915,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1932,7 +1929,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1947,7 +1944,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1963,7 +1960,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1978,16 +1975,14 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
}
static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out)
static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
{
int x, k;
int output_w = stbir_info->output_w;
int output_h = stbir_info->output_h;
stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
float* vertical_coefficients = stbir_info->vertical_coefficients;
int channels = stbir_info->channels;
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
void* output_data = stbir_info->output_data;
int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
float* horizontal_buffer = stbir_info->horizontal_buffer;
int coefficient_width = stbir_info->vertical_coefficient_width;
int contributor = n + stbir_info->vertical_filter_pixel_margin;
@ -1995,14 +1990,13 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
float* ring_buffer = stbir_info->ring_buffer;
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
int n0,n1;
n0 = vertical_contributors[contributor].n0;
n1 = vertical_contributors[contributor].n1;
STBIR__DEBUG_ASSERT(!stbir__use_height_upsampling(stbir_info));
STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
for (k = n0; k <= n1; k++)
{
@ -2010,7 +2004,7 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
int coefficient_group = coefficient_width * contributor;
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
switch (channels) {
case 1:
@ -2067,7 +2061,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
float scale_ratio = stbir_info->vertical_scale;
float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
STBIR__DEBUG_ASSERT(stbir__use_height_upsampling(stbir_info));
STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
for (y = 0; y < stbir_info->output_h; y++)
{
@ -2076,7 +2070,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
STBIR__DEBUG_ASSERT(in_last_scanline - in_first_scanline <= stbir_info->vertical_filter_pixel_width);
STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
if (stbir_info->ring_buffer_begin_index >= 0)
{
@ -2095,7 +2089,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
else
{
stbir_info->ring_buffer_first_scanline++;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
}
}
}
@ -2108,7 +2102,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
// Now all buffers should be ready to write a row of vertical sampling.
stbir__resample_vertical_upsample(stbir_info, y, in_first_scanline, in_last_scanline, in_center_of_out);
stbir__resample_vertical_upsample(stbir_info, y);
STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
}
@ -2153,7 +2147,7 @@ static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessar
else
{
stbir_info->ring_buffer_first_scanline++;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
}
}
}
@ -2168,7 +2162,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
int pixel_margin = stbir_info->vertical_filter_pixel_margin;
int max_y = stbir_info->input_h + pixel_margin;
STBIR__DEBUG_ASSERT(!stbir__use_height_upsampling(stbir_info));
STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
for (y = -pixel_margin; y < max_y; y++)
{
@ -2177,7 +2171,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
STBIR__DEBUG_ASSERT(out_last_scanline - out_first_scanline <= stbir_info->vertical_filter_pixel_width);
STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
if (out_last_scanline < 0 || out_first_scanline >= output_h)
continue;
@ -2194,7 +2188,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
// Now the horizontal buffer is ready to write to all ring buffer rows.
stbir__resample_vertical_downsample(stbir_info, y, out_first_scanline, out_last_scanline, out_center_of_in);
stbir__resample_vertical_downsample(stbir_info, y);
}
stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
@ -2228,8 +2222,8 @@ static void stbir__calculate_transform(stbir__info *info, float s0, float t0, fl
info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
info->horizontal_shift = s0 * info->input_w / (s1 - s0);
info->vertical_shift = t0 * info->input_h / (t1 - t0);
info->horizontal_shift = s0 * info->output_w / (s1 - s0);
info->vertical_shift = t0 * info->output_h / (t1 - t0);
}
}
@ -2251,13 +2245,16 @@ static stbir_uint32 stbir__calculate_memory(stbir__info *info)
info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
// One extra entry because floating point precision problems sometimes cause an extra to be necessary.
info->ring_buffer_num_entries = filter_height + 1;
info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
info->ring_buffer_size = info->output_w * info->channels * filter_height * sizeof(float);
info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
STBIR_ASSERT(info->horizontal_filter != 0);
@ -2379,7 +2376,7 @@ static int stbir__resize_allocated(stbir__info *info,
info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
STBIR__DEBUG_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
}
else
{
@ -2387,7 +2384,7 @@ static int stbir__resize_allocated(stbir__info *info,
info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
info->encode_buffer = NULL;
STBIR__DEBUG_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
}
#undef STBIR__NEXT_MEMPTR
@ -2395,8 +2392,8 @@ static int stbir__resize_allocated(stbir__info *info,
// This signals that the ring buffer is empty
info->ring_buffer_begin_index = -1;
stbir__calculate_filters(info, info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
stbir__calculate_filters(info, info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
STBIR_PROGRESS_REPORT(0);
@ -2408,10 +2405,10 @@ static int stbir__resize_allocated(stbir__info *info,
STBIR_PROGRESS_REPORT(1);
#ifdef STBIR_DEBUG_OVERWRITE_TEST
STBIR__DEBUG_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
STBIR__DEBUG_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
STBIR__DEBUG_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
STBIR__DEBUG_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
#endif
return 1;
@ -2583,3 +2580,45 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
}
#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,7 +1,6 @@
/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
/* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
Before #including,
@ -18,7 +17,7 @@ ABOUT:
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicitly, not optimal image file size
for source code compactness and simplicity, not optimal image file size
or run-time performance.
BUILDING:
@ -35,7 +34,22 @@ USAGE:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(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);
There are also four equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these:
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
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_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
where the callback is:
void stbi_write_func(void *context, void *data, int size);
You can define STBI_WRITE_NO_STDIO to disable the file variant of these
functions, so the library will not use stdio.h at all. However, this will
also disable HDR writing, because it requires stdio for formatted output.
Each function returns 0 on failure and non-0 on success.
@ -63,6 +77,9 @@ USAGE:
data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels.
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.
CREDITS:
PNG/BMP/TGA
@ -73,8 +90,26 @@ CREDITS:
Jean-Sebastien Guay
misc enhancements:
Tim Kelsey
TGA RLE
Alan Hickman
initial file IO callback implementation
Emmanuel Julien
bugfixes:
github:Chribba
Guillaume Chereau
github:jry2
github:romigrou
Sergio Gonzalez
Jonas Karlsson
Filip Wasil
Thatcher Ulrich
github:poppolopoppo
Patrick Boettcher
LICENSE
See end of file for license information.
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
@ -84,10 +119,26 @@ CREDITS:
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
#ifdef STB_IMAGE_WRITE_STATIC
#define STBIWDEF static
#else
#define STBIWDEF extern
extern int stbi_write_tga_with_rle;
#endif
#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_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_hdr(char const *filename, int w, int h, int comp, const float *data);
#endif
typedef void stbi_write_func(void *context, void *data, int size);
STBIWDEF 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);
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_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
#ifdef __cplusplus
}
@ -97,25 +148,43 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#endif
#endif
#ifndef STBI_WRITE_NO_STDIO
#include <stdio.h>
#endif // STBI_WRITE_NO_STDIO
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC)
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
// ok
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC)
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
// ok
#else
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC."
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
#endif
#ifndef STBIW_MALLOC
#define STBIW_MALLOC(sz) malloc(sz)
#define STBIW_REALLOC(p,sz) realloc(p,sz)
#define STBIW_FREE(p) free(p)
#define STBIW_MALLOC(sz) malloc(sz)
#define STBIW_REALLOC(p,newsz) realloc(p,newsz)
#define STBIW_FREE(p) free(p)
#endif
#ifndef STBIW_REALLOC_SIZED
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
#endif
#ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif
@ -126,22 +195,73 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl
#define STBIW_ASSERT(x) assert(x)
#endif
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
typedef struct
{
stbi_write_func *func;
void *context;
} stbi__write_context;
// initialize a callback-based context
static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
{
s->func = c;
s->context = context;
}
#ifndef STBI_WRITE_NO_STDIO
static void stbi__stdio_write(void *context, void *data, int size)
{
fwrite(data,1,size,(FILE*) context);
}
static int stbi__start_write_file(stbi__write_context *s, const char *filename)
{
FILE *f = fopen(filename, "wb");
stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
return f != NULL;
}
static void stbi__end_write_file(stbi__write_context *s)
{
fclose((FILE *)s->context);
}
#endif // !STBI_WRITE_NO_STDIO
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_tga_with_rle = 1;
#else
int stbi_write_tga_with_rle = 1;
#endif
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
s->func(s->context,&x,1);
break; }
case '2': { int x = va_arg(v,int);
unsigned char b[2];
b[0] = STBIW_UCHAR(x);
b[1] = STBIW_UCHAR(x>>8);
s->func(s->context,b,2);
break; }
case '4': { stbiw_uint32 x = va_arg(v,int);
unsigned char b[4];
b[0]=STBIW_UCHAR(x);
b[1]=STBIW_UCHAR(x>>8);
b[2]=STBIW_UCHAR(x>>16);
b[3]=STBIW_UCHAR(x>>24);
s->func(s->context,b,4);
break; }
default:
STBIW_ASSERT(0);
return;
@ -149,18 +269,58 @@ static void writefv(FILE *f, const char *fmt, va_list v)
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
{
va_list v;
va_start(v, fmt);
stbiw__writefv(s, fmt, v);
va_end(v);
}
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
s->func(s->context, arr, 3);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
int k;
if (write_alpha < 0)
s->func(s->context, &d[comp - 1], 1);
switch (comp) {
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
case 1:
if (expand_mono)
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
else
s->func(s->context, d, 1); // monochrome TGA
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k = 0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
break;
}
if (write_alpha > 0)
s->func(s->context, &d[comp - 1], 1);
}
static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
{
stbiw_uint32 zero = 0;
int i,j,k, j_end;
int i,j, j_end;
if (y <= 0)
return;
@ -173,73 +333,147 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1: fwrite(d, 1, 1, f);
break;
case 2: if (expand_mono)
write3(f, d[0],d[0],d[0]); // monochrome bmp
else
fwrite(d, 1, 1, f); // monochrome TGA
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
}
fwrite(&zero,scanline_pad,1,f);
s->func(s->context, &zero, scanline_pad);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
if (y < 0 || x < 0) {
return 0;
} else {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
stbiw__writefv(s, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
fclose(f);
stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
return 1;
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
return stbi_write_bmp_core(&s, x, y, comp, data);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
stbi__write_context s;
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_bmp_core(&s, x, y, comp, data);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif //!STBI_WRITE_NO_STDIO
static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
{
int has_alpha = (comp == 2 || comp == 4);
int colorbytes = has_alpha ? comp-1 : comp;
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
if (y < 0 || x < 0)
return 0;
if (!stbi_write_tga_with_rle) {
return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
} else {
int i,j,k;
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) {
unsigned char *row = (unsigned char *) data + j * x * comp;
int len;
for (i = 0; i < x; i += len) {
unsigned char *begin = row + i * comp;
int diff = 1;
len = 1;
if (i < x - 1) {
++len;
diff = memcmp(begin, row + (i + 1) * comp, comp);
if (diff) {
const unsigned char *prev = begin;
for (k = i + 2; k < x && len < 128; ++k) {
if (memcmp(prev, row + k * comp, comp)) {
prev += comp;
++len;
} else {
--len;
break;
}
}
} else {
for (k = i + 2; k < x && len < 128; ++k) {
if (!memcmp(begin, row + k * comp, comp)) {
++len;
} else {
break;
}
}
}
}
if (diff) {
unsigned char header = STBIW_UCHAR(len - 1);
s->func(s->context, &header, 1);
for (k = 0; k < len; ++k) {
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
}
} else {
unsigned char header = STBIW_UCHAR(len - 129);
s->func(s->context, &header, 1);
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
}
}
}
}
return 1;
}
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__start_write_callbacks(&s, func, context);
return stbi_write_tga_core(&s, x, y, comp, (void *) data);
}
#ifndef STBI_WRITE_NO_STDIO
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
stbi__write_context s;
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif
// *************************************************************************************************
// Radiance RGBE HDR writer
// by Baldur Karlsson
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
@ -247,7 +481,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
if (maxcomp < 1e-32) {
if (maxcomp < 1e-32f) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
@ -259,23 +493,23 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
}
}
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
{
unsigned char lengthbyte = (unsigned char) (length+128);
unsigned char lengthbyte = STBIW_UCHAR(length+128);
STBIW_ASSERT(length+128 <= 255);
fwrite(&lengthbyte, 1, 1, f);
fwrite(&databyte, 1, 1, f);
s->func(s->context, &lengthbyte, 1);
s->func(s->context, &databyte, 1);
}
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
{
unsigned char lengthbyte = (unsigned char )(length & 0xff);
unsigned char lengthbyte = STBIW_UCHAR(length);
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
fwrite(&lengthbyte, 1, 1, f);
fwrite(data, length, 1, f);
s->func(s->context, &lengthbyte, 1);
s->func(s->context, data, length);
}
void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
{
unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
unsigned char rgbe[4];
@ -288,31 +522,31 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
/* skip RLE for images too small or large */
if (width < 8 || width >= 32768) {
for (x=0; x < width; x++) {
switch (comp) {
switch (ncomp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
case 3: linear[2] = scanline[x*ncomp + 2];
linear[1] = scanline[x*ncomp + 1];
linear[0] = scanline[x*ncomp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
default:
linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
fwrite(rgbe, 4, 1, f);
s->func(s->context, rgbe, 4);
}
} else {
int c,r;
/* encode into scratch buffer */
for (x=0; x < width; x++) {
switch(comp) {
switch(ncomp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
case 3: linear[2] = scanline[x*ncomp + 2];
linear[1] = scanline[x*ncomp + 1];
linear[0] = scanline[x*ncomp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
default:
linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
@ -322,7 +556,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
scratch[x + width*3] = rgbe[3];
}
fwrite(scanlineheader, 4, 1, f);
s->func(s->context, scanlineheader, 4);
/* RLE each component separately */
for (c=0; c < 4; c++) {
@ -343,7 +577,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
while (x < r) {
int len = r-x;
if (len > 128) len = 128;
stbiw__write_dump_data(f, len, &comp[x]);
stbiw__write_dump_data(s, len, &comp[x]);
x += len;
}
// if there's a run, output it
@ -355,7 +589,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
while (x < r) {
int len = r-x;
if (len > 127) len = 127;
stbiw__write_run_data(f, len, comp[x]);
stbiw__write_run_data(s, len, comp[x]);
x += len;
}
}
@ -364,27 +598,53 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
}
}
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
{
int i;
FILE *f;
if (y <= 0 || x <= 0 || data == NULL) return 0;
f = fopen(filename, "wb");
if (f) {
/* Each component is stored separately. Allocate scratch space for full output scanline. */
if (y <= 0 || x <= 0 || data == NULL)
return 0;
else {
// Each component is stored separately. Allocate scratch space for full output scanline.
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
int i, len;
char buffer[128];
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1);
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
s->func(s->context, buffer, len);
for(i=0; i < y; i++)
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
STBIW_FREE(scratch);
fclose(f);
return 1;
}
return f != NULL;
}
/////////////////////////////////////////////////////////
// PNG
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__start_write_callbacks(&s, func, context);
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
}
#ifndef STBI_WRITE_NO_STDIO
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
stbi__write_context s;
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif // STBI_WRITE_NO_STDIO
//////////////////////////////////////////////////////////////////////////////
//
// PNG writer
//
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
@ -402,7 +662,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
STBIW_ASSERT(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
@ -415,7 +675,7 @@ static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbiw__sbpush(data, (unsigned char) *bitbuffer);
stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
*bitbuffer >>= 8;
*bitcount -= 8;
}
@ -475,7 +735,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window
@ -547,21 +807,23 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
for (i=0; i < stbiw__ZHASH; ++i)
(void) stbiw__sbfree(hash_table[i]);
STBIW_FREE(hash_table);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
unsigned int s1=1, s2=0;
int blocklen = (int) (data_len % 5552);
j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbiw__sbpush(out, (unsigned char) (s2 >> 8));
stbiw__sbpush(out, (unsigned char) s2);
stbiw__sbpush(out, (unsigned char) (s1 >> 8));
stbiw__sbpush(out, (unsigned char) s1);
stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
stbiw__sbpush(out, STBIW_UCHAR(s2));
stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
stbiw__sbpush(out, STBIW_UCHAR(s1));
}
*out_len = stbiw__sbn(out);
// make returned pointer freeable
@ -569,21 +831,52 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
return (unsigned char *) stbiw__sbraw(out);
}
unsigned int stbiw__crc32(unsigned char *buffer, int len)
static unsigned int stbiw__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
static unsigned int crc_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
int i;
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
@ -596,11 +889,12 @@ static void stbiw__wpcrc(unsigned char **data, int len)
static unsigned char stbiw__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
if (pb <= pc) return STBIW_UCHAR(b);
return STBIW_UCHAR(c);
}
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
@ -617,10 +911,10 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int *mymap = (j != 0) ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
@ -671,7 +965,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
stbiw__wp32(o, x);
stbiw__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = STBIW_UCHAR(ctype[n]);
*o++ = 0;
*o++ = 0;
*o++ = 0;
@ -693,12 +987,13 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
if (png == NULL) return 0;
f = fopen(filename, "wb");
if (!f) { STBIW_FREE(png); return 0; }
fwrite(png, 1, len, f);
@ -706,9 +1001,34 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
STBIW_FREE(png);
return 1;
}
#endif
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
{
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (png == NULL) return 0;
func(context, png, len);
STBIW_FREE(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
1.04 (2017-03-03)
monochrome BMP expansion
1.03 ???
1.02 (2016-04-02)
avoid allocating large structures on the stack
1.01 (2016-01-16)
STBIW_REALLOC_SIZED: support allocators with no realloc support
avoid race-condition in crc initialization
minor compile issues
1.00 (2015-09-14)
installable file IO function
0.99 (2015-09-13)
warning fixes; TGA rle support
0.98 (2015-04-08)
added STBIW_MALLOC, STBIW_ASSERT etc
0.97 (2015-01-18)
@ -728,3 +1048,45 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
first public release
0.90 first internal release
*/
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,7 +1,10 @@
// stb_leakcheck.h - v0.2 - quick & dirty malloc leak-checking - public domain
// stb_leakcheck.h - v0.3 - quick & dirty malloc leak-checking - public domain
// LICENSE
//
// See end of file.
#ifdef STB_LEAKCHECK_IMPLEMENTATION
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implenment more than once
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implement more than once
// if we've already included leakcheck before, undefine the macros
#ifdef malloc
@ -10,6 +13,8 @@
#undef realloc
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
@ -88,14 +93,14 @@ void stb_leakcheck_dumpmem(void)
stb_leakcheck_malloc_info *mi = mi_head;
while (mi) {
if ((ptrdiff_t) mi->size >= 0)
printf("LEAKED: %s (%4d): %8z bytes at %p\n", 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);
mi = mi->next;
}
#ifdef STB_LEAKCHECK_SHOWALL
mi = mi_head;
while (mi) {
if ((ptrdiff_t) mi->size < 0)
printf("FREED : %s (%4d): %8z bytes at %p\n", 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);
mi = mi->next;
}
#endif
@ -115,3 +120,46 @@ extern void stb_leakcheck_free(void *ptr);
extern void stb_leakcheck_dumpmem(void);
#endif // INCLUDE_STB_LEAKCHECK_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,11 +1,16 @@
// stb_perlin.h - v0.2 - perlin noise
// stb_perlin.h - v0.3 - perlin noise
// public domain single-file C implementation by Sean Barrett
//
// LICENSE
//
// See end of file.
//
//
// to create the implementation,
// #define STB_PERLIN_IMPLEMENTATION
// in *one* C/CPP file that includes this file.
//
//
// Documentation:
//
// float stb_perlin_noise3( float x,
@ -26,22 +31,55 @@
// 0 to mean "don't care". (The noise always wraps every 256 due
// details of the implementation, even if you ask for larger or no
// wrapping.)
//
// Fractal Noise:
//
// Three common fractal noise functions are included, which produce
// a wide variety of nice effects depending on the parameters
// provided. Note that each function will call stb_perlin_noise3
// 'octaves' times, so this parameter will affect runtime.
//
// float stb_perlin_ridge_noise3(float x, float y, float z,
// float lacunarity, float gain, float offset, int octaves,
// int x_wrap, int y_wrap, int z_wrap);
//
// float stb_perlin_fbm_noise3(float x, float y, float z,
// float lacunarity, float gain, int octaves,
// int x_wrap, int y_wrap, int z_wrap);
//
// float stb_perlin_turbulence_noise3(float x, float y, float z,
// float lacunarity, float gain,int octaves,
// int x_wrap, int y_wrap, int z_wrap);
//
// Typical values to start playing with:
// octaves = 6 -- number of "octaves" of noise3() to sum
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
// gain = 0.5 -- relative weighting applied to each successive octave
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
//
//
// Contributors:
// Jack Mott - additional noise functions
//
#ifdef __cplusplus
extern "C" float stb_perlin_noise3(float x, float y, float z, int x_wrap=0, int y_wrap=0, int z_wrap=0);
#else
extern "C" {
#endif
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
#ifdef __cplusplus
}
#endif
#ifdef STB_PERLIN_IMPLEMENTATION
#include <math.h> // floor()
// not same permutation table as Perlin's reference to avoid copyright issues;
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
// @OPTIMIZE: should this be unsigned char instead of int for cache?
static int stb__perlin_randtab[512] =
static unsigned char stb__perlin_randtab[512] =
{
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
@ -84,6 +122,12 @@ static float stb__perlin_lerp(float a, float b, float t)
return a + (b-a) * t;
}
static int stb__perlin_fastfloor(float a)
{
int ai = (int) a;
return (a < ai) ? ai-1 : ai;
}
// different grad function from Perlin's, but easy to modify to match reference
static float stb__perlin_grad(int hash, float x, float y, float z)
{
@ -105,7 +149,7 @@ static float stb__perlin_grad(int hash, float x, float y, float z)
// perlin's gradient has 12 cases so some get used 1/16th of the time
// and some 2/16ths. We reduce bias by changing those fractions
// to 5/16ths and 6/16ths, and the same 4 cases get the extra weight.
// to 5/64ths and 6/64ths, and the same 4 cases get the extra weight.
static unsigned char indices[64] =
{
0,1,2,3,4,5,6,7,8,9,10,11,
@ -117,6 +161,7 @@ static float stb__perlin_grad(int hash, float x, float y, float z)
};
// if you use reference permutation table, change 63 below to 15 to match reference
// (this is why the ordering of the table above is funky)
float *grad = basis[indices[hash & 63]];
return grad[0]*x + grad[1]*y + grad[2]*z;
}
@ -131,9 +176,9 @@ float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z
unsigned int x_mask = (x_wrap-1) & 255;
unsigned int y_mask = (y_wrap-1) & 255;
unsigned int z_mask = (z_wrap-1) & 255;
int px = (int) floor(x);
int py = (int) floor(y);
int pz = (int) floor(z);
int px = stb__perlin_fastfloor(x);
int py = stb__perlin_fastfloor(y);
int pz = stb__perlin_fastfloor(z);
int x0 = px & x_mask, x1 = (px+1) & x_mask;
int y0 = py & y_mask, y1 = (py+1) & y_mask;
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
@ -172,4 +217,100 @@ float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z
return stb__perlin_lerp(n0,n1,u);
}
float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap)
{
int i;
float frequency = 1.0f;
float prev = 1.0f;
float amplitude = 0.5f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
float r = (float)(stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap));
r = r<0 ? -r : r; // fabs()
r = offset - r;
r = r*r;
sum += r*amplitude*prev;
prev = r;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
{
int i;
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
sum += stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
{
int i;
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
float r = stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
r = r<0 ? -r : r; // fabs()
sum += r;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
#endif // STB_PERLIN_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,4 +1,4 @@
// stb_rect_pack.h - v0.06 - public domain - rectangle packing
// stb_rect_pack.h - v0.11 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
@ -27,15 +27,26 @@
// Sean Barrett
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes
// [your name could be here]
// Jeremy Jaussaud
//
// Version history:
//
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// See end of file for license information.
//////////////////////////////////////////////////////////////////////////////
//
@ -67,7 +78,7 @@ typedef int stbrp_coord;
typedef unsigned short stbrp_coord;
#endif
STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
@ -88,6 +99,9 @@ STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect
{
@ -140,7 +154,7 @@ enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
@ -190,9 +204,15 @@ struct stbrp_context
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#endif
enum
{
STBRP__INIT_skyline = 1,
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
@ -265,6 +285,9 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
@ -492,8 +515,8 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
static int rect_height_compare(const void *a, const void *b)
{
stbrp_rect *p = (stbrp_rect *) a;
stbrp_rect *q = (stbrp_rect *) b;
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
@ -503,8 +526,8 @@ static int rect_height_compare(const void *a, const void *b)
static int rect_width_compare(const void *a, const void *b)
{
stbrp_rect *p = (stbrp_rect *) a;
stbrp_rect *q = (stbrp_rect *) 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)
@ -514,8 +537,8 @@ static int rect_width_compare(const void *a, const void *b)
static int rect_original_order(const void *a, const void *b)
{
stbrp_rect *p = (stbrp_rect *) a;
stbrp_rect *q = (stbrp_rect *) b;
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
@ -525,9 +548,9 @@ static int rect_original_order(const void *a, const void *b)
#define STBRP__MAXVAL 0xffff
#endif
STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i;
int i, all_rects_packed = 1;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
@ -541,20 +564,72 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags
for (i=0; i < num_rects; ++i)
// set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
if (!rects[i].was_packed)
all_rects_packed = 0;
}
// return the all_rects_packed status
return all_rects_packed;
}
#endif
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

1202
stb_sprintf.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// stb_textedit.h - v1.6 - public domain - Sean Barrett
// stb_textedit.h - v1.11 - public domain - Sean Barrett
// Development of this library was sponsored by RAD Game Tools
//
// This C header file implements the guts of a multi-line text-editing
@ -17,9 +17,7 @@
//
// LICENSE
//
// This software has been placed in the public domain by its author.
// Where that dedication is not recognized, you are granted a perpetual,
// irrevocable license to copy and modify this file as you see fit.
// See end of file for license information.
//
//
// DEPENDENCIES
@ -31,6 +29,11 @@
//
// VERSION HISTORY
//
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
// 1.9 (2016-08-27) customizable move-by-word
// 1.8 (2016-04-02) better keyboard handling when mouse button is down
// 1.7 (2015-09-13) change y range handling in case baseline is non-0
// 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove
// 1.5 (2014-09-10) add support for secondary keys for OS X
// 1.4 (2014-08-17) fix signed/unsigned warnings
@ -45,9 +48,14 @@
// ADDITIONAL CONTRIBUTORS
//
// Ulf Winklemann: move-by-word in 1.1
// Scott Graham: mouse selection bugfix in 1.3
// Fabian Giesen: secondary key inputs in 1.5
// Martins Mozeiko: STB_TEXTEDIT_memmove
// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6
//
// Bugfixes:
// Scott Graham
// Daniel Keller
// Omar Cornut
// Dan Thompson
//
// USAGE
//
@ -142,15 +150,17 @@
// STB_TEXTEDIT_K_REDO keyboard input to perform redo
//
// Optional:
// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode
// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'),
// required for WORDLEFT/WORDRIGHT
// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT
// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT
// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line
// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode
// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'),
// required for default WORDLEFT/WORDRIGHT handlers
// STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to
// STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to
// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT
// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT
// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line
// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
//
// Todo:
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
@ -380,9 +390,6 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
float base_y = 0, prev_x;
int i=0, k;
if (y < 0)
return 0;
r.x0 = r.x1 = 0;
r.ymin = r.ymax = 0;
r.num_chars = 0;
@ -393,6 +400,9 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
if (r.num_chars <= 0)
return n;
if (i==0 && y < base_y + r.ymin)
return 0;
if (y < base_y + r.ymax)
break;
@ -411,10 +421,9 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
// check if it's before the end of the line
if (x < r.x1) {
// search characters in row for one that straddles 'x'
k = i;
prev_x = r.x0;
for (i=0; i < r.num_chars; ++i) {
float w = STB_TEXTEDIT_GETWIDTH(str, k, i);
for (k=0; k < r.num_chars; ++k) {
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
if (x < prev_x+w) {
if (x < prev_x+w/2)
return k+i;
@ -436,6 +445,15 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
// API click: on mouse down, move the cursor to the clicked location, and reset the selection
static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
{
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
// goes off the top or bottom of the text
if( state->single_line )
{
StbTexteditRow r;
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
y = r.ymin;
}
state->cursor = stb_text_locate_coord(str, x, y);
state->select_start = state->cursor;
state->select_end = state->cursor;
@ -445,7 +463,21 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
{
int p = stb_text_locate_coord(str, x, y);
int p = 0;
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
// goes off the top or bottom of the text
if( state->single_line )
{
StbTexteditRow r;
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
y = r.ymin;
}
if (state->select_start == state->select_end)
state->select_start = state->cursor;
p = stb_text_locate_coord(str, x, y);
state->cursor = state->select_end = p;
}
@ -602,15 +634,16 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat
}
#ifdef STB_TEXTEDIT_IS_SPACE
static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx )
static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
{
return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1;
return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
}
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state )
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
{
int c = _state->cursor - 1;
while( c >= 0 && !is_word_boundary( _str, c ) )
--c; // always move at least one character
while( c >= 0 && !is_word_boundary( str, c ) )
--c;
if( c < 0 )
@ -618,12 +651,15 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_Te
return c;
}
#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous
#endif
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state )
#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
{
const int len = STB_TEXTEDIT_STRINGLEN(_str);
int c = _state->cursor+1;
while( c < len && !is_word_boundary( _str, c ) )
const int len = STB_TEXTEDIT_STRINGLEN(str);
++c; // always move at least one character
while( c < len && !is_word_boundary( str, c ) )
++c;
if( c > len )
@ -631,6 +667,9 @@ static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_Texted
return c;
}
#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next
#endif
#endif
// update selection and cursor to match each other
@ -654,9 +693,8 @@ static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
}
// API paste: replace existing selection with passed-in text
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
{
STB_TEXTEDIT_CHARTYPE *text = (STB_TEXTEDIT_CHARTYPE *) ctext;
// if there's a selection, the paste should delete it
stb_textedit_clamp(str, state);
stb_textedit_delete_selection(str,state);
@ -752,21 +790,12 @@ retry:
state->has_preferred_x = 0;
break;
#ifdef STB_TEXTEDIT_IS_SPACE
#ifdef STB_TEXTEDIT_MOVEWORDLEFT
case STB_TEXTEDIT_K_WORDLEFT:
if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_first(state);
else {
state->cursor = stb_textedit_move_to_word_previous(str, state);
stb_textedit_clamp( str, state );
}
break;
case STB_TEXTEDIT_K_WORDRIGHT:
if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_last(str, state);
else {
state->cursor = stb_textedit_move_to_word_next(str, state);
state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
stb_textedit_clamp( str, state );
}
break;
@ -775,17 +804,28 @@ retry:
if( !STB_TEXT_HAS_SELECTION( state ) )
stb_textedit_prep_selection_at_cursor(state);
state->cursor = stb_textedit_move_to_word_previous(str, state);
state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
state->select_end = state->cursor;
stb_textedit_clamp( str, state );
break;
#endif
#ifdef STB_TEXTEDIT_MOVEWORDRIGHT
case STB_TEXTEDIT_K_WORDRIGHT:
if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_last(str, state);
else {
state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
stb_textedit_clamp( str, state );
}
break;
case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
if( !STB_TEXT_HAS_SELECTION( state ) )
stb_textedit_prep_selection_at_cursor(state);
state->cursor = stb_textedit_move_to_word_next(str, state);
state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
state->select_end = state->cursor;
stb_textedit_clamp( str, state );
@ -968,25 +1008,27 @@ retry:
#ifdef STB_TEXTEDIT_K_LINESTART2
case STB_TEXTEDIT_K_LINESTART2:
#endif
case STB_TEXTEDIT_K_LINESTART: {
StbFindState find;
case STB_TEXTEDIT_K_LINESTART:
stb_textedit_clamp(str, state);
stb_textedit_move_to_first(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->cursor = find.first_char;
if (state->single_line)
state->cursor = 0;
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
--state->cursor;
state->has_preferred_x = 0;
break;
}
#ifdef STB_TEXTEDIT_K_LINEEND2
case STB_TEXTEDIT_K_LINEEND2:
#endif
case STB_TEXTEDIT_K_LINEEND: {
StbFindState find;
int n = STB_TEXTEDIT_STRINGLEN(str);
stb_textedit_clamp(str, state);
stb_textedit_move_to_first(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->cursor = find.first_char + find.length;
if (state->single_line)
state->cursor = n;
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
++state->cursor;
state->has_preferred_x = 0;
break;
}
@ -994,25 +1036,29 @@ retry:
#ifdef STB_TEXTEDIT_K_LINESTART2
case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
#endif
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: {
StbFindState find;
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
stb_textedit_clamp(str, state);
stb_textedit_prep_selection_at_cursor(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->cursor = state->select_end = find.first_char;
if (state->single_line)
state->cursor = 0;
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
--state->cursor;
state->select_end = state->cursor;
state->has_preferred_x = 0;
break;
}
#ifdef STB_TEXTEDIT_K_LINEEND2
case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
#endif
case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
StbFindState find;
int n = STB_TEXTEDIT_STRINGLEN(str);
stb_textedit_clamp(str, state);
stb_textedit_prep_selection_at_cursor(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->cursor = state->select_end = find.first_char + find.length;
if (state->single_line)
state->cursor = n;
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
++state->cursor;
state->select_end = state->cursor;
state->has_preferred_x = 0;
break;
}
@ -1287,4 +1333,61 @@ static void stb_textedit_initialize_state(STB_TexteditState *state, int is_singl
{
stb_textedit_clear_state(state, is_single_line);
}
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
{
return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
}
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif//STB_TEXTEDIT_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -1,4 +1,4 @@
// stb_tilemap_editor.h - v0.35 - Sean Barrett - http://nothings.org/stb
// stb_tilemap_editor.h - v0.38 - Sean Barrett - http://nothings.org/stb
// placed in the public domain - not copyrighted - first released 2014-09
//
// Embeddable tilemap editor for C/C++
@ -259,7 +259,7 @@
// #define STBTE_MAX_CATEGORIES 100
// #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB
// #define STBTE_MAX_COPY 90000 // e.g. 300x300
// #define STBTE_MAX_PROPERTIESERTIES 10 // max properties per tile
// #define STBTE_MAX_PROPERTIES 10 // max properties per tile
//
// API
//
@ -275,6 +275,9 @@
// either approach allows cut&pasting between levels.)
//
// REVISION HISTORY
// 0.38 fix warning
// 0.37 fix warning
// 0.36 minor compiler support
// 0.35 layername button changes
// - layername buttons grow with the layer panel
// - fix stbte_create_map being declared as stbte_create
@ -309,13 +312,12 @@
// Additional features:
// Josh Huelsman
// Bugfixes:
// [this could be you!]
// Ryan Whitworth
// Eugene Opalev
//
// LICENSE
//
// This software has been placed in the public domain by its author.
// Where that dedication is not recognized, you are granted a perpetual,
// irrevocable license to copy and modify this file as you see fit.
// See end of file for license information.
@ -326,6 +328,14 @@
#ifndef STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
#define STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
#ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h>
#include <stdio.h>
#endif
typedef struct stbte_tilemap stbte_tilemap;
// these are the drawmodes used in STBTE_DRAW_TILE
@ -3345,7 +3355,7 @@ static void stbte__toolbar(stbte_tilemap *tm, int x0, int y0, int w, int h)
#define STBTE__TEXTCOLOR(n) stbte__color_table[n][STBTE__text][STBTE__idle]
static int stbte__info_value(char *label, int x, int y, int val, int digits, int id)
static int stbte__info_value(const char *label, int x, int y, int val, int digits, int id)
{
if (stbte__ui.event == STBTE__paint) {
int off = 9-stbte__get_char_width(label[0]);
@ -4118,3 +4128,45 @@ void stbte_mouse_sdl(stbte_tilemap *tm, const void *sdl_event, float xs, float y
}
#endif // STB_TILEMAP_EDITOR_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// stb_voxel_render.h - v0.81 - Sean Barrett, 2015 - public domain
// stb_voxel_render.h - v0.85 - Sean Barrett, 2015 - public domain
//
// This library helps render large-scale "voxel" worlds for games,
// in this case, one with blocks that can have textures and that
@ -13,7 +13,7 @@
// It works by creating triangle meshes. The library includes
//
// - converter from dense 3D arrays of block info to vertex mesh
// - shader for the vertex mesh
// - vertex & fragment shaders for the vertex mesh
// - assistance in setting up shader state
//
// For portability, none of the library code actually accesses
@ -24,8 +24,9 @@
// yourself. However, you could also try making a game with
// a small enough world that it's fully loaded rather than
// streaming. Currently the preferred vertex format is 20 bytes
// per quad. There are plans to allow much more compact formats
// with a slight reduction in shader features.
// per quad. There are designs to allow much more compact formats
// with a slight reduction in shader features, but no roadmap
// for actually implementing them.
//
//
// USAGE
@ -108,7 +109,7 @@
// and avoids a potential slow path (gathering non-uniform
// data from uniforms) on some hardware.
//
// In the future I hope to add additional modes that have significantly
// In the future I might add additional modes that have significantly
// smaller meshes but reduce features, down as small as 6 bytes per quad.
// See elsewhere in this file for a table of candidate modes. Switching
// to a mode will require changing some of your mesh creation code, but
@ -186,11 +187,16 @@
// Features Porting Bugfixes & Warnings
// Sean Barrett github:r-leyh Jesus Fernandez
// Miguel Lechon github:Arbeiterunfallversicherungsgesetz
// Thomas Frase
// Thomas Frase James Hofmann
// Stephen Olsen github:guitarfreak
//
// VERSION HISTORY
//
// 0.85 (2017-03-03) add block_selector (by guitarfreak)
// 0.84 (2016-04-02) fix GLSL syntax error on glModelView path
// 0.83 (2015-09-13) remove non-constant struct initializers to support more compilers
// 0.82 (2015-08-01) added input.packed_compact to store rot, vheight & texlerp efficiently
// fix broken tex_overlay2
// 0.81 (2015-05-28) fix broken STBVOX_CONFIG_OPTIMIZED_VHEIGHT
// 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring
// change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so
@ -209,6 +215,11 @@
// stb_voxel_render 20-byte quads 2015/01
// zmc engine 32-byte quads 2013/12
// zmc engine 96-byte quads 2011/10
//
//
// LICENSE
//
// See end of file for license information.
#ifndef INCLUDE_STB_VOXEL_RENDER_H
#define INCLUDE_STB_VOXEL_RENDER_H
@ -253,7 +264,7 @@ extern "C" {
// modes 0,1,20,21, Z in the mesh can extend to 511 instead
// of 255. However, half-height blocks cannot be used.
//
// All of the following just #ifdef tested so need no values, and are optional.
// All of the following are just #ifdef tested so need no values, and are optional.
//
// STBVOX_CONFIG_BLOCKTYPE_SHORT
// use unsigned 16-bit values for 'blocktype' in the input instead of 8-bit values
@ -293,7 +304,7 @@ extern "C" {
//
// STBVOX_CONFIG_DISABLE_TEX2
// This disables all processing of texture 2 in the shader in case
// you don't use it. Eventually this will be replaced with a mode
// you don't use it. Eventually this could be replaced with a mode
// that omits the unused data entirely.
//
// STBVOX_CONFIG_TEX1_EDGE_CLAMP
@ -1581,7 +1592,7 @@ static const char *stbvox_vertex_program =
"uniform vec3 normal_table[32];\n"
#ifndef STBVOX_CONFIG_OPENGL_MODELVIEW
"uniform mat44 model_view;\n"
"uniform mat4x4 model_view;\n"
#endif
// fragment output data
@ -2891,7 +2902,9 @@ static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, in
if (mm->input.selector)
mesh = mm->input.selector[v_off];
else if (mm->input.block_selector)
mesh = mm->input.block_selector[mm->input.blocktype[v_off]];
// check if we're going off the end
if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
mm->full = 1;
@ -3100,7 +3113,9 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
mesh = mm->default_mesh;
if (mm->input.selector)
mesh = mm->input.selector[v_off];
else if (mm->input.block_selector)
mesh = mm->input.block_selector[bt];
if (geo <= STBVOX_GEOM_ceil_slope_north_is_bottom) {
// this is the simple case, we can just use regular block gen with special vmesh calculated with vheight
stbvox_mesh_vertex basevert;
@ -3121,7 +3136,9 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
if (mm->input.selector) {
mesh = mm->input.selector[v_off];
}
} else if (mm->input.block_selector)
mesh = mm->input.block_selector[bt];
// check if we're going off the end
if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
@ -3341,6 +3358,9 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
mesh = mm->input.selector[v_off];
simple_rot = mesh >> 4;
mesh &= 15;
}
if (mm->input.block_selector) {
mesh = mm->input.block_selector[bt];
}
// check if we're going off the end
@ -3374,10 +3394,13 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
static void stbvox_make_mesh_for_column(stbvox_mesh_maker *mm, int x, int y, int z0)
{
stbvox_pos pos = { x,y,0 };
stbvox_pos pos;
int v_off = x * mm->x_stride_in_bytes + y * mm->y_stride_in_bytes;
int ns_off = mm->y_stride_in_bytes;
int ew_off = mm->x_stride_in_bytes;
pos.x = x;
pos.y = y;
pos.z = 0;
if (mm->input.geometry) {
unsigned char *bt = mm->input.blocktype + v_off;
unsigned char *geo = mm->input.geometry + v_off;
@ -3736,3 +3759,45 @@ int main(int argc, char **argv)
// (v: x:2,y:2,z:2,light:2)
#endif // STB_VOXEL_RENDER_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -2,7 +2,7 @@
// a vector<>-like dynamic array for C
//
// version history:
// 1.02 - compiles as C++, but untested
// 1.02 - tweaks to syntax for no good reason
// 1.01 - added a "common uses" documentation section
// 1.0 - fixed bug in the version I posted prematurely
// 0.9 - rewrite to try to avoid strict-aliasing optimization
@ -21,7 +21,7 @@
// - the length of the "in-use" part of the array
// - the current size of the allocated array
//
// I find it to be single most useful non-built-in-structure when
// I find it to be the single most useful non-built-in-structure when
// programming in C (hash tables a close second), but to be clear
// it lacks many of the capabilities of C++ vector<>: there is no
// range checking, the object address isn't stable (see next section
@ -57,7 +57,7 @@
//
// 1. can't take long-term pointers to elements of the array
// 2. have to return the pointer from functions which might expand it
// (either as a return value or by passing it back)
// (either as a return value or by storing it to a ptr-to-ptr)
//
// Now you can do the following things with this array:
//
@ -161,6 +161,10 @@
// The details are trivial and implementation is straightforward;
// 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.
//
// LICENSE
//
// See end of file for license information.
#ifndef STB_STRETCHY_BUFFER_H_INCLUDED
#define STB_STRETCHY_BUFFER_H_INCLUDED
@ -208,3 +212,46 @@ static void * stb__sbgrowf(void *arr, int increment, int itemsize)
}
}
#endif // STB_STRETCHY_BUFFER_H_INCLUDED
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

7
tests/Makefile Normal file
View File

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

View File

@ -1,3 +1,50 @@
#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit
#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit
#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit
#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit
#define STB_C_LEX_C99_HEX_FLOATS Y // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit
#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id
#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring
#define STB_C_LEX_C_SQ_STRINGS Y // single-quote-delimited strings with escapes CLEX_ssstring
#define STB_C_LEX_C_CHARS Y // single-quote-delimited character with escape CLEX_charlits
#define STB_C_LEX_C_COMMENTS Y // "/* comment */"
#define STB_C_LEX_CPP_COMMENTS Y // "// comment to end of line\n"
#define STB_C_LEX_C_COMPARISONS Y // "==" CLEX_eq "!=" CLEX_noteq "<=" CLEX_lesseq ">=" CLEX_greatereq
#define STB_C_LEX_C_LOGICAL Y // "&&" CLEX_andand "||" CLEX_oror
#define STB_C_LEX_C_SHIFTS Y // "<<" CLEX_shl ">>" CLEX_shr
#define STB_C_LEX_C_INCREMENTS Y // "++" CLEX_plusplus "--" CLEX_minusminus
#define STB_C_LEX_C_ARROW Y // "->" CLEX_arrow
#define STB_C_LEX_EQUAL_ARROW Y // "=>" CLEX_eqarrow
#define STB_C_LEX_C_BITWISEEQ Y // "&=" CLEX_andeq "|=" CLEX_oreq "^=" CLEX_xoreq
#define STB_C_LEX_C_ARITHEQ Y // "+=" CLEX_pluseq "-=" CLEX_minuseq
// "*=" CLEX_muleq "/=" CLEX_diveq "%=" CLEX_modeq
// if both STB_C_LEX_SHIFTS & STB_C_LEX_ARITHEQ:
// "<<=" CLEX_shleq ">>=" CLEX_shreq
#define STB_C_LEX_PARSE_SUFFIXES Y // letters after numbers are parsed as part of those numbers, and must be in suffix list below
#define STB_C_LEX_DECIMAL_SUFFIXES "uUlL" // decimal integer suffixes e.g. "uUlL" -- these are returned as-is in string storage
#define STB_C_LEX_HEX_SUFFIXES "lL" // e.g. "uUlL"
#define STB_C_LEX_OCTAL_SUFFIXES "lL" // e.g. "uUlL"
#define STB_C_LEX_FLOAT_SUFFIXES "uulL" //
#define STB_C_LEX_0_IS_EOF N // if Y, ends parsing at '\0'; if N, returns '\0' as token
#define STB_C_LEX_INTEGERS_AS_DOUBLES N // parses integers as doubles so they can be larger than 'int', but only if STB_C_LEX_STDLIB==N
#define STB_C_LEX_MULTILINE_DSTRINGS Y // allow newlines in double-quoted strings
#define STB_C_LEX_MULTILINE_SSTRINGS Y // allow newlines in single-quoted strings
#define STB_C_LEX_USE_STDLIB N // use strtod,strtol for parsing #s; otherwise inaccurate hack
#define STB_C_LEX_DOLLAR_IDENTIFIER Y // allow $ as an identifier character
#define STB_C_LEX_FLOAT_NO_DECIMAL Y // allow floats that have no decimal point if they have an exponent
#define STB_C_LEX_DEFINE_ALL_TOKEN_NAMES Y // if Y, all CLEX_ token names are defined, even if never returned
// leaving it as N should help you catch config bugs
#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess
// still have #line, #pragma, etc)
#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions
#define STB_C_LEXER_IMPLEMENTATION
#define STB_C_LEXER_SELF_TEST
#include "../stb_c_lexer.h"

View File

@ -699,7 +699,7 @@ static int test_plane(plane *p, float x0, float y0, float z0, float x1, float y1
static int is_box_in_frustum(float *bmin, float *bmax)
{
int i;
for (i=0; i < 5; ++i)
for (i=0; i < 6; ++i)
if (!test_plane(&frustum[i], bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]))
return 0;
return 1;

363
tests/grid_reachability.c Normal file
View File

@ -0,0 +1,363 @@
#define STB_CONNECTED_COMPONENTS_IMPLEMENTATION
#define STBCC_GRID_COUNT_X_LOG2 10
#define STBCC_GRID_COUNT_Y_LOG2 10
#include "stb_connected_components.h"
#ifdef GRID_TEST
#include <windows.h>
#include <stdio.h>
#include <direct.h>
//#define STB_DEFINE
#include "stb.h"
//#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
//#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
typedef struct
{
uint16 x,y;
} point;
point leader[1024][1024];
uint32 color[1024][1024];
point find(int x, int y)
{
point p,q;
p = leader[y][x];
if (p.x == x && p.y == y)
return p;
q = find(p.x, p.y);
leader[y][x] = q;
return q;
}
void onion(int x1, int y1, int x2, int y2)
{
point p = find(x1,y1);
point q = find(x2,y2);
if (p.x == q.x && p.y == q.y)
return;
leader[p.y][p.x] = q;
}
void reference(uint8 *map, int w, int h)
{
int i,j;
for (j=0; j < h; ++j) {
for (i=0; i < w; ++i) {
leader[j][i].x = i;
leader[j][i].y = j;
}
}
for (j=1; j < h-1; ++j) {
for (i=1; i < w-1; ++i) {
if (map[j*w+i] == 255) {
if (map[(j+1)*w+i] == 255) onion(i,j, i,j+1);
if (map[(j)*w+i+1] == 255) onion(i,j, i+1,j);
}
}
}
for (j=0; j < h; ++j) {
for (i=0; i < w; ++i) {
uint32 c = 0xff000000;
if (leader[j][i].x == i && leader[j][i].y == j) {
if (map[j*w+i] == 255)
c = stb_randLCG() | 0xff404040;
}
color[j][i] = c;
}
}
for (j=0; j < h; ++j) {
for (i=0; i < w; ++i) {
if (leader[j][i].x != i || leader[j][i].y != j) {
point p = find(i,j);
color[j][i] = color[p.y][p.x];
}
}
}
}
void write_map(stbcc_grid *g, int w, int h, char *filename)
{
int i,j;
for (j=0; j < h; ++j) {
for (i=0; i < w; ++i) {
unsigned int c;
c = stbcc_get_unique_id(g,i,j);
c = stb_rehash_improved(c)&0xffffff;
if (c == STBCC_NULL_UNIQUE_ID)
c = 0xff000000;
else
c = (~c)^0x555555;
if (i % 32 == 0 || j %32 == 0) {
int r = (c >> 16) & 255;
int g = (c >> 8) & 255;
int b = c & 255;
r = (r+130)/2;
g = (g+130)/2;
b = (b+130)/2;
c = 0xff000000 + (r<<16) + (g<<8) + b;
}
color[j][i] = c;
}
}
stbi_write_png(filename, w, h, 4, color, 4*w);
}
void test_connected(stbcc_grid *g)
{
int n = stbcc_query_grid_node_connection(g, 512, 90, 512, 871);
//printf("%d ", n);
}
static char *message;
LARGE_INTEGER start;
void start_timer(char *s)
{
message = s;
QueryPerformanceCounter(&start);
}
void end_timer(void)
{
LARGE_INTEGER end, freq;
double tm;
QueryPerformanceCounter(&end);
QueryPerformanceFrequency(&freq);
tm = (end.QuadPart - start.QuadPart) / (double) freq.QuadPart;
printf("%6.4lf ms: %s\n", tm * 1000, message);
}
extern void quicktest(void);
int loc[5000][2];
int main(int argc, char **argv)
{
stbcc_grid *g;
int w,h, i,j,k=0, count=0, r;
uint8 *map = stbi_load("data/map_03.png", &w, &h, 0, 1);
assert(map);
quicktest();
for (j=0; j < h; ++j)
for (i=0; i < w; ++i)
map[j*w+i] = ~map[j*w+i];
for (i=0; i < w; ++i)
for (j=0; j < h; ++j)
//map[j*w+i] = (((i+1) ^ (j+1)) >> 1) & 1 ? 255 : 0;
map[j*w+i] = stb_max(abs(i-w/2),abs(j-h/2)) & 1 ? 255 : 0;
//map[j*w+i] = (((i ^ j) >> 5) ^ (i ^ j)) & 1 ? 255 : 0;
//map[j*w+i] = stb_rand() & 1 ? 255 : 0;
#if 1
for (i=0; i < 100000; ++i)
map[(stb_rand()%h)*w + stb_rand()%w] ^= 255;
#endif
_mkdir("tests/output/stbcc");
stbi_write_png("tests/output/stbcc/reference.png", w, h, 1, map, 0);
//reference(map, w, h);
g = malloc(stbcc_grid_sizeof());
printf("Size: %d\n", stbcc_grid_sizeof());
#if 0
memset(map, 0, w*h);
stbcc_init_grid(g, map, w, h);
{
int n;
char **s = stb_stringfile("c:/x/clockwork_update.txt", &n);
write_map(g, w, h, "tests/output/stbcc/base.png");
for (i=1; i < n; i += 1) {
int x,y,t;
sscanf(s[i], "%d %d %d", &x, &y, &t);
if (i == 571678)
write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_good.png", i));
stbcc_update_grid(g, x, y, t);
if (i == 571678)
write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_bad.png", i));
//if (i > 571648 && i <= 571712)
//write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_%06d.png", i));
}
write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_%06d.png", i-1));
}
return 0;
#endif
start_timer("init");
stbcc_init_grid(g, map, w, h);
end_timer();
//g = stb_file("c:/x/clockwork_path.bin", 0);
write_map(g, w, h, "tests/output/stbcc/base.png");
for (i=0; i < 5000;) {
loc[i][0] = stb_rand() % w;
loc[i][1] = stb_rand() % h;
if (stbcc_query_grid_open(g, loc[i][0], loc[i][1]))
++i;
}
r = 0;
start_timer("reachable");
for (i=0; i < 2000; ++i) {
for (j=0; j < 2000; ++j) {
int x1 = loc[i][0], y1 = loc[i][1];
int x2 = loc[2000+j][0], y2 = loc[2000+j][1];
r += stbcc_query_grid_node_connection(g, x1,y1, x2,y2);
}
}
end_timer();
printf("%d reachable\n", r);
printf("Cluster size: %d,%d\n", STBCC__CLUSTER_SIZE_X, STBCC__CLUSTER_SIZE_Y);
#if 1
for (j=0; j < 10; ++j) {
for (i=0; i < 5000; ++i) {
loc[i][0] = stb_rand() % w;
loc[i][1] = stb_rand() % h;
}
start_timer("updating 2500");
for (i=0; i < 2500; ++i) {
if (stbcc_query_grid_open(g, loc[i][0], loc[i][1]))
stbcc_update_grid(g, loc[i][0], loc[i][1], 1);
else
stbcc_update_grid(g, loc[i][0], loc[i][1], 0);
}
end_timer();
write_map(g, w, h, stb_sprintf("tests/output/stbcc/update_random_%d.png", j*i));
}
#endif
#if 0
start_timer("removing");
count = 0;
for (i=0; i < 1800; ++i) {
int x,y,a,b;
x = stb_rand() % (w-32);
y = stb_rand() % (h-32);
if (i & 1) {
for (a=0; a < 32; ++a)
for (b=0; b < 1; ++b)
if (stbcc_query_grid_open(g, x+a, y+b)) {
stbcc_update_grid(g, x+a, y+b, 1);
++count;
}
} else {
for (a=0; a < 1; ++a)
for (b=0; b < 32; ++b)
if (stbcc_query_grid_open(g, x+a, y+b)) {
stbcc_update_grid(g, x+a, y+b, 1);
++count;
}
}
//if (i % 100 == 0) write_map(g, w, h, stb_sprintf("tests/output/stbcc/open_random_%d.png", i+1));
}
end_timer();
printf("Removed %d grid spaces\n", count);
write_map(g, w, h, stb_sprintf("tests/output/stbcc/open_random_%d.png", i));
r = 0;
start_timer("reachable");
for (i=0; i < 1000; ++i) {
for (j=0; j < 1000; ++j) {
int x1 = loc[i][0], y1 = loc[i][1];
int x2 = loc[j][0], y2 = loc[j][1];
r += stbcc_query_grid_node_connection(g, x1,y1, x2,y2);
}
}
end_timer();
printf("%d reachable\n", r);
start_timer("adding");
count = 0;
for (i=0; i < 1800; ++i) {
int x,y,a,b;
x = stb_rand() % (w-32);
y = stb_rand() % (h-32);
if (i & 1) {
for (a=0; a < 32; ++a)
for (b=0; b < 1; ++b)
if (!stbcc_query_grid_open(g, x+a, y+b)) {
stbcc_update_grid(g, x+a, y+b, 0);
++count;
}
} else {
for (a=0; a < 1; ++a)
for (b=0; b < 32; ++b)
if (!stbcc_query_grid_open(g, x+a, y+b)) {
stbcc_update_grid(g, x+a, y+b, 0);
++count;
}
}
//if (i % 100 == 0) write_map(g, w, h, stb_sprintf("tests/output/stbcc/close_random_%d.png", i+1));
}
end_timer();
write_map(g, w, h, stb_sprintf("tests/output/stbcc/close_random_%d.png", i));
printf("Added %d grid spaces\n", count);
#endif
#if 0 // for map_02.png
start_timer("process");
for (k=0; k < 20; ++k) {
for (j=0; j < h; ++j) {
int any=0;
for (i=0; i < w; ++i) {
if (map[j*w+i] > 10 && map[j*w+i] < 250) {
//start_timer(stb_sprintf("open %d,%d", i,j));
stbcc_update_grid(g, i, j, 0);
test_connected(g);
//end_timer();
any = 1;
}
}
if (any) write_map(g, w, h, stb_sprintf("tests/output/stbcc/open_row_%04d.png", j));
}
for (j=0; j < h; ++j) {
int any=0;
for (i=0; i < w; ++i) {
if (map[j*w+i] > 10 && map[j*w+i] < 250) {
//start_timer(stb_sprintf("close %d,%d", i,j));
stbcc_update_grid(g, i, j, 1);
test_connected(g);
//end_timer();
any = 1;
}
}
if (any) write_map(g, w, h, stb_sprintf("tests/output/stbcc/close_row_%04d.png", j));
}
}
end_timer();
#endif
return 0;
}
#endif

View File

@ -7,7 +7,7 @@
#define STB_DEFINE
#include "stb.h"
#define PNGSUITE_PRIMARY
//#define PNGSUITE_PRIMARY
#if 0
void test_ycbcr(void)
@ -53,6 +53,13 @@ void test_ycbcr(void)
float hdr_data[200][200][3];
void dummy_write(void *context, void *data, int len)
{
static char dummy[1024];
if (len > 1024) len = 1024;
memcpy(dummy, data, len);
}
int main(int argc, char **argv)
{
int w,h;
@ -73,18 +80,28 @@ int main(int argc, char **argv)
int i, n;
for (i=1; i < argc; ++i) {
int res;
int w2,h2,n2;
unsigned char *data;
printf("%s\n", argv[i]);
res = stbi_info(argv[1], &w2, &h2, &n2);
data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n");
data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n");
data = stbi_load(argv[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n");
data = stbi_load(argv[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n");
data = stbi_load(argv[i], &w, &h, 0, 4);
data = stbi_load(argv[i], &w, &h, &n, 4);
assert(data);
assert(w == w2 && h == h2 && n == n2);
assert(res);
if (data) {
char fname[512];
stb_splitpath(fname, argv[i], STB_FILE);
stbi_write_png(stb_sprintf("output/%s.png", fname), w, h, 4, data, w*4);
stbi_write_bmp(stb_sprintf("output/%s.bmp", fname), w, h, 4, data);
stbi_write_tga(stb_sprintf("output/%s.tga", fname), w, h, 4, data);
stbi_write_png_to_func(dummy_write,0, w, h, 4, data, w*4);
stbi_write_bmp_to_func(dummy_write,0, w, h, 4, data);
stbi_write_tga_to_func(dummy_write,0, w, h, 4, data);
free(data);
} else
printf("FAILED 4\n");

View File

@ -25,6 +25,8 @@
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "user32.lib")
#endif
#ifdef __cplusplus

124
tests/pg_test/pg_test.c Normal file
View File

@ -0,0 +1,124 @@
#define STB_DEFINE
#include "stb.h"
#define STB_PG_IMPLEMENTATION
#include "stb_pg.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
static float *hf;
static int hf_width = 10001;
static int hf_height = 10001;
static float get_height(float x, float y)
{
float h00,h01,h10,h11,h0,h1;
int ix,iy;
if (x < 0) x = 0;
if (x > hf_width-1) x = (float) hf_width-1;
if (y < 0) y = 0;
if (y > hf_height-1) y = (float) hf_height-1;
ix = (int) x; x -= ix;
iy = (int) y; y -= iy;
h00 = hf[(iy+0)*hf_height+(ix+0)];
h10 = hf[(iy+0)*hf_height+(ix+1)];
h01 = hf[(iy+1)*hf_height+(ix+0)];
h11 = hf[(iy+1)*hf_height+(ix+1)];
h0 = stb_lerp(y, h00, h01);
h1 = stb_lerp(y, h10, h11);
return stb_lerp(x, h0, h1);
}
void stbpg_tick(float dt)
{
int i=0,j=0;
int step = 1;
glUseProgram(0);
glClearColor(0.6f,0.7f,1.0f,1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
#if 1
glEnable(GL_CULL_FACE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1920/1080.0f, 0.02f, 8000.0f);
//glOrtho(-8,8,-6,6, -100, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-90, 1,0,0); // z-up
{
float x,y;
stbpg_get_mouselook(&x,&y);
glRotatef(-y, 1,0,0);
glRotatef(-x, 0,0,1);
}
{
static float cam_x = 1000;
static float cam_y = 1000;
static float cam_z = 700;
float x=0,y=0;
stbpg_get_keymove(&x,&y);
cam_x += x*dt*5.0f;
cam_y += y*dt*5.0f;
glTranslatef(-cam_x, -cam_y, -cam_z);
if (cam_x >= 0 && cam_x < hf_width && cam_y >= 0 && cam_y < hf_height)
cam_z = get_height(cam_x, cam_y) + 1.65f; // average eye height in meters
}
for (j=501; j+1 < 1500+0*hf_height; j += step) {
glBegin(GL_QUAD_STRIP);
for (i=501; i < 1500+0*hf_width; i += step) {
static int flip=0;
if (flip)
glColor3f(0.5,0.5,0.5);
else
glColor3f(0.4f,0.4f,0.4f);
flip = !flip;
glVertex3f((float) i, (float) j+step,hf[(j+step)*hf_width+i]);
glVertex3f((float) i, (float) j ,hf[ j *hf_width+i]);
}
glEnd();
}
glBegin(GL_LINES);
glColor3f(1,0,0); glVertex3f(10,0,0); glVertex3f(0,0,0);
glColor3f(0,1,0); glVertex3f(0,10,0); glVertex3f(0,0,0);
glColor3f(0,0,1); glVertex3f(0,0,10); glVertex3f(0,0,0);
glEnd();
#endif
}
void stbpg_main(int argc, char **argv)
{
int i,j;
#if 0
int w,h,c;
unsigned short *data = stbi_load_16("c:/x/ned_1m/test2.png", &w, &h, &c, 1);
stb_filewrite("c:/x/ned_1m/x73_y428_10012_10012.bin", data, w*h*2);
#else
unsigned short *data = stb_file("c:/x/ned_1m/x73_y428_10012_10012.bin", NULL);
int w=10012, h = 10012;
#endif
hf = malloc(hf_width * hf_height * 4);
for (j=0; j < hf_height; ++j)
for (i=0; i < hf_width; ++i)
hf[j*hf_width+i] = data[j*w+i] / 32.0f;
stbpg_gl_compat_version(1,1);
stbpg_windowed("terrain_edit", 1920, 1080);
stbpg_run();
return;
}

View File

@ -1,4 +1,5 @@
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#if defined(_WIN32) && _MSC_VER > 1200
#define STBIR_ASSERT(x) \
@ -69,9 +70,11 @@ void stbir_progress(float p)
#ifdef _WIN32
#include <sys/timeb.h>
#endif
#include <direct.h>
#define mkdir(a, b) _mkdir(a)
#else
#include <sys/stat.h>
#endif
#define MT_SIZE 624
static size_t g_aiMT[MT_SIZE];
@ -356,6 +359,54 @@ void test_subpixel(const char* file, float width_percent, float height_percent,
free(output_data);
}
void test_subpixel_region(const char* file, float width_percent, float height_percent, float s0, float t0, float s1, float t1)
{
int w, h, n;
unsigned char* input_data = stbi_load(file, &w, &h, &n, 0);
if (input_data == NULL)
return;
int new_w = (int)(w * width_percent);
int new_h = (int)(h * height_percent);
unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char));
stbir_resize_region(input_data, w, h, 0, output_data, new_w, new_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, s0, t0, s1, t1);
stbi_image_free(input_data);
char output[200];
sprintf(output, "test-output/subpixel-region-%d-%d-%f-%f-%f-%f-%s", new_w, new_h, s0, t0, s1, t1, file);
stbi_write_png(output, new_w, new_h, n, output_data, 0);
free(output_data);
}
void test_subpixel_command(const char* file, float width_percent, float height_percent, float x_scale, float y_scale, float x_offset, float y_offset)
{
int w, h, n;
unsigned char* input_data = stbi_load(file, &w, &h, &n, 0);
if (input_data == NULL)
return;
int new_w = (int)(w * width_percent);
int new_h = (int)(h * height_percent);
unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char));
stbir_resize_subpixel(input_data, w, h, 0, output_data, new_w, new_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, x_scale, y_scale, x_offset, y_offset);
stbi_image_free(input_data);
char output[200];
sprintf(output, "test-output/subpixel-command-%d-%d-%f-%f-%f-%f-%s", new_w, new_h, x_scale, y_scale, x_offset, y_offset, file);
stbi_write_png(output, new_w, new_h, n, output_data, 0);
free(output_data);
}
unsigned int* pixel(unsigned int* buffer, int x, int y, int c, int w, int n)
{
return &buffer[y*w*n + x*n + c];
@ -461,6 +512,18 @@ void test_subpixel_1()
STBIR_ASSERT(output_data[y * 16 + x + 8] == output_right[y * 8 + x]);
}
}
stbir_resize_subpixel(image, 8, 8, 0, output_left, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 0, 0);
stbir_resize_subpixel(image, 8, 8, 0, output_right, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 8, 0);
{for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 16; y++)
{
STBIR_ASSERT(output_data[y * 16 + x] == output_left[y * 8 + x]);
STBIR_ASSERT(output_data[y * 16 + x + 8] == output_right[y * 8 + x]);
}
}}
}
// test that replicating an image and using a subtile of it produces same results as wraparound
@ -498,6 +561,14 @@ void test_subpixel_2()
for (int y = 0; y < 16; y++)
STBIR_ASSERT(output_data_1[y * 16 + x] == output_data_2[y * 16 + x]);
}}
stbir_resize_subpixel(large_image, 32, 32, 0, output_data_2, 16, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_WRAP, STBIR_EDGE_WRAP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 16, 16);
{for (int x = 0; x < 16; x++)
{
for (int y = 0; y < 16; y++)
STBIR_ASSERT(output_data_1[y * 16 + x] == output_data_2[y * 16 + x]);
}}
}
// test that 0,0,1,1 subpixel produces same result as no-rect
@ -521,6 +592,14 @@ void test_subpixel_3()
for (int y = 0; y < 32; y++)
STBIR_ASSERT(output_data_1[y * 32 + x] == output_data_2[y * 32 + x]);
}
stbir_resize_subpixel(image, 8, 8, 0, output_data_1, 32, 32, 0, STBIR_TYPE_UINT8, 1, 0, STBIR_ALPHA_CHANNEL_NONE, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_LINEAR, NULL, 4, 4, 0, 0);
{for (int x = 0; x < 32; x++)
{
for (int y = 0; y < 32; y++)
STBIR_ASSERT(output_data_1[y * 32 + x] == output_data_2[y * 32 + x]);
}}
}
// test that 1:1 resample using s,t=0,0,1,1 with bilinear produces original image
@ -537,6 +616,9 @@ void test_subpixel_4()
stbir_resize_region(image, 8, 8, 0, output, 8, 8, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, &g_context, 0, 0, 1, 1);
STBIR_ASSERT(memcmp(image, output, 8 * 8) == 0);
stbir_resize_subpixel(image, 8, 8, 0, output, 8, 8, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, &g_context, 1, 1, 0, 0);
STBIR_ASSERT(memcmp(image, output, 8 * 8) == 0);
}
static unsigned int image88_int[8][8];
@ -753,7 +835,7 @@ void test_filters(void)
#define UMAX32 4294967295U
static void write32(char *filename, stbir_uint32 *output, int w, int h)
static void write32(const char *filename, stbir_uint32 *output, int w, int h)
{
stbir_uint8 *data = (stbir_uint8*) malloc(w*h*3);
for (int i=0; i < w*h*3; ++i)
@ -789,9 +871,9 @@ static void test_32(void)
void test_suite(int argc, char **argv)
{
int i;
char *barbara;
const char *barbara;
_mkdir("test-output");
mkdir("test-output", 777);
if (argc > 1)
barbara = argv[1];
@ -880,17 +962,70 @@ void test_suite(int argc, char **argv)
stbir_resize(image88, 8, 8, 0, output88, 16, 4, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context);
stbir_resize(image88, 8, 8, 0, output88, 16, 4, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_BOX, STBIR_COLORSPACE_SRGB, &g_context);
for (i = 0; i < 10; i++)
int barbara_width, barbara_height, barbara_channels;
stbi_image_free(stbi_load(barbara, &barbara_width, &barbara_height, &barbara_channels, 0));
int res = 10;
// Downscaling
{for (int i = 0; i <= res; i++)
{
float t = (float)i/res;
float scale = 0.5;
float out_scale = 2.0f/3;
float x_shift = (barbara_width*out_scale - barbara_width*scale) * t;
float y_shift = (barbara_height*out_scale - barbara_height*scale) * t;
test_subpixel_command(barbara, scale, scale, out_scale, out_scale, x_shift, y_shift);
}}
// Upscaling
{for (int i = 0; i <= res; i++)
{
float t = (float)i/res;
float scale = 2;
float out_scale = 3;
float x_shift = (barbara_width*out_scale - barbara_width*scale) * t;
float y_shift = (barbara_height*out_scale - barbara_height*scale) * t;
test_subpixel_command(barbara, scale, scale, out_scale, out_scale, x_shift, y_shift);
}}
// Downscaling
{for (int i = 0; i <= res; i++)
{
float t = (float)i/res / 2;
test_subpixel_region(barbara, 0.25f, 0.25f, t, t, t+0.5f, t+0.5f);
}}
// No scaling
{for (int i = 0; i <= res; i++)
{
float t = (float)i/res / 2;
test_subpixel_region(barbara, 0.5f, 0.5f, t, t, t+0.5f, t+0.5f);
}}
// Upscaling
{for (int i = 0; i <= res; i++)
{
float t = (float)i/res / 2;
test_subpixel_region(barbara, 1, 1, t, t, t+0.5f, t+0.5f);
}}
{for (i = 0; i < 10; i++)
test_subpixel(barbara, 0.5f, 0.5f, (float)i / 10, 1);
}
for (i = 0; i < 10; i++)
{for (i = 0; i < 10; i++)
test_subpixel(barbara, 0.5f, 0.5f, 1, (float)i / 10);
}
for (i = 0; i < 10; i++)
{for (i = 0; i < 10; i++)
test_subpixel(barbara, 2, 2, (float)i / 10, 1);
}
for (i = 0; i < 10; i++)
{for (i = 0; i < 10; i++)
test_subpixel(barbara, 2, 2, 1, (float)i / 10);
}
// Channels test
test_channels(barbara, 0.5f, 0.5f, 1);
@ -916,40 +1051,40 @@ void test_suite(int argc, char **argv)
resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_CATMULLROM , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-catmullrom.png");
resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_MITCHELL , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-mitchell.png");
for (i = 10; i < 100; i++)
{for (i = 10; i < 100; i++)
{
char outname[200];
sprintf(outname, "test-output/barbara-width-%d.jpg", i);
resize_image(barbara, (float)i / 100, 1, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
}
}}
for (i = 110; i < 500; i += 10)
{for (i = 110; i < 500; i += 10)
{
char outname[200];
sprintf(outname, "test-output/barbara-width-%d.jpg", i);
resize_image(barbara, (float)i / 100, 1, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
}
}}
for (i = 10; i < 100; i++)
{for (i = 10; i < 100; i++)
{
char outname[200];
sprintf(outname, "test-output/barbara-height-%d.jpg", i);
resize_image(barbara, 1, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
}
}}
for (i = 110; i < 500; i += 10)
{for (i = 110; i < 500; i += 10)
{
char outname[200];
sprintf(outname, "test-output/barbara-height-%d.jpg", i);
resize_image(barbara, 1, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
}
}}
for (i = 50; i < 200; i += 10)
{for (i = 50; i < 200; i += 10)
{
char outname[200];
sprintf(outname, "test-output/barbara-width-height-%d.jpg", i);
resize_image(barbara, 100 / (float)i, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
}
}}
test_format<unsigned short>(barbara, 0.5, 2.0, STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB);
test_format<unsigned short>(barbara, 0.5, 2.0, STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR);

View File

@ -3,3 +3,6 @@
#include "stb_image_resize.h"
// Just to make sure it will build properly with a c compiler
int main() {
}

View File

@ -42,7 +42,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /G6 /MT /W3 /GX /Z7 /O2 /Ob2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FD /c
# ADD CPP /nologo /G6 /MT /W3 /GX /Z7 /O2 /Ob2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GRID_TEST" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@ -66,7 +66,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GRID_TEST" /FR /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@ -86,6 +86,10 @@ LINK32=link.exe
# Name "stb - Win32 Debug"
# Begin Source File
SOURCE=.\grid_reachability.c
# End Source File
# Begin Source File
SOURCE=.\stb.c
# End Source File
# Begin Source File
@ -98,6 +102,10 @@ SOURCE=..\stb_c_lexer.h
# End Source File
# Begin Source File
SOURCE=..\stb_connected_components.h
# End Source File
# Begin Source File
SOURCE=..\stb_divide.h
# End Source File
# Begin Source File
@ -106,6 +114,10 @@ SOURCE=..\stb_dxt.h
# End Source File
# Begin Source File
SOURCE=..\stb_easy_font.h
# End Source File
# Begin Source File
SOURCE=..\stb_herringbone_wang_tile.h
# End Source File
# Begin Source File
@ -126,14 +138,26 @@ SOURCE=..\stb_leakcheck.h
# End Source File
# Begin Source File
SOURCE=..\stb_malloc.h
# End Source File
# Begin Source File
SOURCE=..\stb_perlin.h
# End Source File
# Begin Source File
SOURCE=..\stb_pg.h
# End Source File
# Begin Source File
SOURCE=..\stb_rect_pack.h
# End Source File
# Begin Source File
SOURCE=..\stb_sprintf.h
# End Source File
# Begin Source File
SOURCE=..\stb_textedit.h
# End Source File
# Begin Source File

View File

@ -63,7 +63,19 @@ Package=<4>
###############################################################################
Project: "resize"=.\resize\resize.dsp - Package Owner=<4>
Project: "pg_test"=.\pg_test\pg_test.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "resize"=.\resize.dsp - Package Owner=<4>
Package=<5>
{{{
@ -123,6 +135,30 @@ Package=<4>
###############################################################################
Project: "unicode"=..\tools\unicode\unicode.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "vorbseek"=.\vorbseek\vorbseek.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>

View File

@ -1,3 +1,7 @@
#include "stb_sprintf.h"
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
#define STB_PERLIN_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_DXT_IMPLEMENATION
@ -8,7 +12,9 @@
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STB_RECT_PACK_IMPLEMENTATION
#define STB_VOXEL_RENDER_IMPLEMENTATION
#define STB_EASY_FONT_IMPLEMENTATION
#include "stb_easy_font.h"
#include "stb_herringbone_wang_tile.h"
#include "stb_image.h"
#include "stb_image_write.h"
@ -26,3 +32,11 @@
#define STBTE_DRAW_TILE(x,y,id,highlight,data) 0
#define STB_TILEMAP_EDITOR_IMPLEMENTATION
#include "stb_tilemap_editor.h"
int quicktest(void)
{
char buffer[999];
stbsp_sprintf(buffer, "test%%test");
return 0;
}

View File

@ -1,3 +1,7 @@
#include "stb_sprintf.h"
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
#define STB_TRUETYPE_IMPLEMENTATION
#define STB_PERLIN_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
@ -8,6 +12,7 @@
#define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION
#define STB_RECT_PACK_IMPLEMENTATION
#define STB_VOXEL_RENDER_IMPLEMENTATION
#define STB_CONNECTED_COMPONENTS_IMPLEMENTATION
#define STBI_MALLOC my_malloc
#define STBI_FREE my_free
@ -27,6 +32,10 @@ void my_free(void *) { }
#include "stb_divide.h"
#include "stb_herringbone_wang_tile.h"
#define STBCC_GRID_COUNT_X_LOG2 10
#define STBCC_GRID_COUNT_Y_LOG2 10
#include "stb_connected_components.h"
#define STBVOX_CONFIG_MODE 1
#include "stb_voxel_render.h"

View File

@ -3,13 +3,13 @@
#include "stb_truetype.h"
#include "stb_image_write.h"
#ifdef TT_TEST
#include <stdio.h>
char ttf_buffer[1<<25];
unsigned char output[512*100];
#ifdef TT_TEST
void debug(void)
{
stbtt_fontinfo font;
@ -24,6 +24,7 @@ void debug(void)
unsigned char temp_bitmap[BITMAP_H][BITMAP_W];
stbtt_bakedchar cdata[256*2]; // ASCII 32..126 is 95 glyphs
stbtt_packedchar pdata[256*2];
int main(int argc, char **argv)
{
stbtt_fontinfo font;
@ -35,6 +36,17 @@ int main(int argc, char **argv)
// @TODO: why is minglui.ttc failing?
fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/mingliu.ttc", "rb"));
//fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/x/DroidSansMono.ttf", "rb"));
{
static stbtt_pack_context pc;
static stbtt_packedchar cd[256];
static unsigned char atlas[1024*1024];
stbtt_PackBegin(&pc, atlas, 1024,1024,1024,1,NULL);
stbtt_PackFontRange(&pc, ttf_buffer, 0, 32.0, 0, 256, cd);
stbtt_PackEnd(&pc);
}
#if 0
stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits!
stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0);

View File

@ -1,3 +1,7 @@
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_VORBIS_HEADER_ONLY
#include "stb_vorbis.c"
#include "stb.h"
@ -8,10 +12,11 @@ extern void stb_vorbis_dumpmem(void);
int main(int argc, char **argv)
{
size_t memlen;
unsigned char *mem = stb_fileu("c:/x/theme_03.ogg", &memlen);
unsigned char *mem = stb_fileu("c:/x/sketch008.ogg", &memlen);
int chan, samplerate;
short *output;
int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output);
stb_filewrite("c:/x/sketch008.raw", output, samples*4);
return 0;
}
#endif

125
tests/vorbseek/vorbseek.c Normal file
View File

@ -0,0 +1,125 @@
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define STB_VORBIS_HEADER_ONLY
#include "stb_vorbis.c"
#define SAMPLES_TO_TEST 3000
int test_count [5] = { 5000, 3000, 2000, 50000, 50000 };
int test_spacing[5] = { 1, 111, 3337, 7779, 72717 };
int try_seeking(stb_vorbis *v, unsigned int pos, short *output, unsigned int num_samples)
{
int count;
short samples[SAMPLES_TO_TEST*2];
assert(pos <= num_samples);
if (!stb_vorbis_seek(v, pos)) {
fprintf(stderr, "Seek to %u returned error from stb_vorbis\n", pos);
return 0;
}
count = stb_vorbis_get_samples_short_interleaved(v, 2, samples, SAMPLES_TO_TEST*2);
if (count > (int) (num_samples - pos)) {
fprintf(stderr, "Seek to %u allowed decoding %d samples when only %d should have been valid.\n",
pos, count, (int) (num_samples - pos));
return 0;
}
if (count < SAMPLES_TO_TEST && count < (int) (num_samples - pos)) {
fprintf(stderr, "Seek to %u only decoded %d samples of %d attempted when at least %d should have been valid.\n",
pos, count, SAMPLES_TO_TEST, num_samples - pos);
return 0;
}
if (0 != memcmp(samples, output + pos*2, count*2)) {
int k;
for (k=0; k < SAMPLES_TO_TEST*2; ++k) {
if (samples[k] != output[k]) {
fprintf(stderr, "Seek to %u produced incorrect samples starting at sample %u (short #%d in buffer).\n",
pos, pos + (k/2), k);
break;
}
}
assert(k != SAMPLES_TO_TEST*2);
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
int num_chan, samprate;
int i, j, test, phase;
short *output;
if (argc == 1) {
fprintf(stderr, "Usage: vorbseek {vorbisfile} [{vorbisfile]*]\n");
fprintf(stderr, "Tests various seek offsets to make sure they're sample exact.\n");
return 0;
}
#if 0
{
// check that outofmem occurs correctly
stb_vorbis_alloc va;
va.alloc_buffer = malloc(1024*1024);
for (i=0; i < 1024*1024; i += 10) {
int error=0;
stb_vorbis *v;
va.alloc_buffer_length_in_bytes = i;
v = stb_vorbis_open_filename(argv[1], &error, &va);
if (v != NULL)
break;
printf("Error %d at %d\n", error, i);
}
}
#endif
for (j=1; j < argc; ++j) {
unsigned int successes=0, attempts = 0;
unsigned int num_samples = stb_vorbis_decode_filename(argv[j], &num_chan, &samprate, &output);
break;
if (num_samples == 0xffffffff) {
fprintf(stderr, "Error: couldn't open file or not vorbis file: %s\n", argv[j]);
goto fail;
}
if (num_chan != 2) {
fprintf(stderr, "vorbseek testing only works with files with 2 channels, %s has %d\n", argv[j], num_chan);
goto fail;
}
for (test=0; test < 5; ++test) {
int error;
stb_vorbis *v = stb_vorbis_open_filename(argv[j], &error, NULL);
if (v == NULL) {
fprintf(stderr, "Couldn't re-open %s for test #%d\n", argv[j], test);
goto fail;
}
for (phase=0; phase < 3; ++phase) {
unsigned int base = phase == 0 ? 0 : phase == 1 ? num_samples - test_count[test]*test_spacing[test] : num_samples/3;
for (i=0; i < test_count[test]; ++i) {
unsigned int pos = base + i*test_spacing[test];
if (pos > num_samples) // this also catches underflows
continue;
successes += try_seeking(v, pos, output, num_samples);
attempts += 1;
}
}
stb_vorbis_close(v);
}
printf("%d of %d seeks failed in %s (%d samples)\n", attempts-successes, attempts, argv[j], num_samples);
free(output);
}
return 0;
fail:
return 1;
}

View File

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

View File

@ -4,15 +4,40 @@ FAQ
#### What's the license?
These libraries are in the public domain (or the equivalent where that is not
possible). You can do anything you want with them. You have no legal obligation
These libraries are in the public domain. You can do anything you
want with them. You have no legal obligation
to do anything else, although I appreciate attribution.
#### If I wrap an stb library in a new library, does the new library have to be public domain?
They are also licensed under the MIT open source license, if you have lawyers
who are unhappy with public domain. Every source file includes an explicit
dual-license for you to choose from.
No.
#### <a name="other_libs"></a> Are there other single-file public-domain/open source libraries with minimal dependencies out there?
#### A lot of these libraries seem redundant to existing open source libraries. Are they better somehow?
[Yes.](https://github.com/nothings/single_file_libs)
#### If I wrap an stb library in a new library, does the new library have to be public domain/MIT?
No, because it's public domain you can freely relicense it to whatever license your new
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?
Generally they're only better in that they're easier to integrate,
easier to use, and easier to release (single file; good API; no
@ -20,6 +45,10 @@ attribution requirement). They may be less featureful, slower,
and/or use more memory. If you're already using an equivalent
library, there's probably no good reason to switch.
#### Can I link directly to the table of stb libraries?
You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list.
#### Why do you list "lines of code"? It's a terrible metric.
Just to give you some idea of the internal complexity of the library,
@ -57,10 +86,10 @@ remember to attach *two* files, etc.
#### Why "stb"? Is this something to do with Set-Top Boxes?
No, they are just the initials for my name, Sean T. Barrett.
This was not chosen out of egomania, but as a semi-robust
This was not chosen out of egomania, but as a moderately sane
way of namespacing the filenames and source function names.
#### Will you add more image types to stb_image.c?
#### Will you add more image types to stb_image.h?
If people submit them, I generally add them, but the goal of stb_image
is less for applications like image viewer apps (which need to support
@ -68,10 +97,6 @@ every type of image under the sun) and more for things like games which
can choose what images to use, so I may decline to add them if they're
too rare or if the size of implementation vs. apparent benefit is too low.
#### Are there other single-file public-domain libraries out there?
Yes. I'll put a list here when people remind me what they are.
#### Do you have any advice on how to create my own single-file library?
Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt

View File

@ -1,7 +1,11 @@
stb
===
single-file public domain libraries for C/C++
single-file public domain (or MIT licensed) libraries for C/C++ <a name="stb_libs"></a>
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | --------------------------------

View File

@ -4,8 +4,9 @@ stb_truetype.h | graphics | parse, decode, and rasterize ch
stb_image_write.h | graphics | image writing to disk: PNG, TGA, BMP
stb_image_resize.h | graphics | resize images larger/smaller with good quality
stb_rect_pack.h | graphics | simple 2D rectangle packer with decent quality
stb_sprintf.h | utility | fast sprintf, snprintf for C/C++
stretchy_buffer.h | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
stb_textedit.h | UI | guts of a text editor for games etc implementing them from scratch
stb_textedit.h | user interface | guts of a text editor for games etc implementing them from scratch
stb_voxel_render.h | 3D graphics | Minecraft-esque voxel rendering "engine" with many more features
stb_dxt.h | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor
stb_perlin.h | 3D graphics | revised Perlin noise (3D input, 1D output)
@ -14,5 +15,6 @@ stb_tilemap_editor.h | game dev | embeddable tilemap editor
stb_herringbone_wang_tile.h | game dev | herringbone Wang tile map generator
stb_c_lexer.h | parsing | simplify writing parsers for C-like languages
stb_divide.h | math | more useful 32-bit modulus e.g. "euclidean divide"
stb_connected_components.h | misc | incrementally compute reachability on grids
stb.h | misc | helper functions for C, mostly redundant in C++; basically author's personal stuff
stb_leakcheck.h | misc | quick-and-dirty malloc/free leak-checking

View File

@ -30,15 +30,18 @@ int main(int argc, char **argv)
if (*s1 == 'v') ++s1;
s3 = tokens[0];
stb_trimwhite(s3);
fprintf(f, "**[");
if (strlen(s3) < 21) {
fprintf(f, "**%s** | %s", tokens[0], s1);
fprintf(f, "%s", tokens[0]);
} else {
char buffer[256];
strncpy(buffer, s3, 18);
buffer[18] = 0;
strcat(buffer, "...");
fprintf(f, "**%s** | %s", buffer, s1);
fprintf(f, "%s", buffer);
}
fprintf(f, "](%s)**", tokens[0]);
fprintf(f, " | %s", s1);
s1 = stb_trimwhite(tokens[1]); // stb_trimwhite -- advance pointer to after whitespace & delete trailing whitespace
s2 = stb_dupreplace(s1, " ", "&nbsp;"); // stb_dupreplace -- search & replace string and malloc result
fprintf(f, " | %s", s2);

749
tools/unicode.c Normal file
View File

@ -0,0 +1,749 @@
#define STB_DEFINE
#include "../stb.h"
// create unicode mappings
//
// Two kinds of mappings:
// map to a number
// map to a bit
//
// For mapping to a number, we use the following strategy:
//
// User supplies:
// 1. a table of numbers (for now we use uint16, so full Unicode table is 4MB)
// 2. a "don't care" value
// 3. define a 'fallback' value (typically 0)
// 4. define a fast-path range (typically 0..255 or 0..1023) [@TODO: automate detecting this]
//
// Code:
// 1. Determine range of *end* of unicode codepoints (U+10FFFF and down) which
// all have the same value (or don't care). If large enough, emit this as a
// special case in the code.
// 2. Repeat above, limited to at most U+FFFF.
// 3. Cluster the data into intervals of 8,16,32,64,128,256 numeric values.
// 3a. If all the values in an interval are fallback/dont-care, no further processing
// 3b. Find the "trimmed range" outside which all the values are the fallback or don't care
// 3c. Find the "special trimmed range" outside which all the values are some constant or don't care
// 4. Pack the clusters into continuous memory, and find previous instances of
// the cluster. Repeat for trimmed & special-trimmed. In the first case, find
// previous instances of the cluster (allow don't-care to match in either
// direction), both aligned and mis-aligned; in the latter, starting where
// things start or mis-aligned. Build an index table specifiying the
// location of each cluster (and its length). Allow an extra indirection here;
// the full-sized index can index a smaller table which has the actual offset
// (and lengths).
// 5. Associate with each packed continuous memory above the amount of memory
// required to store the data w/ smallest datatype (of uint8, uint16, uint32).
// Discard the continuous memory. Recurse on each index table, but avoid the
// smaller packing.
//
// For mapping to a bit, we pack the results for 8 characters into a byte, and then apply
// the above strategy. Note that there may be more optimal approaches with e.g. packing
// 8 different bits into a single structure, though, which we should explore eventually.
// currently we limit *indices* to being 2^16, and we pack them as
// index + end_trim*2^16 + start_trim*2^24; specials have to go in a separate table
typedef uint32 uval;
#define UVAL_DONT_CARE_DEFAULT 0xffffffff
typedef struct
{
uval *input;
uint32 dont_care;
uint32 fallback;
int fastpath;
int length;
int depth;
int has_sign;
int splittable;
int replace_fallback_with_codepoint;
size_t input_size;
size_t inherited_storage;
} table;
typedef struct
{
int split_log2;
table result; // index into not-returned table
int storage;
} output;
typedef struct
{
table t;
char **output_name;
} info;
typedef struct
{
size_t path;
size_t size;
} result;
typedef struct
{
uint8 trim_end;
uint8 trim_start;
uint8 special;
uint8 aligned;
uint8 indirect;
uint16 overhead; // add some forced overhead for each mode to avoid getting complex encoding when it doesn't save much
} mode_info;
mode_info modes[] =
{
{ 0,0,0,0,0, 32, },
{ 0,0,0,0,1, 100, },
{ 0,0,0,1,0, 32, },
{ 0,0,0,1,1, 100, },
{ 0,0,1,0,1, 100, },
{ 0,0,1,1,0, 32, },
{ 0,0,1,1,1, 200, },
{ 1,0,0,0,0, 100, },
{ 1,0,0,0,1, 120, },
{ 1,1,0,0,0, 100, },
{ 1,1,0,0,1, 130, },
{ 1,0,1,0,0, 130, },
{ 1,0,1,0,1, 180, },
{ 1,1,1,0,0, 180, },
{ 1,1,1,0,1, 200, },
};
#define MODECOUNT (sizeof(modes)/sizeof(modes[0]))
#define CLUSTERSIZECOUNT 6 // 8,16, 32,64, 128,256
size_t size_for_max_number(uint32 number)
{
if (number == 0) return 0;
if (number < 256) return 1;
if (number < 256*256) return 2;
if (number < 256*256*256) return 3;
return 4;
}
size_t size_for_max_number_aligned(uint32 number)
{
size_t n = size_for_max_number(number);
return n == 3 ? 4 : n;
}
uval get_data(uval *data, int offset, uval *end)
{
if (data + offset >= end)
return 0;
else
return data[offset];
}
int safe_len(uval *data, int len, uval *end)
{
if (len > end - data)
return end - data;
return len;
}
uval tempdata[256];
int dirty=0;
size_t find_packed(uval **packed, uval *data, int len, int aligned, int fastpath, uval *end, int offset, int replace)
{
int packlen = stb_arr_len(*packed);
int i,p;
if (data+len > end || replace) {
int safelen = safe_len(data, len, end);
memset(tempdata, 0, dirty*sizeof(tempdata[0]));
memcpy(tempdata, data, safelen * sizeof(data[0]));
data = tempdata;
dirty = len;
}
if (replace) {
int i;
int safelen = safe_len(data, len, end);
for (i=0; i < safelen; ++i)
if (data[i] == 0)
data[i] = offset+i;
}
if (len <= 0)
return 0;
if (!fastpath) {
if (aligned) {
for (i=0; i < packlen; i += len)
if ((*packed)[i] == data[0] && 0==memcmp(&(*packed)[i], data, len * sizeof(uval)))
return i / len;
} else {
for (i=0; i < packlen-len+1; i += 1 )
if ((*packed)[i] == data[0] && 0==memcmp(&(*packed)[i], data, len * sizeof(uval)))
return i;
}
}
p = stb_arr_len(*packed);
for (i=0; i < len; ++i)
stb_arr_push(*packed, data[i]);
return p;
}
void output_table(char *name1, char *name2, uval *data, int length, int sign, char **names)
{
char temp[20];
uval maxv = 0;
int bytes, numlen, at_newline;
int linelen = 79; // @TODO: make table more readable by choosing a length that's a multiple?
int i,pos, do_split=0;
for (i=0; i < length; ++i)
if (sign)
maxv = stb_max(maxv, (uval)abs((int)data[i]));
else
maxv = stb_max(maxv, data[i]);
bytes = size_for_max_number_aligned(maxv);
sprintf(temp, "%d", maxv);
numlen=strlen(temp);
if (sign)
++numlen;
if (bytes == 0)
return;
printf("uint%d %s%s[%d] = {\n", bytes*8, name1, name2, length);
at_newline = 1;
for (i=0; i < length; ++i) {
if (pos + numlen + 2 > linelen) {
printf("\n");
at_newline = 1;
pos = 0;
}
if (at_newline) {
printf(" ");
pos = 2;
at_newline = 0;
} else {
printf(" ");
++pos;
}
printf("%*d,", numlen, data[i]);
pos += numlen+1;
}
if (!at_newline) printf("\n");
printf("};\n");
}
void output_table_with_trims(char *name1, char *name2, uval *data, int length)
{
uval maxt=0, maxp=0;
int i,d,s,e, count;
// split the table into two pieces
uval *trims = NULL;
if (length == 0)
return;
for (i=0; i < stb_arr_len(data); ++i) {
stb_arr_push(trims, data[i] >> 16);
data[i] &= 0xffff;
maxt = stb_max(maxt, trims[i]);
maxp = stb_max(maxp, data[i]);
}
d=s=e=1;
if (maxt >= 256) {
// need to output start & end values
if (maxp >= 256) {
// can pack into a single table
printf("struct { uint16 val; uint8 start, end; } %s%s[%d] = {\n", name1, name2, length);
} else {
output_table(name1, name2, data, length, 0, 0);
d=0;
printf("struct { uint8 start, end; } %s%s_trim[%d] = {\n", name1, name2, length);
}
} else if (maxt > 0) {
if (maxp >= 256) {
output_table(name1, name2, data, length, 0, 0);
output_table(name1, stb_sprintf("%s_end", name2), trims, length, 0, 0);
return;
} else {
printf("struct { uint8 val, end; } %s%s[%d] = {\n", name1, name2, length);
s=0;
}
} else {
output_table(name1, name2, data, length, 0, 0);
return;
}
// d or s can be zero (but not both), e is always present and last
count = d + s + e;
assert(count >= 2 && count <= 3);
{
char temp[60];
uval maxv = 0;
int numlen, at_newline, len;
int linelen = 79; // @TODO: make table more readable by choosing a length that's a multiple?
int i,pos, do_split=0;
numlen = 0;
for (i=0; i < length; ++i) {
if (count == 2)
sprintf(temp, "{%d,%d}", d ? data[i] : (trims[i]>>8), trims[i]&255);
else
sprintf(temp, "{%d,%d,%d}", data[i], trims[i]>>8, trims[i]&255);
len = strlen(temp);
numlen = stb_max(len, numlen);
}
at_newline = 1;
for (i=0; i < length; ++i) {
if (pos + numlen + 2 > linelen) {
printf("\n");
at_newline = 1;
pos = 0;
}
if (at_newline) {
printf(" ");
pos = 2;
at_newline = 0;
} else {
printf(" ");
++pos;
}
if (count == 2)
sprintf(temp, "{%d,%d}", d ? data[i] : (trims[i]>>8), trims[i]&255);
else
sprintf(temp, "{%d,%d,%d}", data[i], trims[i]>>8, trims[i]&255);
printf("%*s,", numlen, temp);
pos += numlen+1;
}
if (!at_newline) printf("\n");
printf("};\n");
}
}
int weight=1;
table pack_for_mode(table *t, int mode, char *table_name)
{
size_t extra_size;
int i;
uval maxv;
mode_info mi = modes[mode % MODECOUNT];
int size = 8 << (mode / MODECOUNT);
table newtab;
uval *packed = NULL;
uval *index = NULL;
uval *indirect = NULL;
uval *specials = NULL;
newtab.dont_care = UVAL_DONT_CARE_DEFAULT;
if (table_name)
printf("// clusters of %d\n", size);
for (i=0; i < t->length; i += size) {
uval newval;
int fastpath = (i < t->fastpath);
if (mi.special) {
int end_trim = size-1;
int start_trim = 0;
uval special;
// @TODO: pick special from start or end instead of only end depending on which is longer
for(;;) {
special = t->input[i + end_trim];
if (special != t->dont_care || end_trim == 0)
break;
--end_trim;
}
// at this point, special==inp[end_trim], and end_trim >= 0
if (special == t->dont_care && !fastpath) {
// entire block is don't care, so OUTPUT don't care
stb_arr_push(index, newtab.dont_care);
continue;
} else {
uval pos, trim;
if (mi.trim_end && !fastpath) {
while (end_trim >= 0) {
if (t->input[i + end_trim] == special || t->input[i + end_trim] == t->dont_care)
--end_trim;
else
break;
}
}
if (mi.trim_start && !fastpath) {
while (start_trim < end_trim) {
if (t->input[i + start_trim] == special || t->input[i + start_trim] == t->dont_care)
++start_trim;
else
break;
}
}
// end_trim points to the last character we have to output
// find the first match, or add it
pos = find_packed(&packed, &t->input[i+start_trim], end_trim-start_trim+1, mi.aligned, fastpath, &t->input[t->length], i+start_trim, t->replace_fallback_with_codepoint);
// encode as a uval
if (!mi.trim_end) {
if (end_trim == 0)
pos = special;
else
pos = pos | 0x80000000;
} else {
assert(end_trim < size && end_trim >= -1);
if (!fastpath) assert(end_trim < size-1); // special always matches last one
assert(end_trim < size && end_trim+1 >= 0);
if (!fastpath) assert(end_trim+1 < size);
if (mi.trim_start)
trim = start_trim*256 + (end_trim+1);
else
trim = end_trim+1;
assert(pos < 65536); // @TODO: if this triggers, just bail on this search path
pos = pos + (trim << 16);
}
newval = pos;
stb_arr_push(specials, special);
}
} else if (mi.trim_end) {
int end_trim = size-1;
int start_trim = 0;
uval pos, trim;
while (end_trim >= 0 && !fastpath)
if (t->input[i + end_trim] == t->fallback || t->input[i + end_trim] == t->dont_care)
--end_trim;
else
break;
if (mi.trim_start && !fastpath) {
while (start_trim < end_trim) {
if (t->input[i + start_trim] == t->fallback || t->input[i + start_trim] == t->dont_care)
++start_trim;
else
break;
}
}
// end_trim points to the last character we have to output, and can be -1
++end_trim; // make exclusive at end
if (end_trim == 0 && size == 256)
start_trim = end_trim = 1; // we can't make encode a length from 0..256 in 8 bits, so restrict end_trim to 1..256
// find the first match, or add it
pos = find_packed(&packed, &t->input[i+start_trim], end_trim - start_trim, mi.aligned, fastpath, &t->input[t->length], i+start_trim, t->replace_fallback_with_codepoint);
assert(end_trim <= size && end_trim >= 0);
if (size == 256)
assert(end_trim-1 < 256 && end_trim-1 >= 0);
else
assert(end_trim < 256 && end_trim >= 0);
if (size == 256)
--end_trim;
if (mi.trim_start)
trim = start_trim*256 + end_trim;
else
trim = end_trim;
assert(pos < 65536); // @TODO: if this triggers, just bail on this search path
pos = pos + (trim << 16);
newval = pos;
} else {
newval = find_packed(&packed, &t->input[i], size, mi.aligned, fastpath, &t->input[t->length], i, t->replace_fallback_with_codepoint);
}
if (mi.indirect) {
int j;
for (j=0; j < stb_arr_len(indirect); ++j)
if (indirect[j] == newval)
break;
if (j == stb_arr_len(indirect))
stb_arr_push(indirect, newval);
stb_arr_push(index, j);
} else {
stb_arr_push(index, newval);
}
}
// total up the new size for everything but the index table
extra_size = mi.overhead * weight; // not the actual overhead cost; a penalty to avoid excessive complexity
extra_size += 150; // per indirection
if (table_name)
extra_size = 0;
if (t->has_sign) {
// 'packed' contains two values, which should be packed positive & negative for size
uval maxv2;
for (i=0; i < stb_arr_len(packed); ++i)
if (packed[i] & 0x80000000)
maxv2 = stb_max(maxv2, packed[i]);
else
maxv = stb_max(maxv, packed[i]);
maxv = stb_max(maxv, maxv2) << 1;
} else {
maxv = 0;
for (i=0; i < stb_arr_len(packed); ++i)
if (packed[i] > maxv && packed[i] != t->dont_care)
maxv = packed[i];
}
extra_size += stb_arr_len(packed) * (t->splittable ? size_for_max_number(maxv) : size_for_max_number_aligned(maxv));
if (table_name) {
if (t->splittable)
output_table_with_trims(table_name, "", packed, stb_arr_len(packed));
else
output_table(table_name, "", packed, stb_arr_len(packed), t->has_sign, NULL);
}
maxv = 0;
for (i=0; i < stb_arr_len(specials); ++i)
if (specials[i] > maxv)
maxv = specials[i];
extra_size += stb_arr_len(specials) * size_for_max_number_aligned(maxv);
if (table_name)
output_table(table_name, "_default", specials, stb_arr_len(specials), 0, NULL);
maxv = 0;
for (i=0; i < stb_arr_len(indirect); ++i)
if (indirect[i] > maxv)
maxv = indirect[i];
extra_size += stb_arr_len(indirect) * size_for_max_number(maxv);
if (table_name && stb_arr_len(indirect)) {
if (mi.trim_end)
output_table_with_trims(table_name, "_index", indirect, stb_arr_len(indirect));
else {
assert(0); // this case should only trigger in very extreme circumstances
output_table(table_name, "_index", indirect, stb_arr_len(indirect), 0, NULL);
}
mi.trim_end = mi.special = 0;
}
if (table_name)
printf("// above tables should be %d bytes\n", extra_size);
maxv = 0;
for (i=0; i < stb_arr_len(index); ++i)
if (index[i] > maxv && index[i] != t->dont_care)
maxv = index[i];
newtab.splittable = mi.trim_end;
newtab.input_size = newtab.splittable ? size_for_max_number(maxv) : size_for_max_number_aligned(maxv);
newtab.input = index;
newtab.length = stb_arr_len(index);
newtab.inherited_storage = t->inherited_storage + extra_size;
newtab.fastpath = 0;
newtab.depth = t->depth+1;
stb_arr_free(indirect);
stb_arr_free(packed);
stb_arr_free(specials);
return newtab;
}
result pack_table(table *t, size_t path, int min_storage)
{
int i;
result best;
best.size = t->inherited_storage + t->input_size * t->length;
best.path = path;
if ((int) t->inherited_storage > min_storage) {
best.size = stb_max(best.size, t->inherited_storage);
return best;
}
if (t->length <= 256 || t->depth >= 4) {
//printf("%08x: %7d\n", best.path, best.size);
return best;
}
path <<= 7;
for (i=0; i < MODECOUNT * CLUSTERSIZECOUNT; ++i) {
table newtab;
result r;
newtab = pack_for_mode(t, i, 0);
r = pack_table(&newtab, path+i+1, min_storage);
if (r.size < best.size)
best = r;
stb_arr_free(newtab.input);
//printf("Size: %6d + %6d\n", newtab.inherited_storage, newtab.input_size * newtab.length);
}
return best;
}
int pack_table_by_modes(table *t, int *modes)
{
table s = *t;
while (*modes > -1) {
table newtab;
newtab = pack_for_mode(&s, *modes, 0);
if (s.input != t->input)
stb_arr_free(s.input);
s = newtab;
++modes;
}
return s.inherited_storage + s.input_size * s.length;
}
int strip_table(table *t, int exceptions)
{
uval terminal_value;
int p = t->length-1;
while (t->input[p] == t->dont_care)
--p;
terminal_value = t->input[p];
while (p >= 0x10000) {
if (t->input[p] != terminal_value && t->input[p] != t->dont_care) {
if (exceptions)
--exceptions;
else
break;
}
--p;
}
return p+1; // p is a character we must output
}
void optimize_table(table *t, char *table_name)
{
int modelist[3] = { 85, -1 };
int modes[8];
int num_modes = 0;
int decent_size;
result r;
size_t path;
table s;
// strip tail end of table
int orig_length = t->length;
int threshhold = 0xffff;
int p = strip_table(t, 2);
int len_saved = t->length - p;
if (len_saved >= threshhold) {
t->length = p;
while (p > 0x10000) {
p = strip_table(t, 0);
len_saved = t->length - p;
if (len_saved < 0x10000)
break;
len_saved = orig_length - p;
if (len_saved < threshhold)
break;
threshhold *= 2;
}
}
t->depth = 1;
// find size of table if we use path 86
decent_size = pack_table_by_modes(t, modelist);
#if 1
// find best packing of remainder of table by exploring tree of packings
r = pack_table(t, 0, decent_size);
// use the computed 'path' to evaluate and output tree
path = r.path;
#else
path = 86;//90;//132097;
#endif
while (path) {
modes[num_modes++] = (path & 127) - 1;
path >>= 7;
}
printf("// modes: %d\n", r.path);
s = *t;
while (num_modes > 0) {
char name[256];
sprintf(name, "%s_%d", table_name, num_modes+1);
--num_modes;
s = pack_for_mode(&s, modes[num_modes], name);
}
// output the final table as-is
if (s.splittable)
output_table_with_trims(table_name, "_1", s.input, s.length);
else
output_table(table_name, "_1", s.input, s.length, 0, NULL);
}
uval unicode_table[0x110000];
typedef struct
{
uval lo,hi;
} char_range;
char_range get_range(char *str)
{
char_range cr;
char *p;
cr.lo = strtol(str, &p, 16);
p = stb_skipwhite(p);
if (*p == '.')
cr.hi = strtol(p+2, NULL, 16);
else
cr.hi = cr.lo;
return cr;
}
char *skip_semi(char *s, int count)
{
while (count) {
s = strchr(s, ';');
assert(s != NULL);
++s;
--count;
}
return s;
}
int main(int argc, char **argv)
{
table t;
uval maxv=0;
int i,n=0;
char **s = stb_stringfile("../../data/UnicodeData.txt", &n);
assert(s);
for (i=0; i < n; ++i) {
if (s[i][0] == '#' || s[i][0] == '\n' || s[i][0] == 0)
;
else {
char_range cr = get_range(s[i]);
char *t = skip_semi(s[i], 13);
uval j, v;
if (*t == ';' || *t == '\n' || *t == 0)
v = 0;
else {
v = strtol(t, NULL, 16);
if (v < 65536) {
maxv = stb_max(v, maxv);
for (j=cr.lo; j <= cr.hi; ++j) {
unicode_table[j] = v;
//printf("%06x => %06x\n", j, v);
}
}
}
}
}
t.depth = 0;
t.dont_care = UVAL_DONT_CARE_DEFAULT;
t.fallback = 0;
t.fastpath = 256;
t.inherited_storage = 0;
t.has_sign = 0;
t.splittable = 0;
t.input = unicode_table;
t.input_size = size_for_max_number(maxv);
t.length = 0x110000;
t.replace_fallback_with_codepoint = 1;
optimize_table(&t, "stbu_upppercase");
return 0;
}

88
tools/unicode/unicode.dsp Normal file
View File

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