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 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 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_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** | 2.06 | graphics | 6437 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **[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** | 1.06 | graphics | 2632 | parse, decode, and rasterize characters from truetype fonts **[stb_truetype.h](stb_truetype.h)** | 1.15 | graphics | 4061 | 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_write.h](stb_image_write.h)** | 1.05 | graphics | 1092 | image writing to disk: PNG, TGA, BMP
**stb_image_resize.h** | 0.90 | graphics | 2585 | resize images larger/smaller with good quality **[stb_image_resize.h](stb_image_resize.h)** | 0.94 | graphics | 2624 | resize images larger/smaller with good quality
**stb_rect_pack.h** | 0.06 | graphics | 560 | simple 2D rectangle packer with decent quality **[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 635 | 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_sprintf.h](stb_sprintf.h)** | 1.02 | utility | 1202 | fast sprintf, snprintf for C/C++
**stb_textedit.h** | 1.6 | UI | 1290 | guts of a text editor for games etc implementing them from scratch **[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_voxel_render.h** | 0.81 | 3D&nbsp;graphics | 3644 | Minecraft-esque voxel rendering "engine" with many more features **[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_dxt.h** | 1.04 | 3D&nbsp;graphics | 624 | Fabian "ryg" Giesen's real-time DXT compressor **[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D&nbsp;graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
**stb_perlin.h** | 0.2 | 3D&nbsp;graphics | 175 | revised Perlin noise (3D input, 1D output) **[stb_dxt.h](stb_dxt.h)** | 1.06 | 3D&nbsp;graphics | 687 | Fabian "ryg" Giesen's real-time DXT compressor
**stb_easy_font.h** | 0.5 | 3D&nbsp;graphics | 220 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc **[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D&nbsp;graphics | 316 | revised Perlin noise (3D input, 1D output)
**stb_tilemap_editor.h** | 0.35 | game&nbsp;dev | 4120 | embeddable tilemap editor **[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_herringbone_wa...** | 0.6 | game&nbsp;dev | 1217 | herringbone Wang tile map generator **[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game&nbsp;dev | 4172 | embeddable tilemap editor
**stb_c_lexer.h** | 0.06 | parsing | 809 | simplify writing parsers for C-like languages **[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.6 | game&nbsp;dev | 1220 | herringbone Wang tile map generator
**stb_divide.h** | 0.91 | math | 373 | more useful 32-bit modulus e.g. "euclidean divide" **[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages
**stb.h** | 2.24 | misc | 14086 | helper functions for C, mostly redundant in C++; basically author's personal stuff **[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide"
**stb_leakcheck.h** | 0.2 | misc | 117 | quick-and-dirty malloc/free leak-checking **[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 libraries: 20
Total lines of C code: 45274 Total lines of C code: 51304
FAQ FAQ
@ -35,15 +41,40 @@ FAQ
#### What's the license? #### What's the license?
These libraries are in the public domain (or the equivalent where that is not These libraries are in the public domain. You can do anything you
possible). You can do anything you want with them. You have no legal obligation want with them. You have no legal obligation
to do anything else, although I appreciate attribution. 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, Generally they're only better in that they're easier to integrate,
easier to use, and easier to release (single file; good API; no 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 and/or use more memory. If you're already using an equivalent
library, there's probably no good reason to switch. 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. #### 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, 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? #### Why "stb"? Is this something to do with Set-Top Boxes?
No, they are just the initials for my name, Sean T. Barrett. 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. 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 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 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 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. 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? #### 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 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, in the USA and some other locations. For that reason,
I recommend a declaration along these lines: I recommend a declaration along these lines:
// This software is in the public domain. Where that dedication is not // This software is dual-licensed to the public domain and under the following
// recognized, you are granted a perpetual, irrevocable license to copy // license: you are granted a perpetual, irrevocable license to copy, modify,
// and modify this file as you see fit. // publish, and distribute this file as you see fit.
I typically place this declaration at the end of the initial I typically place this declaration at the end of the initial
comment block of the file and just say 'public domain' 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, in the USA and some other locations. For that reason,
I recommend a declaration along these lines: I recommend a declaration along these lines:
// This software is in the public domain. Where that dedication is not // This software is dual-licensed to the public domain and under the following
// recognized, you are granted a perpetual, irrevocable license to copy // license: you are granted a perpetual, irrevocable license to copy, modify,
// and modify this file as you see fit. // publish, and distribute this file as you see fit.
I typically place this declaration at the end of the initial I typically place this declaration at the end of the initial
comment block of the file and just say 'public domain' 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 no warranty is offered or implied; use this code at your own risk
This is a single header file with a bunch of useful utilities This is a single header file with a bunch of useful utilities
@ -25,6 +25,11 @@
Version History 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.24 various warning & bugfixes
2.23 fix 2.22 2.23 fix 2.22
2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name 2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name
@ -166,6 +171,26 @@ Version History
(stb_array), (stb_arena) (stb_array), (stb_arena)
Parenthesized items have since been removed. 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 #ifndef STB__INCLUDE_STB_H
@ -186,10 +211,28 @@ Parenthesized items have since been removed.
#endif #endif
#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 <stdlib.h> // stdlib could have min/max
#include <stdio.h> // need FILE #include <stdio.h> // need FILE
#include <string.h> // stb_define_hash needs memcpy/memset #include <string.h> // stb_define_hash needs memcpy/memset
#include <time.h> // stb_dirtree #include <time.h> // stb_dirtree
#ifdef __MINGW32__
#include <fcntl.h> // O_RDWR
#endif
#ifdef STB_PERSONAL #ifdef STB_PERSONAL
typedef int Bool; 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, // add platform-specific ways of checking for sizeof(char*) == 8,
// and make those define STB_PTR64 // 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 #define STB_PTR64
#endif #endif
@ -682,20 +725,42 @@ STB_EXTERN char * stb_sstrdup(char *s);
STB_EXTERN void stbprint(const char *fmt, ...); STB_EXTERN void stbprint(const char *fmt, ...);
STB_EXTERN char *stb_sprintf(const char *fmt, ...); STB_EXTERN char *stb_sprintf(const char *fmt, ...);
STB_EXTERN char *stb_mprintf(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 #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, ...) char *stb_sprintf(const char *fmt, ...)
{ {
static char buffer[1024]; static char buffer[1024];
va_list v; va_list v;
va_start(v,fmt); va_start(v,fmt);
#ifdef _WIN32 stb_vsnprintf(buffer,1024,fmt,v);
_vsnprintf(buffer, 1024, fmt, v);
#else
vsnprintf(buffer, 1024, fmt, v);
#endif
va_end(v); va_end(v);
buffer[1023] = 0;
return buffer; return buffer;
} }
@ -704,13 +769,8 @@ char *stb_mprintf(const char *fmt, ...)
static char buffer[1024]; static char buffer[1024];
va_list v; va_list v;
va_start(v,fmt); va_start(v,fmt);
#ifdef _WIN32 stb_vsnprintf(buffer,1024,fmt,v);
_vsnprintf(buffer, 1024, fmt, v);
#else
vsnprintf(buffer, 1024, fmt, v);
#endif
va_end(v); va_end(v);
buffer[1023] = 0;
return strdup(buffer); return strdup(buffer);
} }
@ -810,9 +870,8 @@ void stbprint(const char *fmt, ...)
va_list v; va_list v;
va_start(v,fmt); va_start(v,fmt);
res = _vsnprintf(buffer, sizeof(buffer), fmt, v); res = stb_vsnprintf(buffer, sizeof(buffer), fmt, v);
va_end(v); va_end(v);
buffer[sizeof(buffer)-1] = 0;
if (res < 0) { if (res < 0) {
tbuf = (char *) malloc(16384); tbuf = (char *) malloc(16384);
@ -1021,9 +1080,15 @@ void stb_fatal(char *s, ...)
vfprintf(stderr, s, a); vfprintf(stderr, s, a);
va_end(a); va_end(a);
fputs("\n", stderr); fputs("\n", stderr);
#ifdef _WIN32
#ifdef STB_DEBUG #ifdef STB_DEBUG
#ifdef _MSC_VER
#ifndef STB_PTR64
__asm int 3; // trap to debugger! __asm int 3; // trap to debugger!
#else
__debugbreak();
#endif
#else
__builtin_trap();
#endif #endif
#endif #endif
exit(1); 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') // 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 // 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(push)
#pragma warning(disable: 4035) // disable warning about no return value #pragma warning(disable: 4035) // disable warning about no return value
int stb_log2_floor(unsigned int n) int stb_log2_floor(unsigned int n)
{ {
#if _MSC_VER > 1700 #if _MSC_VER > 1700
DWORD i; unsigned long i;
_BitScanReverse(&i, n); _BitScanReverse(&i, n);
return i != 0 ? i : -1; return i != 0 ? i : -1;
#else #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 char * stb_stristr(char *s, char *t);
STB_EXTERN int stb_prefix_count(char *s, char *t); STB_EXTERN int stb_prefix_count(char *s, char *t);
STB_EXTERN char * stb_plural(int n); // "s" or "" STB_EXTERN 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(char *src, char *delimit, int *count);
STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out); 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 #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) char *stb_plural(int n)
{ {
return n == 1 ? "" : "s"; 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) static void * stb__try_chunk(stb__chunk *c, int size, int align, int pre_align)
{ {
char *memblock = (char *) (c+1), *q; 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, // 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'. // 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_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) #define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature)
#else #else
#define stb_arr_check(a) 0 #define stb_arr_check(a) ((void) 0)
#define stb_arr_check2(a) 0 #define stb_arr_check2(a) ((void) 0)
#endif #endif
// ARRAY LENGTH // ARRAY LENGTH
@ -3023,7 +3101,7 @@ typedef struct
#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n)) #define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n))
// insert an element at i // 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' // 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)) #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); 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)); memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i));
} }
*pp = p; *pp = p;
@ -3219,7 +3297,7 @@ void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS)
{ {
void *p = *pp; void *p = *pp;
if (n) { 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; stb_arrhead2(p)->len -= n;
} }
*pp = p; *pp = p;
@ -3297,7 +3375,7 @@ unsigned int stb_hashptr(void *p)
unsigned int stb_rehash_improved(unsigned int v) 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) 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); fwrite(&x, 4, 1, f);
} }
#ifdef _MSC_VER #if defined(_MSC_VER) || defined(__MINGW32__)
#define stb__stat _stat #define stb__stat _stat
#else #else
#define stb__stat stat #define stb__stat stat
@ -5112,7 +5190,18 @@ int stb_filewrite(char *filename, void *data, size_t length)
{ {
FILE *f = stb_fopen(filename, "wb"); FILE *f = stb_fopen(filename, "wb");
if (f) { 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); stb_fclose(f, stb_keep_if_different);
} }
return f != NULL; return f != NULL;
@ -5389,7 +5478,11 @@ FILE * stb_fopen(char *filename, char *mode)
#else #else
{ {
strcpy(temp_full+p, "stmpXXXXXX"); 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; if (fd == -1) return NULL;
f = fdopen(fd, mode); f = fdopen(fd, mode);
if (f == NULL) { if (f == NULL) {
@ -5708,6 +5801,19 @@ char *stb_strip_final_slash(char *t)
} }
return 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 #endif
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -5820,42 +5926,57 @@ void stb_readdir_free(char **files)
stb_arr_free(f2); 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); STB_EXTERN int stb_wildmatchi(char *expr, char *candidate);
static char **readdir_raw(char *dir, int return_subdirs, char *mask) static char **readdir_raw(char *dir, int return_subdirs, char *mask)
{ {
char **results = NULL; char **results = NULL;
char buffer[512], with_slash[512]; char buffer[4096], with_slash[4096];
int n; size_t n;
#ifdef _MSC_VER #ifdef _MSC_VER
stb__wchar *ws; stb__wchar *ws;
struct _wfinddata_t data; struct _wfinddata_t data;
#ifdef _WIN64
const intptr_t none = -1;
intptr_t z;
#else
const long none = -1; const long none = -1;
long z; long z;
#else #endif
#else // !_MSC_VER
const DIR *none = NULL; const DIR *none = NULL;
DIR *z; DIR *z;
#endif #endif
strcpy(buffer,dir); n = stb_strscpy(buffer,dir,sizeof(buffer));
if (!n || n >= sizeof(buffer))
return NULL;
stb_fixpath(buffer); stb_fixpath(buffer);
n = strlen(buffer); n--;
if (n > 0 && (buffer[n-1] != '/')) { if (n > 0 && (buffer[n-1] != '/')) {
buffer[n++] = '/'; buffer[n++] = '/';
} }
buffer[n] = 0; buffer[n] = 0;
strcpy(with_slash, buffer); if (!stb_strscpy(with_slash,buffer,sizeof(with_slash)))
return NULL;
#ifdef _MSC_VER #ifdef _MSC_VER
strcpy(buffer+n, "*.*"); if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n))
return NULL;
ws = stb__from_utf8(buffer); ws = stb__from_utf8(buffer);
z = _wfindfirst((const wchar_t *)ws, &data); z = _wfindfirst((const wchar_t *)ws, &data);
#else #else
z = opendir(dir); z = opendir(dir);
#endif #endif
if (z != none) { if (z != none) {
int nonempty = STB_TRUE; int nonempty = STB_TRUE;
#ifndef _MSC_VER #ifndef _MSC_VER
@ -5876,17 +5997,18 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
is_subdir = !!(data.attrib & _A_SUBDIR); is_subdir = !!(data.attrib & _A_SUBDIR);
#else #else
char *name = data->d_name; char *name = data->d_name;
strcpy(buffer+n,name); if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n))
DIR *y = opendir(buffer); break;
is_subdir = (y != NULL); // Could follow DT_LNK, but would need to check for recursive links.
if (y != NULL) closedir(y); is_subdir = !!(data->d_type & DT_DIR);
#endif #endif
if (is_subdir == return_subdirs) { if (is_subdir == return_subdirs) {
if (!is_subdir || name[0] != '.') { if (!is_subdir || !isdotdirname(name)) {
if (!mask || stb_wildmatchi(mask, name)) { if (!mask || stb_wildmatchi(mask, name)) {
char buffer[512],*p=buffer; char buffer[4096],*p=buffer;
sprintf(buffer, "%s%s", with_slash, name); if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 )
break;
if (buffer[0] == '.' && buffer[1] == '/') if (buffer[0] == '.' && buffer[1] == '/')
p = buffer+2; p = buffer+2;
stb_arr_push(results, strdup(p)); stb_arr_push(results, strdup(p));
@ -6649,14 +6771,16 @@ typedef struct
char * path; // full path from passed-in root char * path; // full path from passed-in root
time_t last_modified; time_t last_modified;
int num_files; int num_files;
int flag;
} stb_dirtree_dir; } stb_dirtree_dir;
typedef struct typedef struct
{ {
char *name; // name relative to path char *name; // name relative to path
int dir; // index into dirs[] array int dir; // index into dirs[] array
unsigned long size; // size, max 4GB stb_int64 size; // size, max 4GB
time_t last_modified; time_t last_modified;
int flag;
} stb_dirtree_file; } stb_dirtree_file;
typedef struct 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 // do a call to stb_dirtree_get() with the same cache file at about the same
// time, but I _think_ it might just work. // 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 #ifdef STB_DEFINE
static void stb__dirtree_add_dir(char *path, time_t last, stb_dirtree *active) 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); 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; stb_dirtree_file f;
f.dir = dir; 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); 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) static void stb__dirtree_save_db(char *filename, stb_dirtree *data, char *root)
{ {
int i, num_dirs_final=0, num_files_final; int i, num_dirs_final=0, num_files_final;
char *info = root ? root : "";
int *remap; int *remap;
FILE *f = fopen(filename, "wb"); FILE *f = fopen(filename, "wb");
if (!f) return; if (!f) return;
fwrite(stb__signature, sizeof(stb__signature), 1, f); 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 // 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 // build remapping table of all dirs we'll be writing out
remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(data->dirs)); remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(data->dirs));
for (i=0; i < stb_arr_len(data->dirs); ++i) { 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; remap[i] = -1;
} else { } else {
remap[i] = num_dirs_final++; 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; num_files_final = 0;
for (i=0; i < stb_arr_len(data->files); ++i) 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; ++num_files_final;
fwrite(&num_files_final, 4, 1, f); fwrite(&num_files_final, 4, 1, f);
for (i=0; i < stb_arr_len(data->files); ++i) { 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_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); fwrite(&data->files[i].last_modified, 4, 1, f);
stb_fput_string(f, data->files[i].name); 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); stb_arr_setlen(data->files, n);
for (i=0; i < stb_arr_len(data->files); ++i) { 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].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); fread(&data->files[i].last_modified, 4, 1, f);
data->files[i].name = stb_fget_string(f, data->string_pool); data->files[i].name = stb_fget_string(f, data->string_pool);
if (data->files[i].name == NULL) goto bail; 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); 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) static void stb__dirtree_scandir(char *path, time_t last_time, stb_dirtree *active)
{ {
// this is dumb depth first; theoretically it might be faster // 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; int n;
struct _wfinddata_t c_file; struct _wfinddatai64_t c_file;
long hFile; long hFile;
stb__wchar full_path[1024]; stb__wchar full_path[1024];
int has_slash; int has_slash;
if (stb__showfile) printf("<");
has_slash = (path[0] && path[strlen(path)-1] == '/'); 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) if (has_slash)
swprintf((wchar_t *)full_path, L"%s*", stb__from_utf8(path)); swprintf(full_path, L"%s*", stb__from_utf8(path));
else 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 // 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 // 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) 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; return;
}
if (stb__showfile) printf("E");
// otherwise, we need to add it // otherwise, we need to add it
stb__dirtree_add_dir(path, last_time, active); stb__dirtree_add_dir(path, last_time, active);
n = stb_arr_lastn(active->dirs); 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 { do {
if (stb__showfile) printf(")");
if (c_file.attrib & _A_SUBDIR) { if (c_file.attrib & _A_SUBDIR) {
// ignore subdirectories starting with '.', e.g. "." and ".." // ignore subdirectories starting with '.', e.g. "." and ".."
if (c_file.name[0] != '.') { if (c_file.name[0] != '.') {
char *new_path = (char *) full_path; 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) if (has_slash)
sprintf(new_path, "%s%s", path, temp); sprintf(new_path, "%s%s", path, temp);
else else
sprintf(new_path, "%s/%s", path, temp); 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); stb__dirtree_scandir(new_path, c_file.time_write, active);
} }
} else { } 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); 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 ); _findclose( hFile );
} }
if (stb__showfile) printf(">\n");
} }
// scan the database and see if it's all valid // 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) { for (i=0; i < stb_arr_len(db->dirs); ++i) {
struct _stat info; 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 (0 == _stat(db->dirs[i].path, &info)) {
if (info.st_mode & _S_IFDIR) { if (info.st_mode & _S_IFDIR) {
// it's still a directory, as expected // 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 // it's changed! force a rescan
// we don't want to scan it until we've stat()d its // we don't want to scan it until we've stat()d its
// subdirs, though, so we queue it // 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); stb_arr_push(rescan, i);
// update the last_mod time // update the last_mod time
db->dirs[i].last_modified = info.st_mtime; 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) if (cache_file != NULL)
stb__dirtree_load_db(cache_file, &db, stripped_dir); stb__dirtree_load_db(cache_file, &db, stripped_dir);
else if (stb__showfile)
printf("No cache file\n");
active.files = NULL; active.files = NULL;
active.dirs = 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 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 // done with the DB; write it back out if any changes, i.e. either
// 1. any inconsistency found between cached information and actual disk // 1. any inconsistency found between cached information and actual disk
// or 2. if scanning the root found any new directories--which we detect because // 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); stb__dirtree_free_raw(d);
free(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 // STB_DEFINE
#endif // _WIN32 #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; // but some entries of the list may be invalid;
// test with 'stb_ps_fastlist_valid(x)' // 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 #ifdef STB_DEFINE
@ -7359,8 +7560,6 @@ typedef struct
#define GetBucket(p) ((stb_ps_bucket *) ((char *) (p) - STB_ps_bucket)) #define GetBucket(p) ((stb_ps_bucket *) ((char *) (p) - STB_ps_bucket))
#define EncodeBucket(p) ((stb_ps *) ((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) static void stb_bucket_free(stb_ps_bucket *b)
{ {
free(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) void ** stb_ps_getlist(stb_ps *ps, int *count)
{ {
int i,n=0; int i,n=0;
void **p; void **p = NULL;
switch (3 & (int) ps) { switch (3 & (int) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) { *count = 0; return NULL; } 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 == NULL) return NULL;
if (p[0] != 0x57 || p[1] != 0xBc || p[2] || p[3]) { free(p); 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); 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); *len = stb_decompress((unsigned char *) q, p, n);
if (*len) q[*len] = 0; if (*len) q[*len] = 0;
free(p); free(p);
@ -10407,15 +10606,15 @@ int stb_compress_intofile(FILE *f, char *input, unsigned int length)
////////////////////// streaming I/O version ///////////////////// ////////////////////// streaming I/O version /////////////////////
static stb_uint stb_out_backpatch_id(void) static size_t stb_out_backpatch_id(void)
{ {
if (stb__out) if (stb__out)
return (stb_uint) stb__out; return (size_t) stb__out;
else else
return ftell(stb__outfile); 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 }; stb_uchar data[4] = { value >> 24, value >> 16, value >> 8, value };
if (stb__out) { if (stb__out) {
@ -11107,7 +11306,7 @@ int stb_arith_decode_byte(stb_arith *a)
// Threads // Threads
// //
#ifndef WIN32 #ifndef _WIN32
#ifdef STB_THREADS #ifdef STB_THREADS
#error "threads not implemented except for Windows" #error "threads not implemented except for Windows"
#endif #endif
@ -14077,10 +14276,49 @@ void stua_run_script(char *s)
stua_gc(1); stua_gc(1);
} }
#endif // STB_DEFINE #endif // STB_DEFINE
#endif // STB_STUA #endif // STB_STUA
#undef STB_EXTERN #undef STB_EXTERN
#endif // STB_INCLUDE_STB_H #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 // lexer for making little C-like languages with recursive-descent parsers
// //
// This file provides both the interface and the implementation. // This file provides both the interface and the implementation.
@ -10,6 +10,9 @@
// suffixes on integer constants are not handled (you can override this). // suffixes on integer constants are not handled (you can override this).
// //
// History: // 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.06 fix missing next character after ending quote mark (Andreas Fredriksson)
// 0.05 refixed get_location because github version had lost the fix // 0.05 refixed get_location because github version had lost the fix
// 0.04 fix octal parsing bug // 0.04 fix octal parsing bug
@ -28,6 +31,14 @@
// - haven't implemented octal/hex character constants // - haven't implemented octal/hex character constants
// - haven't implemented support for unicode CLEX_char // - haven't implemented support for unicode CLEX_char
// - need to expand error reporting so you don't just get "CLEX_parse_error" // - 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 #ifndef STB_C_LEXER_DEFINITIONS
// to change the default parsing rules, copy the following lines // 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_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_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_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_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_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 #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 #define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess
// still have #line, #pragma, etc) // 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 #define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions
// --END-- // --END--
@ -164,11 +176,6 @@ extern void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where,
#define Y(x) 1 #define Y(x) 1
#define N(x) 0 #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) #if STB_C_LEX_INTEGERS_AS_DOUBLES(x)
typedef double stb__clex_int; typedef double stb__clex_int;
#define intfield real_number #define intfield real_number
@ -193,6 +200,10 @@ typedef long stb__clex_int;
#define STB__clex_define_shifts #define STB__clex_define_shifts
#endif #endif
#if STB_C_LEX_C99_HEX_FLOATS(x)
#define STB__clex_hex_floats
#endif
#if STB_C_LEX_C_HEX_INTS(x) #if STB_C_LEX_C_HEX_INTS(x)
#define STB__clex_hex_ints #define STB__clex_hex_ints
#endif #endif
@ -213,6 +224,11 @@ typedef long stb__clex_int;
#define STB__clex_discard_preprocessor #define STB__clex_discard_preprocessor
#endif #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 // Now pick a definition of Y/N that's conducive to
// defining the enum of token names. // defining the enum of token names.
#if STB_C_LEX_DEFINE_ALL_TOKEN_NAMES(x) || defined(STB_C_LEXER_SELF_TEST) #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 #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) static double stb__clex_parse_float(char *p, char **q)
{ {
char *s = p;
double value=0; double value=0;
while (*p >= '0' && *p <= '9') int base=10;
value = value*10 + (*p++ - '0'); int exponent=0;
if (*p == '.') {
double powten=1, addend = 0; #ifdef STB__clex_hex_floats
++p; if (*p == '0') {
while (*p >= '0' && *p <= '9') { if (p[1] == 'x' || p[1] == 'X') {
addend = addend + 10*(*p++ - '0'); base=16;
powten *= 10; 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 sign = p[1] == '-';
int exponent=0; unsigned int exponent=0;
double pow10=1; double power=1;
p += 1+sign; ++p;
if (*p == '-' || *p == '+')
++p;
while (*p >= '0' && *p <= '9') while (*p >= '0' && *p <= '9')
exponent = exponent*10 + (*p++ - '0'); exponent = exponent*10 + (*p++ - '0');
// can't use pow() from stdlib, so do it slow way
while (exponent-- > 0) #ifdef STB__clex_hex_floats
pow10 *= 10; if (base == 16)
if (sign) power = stb__clex_pow(2, exponent);
value /= pow10;
else else
value *= pow10; #endif
power = stb__clex_pow(10, exponent);
if (sign)
value /= power;
else
value *= power;
} }
*q = p; *q = p;
return value; return value;
@ -452,7 +529,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
int n; int n;
n = STB_C_LEX_ISWHITE(p); n = STB_C_LEX_ISWHITE(p);
if (n == 0) break; 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); return stb__clex_token(tok, CLEX_parse_error, p,lexer->eof-1);
p += n; p += n;
} }
@ -623,33 +700,57 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
goto single_char; goto single_char;
case '0': 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 != lexer->eof) {
if (p[1] == 'x' || p[1] == 'X') { if (p[1] == 'x' || p[1] == 'X') {
char *q = p+2; char *q;
#ifdef STB__CLEX_use_stdlib
lexer->int_number = strtol((char *) p, (char **) q, 16); #ifdef STB__clex_hex_floats
#else for (q=p+2;
stb__clex_int n=0; q != lexer->eof && ((*q >= '0' && *q <= '9') || (*q >= 'a' && *q <= 'f') || (*q >= 'A' && *q <= 'F'));
while (q != lexer->eof) { ++q);
if (*q >= '0' && *q <= '9') if (q != lexer->eof) {
n = n*16 + (*q - '0'); if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'p' || *q == 'P')) {
else if (*q >= 'a' && *q <= 'f') #ifdef STB__CLEX_use_stdlib
n = n*16 + (*q - 'a') + 10; lexer->real_number = strtod((char *) p, (char**) &q);
else if (*q >= 'A' && *q <= 'F') #else
n = n*16 + (*q - 'A') + 10; lexer->real_number = stb__clex_parse_float(p, &q);
else #endif
break;
++q; 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 #endif
if (q == p+2) if (q == p+2)
return stb__clex_token(lexer, CLEX_parse_error, p-2,p-1); 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); 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', // can't test for octal because we might parse '0.0' as float or as '0' '.' '0',
// so have to do float first // so have to do float first
@ -685,14 +786,14 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
stb__clex_int n=0; stb__clex_int n=0;
while (q != lexer->eof) { while (q != lexer->eof) {
if (*q >= '0' && *q <= '7') if (*q >= '0' && *q <= '7')
n = n*8 + (q - '0'); n = n*8 + (*q - '0');
else else
break; break;
++q; ++q;
} }
if (q != lexer->eof && (*q == '8' || *q=='9')) if (q != lexer->eof && (*q == '8' || *q=='9'))
return stb__clex_token(tok, CLEX_parse_error, p, q); return stb__clex_token(lexer, CLEX_parse_error, p, q);
lexer->int_field = n; lexer->int_number = n;
#endif #endif
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES); 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; stb__clex_int n=0;
while (q != lexer->eof) { while (q != lexer->eof) {
if (*q >= '0' && *q <= '9') if (*q >= '0' && *q <= '9')
n = n*10 + (q - '0'); n = n*10 + (*q - '0');
else else
break; break;
++q; ++q;
} }
lexer->int_field = n; lexer->int_number = n;
#endif #endif
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES); 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 #ifdef STB_C_LEXER_SELF_TEST
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
static void print_token(stb_lexer *lexer) static void print_token(stb_lexer *lexer)
{ {
@ -780,7 +882,15 @@ multiline comments */
void dummy(void) 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) int main(int argc, char **argv)
@ -791,11 +901,13 @@ int main(int argc, char **argv)
stb_lexer lex; stb_lexer lex;
if (len < 0) { if (len < 0) {
fprintf(stderr, "Error opening file\n"); fprintf(stderr, "Error opening file\n");
free(text);
fclose(f);
return 1; return 1;
} }
fclose(f); 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)) { while (stb_c_lexer_get_token(&lex)) {
if (lex.token == CLEX_parse_error) { if (lex.token == CLEX_parse_error) {
printf("\n<<<PARSE ERROR>>>\n"); printf("\n<<<PARSE ERROR>>>\n");
@ -807,3 +919,44 @@ int main(int argc, char **argv)
return 0; return 0;
} }
#endif #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 // 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. // always true. If any such platform turns up, we can add more cases.
// (Possibly only stb_div_trunc currently relies on property (b).) // (Possibly only stb_div_trunc currently relies on property (b).)
//
// LICENSE
//
// See end of file for license information.
#ifndef INCLUDE_STB_DIVIDE_H #ifndef INCLUDE_STB_DIVIDE_H
@ -371,3 +375,45 @@ int main(int argc, char **argv)
#endif // STB_DIVIDE_TEST #endif // STB_DIVIDE_TEST
#endif // STB_DIVIDE_IMPLEMENTATION #endif // STB_DIVIDE_IMPLEMENTATION
#endif // INCLUDE_STB_DIVIDE_H #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 // original by fabian "ryg" giesen - ported to C by stb
// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation // use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation
// //
@ -9,6 +9,8 @@
// and "high quality" using mode. // and "high quality" using mode.
// //
// version history: // 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); // 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); // single color match fix (allow for inexact color interpolation);
// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps. // optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps.
@ -16,6 +18,10 @@
// v1.02 - (stb) fix alpha encoding bug // v1.02 - (stb) fix alpha encoding bug
// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom // v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom
// v1.00 - (stb) first release // v1.00 - (stb) first release
//
// LICENSE
//
// See end of file for license information.
#ifndef STB_INCLUDE_STB_DXT_H #ifndef STB_INCLUDE_STB_DXT_H
#define 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_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. #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 #define STB_COMPRESS_DXT_BLOCK
#ifdef STB_DXT_IMPLEMENTATION #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) // 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; int i,dist,bias,dist4,dist2,bits,mask;
// find min/max color // find min/max color
int mn,mx; int mn,mx;
mn = mx = src[3]; mn = mx = src[0];
for (i=1;i<16;i++) for (i=1;i<16;i++)
{ {
if (src[i*4+3] < mn) mn = src[i*4+3]; if (src[i*stride] < mn) mn = src[i*stride];
else if (src[i*4+3] > mx) mx = src[i*4+3]; else if (src[i*stride] > mx) mx = src[i*stride];
} }
// encode them // encode them
@ -562,7 +578,7 @@ static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int m
bits = 0,mask=0; bits = 0,mask=0;
for (i=0;i<16;i++) { for (i=0;i<16;i++) {
int a = src[i*4+3]*7 + bias; int a = src[i*stride]*7 + bias;
int ind,t; int ind,t;
// select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max). // 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) { if (alpha) {
stb__CompressAlphaBlock(dest,(unsigned char*) src,mode); stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4);
dest += 8; dest += 8;
} }
stb__CompressColorBlock(dest,(unsigned char*) src,mode); 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 #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 // Sean Barrett, Feb 2015
// //
// Easy-to-deploy, // Easy-to-deploy,
@ -16,8 +16,10 @@
// DOCUMENTATION: // DOCUMENTATION:
// //
// int stb_easy_font_width(char *text) // 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, // int stb_easy_font_print(float x, float y,
// char *text, unsigned char color[4], // char *text, unsigned char color[4],
@ -40,7 +42,7 @@
// //
// You can ignore z and color if you get them from elsewhere // You can ignore z and color if you get them from elsewhere
// This format was chosen in the hopes it would make it // 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. // 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 // compact to me; -0.5 is a reasonable compromise as long as
// you're scaling the font up. // 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: // SAMPLE CODE:
// //
// Here's sample code for old OpenGL; it's a lot more complicated // Here's sample code for old OpenGL; it's a lot more complicated
// to make work on modern APIs, and that's your problem. // 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) void print_string(float x, float y, char *text, float r, float g, float b)
{ {
static char buffer[99999]; // ~500 chars 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 #define INCLUDE_STB_EASY_FONT_H
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
struct { struct stb_easy_font_info_struct {
unsigned char advance; unsigned char advance;
unsigned char h_seg; unsigned char h_seg;
unsigned char v_seg; unsigned char v_seg;
} stb_easy_font_charinfo[96] = { } 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 }, { 7, 3, 7 }, { 7, 6, 12 }, { 7, 8, 19 }, { 4, 16, 21 },
{ 4, 17, 22 }, { 4, 19, 23 }, { 23, 21, 24 }, { 23, 22, 31 }, { 4, 17, 22 }, { 4, 19, 23 }, { 23, 21, 24 }, { 23, 22, 31 },
{ 20, 23, 34 }, { 22, 23, 36 }, { 19, 24, 36 }, { 21, 25, 36 }, { 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 }, { 7,109,165 }, { 7,118,167 }, { 6,118,172 }, { 4,120,176 },
{ 6,122,177 }, { 4,122,181 }, { 23,124,182 }, { 22,129,182 }, { 6,122,177 }, { 4,122,181 }, { 23,124,182 }, { 22,129,182 },
{ 4,130,182 }, { 22,131,183 }, { 6,133,187 }, { 22,135,191 }, { 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 }, { 6,150,202 }, { 19,151,206 }, { 21,152,207 }, { 6,155,209 },
{ 3,160,210 }, { 23,160,211 }, { 22,164,216 }, { 22,165,220 }, { 3,160,210 }, { 23,160,211 }, { 22,164,216 }, { 22,165,220 },
{ 22,167,224 }, { 22,169,228 }, { 21,171,232 }, { 21,173,233 }, { 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) static int stb_easy_font_width(char *text)
{ {
float len = 0; float len = 0;
float max_len = 0;
while (*text) { while (*text) {
len += stb_easy_font_charinfo[*text-32].advance & 15; if (*text == '\n') {
len += stb_easy_font_spacing_val; 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; ++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 #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 /* stbhw - v0.6 - http://nothings.org/gamedev/herringbone
Herringbone Wang Tile Generator - Sean Barrett 2014 - public domain Herringbone Wang Tile Generator - Sean Barrett 2014 - public domain
This file is in the public domain. In case that declaration is ineffective, == LICENSE ==============================
you are also granted a license to use and modify it without restriction.
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 =========================== == 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 by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb http://github.com/nothings/stb
@ -107,8 +107,8 @@
industry, it is still uncommon in the videogame/real-time world. industry, it is still uncommon in the videogame/real-time world.
If you linearly filter non-premultiplied alpha, strange effects If you linearly filter non-premultiplied alpha, strange effects
occur. (For example, the average of 1% opaque bright green occur. (For example, the 50/50 average of 99% transparent bright green
and 99% opaque black produces 50% transparent dark green when and 1% transparent black produces 50% transparent dark green when
non-premultiplied, whereas premultiplied it produces 50% non-premultiplied, whereas premultiplied it produces 50%
transparent near-black. The former introduces green energy transparent near-black. The former introduces green energy
that doesn't exist in the source image.) that doesn't exist in the source image.)
@ -152,16 +152,20 @@
(For example, graphics hardware does not apply sRGB conversion (For example, graphics hardware does not apply sRGB conversion
to the alpha channel.) to the alpha channel.)
ADDITIONAL CONTRIBUTORS CONTRIBUTORS
Jorge L Rodriguez: Implementation
Sean Barrett: API design, optimizations Sean Barrett: API design, optimizations
Aras Pranckevicius: bugfix
REVISIONS 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 0.90 (2014-09-17) first released version
LICENSE LICENSE
This software is in the public domain. Where that dedication is not See end of file for license information.
recognized, you are granted a perpetual, irrevocable license to copy
and modify this file as you see fit.
TODO TODO
Don't decode all of the image data when only processing a partial tile 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) #define STBIR_ASSERT(x) assert(x)
#endif #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 // For memset
#include <string.h> #include <string.h>
@ -538,10 +533,11 @@ typedef struct
int horizontal_num_contributors; int horizontal_num_contributors;
int vertical_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_first_scanline;
int ring_buffer_last_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* ring_buffer;
float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. 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; int encode_buffer_size;
} stbir__info; } 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) static stbir__inline int stbir__min(int a, int b)
{ {
return a < b ? a : 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) static stbir__inline float stbir__saturate(float x)
{ {
if (x < 0) if (x < 0)
@ -757,7 +754,7 @@ static float stbir__filter_trapezoid(float x, float scale)
{ {
float halfscale = scale / 2; float halfscale = scale / 2;
float t = 0.5f + halfscale; float t = 0.5f + halfscale;
STBIR__DEBUG_ASSERT(scale <= 1); STBIR_ASSERT(scale <= 1);
x = (float)fabs(x); x = (float)fabs(x);
@ -775,7 +772,7 @@ static float stbir__filter_trapezoid(float x, float scale)
static float stbir__support_trapezoid(float scale) static float stbir__support_trapezoid(float scale)
{ {
STBIR__DEBUG_ASSERT(scale <= 1); STBIR_ASSERT(scale <= 1);
return 0.5f + scale / 2; 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 return n; // NOTREACHED
default: default:
STBIR__UNIMPLEMENTED("Unimplemented edge type"); STBIR_ASSERT(!"Unimplemented edge type");
return 0; 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)); *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; int i;
float total_filter = 0; float total_filter = 0;
float filter_scale; 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->n0 = in_first_pixel;
contributor->n1 = in_last_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++) 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]; 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_ASSERT(total_filter > 0.9);
STBIR__DEBUG_ASSERT(total_filter < 1.1f); // Make sure it's not way off. STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
// Make sure the sum of all coefficients is 1. // Make sure the sum of all coefficients is 1.
filter_scale = 1 / total_filter; 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; 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->n0 = out_first_pixel;
contributor->n1 = out_last_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++) 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; 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--) 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_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); 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; break;
} }
STBIR__DEBUG_ASSERT(total > 0.9f); STBIR_ASSERT(total > 0.9f);
STBIR__DEBUG_ASSERT(total < 1.1f); STBIR_ASSERT(total < 1.1f);
scale = 1 / total; 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 // 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. // 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 n;
int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); 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_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 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_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 type = stbir_info->type;
int colorspace = stbir_info->colorspace; int colorspace = stbir_info->colorspace;
int input_w = stbir_info->input_w; 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); float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir_edge edge_horizontal = stbir_info->edge_horizontal; stbir_edge edge_horizontal = stbir_info->edge_horizontal;
stbir_edge edge_vertical = stbir_info->edge_vertical; 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; 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 max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
int decode = STBIR__DECODE(type, colorspace); 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 decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) 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; 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]]; 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)) 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; break;
@ -1298,7 +1295,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) 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; break;
@ -1308,10 +1305,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) 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)) 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; break;
@ -1321,7 +1318,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) 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; break;
@ -1331,10 +1328,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int decode_pixel_index = x * channels; int decode_pixel_index = x * channels;
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
for (c = 0; c < channels; c++) 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)) 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; break;
@ -1363,7 +1360,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
break; break;
default: default:
STBIR__UNIMPLEMENTED("Unknown type/colorspace/channels combination."); STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
break; break;
} }
@ -1416,6 +1413,8 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
int ring_buffer_index; int ring_buffer_index;
float* ring_buffer; float* ring_buffer;
stbir_info->ring_buffer_last_scanline = n;
if (stbir_info->ring_buffer_begin_index < 0) if (stbir_info->ring_buffer_begin_index < 0)
{ {
ring_buffer_index = 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 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; 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__DEBUG_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); 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)); 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); memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
stbir_info->ring_buffer_last_scanline = n;
return ring_buffer; 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 x, k;
int output_w = stbir_info->output_w; int output_w = stbir_info->output_w;
int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
int channels = stbir_info->channels; int channels = stbir_info->channels;
float* decode_buffer = stbir__get_decode_buffer(stbir_info); float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; 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_group = coefficient_width * x;
int coefficient_counter = 0; int coefficient_counter = 0;
STBIR__DEBUG_ASSERT(n1 >= n0); STBIR_ASSERT(n1 >= n0);
STBIR__DEBUG_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
STBIR__DEBUG_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
STBIR__DEBUG_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); STBIR_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 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
switch (channels) { switch (channels) {
case 1: case 1:
@ -1468,7 +1464,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
{ {
int in_pixel_index = k * 1; int in_pixel_index = k * 1;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; 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 + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
} }
break; break;
@ -1477,7 +1473,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
{ {
int in_pixel_index = k * 2; int in_pixel_index = k * 2;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; 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 + 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 + 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; int in_pixel_index = k * 3;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; 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 + 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 + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * 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; int in_pixel_index = k * 4;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; 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 + 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 + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * 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; int in_pixel_index = k * channels;
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
int c; int c;
STBIR__DEBUG_ASSERT(coefficient != 0); STBIR_ASSERT(coefficient != 0);
for (c = 0; c < channels; c++) for (c = 0; c < channels; c++)
output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; 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 x, k;
int input_w = stbir_info->input_w; 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; int channels = stbir_info->channels;
float* decode_buffer = stbir__get_decode_buffer(stbir_info); float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; 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 filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
int max_x = input_w + filter_pixel_margin * 2; 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) { switch (channels) {
case 1: case 1:
@ -1552,7 +1546,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
{ {
int out_pixel_index = k * 1; int out_pixel_index = k * 1;
float coefficient = horizontal_coefficients[coefficient_group + k - n0]; 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 + 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; int out_pixel_index = k * 2;
float coefficient = horizontal_coefficients[coefficient_group + k - n0]; 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 + 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 + 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; int out_pixel_index = k * 3;
float coefficient = horizontal_coefficients[coefficient_group + k - n0]; 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 + 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 + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * 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; int out_pixel_index = k * 4;
float coefficient = horizontal_coefficients[coefficient_group + k - n0]; 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 + 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 + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * 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 c;
int out_pixel_index = k * channels; int out_pixel_index = k * channels;
float coefficient = horizontal_coefficients[coefficient_group + k - n0]; float coefficient = horizontal_coefficients[coefficient_group + k - n0];
STBIR__DEBUG_ASSERT(coefficient != 0); STBIR_ASSERT(coefficient != 0);
for (c = 0; c < channels; c++) for (c = 0; c < channels; c++)
output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; 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. // Now resample it into the ring buffer.
if (stbir__use_width_upsampling(stbir_info)) 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 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. // 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. // Now resample it into the horizontal buffer.
if (stbir__use_width_upsampling(stbir_info)) 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 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. // 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. // 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); 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 // build a table of all channels that need colorspace correction, so
// we don't perform colorspace correction on channels that don't need it. // 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)) 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_INT(f) ((int) ((f)+0.5))
#define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
#ifdef STBIR__SATURATE_INT #ifdef STBIR__SATURATE_INT
#define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * 255 )) #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) * 65535)) #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
#else #else
#define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * 255 ) #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) * 65535) #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
#endif #endif
switch (decode) 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++) for (n = 0; n < num_nonalpha; n++)
{ {
int index = pixel_index + 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)) 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++) for (n = 0; n < channels; n++)
{ {
int index = pixel_index + 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; 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++) for (n = 0; n < num_nonalpha; n++)
{ {
int index = pixel_index + 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)) 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; break;
@ -1855,12 +1853,12 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
break; break;
default: default:
STBIR__UNIMPLEMENTED("Unknown type/colorspace/channels combination."); STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
break; 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 x, k;
int output_w = stbir_info->output_w; 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 alpha_channel = stbir_info->alpha_channel;
int type = stbir_info->type; int type = stbir_info->type;
int colorspace = stbir_info->colorspace; 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; void* output_data = stbir_info->output_data;
float* encode_buffer = stbir_info->encode_buffer; float* encode_buffer = stbir_info->encode_buffer;
int decode = STBIR__DECODE(type, colorspace); 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; float* ring_buffer = stbir_info->ring_buffer;
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; 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_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 ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
int n0,n1, output_row_start; 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; 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); 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++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; 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]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) 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++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; 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]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) 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++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; 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]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) 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++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; 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]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) 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++) for (k = n0; k <= n1; k++)
{ {
int coefficient_index = coefficient_counter++; 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]; float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x) 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); 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 x, k;
int output_w = stbir_info->output_w; int output_w = stbir_info->output_w;
int output_h = stbir_info->output_h;
stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
float* vertical_coefficients = stbir_info->vertical_coefficients; float* vertical_coefficients = stbir_info->vertical_coefficients;
int channels = stbir_info->channels; int channels = stbir_info->channels;
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* horizontal_buffer = stbir_info->horizontal_buffer; float* horizontal_buffer = stbir_info->horizontal_buffer;
int coefficient_width = stbir_info->vertical_coefficient_width; int coefficient_width = stbir_info->vertical_coefficient_width;
int contributor = n + stbir_info->vertical_filter_pixel_margin; 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; float* ring_buffer = stbir_info->ring_buffer;
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; 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_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 ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
int n0,n1; int n0,n1;
n0 = vertical_contributors[contributor].n0; n0 = vertical_contributors[contributor].n0;
n1 = vertical_contributors[contributor].n1; 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++) 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; int coefficient_group = coefficient_width * contributor;
float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; 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) { switch (channels) {
case 1: case 1:
@ -2067,7 +2061,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
float scale_ratio = stbir_info->vertical_scale; 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; 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++) 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__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) if (stbir_info->ring_buffer_begin_index >= 0)
{ {
@ -2095,7 +2089,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
else else
{ {
stbir_info->ring_buffer_first_scanline++; 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); 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. // 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); 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 else
{ {
stbir_info->ring_buffer_first_scanline++; 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 pixel_margin = stbir_info->vertical_filter_pixel_margin;
int max_y = stbir_info->input_h + 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++) 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__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) if (out_last_scanline < 0 || out_first_scanline >= output_h)
continue; 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); 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. // 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); 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->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
info->horizontal_shift = s0 * info->input_w / (s1 - s0); info->horizontal_shift = s0 * info->output_w / (s1 - s0);
info->vertical_shift = t0 * info->input_h / (t1 - t0); 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->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); 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_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); 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_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); 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->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->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); info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
STBIR_ASSERT(info->horizontal_filter != 0); 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->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_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 else
{ {
@ -2387,7 +2384,7 @@ static int stbir__resize_allocated(stbir__info *info,
info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
info->encode_buffer = NULL; 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 #undef STBIR__NEXT_MEMPTR
@ -2395,8 +2392,8 @@ static int stbir__resize_allocated(stbir__info *info,
// This signals that the ring buffer is empty // This signals that the ring buffer is empty
info->ring_buffer_begin_index = -1; 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->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->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
STBIR_PROGRESS_REPORT(0); STBIR_PROGRESS_REPORT(0);
@ -2408,10 +2405,10 @@ static int stbir__resize_allocated(stbir__info *info,
STBIR_PROGRESS_REPORT(1); STBIR_PROGRESS_REPORT(1);
#ifdef STBIR_DEBUG_OVERWRITE_TEST #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_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_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_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_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
#endif #endif
return 1; return 1;
@ -2583,3 +2580,45 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
} }
#endif // STB_IMAGE_RESIZE_IMPLEMENTATION #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 /* 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 writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
Before #including, Before #including,
@ -18,7 +17,7 @@ ABOUT:
The PNG output is not optimal; it is 20-50% larger than the file The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed written by a decent optimizing implementation. 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. or run-time performance.
BUILDING: 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_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const 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. 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 data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels. 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: CREDITS:
PNG/BMP/TGA PNG/BMP/TGA
@ -73,8 +90,26 @@ CREDITS:
Jean-Sebastien Guay Jean-Sebastien Guay
misc enhancements: misc enhancements:
Tim Kelsey Tim Kelsey
TGA RLE
Alan Hickman
initial file IO callback implementation
Emmanuel Julien
bugfixes: bugfixes:
github:Chribba 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 #ifndef INCLUDE_STB_IMAGE_WRITE_H
@ -84,10 +119,26 @@ CREDITS:
extern "C" { extern "C" {
#endif #endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); #ifdef STB_IMAGE_WRITE_STATIC
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); #define STBIWDEF static
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); #else
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); #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 #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 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 <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <math.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 // 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 // ok
#else #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 #endif
#ifndef STBIW_MALLOC #ifndef STBIW_MALLOC
#define STBIW_MALLOC(sz) malloc(sz) #define STBIW_MALLOC(sz) malloc(sz)
#define STBIW_REALLOC(p,sz) realloc(p,sz) #define STBIW_REALLOC(p,newsz) realloc(p,newsz)
#define STBIW_FREE(p) free(p) #define STBIW_FREE(p) free(p)
#endif #endif
#ifndef STBIW_REALLOC_SIZED
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
#endif
#ifndef STBIW_MEMMOVE #ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif #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) #define STBIW_ASSERT(x) assert(x)
#endif #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 unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
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) { while (*fmt) {
switch (*fmt++) { switch (*fmt++) {
case ' ': break; case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; } case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
case '2': { int x = va_arg(v,int); unsigned char b[2]; s->func(s->context,&x,1);
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8); break; }
fwrite(b,2,1,f); break; } case '2': { int x = va_arg(v,int);
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4]; unsigned char b[2];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8); b[0] = STBIW_UCHAR(x);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24); b[1] = STBIW_UCHAR(x>>8);
fwrite(b,4,1,f); break; } 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: default:
STBIW_ASSERT(0); STBIW_ASSERT(0);
return; 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]; unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c; 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]; 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; stbiw_uint32 zero = 0;
int i,j,k, j_end; int i,j, j_end;
if (y <= 0) if (y <= 0)
return; 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 (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) { for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp; unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0) stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
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);
} }
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) {
if (y < 0 || x < 0) return 0; return 0;
f = fopen(filename, "wb"); } else {
if (f) {
va_list v; va_list v;
va_start(v, fmt); va_start(v, fmt);
writefv(f, fmt, v); stbiw__writefv(s, fmt, v);
va_end(v); va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono); stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
fclose(f); 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; 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", "11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header '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 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 has_alpha = (comp == 2 || comp == 4);
int colorbytes = has_alpha ? comp-1 : comp; 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 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 // Radiance RGBE HDR writer
// by Baldur Karlsson // by Baldur Karlsson
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) #define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) 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; int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); 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; rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else { } else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; 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); STBIW_ASSERT(length+128 <= 255);
fwrite(&lengthbyte, 1, 1, f); s->func(s->context, &lengthbyte, 1);
fwrite(&databyte, 1, 1, f); 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 STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
fwrite(&lengthbyte, 1, 1, f); s->func(s->context, &lengthbyte, 1);
fwrite(data, length, 1, f); 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 scanlineheader[4] = { 2, 2, 0, 0 };
unsigned char rgbe[4]; 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 */ /* skip RLE for images too small or large */
if (width < 8 || width >= 32768) { if (width < 8 || width >= 32768) {
for (x=0; x < width; x++) { for (x=0; x < width; x++) {
switch (comp) { switch (ncomp) {
case 4: /* fallthrough */ case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2]; case 3: linear[2] = scanline[x*ncomp + 2];
linear[1] = scanline[x*comp + 1]; linear[1] = scanline[x*ncomp + 1];
linear[0] = scanline[x*comp + 0]; linear[0] = scanline[x*ncomp + 0];
break; break;
case 2: /* fallthrough */ default:
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0]; linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
break; break;
} }
stbiw__linear_to_rgbe(rgbe, linear); stbiw__linear_to_rgbe(rgbe, linear);
fwrite(rgbe, 4, 1, f); s->func(s->context, rgbe, 4);
} }
} else { } else {
int c,r; int c,r;
/* encode into scratch buffer */ /* encode into scratch buffer */
for (x=0; x < width; x++) { for (x=0; x < width; x++) {
switch(comp) { switch(ncomp) {
case 4: /* fallthrough */ case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2]; case 3: linear[2] = scanline[x*ncomp + 2];
linear[1] = scanline[x*comp + 1]; linear[1] = scanline[x*ncomp + 1];
linear[0] = scanline[x*comp + 0]; linear[0] = scanline[x*ncomp + 0];
break; break;
case 2: /* fallthrough */ default:
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0]; linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
break; break;
} }
stbiw__linear_to_rgbe(rgbe, linear); 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]; scratch[x + width*3] = rgbe[3];
} }
fwrite(scanlineheader, 4, 1, f); s->func(s->context, scanlineheader, 4);
/* RLE each component separately */ /* RLE each component separately */
for (c=0; c < 4; c++) { 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) { while (x < r) {
int len = r-x; int len = r-x;
if (len > 128) len = 128; if (len > 128) len = 128;
stbiw__write_dump_data(f, len, &comp[x]); stbiw__write_dump_data(s, len, &comp[x]);
x += len; x += len;
} }
// if there's a run, output it // 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) { while (x < r) {
int len = r-x; int len = r-x;
if (len > 127) len = 127; if (len > 127) len = 127;
stbiw__write_run_data(f, len, comp[x]); stbiw__write_run_data(s, len, comp[x]);
x += len; 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; if (y <= 0 || x <= 0 || data == NULL)
FILE *f; return 0;
if (y <= 0 || x <= 0 || data == NULL) return 0; else {
f = fopen(filename, "wb"); // Each component is stored separately. Allocate scratch space for full output scanline.
if (f) {
/* Each component is stored separately. Allocate scratch space for full output scanline. */
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); 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" ); int i, len;
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x); 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++) 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); STBIW_FREE(scratch);
fclose(f); return 1;
} }
return f != NULL;
} }
///////////////////////////////////////////////////////// int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
// PNG {
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() // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2) #define stbiw__sbraw(a) ((int *) (a) - 2)
@ -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) static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
{ {
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; 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); STBIW_ASSERT(p);
if (p) { if (p) {
if (!*arr) ((int *) p)[1] = 0; 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) static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{ {
while (*bitcount >= 8) { while (*bitcount >= 8) {
stbiw__sbpush(data, (unsigned char) *bitbuffer); stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
*bitbuffer >>= 8; *bitbuffer >>= 8;
*bitcount -= 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; unsigned int bitbuf=0;
int i,j, bitcount=0; int i,j, bitcount=0;
unsigned char *out = NULL; 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; if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window 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) for (i=0; i < stbiw__ZHASH; ++i)
(void) stbiw__sbfree(hash_table[i]); (void) stbiw__sbfree(hash_table[i]);
STBIW_FREE(hash_table);
{ {
// compute adler32 on input // compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552; unsigned int s1=1, s2=0;
int j=0; int blocklen = (int) (data_len % 5552);
j=0;
while (j < data_len) { while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521; s1 %= 65521, s2 %= 65521;
j += blocklen; j += blocklen;
blocklen = 5552; blocklen = 5552;
} }
stbiw__sbpush(out, (unsigned char) (s2 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
stbiw__sbpush(out, (unsigned char) s2); stbiw__sbpush(out, STBIW_UCHAR(s2));
stbiw__sbpush(out, (unsigned char) (s1 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
stbiw__sbpush(out, (unsigned char) s1); stbiw__sbpush(out, STBIW_UCHAR(s1));
} }
*out_len = stbiw__sbn(out); *out_len = stbiw__sbn(out);
// make returned pointer freeable // 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); 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; unsigned int crc = ~0u;
int i,j; int i;
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);
for (i=0; i < len; ++i) for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc; 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__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]) #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) 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); 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 (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
if (pb <= pc) return (unsigned char) b; if (pb <= pc) return STBIW_UCHAR(b);
return (unsigned char) c; 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) 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 }; 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) { for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 }; static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 }; static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap; int *mymap = (j != 0) ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff; int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) { 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; int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j; unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i) 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, x);
stbiw__wp32(o, y); stbiw__wp32(o, y);
*o++ = 8; *o++ = 8;
*o++ = (unsigned char) ctype[n]; *o++ = STBIW_UCHAR(ctype[n]);
*o++ = 0; *o++ = 0;
*o++ = 0; *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; 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; FILE *f;
int len; int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0; if (png == NULL) return 0;
f = fopen(filename, "wb"); f = fopen(filename, "wb");
if (!f) { STBIW_FREE(png); return 0; } if (!f) { STBIW_FREE(png); return 0; }
fwrite(png, 1, len, f); 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); STBIW_FREE(png);
return 1; 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 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* 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) 0.98 (2015-04-08)
added STBIW_MALLOC, STBIW_ASSERT etc added STBIW_MALLOC, STBIW_ASSERT etc
0.97 (2015-01-18) 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 first public release
0.90 first internal 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 #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 // if we've already included leakcheck before, undefine the macros
#ifdef malloc #ifdef malloc
@ -10,6 +13,8 @@
#undef realloc #undef realloc
#endif #endif
#include <assert.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stddef.h> #include <stddef.h>
@ -88,14 +93,14 @@ void stb_leakcheck_dumpmem(void)
stb_leakcheck_malloc_info *mi = mi_head; stb_leakcheck_malloc_info *mi = mi_head;
while (mi) { while (mi) {
if ((ptrdiff_t) mi->size >= 0) if ((ptrdiff_t) mi->size >= 0)
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; mi = mi->next;
} }
#ifdef STB_LEAKCHECK_SHOWALL #ifdef STB_LEAKCHECK_SHOWALL
mi = mi_head; mi = mi_head;
while (mi) { while (mi) {
if ((ptrdiff_t) mi->size < 0) 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; mi = mi->next;
} }
#endif #endif
@ -115,3 +120,46 @@ extern void stb_leakcheck_free(void *ptr);
extern void stb_leakcheck_dumpmem(void); extern void stb_leakcheck_dumpmem(void);
#endif // INCLUDE_STB_LEAKCHECK_H #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 // public domain single-file C implementation by Sean Barrett
// //
// LICENSE
//
// See end of file.
//
//
// to create the implementation, // to create the implementation,
// #define STB_PERLIN_IMPLEMENTATION // #define STB_PERLIN_IMPLEMENTATION
// in *one* C/CPP file that includes this file. // in *one* C/CPP file that includes this file.
//
//
// Documentation: // Documentation:
// //
// float stb_perlin_noise3( float x, // float stb_perlin_noise3( float x,
@ -26,22 +31,55 @@
// 0 to mean "don't care". (The noise always wraps every 256 due // 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 // details of the implementation, even if you ask for larger or no
// wrapping.) // 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 #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); extern "C" {
#else #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_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 #endif
#ifdef STB_PERLIN_IMPLEMENTATION #ifdef STB_PERLIN_IMPLEMENTATION
#include <math.h> // floor()
// not same permutation table as Perlin's reference to avoid copyright issues; // 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/ // Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
// @OPTIMIZE: should this be unsigned char instead of int for cache? // @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, 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, 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; 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 // 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) 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 // 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 // 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] = static unsigned char indices[64] =
{ {
0,1,2,3,4,5,6,7,8,9,10,11, 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 // 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]]; float *grad = basis[indices[hash & 63]];
return grad[0]*x + grad[1]*y + grad[2]*z; 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 x_mask = (x_wrap-1) & 255;
unsigned int y_mask = (y_wrap-1) & 255; unsigned int y_mask = (y_wrap-1) & 255;
unsigned int z_mask = (z_wrap-1) & 255; unsigned int z_mask = (z_wrap-1) & 255;
int px = (int) floor(x); int px = stb__perlin_fastfloor(x);
int py = (int) floor(y); int py = stb__perlin_fastfloor(y);
int pz = (int) floor(z); int pz = stb__perlin_fastfloor(z);
int x0 = px & x_mask, x1 = (px+1) & x_mask; int x0 = px & x_mask, x1 = (px+1) & x_mask;
int y0 = py & y_mask, y1 = (py+1) & y_mask; int y0 = py & y_mask, y1 = (py+1) & y_mask;
int z0 = pz & z_mask, z1 = (pz+1) & z_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); 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 #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 // Sean Barrett 2014
// //
// Useful for e.g. packing rectangular textures into an atlas. // Useful for e.g. packing rectangular textures into an atlas.
@ -27,15 +27,26 @@
// Sean Barrett // Sean Barrett
// Minor features // Minor features
// Martins Mozeiko // Martins Mozeiko
// github:IntellectualKitty
//
// Bugfixes / warning fixes // Bugfixes / warning fixes
// [your name could be here] // Jeremy Jaussaud
// //
// Version history: // 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.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert // 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support // 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release // 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; typedef unsigned short stbrp_coord;
#endif #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 // Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there // 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them. // 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 // arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is // a single time with the full rectangle array, but the option is
// available. // available.
//
// The function returns 1 if all of the rectangles were successfully
// packed and 0 otherwise.
struct stbrp_rect struct stbrp_rect
{ {
@ -140,7 +154,7 @@ enum
{ {
STBRP_HEURISTIC_Skyline_default=0, STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 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 #define STBRP_ASSERT assert
#endif #endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#endif
enum enum
{ {
STBRP__INIT_skyline = 1, STBRP__INIT_skyline = 1
}; };
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 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; stbrp_node *node = first;
int x1 = x0 + width; int x1 = x0 + width;
int min_y, visited_width, waste_area; int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0); STBRP_ASSERT(first->x <= x0);
#if 0 #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) static int rect_height_compare(const void *a, const void *b)
{ {
stbrp_rect *p = (stbrp_rect *) a; const stbrp_rect *p = (const stbrp_rect *) a;
stbrp_rect *q = (stbrp_rect *) b; const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h) if (p->h > q->h)
return -1; return -1;
if (p->h < q->h) 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) static int rect_width_compare(const void *a, const void *b)
{ {
stbrp_rect *p = (stbrp_rect *) a; const stbrp_rect *p = (const stbrp_rect *) a;
stbrp_rect *q = (stbrp_rect *) b; const stbrp_rect *q = (const stbrp_rect *) b;
if (p->w > q->w) if (p->w > q->w)
return -1; return -1;
if (p->w < q->w) 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) static int rect_original_order(const void *a, const void *b)
{ {
stbrp_rect *p = (stbrp_rect *) a; const stbrp_rect *p = (const stbrp_rect *) a;
stbrp_rect *q = (stbrp_rect *) b; const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 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 #define STBRP__MAXVAL 0xffff
#endif #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 // we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) { 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); STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) { for (i=0; i < num_rects; ++i) {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); if (rects[i].w == 0 || rects[i].h == 0) {
if (fr.prev_link) { rects[i].x = rects[i].y = 0; // empty rect needs no space
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else { } 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 // unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags // set was_packed flags and all_rects_packed status
for (i=0; i < num_rects; ++i) for (i=0; i < num_rects; ++i) {
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 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 #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 // Development of this library was sponsored by RAD Game Tools
// //
// This C header file implements the guts of a multi-line text-editing // This C header file implements the guts of a multi-line text-editing
@ -17,9 +17,7 @@
// //
// LICENSE // LICENSE
// //
// This software has been placed in the public domain by its author. // See end of file for license information.
// Where that dedication is not recognized, you are granted a perpetual,
// irrevocable license to copy and modify this file as you see fit.
// //
// //
// DEPENDENCIES // DEPENDENCIES
@ -31,6 +29,11 @@
// //
// VERSION HISTORY // 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.6 (2015-04-15) allow STB_TEXTEDIT_memmove
// 1.5 (2014-09-10) add support for secondary keys for OS X // 1.5 (2014-09-10) add support for secondary keys for OS X
// 1.4 (2014-08-17) fix signed/unsigned warnings // 1.4 (2014-08-17) fix signed/unsigned warnings
@ -45,9 +48,14 @@
// ADDITIONAL CONTRIBUTORS // ADDITIONAL CONTRIBUTORS
// //
// Ulf Winklemann: move-by-word in 1.1 // Ulf Winklemann: move-by-word in 1.1
// Scott Graham: mouse selection bugfix in 1.3
// Fabian Giesen: secondary key inputs in 1.5 // 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 // USAGE
// //
@ -142,15 +150,17 @@
// STB_TEXTEDIT_K_REDO keyboard input to perform redo // STB_TEXTEDIT_K_REDO keyboard input to perform redo
// //
// Optional: // Optional:
// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode
// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'),
// required for WORDLEFT/WORDRIGHT // required for default WORDLEFT/WORDRIGHT handlers
// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT // STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to
// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT // STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to
// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT
// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text // STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text // 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: // Todo:
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page // 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; float base_y = 0, prev_x;
int i=0, k; int i=0, k;
if (y < 0)
return 0;
r.x0 = r.x1 = 0; r.x0 = r.x1 = 0;
r.ymin = r.ymax = 0; r.ymin = r.ymax = 0;
r.num_chars = 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) if (r.num_chars <= 0)
return n; return n;
if (i==0 && y < base_y + r.ymin)
return 0;
if (y < base_y + r.ymax) if (y < base_y + r.ymax)
break; 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 // check if it's before the end of the line
if (x < r.x1) { if (x < r.x1) {
// search characters in row for one that straddles 'x' // search characters in row for one that straddles 'x'
k = i;
prev_x = r.x0; prev_x = r.x0;
for (i=0; i < r.num_chars; ++i) { for (k=0; k < r.num_chars; ++k) {
float w = STB_TEXTEDIT_GETWIDTH(str, k, i); float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
if (x < prev_x+w) { if (x < prev_x+w) {
if (x < prev_x+w/2) if (x < prev_x+w/2)
return k+i; 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 // 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) 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->cursor = stb_text_locate_coord(str, x, y);
state->select_start = state->cursor; state->select_start = state->cursor;
state->select_end = 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 // 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) 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; 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 #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; --c; // always move at least one character
while( c >= 0 && !is_word_boundary( _str, c ) ) while( c >= 0 && !is_word_boundary( str, c ) )
--c; --c;
if( c < 0 ) if( c < 0 )
@ -618,12 +651,15 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_Te
return c; 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); const int len = STB_TEXTEDIT_STRINGLEN(str);
int c = _state->cursor+1; ++c; // always move at least one character
while( c < len && !is_word_boundary( _str, c ) ) while( c < len && !is_word_boundary( str, c ) )
++c; ++c;
if( c > len ) if( c > len )
@ -631,6 +667,9 @@ static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_Texted
return c; return c;
} }
#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next
#endif
#endif #endif
// update selection and cursor to match each other // 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 // 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 // if there's a selection, the paste should delete it
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_delete_selection(str,state); stb_textedit_delete_selection(str,state);
@ -752,21 +790,12 @@ retry:
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
#ifdef STB_TEXTEDIT_IS_SPACE #ifdef STB_TEXTEDIT_MOVEWORDLEFT
case STB_TEXTEDIT_K_WORDLEFT: case STB_TEXTEDIT_K_WORDLEFT:
if (STB_TEXT_HAS_SELECTION(state)) if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_first(state); stb_textedit_move_to_first(state);
else { else {
state->cursor = stb_textedit_move_to_word_previous(str, state); state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
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);
stb_textedit_clamp( str, state ); stb_textedit_clamp( str, state );
} }
break; break;
@ -775,17 +804,28 @@ retry:
if( !STB_TEXT_HAS_SELECTION( state ) ) if( !STB_TEXT_HAS_SELECTION( state ) )
stb_textedit_prep_selection_at_cursor(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; state->select_end = state->cursor;
stb_textedit_clamp( str, state ); stb_textedit_clamp( str, state );
break; 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: case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
if( !STB_TEXT_HAS_SELECTION( state ) ) if( !STB_TEXT_HAS_SELECTION( state ) )
stb_textedit_prep_selection_at_cursor(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; state->select_end = state->cursor;
stb_textedit_clamp( str, state ); stb_textedit_clamp( str, state );
@ -968,25 +1008,27 @@ retry:
#ifdef STB_TEXTEDIT_K_LINESTART2 #ifdef STB_TEXTEDIT_K_LINESTART2
case STB_TEXTEDIT_K_LINESTART2: case STB_TEXTEDIT_K_LINESTART2:
#endif #endif
case STB_TEXTEDIT_K_LINESTART: { case STB_TEXTEDIT_K_LINESTART:
StbFindState find;
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_move_to_first(state); stb_textedit_move_to_first(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); if (state->single_line)
state->cursor = find.first_char; 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; state->has_preferred_x = 0;
break; break;
}
#ifdef STB_TEXTEDIT_K_LINEEND2 #ifdef STB_TEXTEDIT_K_LINEEND2
case STB_TEXTEDIT_K_LINEEND2: case STB_TEXTEDIT_K_LINEEND2:
#endif #endif
case STB_TEXTEDIT_K_LINEEND: { case STB_TEXTEDIT_K_LINEEND: {
StbFindState find; int n = STB_TEXTEDIT_STRINGLEN(str);
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_move_to_first(state); stb_textedit_move_to_first(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); if (state->single_line)
state->cursor = find.first_char + find.length; state->cursor = n;
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
++state->cursor;
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
} }
@ -994,25 +1036,29 @@ retry:
#ifdef STB_TEXTEDIT_K_LINESTART2 #ifdef STB_TEXTEDIT_K_LINESTART2
case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
#endif #endif
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: { case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
StbFindState find;
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_prep_selection_at_cursor(state); stb_textedit_prep_selection_at_cursor(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); if (state->single_line)
state->cursor = state->select_end = find.first_char; 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; state->has_preferred_x = 0;
break; break;
}
#ifdef STB_TEXTEDIT_K_LINEEND2 #ifdef STB_TEXTEDIT_K_LINEEND2
case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
#endif #endif
case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
StbFindState find; int n = STB_TEXTEDIT_STRINGLEN(str);
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_prep_selection_at_cursor(state); stb_textedit_prep_selection_at_cursor(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); if (state->single_line)
state->cursor = state->select_end = find.first_char + find.length; 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; state->has_preferred_x = 0;
break; 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); 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 #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 // placed in the public domain - not copyrighted - first released 2014-09
// //
// Embeddable tilemap editor for C/C++ // Embeddable tilemap editor for C/C++
@ -259,7 +259,7 @@
// #define STBTE_MAX_CATEGORIES 100 // #define STBTE_MAX_CATEGORIES 100
// #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB // #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB
// #define STBTE_MAX_COPY 90000 // e.g. 300x300 // #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 // API
// //
@ -275,6 +275,9 @@
// either approach allows cut&pasting between levels.) // either approach allows cut&pasting between levels.)
// //
// REVISION HISTORY // REVISION HISTORY
// 0.38 fix warning
// 0.37 fix warning
// 0.36 minor compiler support
// 0.35 layername button changes // 0.35 layername button changes
// - layername buttons grow with the layer panel // - layername buttons grow with the layer panel
// - fix stbte_create_map being declared as stbte_create // - fix stbte_create_map being declared as stbte_create
@ -309,13 +312,12 @@
// Additional features: // Additional features:
// Josh Huelsman // Josh Huelsman
// Bugfixes: // Bugfixes:
// [this could be you!] // Ryan Whitworth
// Eugene Opalev
// //
// LICENSE // LICENSE
// //
// This software has been placed in the public domain by its author. // See end of file for license information.
// Where that dedication is not recognized, you are granted a perpetual,
// irrevocable license to copy and modify this file as you see fit.
@ -326,6 +328,14 @@
#ifndef STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H #ifndef STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
#define 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; typedef struct stbte_tilemap stbte_tilemap;
// these are the drawmodes used in STBTE_DRAW_TILE // 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] #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) { if (stbte__ui.event == STBTE__paint) {
int off = 9-stbte__get_char_width(label[0]); 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 #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, // This library helps render large-scale "voxel" worlds for games,
// in this case, one with blocks that can have textures and that // 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 // It works by creating triangle meshes. The library includes
// //
// - converter from dense 3D arrays of block info to vertex mesh // - 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 // - assistance in setting up shader state
// //
// For portability, none of the library code actually accesses // For portability, none of the library code actually accesses
@ -24,8 +24,9 @@
// yourself. However, you could also try making a game with // yourself. However, you could also try making a game with
// a small enough world that it's fully loaded rather than // a small enough world that it's fully loaded rather than
// streaming. Currently the preferred vertex format is 20 bytes // streaming. Currently the preferred vertex format is 20 bytes
// per quad. There are plans to allow much more compact formats // per quad. There are designs to allow much more compact formats
// with a slight reduction in shader features. // with a slight reduction in shader features, but no roadmap
// for actually implementing them.
// //
// //
// USAGE // USAGE
@ -108,7 +109,7 @@
// and avoids a potential slow path (gathering non-uniform // and avoids a potential slow path (gathering non-uniform
// data from uniforms) on some hardware. // 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. // 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 // 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 // to a mode will require changing some of your mesh creation code, but
@ -186,11 +187,16 @@
// Features Porting Bugfixes & Warnings // Features Porting Bugfixes & Warnings
// Sean Barrett github:r-leyh Jesus Fernandez // Sean Barrett github:r-leyh Jesus Fernandez
// Miguel Lechon github:Arbeiterunfallversicherungsgesetz // Miguel Lechon github:Arbeiterunfallversicherungsgesetz
// Thomas Frase // Thomas Frase James Hofmann
// Stephen Olsen github:guitarfreak
// //
// VERSION HISTORY // 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 // 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.81 (2015-05-28) fix broken STBVOX_CONFIG_OPTIMIZED_VHEIGHT
// 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring // 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring
// change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so // change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so
@ -209,6 +215,11 @@
// stb_voxel_render 20-byte quads 2015/01 // stb_voxel_render 20-byte quads 2015/01
// zmc engine 32-byte quads 2013/12 // zmc engine 32-byte quads 2013/12
// zmc engine 96-byte quads 2011/10 // zmc engine 96-byte quads 2011/10
//
//
// LICENSE
//
// See end of file for license information.
#ifndef INCLUDE_STB_VOXEL_RENDER_H #ifndef INCLUDE_STB_VOXEL_RENDER_H
#define 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 // modes 0,1,20,21, Z in the mesh can extend to 511 instead
// of 255. However, half-height blocks cannot be used. // 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 // STBVOX_CONFIG_BLOCKTYPE_SHORT
// use unsigned 16-bit values for 'blocktype' in the input instead of 8-bit values // 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 // STBVOX_CONFIG_DISABLE_TEX2
// This disables all processing of texture 2 in the shader in case // 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. // that omits the unused data entirely.
// //
// STBVOX_CONFIG_TEX1_EDGE_CLAMP // STBVOX_CONFIG_TEX1_EDGE_CLAMP
@ -1581,7 +1592,7 @@ static const char *stbvox_vertex_program =
"uniform vec3 normal_table[32];\n" "uniform vec3 normal_table[32];\n"
#ifndef STBVOX_CONFIG_OPENGL_MODELVIEW #ifndef STBVOX_CONFIG_OPENGL_MODELVIEW
"uniform mat44 model_view;\n" "uniform mat4x4 model_view;\n"
#endif #endif
// fragment output data // 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) if (mm->input.selector)
mesh = mm->input.selector[v_off]; 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 // 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]) { if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
mm->full = 1; 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; mesh = mm->default_mesh;
if (mm->input.selector) if (mm->input.selector)
mesh = mm->input.selector[v_off]; 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) { 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 // this is the simple case, we can just use regular block gen with special vmesh calculated with vheight
stbvox_mesh_vertex basevert; 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); basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
if (mm->input.selector) { if (mm->input.selector) {
mesh = mm->input.selector[v_off]; 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 // 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]) { 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]; mesh = mm->input.selector[v_off];
simple_rot = mesh >> 4; simple_rot = mesh >> 4;
mesh &= 15; mesh &= 15;
}
if (mm->input.block_selector) {
mesh = mm->input.block_selector[bt];
} }
// check if we're going off the end // 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) 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 v_off = x * mm->x_stride_in_bytes + y * mm->y_stride_in_bytes;
int ns_off = mm->y_stride_in_bytes; int ns_off = mm->y_stride_in_bytes;
int ew_off = mm->x_stride_in_bytes; int ew_off = mm->x_stride_in_bytes;
pos.x = x;
pos.y = y;
pos.z = 0;
if (mm->input.geometry) { if (mm->input.geometry) {
unsigned char *bt = mm->input.blocktype + v_off; unsigned char *bt = mm->input.blocktype + v_off;
unsigned char *geo = mm->input.geometry + 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) // (v: x:2,y:2,z:2,light:2)
#endif // STB_VOXEL_RENDER_IMPLEMENTATION #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 // a vector<>-like dynamic array for C
// //
// version history: // 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.01 - added a "common uses" documentation section
// 1.0 - fixed bug in the version I posted prematurely // 1.0 - fixed bug in the version I posted prematurely
// 0.9 - rewrite to try to avoid strict-aliasing optimization // 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 length of the "in-use" part of the array
// - the current size of the allocated 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 // programming in C (hash tables a close second), but to be clear
// it lacks many of the capabilities of C++ vector<>: there is no // it lacks many of the capabilities of C++ vector<>: there is no
// range checking, the object address isn't stable (see next section // 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 // 1. can't take long-term pointers to elements of the array
// 2. have to return the pointer from functions which might expand it // 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: // Now you can do the following things with this array:
// //
@ -161,6 +161,10 @@
// The details are trivial and implementation is straightforward; // The details are trivial and implementation is straightforward;
// the main trick is in realizing in the first place that it's // the main trick is in realizing in the first place that it's
// possible to do this in a generic, type-safe way in C. // possible to do this in a generic, type-safe way in C.
//
// LICENSE
//
// See end of file for license information.
#ifndef STB_STRETCHY_BUFFER_H_INCLUDED #ifndef STB_STRETCHY_BUFFER_H_INCLUDED
#define 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 #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_IMPLEMENTATION
#define STB_C_LEXER_SELF_TEST #define STB_C_LEXER_SELF_TEST
#include "../stb_c_lexer.h" #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) static int is_box_in_frustum(float *bmin, float *bmax)
{ {
int i; 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])) if (!test_plane(&frustum[i], bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]))
return 0; return 0;
return 1; 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 #define STB_DEFINE
#include "stb.h" #include "stb.h"
#define PNGSUITE_PRIMARY //#define PNGSUITE_PRIMARY
#if 0 #if 0
void test_ycbcr(void) void test_ycbcr(void)
@ -53,6 +53,13 @@ void test_ycbcr(void)
float hdr_data[200][200][3]; 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 main(int argc, char **argv)
{ {
int w,h; int w,h;
@ -73,18 +80,28 @@ int main(int argc, char **argv)
int i, n; int i, n;
for (i=1; i < argc; ++i) { for (i=1; i < argc; ++i) {
int res;
int w2,h2,n2;
unsigned char *data; unsigned char *data;
printf("%s\n", argv[i]); 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, &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, 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, 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, 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(data);
assert(w == w2 && h == h2 && n == n2);
assert(res);
if (data) { if (data) {
char fname[512]; char fname[512];
stb_splitpath(fname, argv[i], STB_FILE); stb_splitpath(fname, argv[i], STB_FILE);
stbi_write_png(stb_sprintf("output/%s.png", fname), w, h, 4, data, w*4); 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); free(data);
} else } else
printf("FAILED 4\n"); printf("FAILED 4\n");

View File

@ -25,6 +25,8 @@
#pragma comment(lib, "opengl32.lib") #pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib") #pragma comment(lib, "glu32.lib")
#pragma comment(lib, "winmm.lib") #pragma comment(lib, "winmm.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "user32.lib")
#endif #endif
#ifdef __cplusplus #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 #if defined(_WIN32) && _MSC_VER > 1200
#define STBIR_ASSERT(x) \ #define STBIR_ASSERT(x) \
@ -69,9 +70,11 @@ void stbir_progress(float p)
#ifdef _WIN32 #ifdef _WIN32
#include <sys/timeb.h> #include <sys/timeb.h>
#endif
#include <direct.h> #include <direct.h>
#define mkdir(a, b) _mkdir(a)
#else
#include <sys/stat.h>
#endif
#define MT_SIZE 624 #define MT_SIZE 624
static size_t g_aiMT[MT_SIZE]; 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); 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) unsigned int* pixel(unsigned int* buffer, int x, int y, int c, int w, int n)
{ {
return &buffer[y*w*n + x*n + c]; 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_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 // 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++) for (int y = 0; y < 16; y++)
STBIR_ASSERT(output_data_1[y * 16 + x] == output_data_2[y * 16 + x]); 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 // 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++) for (int y = 0; y < 32; y++)
STBIR_ASSERT(output_data_1[y * 32 + x] == output_data_2[y * 32 + x]); 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 // 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_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_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]; static unsigned int image88_int[8][8];
@ -753,7 +835,7 @@ void test_filters(void)
#define UMAX32 4294967295U #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); stbir_uint8 *data = (stbir_uint8*) malloc(w*h*3);
for (int i=0; i < w*h*3; ++i) 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) void test_suite(int argc, char **argv)
{ {
int i; int i;
char *barbara; const char *barbara;
_mkdir("test-output"); mkdir("test-output", 777);
if (argc > 1) if (argc > 1)
barbara = argv[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_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); 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); 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); 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); 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); test_subpixel(barbara, 2, 2, 1, (float)i / 10);
}
// Channels test // Channels test
test_channels(barbara, 0.5f, 0.5f, 1); 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_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"); 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]; char outname[200];
sprintf(outname, "test-output/barbara-width-%d.jpg", i); 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); 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]; char outname[200];
sprintf(outname, "test-output/barbara-width-%d.jpg", i); 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); 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]; char outname[200];
sprintf(outname, "test-output/barbara-height-%d.jpg", i); 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); 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]; char outname[200];
sprintf(outname, "test-output/barbara-height-%d.jpg", i); 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); 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]; char outname[200];
sprintf(outname, "test-output/barbara-width-height-%d.jpg", i); 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); 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_SRGB);
test_format<unsigned short>(barbara, 0.5, 2.0, STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR); 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" #include "stb_image_resize.h"
// Just to make sure it will build properly with a c compiler // 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 Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # 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 BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -66,7 +66,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c # ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GRID_TEST" /FR /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"
@ -86,6 +86,10 @@ LINK32=link.exe
# Name "stb - Win32 Debug" # Name "stb - Win32 Debug"
# Begin Source File # Begin Source File
SOURCE=.\grid_reachability.c
# End Source File
# Begin Source File
SOURCE=.\stb.c SOURCE=.\stb.c
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -98,6 +102,10 @@ SOURCE=..\stb_c_lexer.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb_connected_components.h
# End Source File
# Begin Source File
SOURCE=..\stb_divide.h SOURCE=..\stb_divide.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -106,6 +114,10 @@ SOURCE=..\stb_dxt.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb_easy_font.h
# End Source File
# Begin Source File
SOURCE=..\stb_herringbone_wang_tile.h SOURCE=..\stb_herringbone_wang_tile.h
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -126,14 +138,26 @@ SOURCE=..\stb_leakcheck.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb_malloc.h
# End Source File
# Begin Source File
SOURCE=..\stb_perlin.h SOURCE=..\stb_perlin.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb_pg.h
# End Source File
# Begin Source File
SOURCE=..\stb_rect_pack.h SOURCE=..\stb_rect_pack.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb_sprintf.h
# End Source File
# Begin Source File
SOURCE=..\stb_textedit.h SOURCE=..\stb_textedit.h
# End Source File # End Source File
# Begin 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> 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: Global:
Package=<5> 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_PERLIN_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_DXT_IMPLEMENATION #define STB_DXT_IMPLEMENATION
@ -8,7 +12,9 @@
#define STB_IMAGE_RESIZE_IMPLEMENTATION #define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
#define STB_VOXEL_RENDER_IMPLEMENTATION #define STB_VOXEL_RENDER_IMPLEMENTATION
#define STB_EASY_FONT_IMPLEMENTATION
#include "stb_easy_font.h"
#include "stb_herringbone_wang_tile.h" #include "stb_herringbone_wang_tile.h"
#include "stb_image.h" #include "stb_image.h"
#include "stb_image_write.h" #include "stb_image_write.h"
@ -26,3 +32,11 @@
#define STBTE_DRAW_TILE(x,y,id,highlight,data) 0 #define STBTE_DRAW_TILE(x,y,id,highlight,data) 0
#define STB_TILEMAP_EDITOR_IMPLEMENTATION #define STB_TILEMAP_EDITOR_IMPLEMENTATION
#include "stb_tilemap_editor.h" #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_TRUETYPE_IMPLEMENTATION
#define STB_PERLIN_IMPLEMENTATION #define STB_PERLIN_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
@ -8,6 +12,7 @@
#define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION #define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
#define STB_VOXEL_RENDER_IMPLEMENTATION #define STB_VOXEL_RENDER_IMPLEMENTATION
#define STB_CONNECTED_COMPONENTS_IMPLEMENTATION
#define STBI_MALLOC my_malloc #define STBI_MALLOC my_malloc
#define STBI_FREE my_free #define STBI_FREE my_free
@ -27,6 +32,10 @@ void my_free(void *) { }
#include "stb_divide.h" #include "stb_divide.h"
#include "stb_herringbone_wang_tile.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 #define STBVOX_CONFIG_MODE 1
#include "stb_voxel_render.h" #include "stb_voxel_render.h"

View File

@ -3,13 +3,13 @@
#include "stb_truetype.h" #include "stb_truetype.h"
#include "stb_image_write.h" #include "stb_image_write.h"
#ifdef TT_TEST
#include <stdio.h> #include <stdio.h>
char ttf_buffer[1<<25]; char ttf_buffer[1<<25];
unsigned char output[512*100]; unsigned char output[512*100];
#ifdef TT_TEST
void debug(void) void debug(void)
{ {
stbtt_fontinfo font; stbtt_fontinfo font;
@ -24,6 +24,7 @@ void debug(void)
unsigned char temp_bitmap[BITMAP_H][BITMAP_W]; unsigned char temp_bitmap[BITMAP_H][BITMAP_W];
stbtt_bakedchar cdata[256*2]; // ASCII 32..126 is 95 glyphs stbtt_bakedchar cdata[256*2]; // ASCII 32..126 is 95 glyphs
stbtt_packedchar pdata[256*2]; stbtt_packedchar pdata[256*2];
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
stbtt_fontinfo font; stbtt_fontinfo font;
@ -35,6 +36,17 @@ int main(int argc, char **argv)
// @TODO: why is minglui.ttc failing? // @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:/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 #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! 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); 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 #define STB_VORBIS_HEADER_ONLY
#include "stb_vorbis.c" #include "stb_vorbis.c"
#include "stb.h" #include "stb.h"
@ -8,10 +12,11 @@ extern void stb_vorbis_dumpmem(void);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
size_t memlen; 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; int chan, samplerate;
short *output; short *output;
int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output); int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output);
stb_filewrite("c:/x/sketch008.raw", output, samples*4);
return 0; return 0;
} }
#endif #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? #### What's the license?
These libraries are in the public domain (or the equivalent where that is not These libraries are in the public domain. You can do anything you
possible). You can do anything you want with them. You have no legal obligation want with them. You have no legal obligation
to do anything else, although I appreciate attribution. 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, Generally they're only better in that they're easier to integrate,
easier to use, and easier to release (single file; good API; no 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 and/or use more memory. If you're already using an equivalent
library, there's probably no good reason to switch. 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. #### 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, 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? #### Why "stb"? Is this something to do with Set-Top Boxes?
No, they are just the initials for my name, Sean T. Barrett. 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. 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 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 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 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. 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? #### 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 Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt

View File

@ -1,7 +1,11 @@
stb 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 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_write.h | graphics | image writing to disk: PNG, TGA, BMP
stb_image_resize.h | graphics | resize images larger/smaller with good quality 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_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++ 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_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_dxt.h | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor
stb_perlin.h | 3D graphics | revised Perlin noise (3D input, 1D output) 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_herringbone_wang_tile.h | game dev | herringbone Wang tile map generator
stb_c_lexer.h | parsing | simplify writing parsers for C-like languages 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_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.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 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; if (*s1 == 'v') ++s1;
s3 = tokens[0]; s3 = tokens[0];
stb_trimwhite(s3); stb_trimwhite(s3);
fprintf(f, "**[");
if (strlen(s3) < 21) { if (strlen(s3) < 21) {
fprintf(f, "**%s** | %s", tokens[0], s1); fprintf(f, "%s", tokens[0]);
} else { } else {
char buffer[256]; char buffer[256];
strncpy(buffer, s3, 18); strncpy(buffer, s3, 18);
buffer[18] = 0; buffer[18] = 0;
strcat(buffer, "..."); 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 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 s2 = stb_dupreplace(s1, " ", "&nbsp;"); // stb_dupreplace -- search & replace string and malloc result
fprintf(f, " | %s", s2); 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