mirror of https://github.com/nothings/stb.git
commit
fa98e4f6cf
|
@ -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.
|
||||
|
|
@ -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.
|
|
@ -0,0 +1,5 @@
|
|||
language: C
|
||||
install: true
|
||||
script:
|
||||
- cd tests
|
||||
- make all
|
95
README.md
95
README.md
|
@ -3,31 +3,37 @@
|
|||
stb
|
||||
===
|
||||
|
||||
single-file public domain libraries for C/C++
|
||||
single-file public domain (or MIT licensed) libraries for C/C++ <a name="stb_libs"></a>
|
||||
|
||||
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
|
||||
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
|
||||
|
||||
|
||||
library | lastest version | category | LoC | description
|
||||
--------------------- | ---- | -------- | --- | --------------------------------
|
||||
**stb_vorbis.c** | 1.05 | audio | 5445 | decode ogg vorbis files from file/memory to float/16-bit signed output
|
||||
**stb_image.h** | 2.06 | graphics | 6437 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
|
||||
**stb_truetype.h** | 1.06 | graphics | 2632 | parse, decode, and rasterize characters from truetype fonts
|
||||
**stb_image_write.h** | 0.98 | graphics | 730 | image writing to disk: PNG, TGA, BMP
|
||||
**stb_image_resize.h** | 0.90 | graphics | 2585 | resize images larger/smaller with good quality
|
||||
**stb_rect_pack.h** | 0.06 | graphics | 560 | simple 2D rectangle packer with decent quality
|
||||
**stretchy_buffer.h** | 1.02 | utility | 210 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
|
||||
**stb_textedit.h** | 1.6 | UI | 1290 | guts of a text editor for games etc implementing them from scratch
|
||||
**stb_voxel_render.h** | 0.81 | 3D graphics | 3644 | Minecraft-esque voxel rendering "engine" with many more features
|
||||
**stb_dxt.h** | 1.04 | 3D graphics | 624 | Fabian "ryg" Giesen's real-time DXT compressor
|
||||
**stb_perlin.h** | 0.2 | 3D graphics | 175 | revised Perlin noise (3D input, 1D output)
|
||||
**stb_easy_font.h** | 0.5 | 3D graphics | 220 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
|
||||
**stb_tilemap_editor.h** | 0.35 | game dev | 4120 | embeddable tilemap editor
|
||||
**stb_herringbone_wa...** | 0.6 | game dev | 1217 | herringbone Wang tile map generator
|
||||
**stb_c_lexer.h** | 0.06 | parsing | 809 | simplify writing parsers for C-like languages
|
||||
**stb_divide.h** | 0.91 | math | 373 | more useful 32-bit modulus e.g. "euclidean divide"
|
||||
**stb.h** | 2.24 | misc | 14086 | helper functions for C, mostly redundant in C++; basically author's personal stuff
|
||||
**stb_leakcheck.h** | 0.2 | misc | 117 | quick-and-dirty malloc/free leak-checking
|
||||
**[stb_vorbis.c](stb_vorbis.c)** | 1.10 | audio | 5447 | decode ogg vorbis files from file/memory to float/16-bit signed output
|
||||
**[stb_image.h](stb_image.h)** | 2.15 | graphics | 7177 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
|
||||
**[stb_truetype.h](stb_truetype.h)** | 1.15 | graphics | 4061 | parse, decode, and rasterize characters from truetype fonts
|
||||
**[stb_image_write.h](stb_image_write.h)** | 1.05 | graphics | 1092 | image writing to disk: PNG, TGA, BMP
|
||||
**[stb_image_resize.h](stb_image_resize.h)** | 0.94 | graphics | 2624 | resize images larger/smaller with good quality
|
||||
**[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 635 | simple 2D rectangle packer with decent quality
|
||||
**[stb_sprintf.h](stb_sprintf.h)** | 1.02 | utility | 1202 | fast sprintf, snprintf for C/C++
|
||||
**[stretchy_buffer.h](stretchy_buffer.h)** | 1.02 | utility | 257 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
|
||||
**[stb_textedit.h](stb_textedit.h)** | 1.11 | user interface | 1393 | guts of a text editor for games etc implementing them from scratch
|
||||
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features
|
||||
**[stb_dxt.h](stb_dxt.h)** | 1.06 | 3D graphics | 687 | Fabian "ryg" Giesen's real-time DXT compressor
|
||||
**[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D graphics | 316 | revised Perlin noise (3D input, 1D output)
|
||||
**[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
|
||||
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game dev | 4172 | embeddable tilemap editor
|
||||
**[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.6 | game dev | 1220 | herringbone Wang tile map generator
|
||||
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages
|
||||
**[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide"
|
||||
**[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids
|
||||
**[stb.h](stb.h)** | 2.29 | misc | 14324 | helper functions for C, mostly redundant in C++; basically author's personal stuff
|
||||
**[stb_leakcheck.h](stb_leakcheck.h)** | 0.3 | misc | 165 | quick-and-dirty malloc/free leak-checking
|
||||
|
||||
Total libraries: 18
|
||||
Total lines of C code: 45274
|
||||
Total libraries: 20
|
||||
Total lines of C code: 51304
|
||||
|
||||
|
||||
FAQ
|
||||
|
@ -35,15 +41,40 @@ FAQ
|
|||
|
||||
#### What's the license?
|
||||
|
||||
These libraries are in the public domain (or the equivalent where that is not
|
||||
possible). You can do anything you want with them. You have no legal obligation
|
||||
These libraries are in the public domain. You can do anything you
|
||||
want with them. You have no legal obligation
|
||||
to do anything else, although I appreciate attribution.
|
||||
|
||||
#### If I wrap an stb library in a new library, does the new library have to be public domain?
|
||||
They are also licensed under the MIT open source license, if you have lawyers
|
||||
who are unhappy with public domain. Every source file includes an explicit
|
||||
dual-license for you to choose from.
|
||||
|
||||
No.
|
||||
#### <a name="other_libs"></a> Are there other single-file public-domain/open source libraries with minimal dependencies out there?
|
||||
|
||||
#### A lot of these libraries seem redundant to existing open source libraries. Are they better somehow?
|
||||
[Yes.](https://github.com/nothings/single_file_libs)
|
||||
|
||||
#### If I wrap an stb library in a new library, does the new library have to be public domain/MIT?
|
||||
|
||||
No, because it's public domain you can freely relicense it to whatever license your new
|
||||
library wants to be.
|
||||
|
||||
#### What's the deal with SSE support in GCC-based compilers?
|
||||
|
||||
stb_image will either use SSE2 (if you compile with -msse2) or
|
||||
will not use any SIMD at all, rather than trying to detect the
|
||||
processor at runtime and handle it correctly. As I understand it,
|
||||
the approved path in GCC for runtime-detection require
|
||||
you to use multiple source files, one for each CPU configuration.
|
||||
Because stb_image is a header-file library that compiles in only
|
||||
one source file, there's no approved way to build both an
|
||||
SSE-enabled and a non-SSE-enabled variation.
|
||||
|
||||
While we've tried to work around it, we've had multiple issues over
|
||||
the years due to specific versions of gcc breaking what we're doing,
|
||||
so we've given up on it. See https://github.com/nothings/stb/issues/280
|
||||
and https://github.com/nothings/stb/issues/410 for examples.
|
||||
|
||||
#### Some of these libraries seem redundant to existing open source libraries. Are they better somehow?
|
||||
|
||||
Generally they're only better in that they're easier to integrate,
|
||||
easier to use, and easier to release (single file; good API; no
|
||||
|
@ -51,6 +82,10 @@ attribution requirement). They may be less featureful, slower,
|
|||
and/or use more memory. If you're already using an equivalent
|
||||
library, there's probably no good reason to switch.
|
||||
|
||||
#### Can I link directly to the table of stb libraries?
|
||||
|
||||
You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list.
|
||||
|
||||
#### Why do you list "lines of code"? It's a terrible metric.
|
||||
|
||||
Just to give you some idea of the internal complexity of the library,
|
||||
|
@ -88,10 +123,10 @@ remember to attach *two* files, etc.
|
|||
#### Why "stb"? Is this something to do with Set-Top Boxes?
|
||||
|
||||
No, they are just the initials for my name, Sean T. Barrett.
|
||||
This was not chosen out of egomania, but as a semi-robust
|
||||
This was not chosen out of egomania, but as a moderately sane
|
||||
way of namespacing the filenames and source function names.
|
||||
|
||||
#### Will you add more image types to stb_image.c?
|
||||
#### Will you add more image types to stb_image.h?
|
||||
|
||||
If people submit them, I generally add them, but the goal of stb_image
|
||||
is less for applications like image viewer apps (which need to support
|
||||
|
@ -99,10 +134,6 @@ every type of image under the sun) and more for things like games which
|
|||
can choose what images to use, so I may decline to add them if they're
|
||||
too rare or if the size of implementation vs. apparent benefit is too low.
|
||||
|
||||
#### Are there other single-file public-domain libraries out there?
|
||||
|
||||
Yes. I'll put a list here when people remind me what they are.
|
||||
|
||||
#### Do you have any advice on how to create my own single-file library?
|
||||
|
||||
Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
Moved to https://github.com/nothings/single_file_libs
|
|
@ -165,9 +165,9 @@ public domain declarations aren't necessary recognized
|
|||
in the USA and some other locations. For that reason,
|
||||
I recommend a declaration along these lines:
|
||||
|
||||
// This software is in the public domain. Where that dedication is not
|
||||
// recognized, you are granted a perpetual, irrevocable license to copy
|
||||
// and modify this file as you see fit.
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
|
||||
I typically place this declaration at the end of the initial
|
||||
comment block of the file and just say 'public domain'
|
||||
|
|
|
@ -95,9 +95,9 @@ public domain declarations aren't necessary recognized
|
|||
in the USA and some other locations. For that reason,
|
||||
I recommend a declaration along these lines:
|
||||
|
||||
// This software is in the public domain. Where that dedication is not
|
||||
// recognized, you are granted a perpetual, irrevocable license to copy
|
||||
// and modify this file as you see fit.
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
|
||||
I typically place this declaration at the end of the initial
|
||||
comment block of the file and just say 'public domain'
|
||||
|
|
388
stb.h
388
stb.h
|
@ -1,4 +1,4 @@
|
|||
/* stb.h - v2.24 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
|
||||
/* stb.h - v2.29 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
|
||||
no warranty is offered or implied; use this code at your own risk
|
||||
|
||||
This is a single header file with a bunch of useful utilities
|
||||
|
@ -25,6 +25,11 @@
|
|||
|
||||
Version History
|
||||
|
||||
2.29 attempt to fix use of swprintf()
|
||||
2.28 various new functionality
|
||||
2.27 test _WIN32 not WIN32 in STB_THREADS
|
||||
2.26 various warning & bugfixes
|
||||
2.25 various warning & bugfixes
|
||||
2.24 various warning & bugfixes
|
||||
2.23 fix 2.22
|
||||
2.22 64-bit fixes from '!='; fix stb_sdict_copy() to have preferred name
|
||||
|
@ -166,6 +171,26 @@ Version History
|
|||
(stb_array), (stb_arena)
|
||||
|
||||
Parenthesized items have since been removed.
|
||||
|
||||
LICENSE
|
||||
|
||||
See end of file for license information.
|
||||
|
||||
CREDITS
|
||||
|
||||
Written by Sean Barrett.
|
||||
|
||||
Fixes:
|
||||
Philipp Wiesemann
|
||||
Robert Nix
|
||||
r-lyeh
|
||||
blackpawn
|
||||
Mojofreem@github
|
||||
Ryan Whitworth
|
||||
Vincent Isambart
|
||||
Mike Sartain
|
||||
Eugene Opalev
|
||||
Tim Sjostrand
|
||||
*/
|
||||
|
||||
#ifndef STB__INCLUDE_STB_H
|
||||
|
@ -186,10 +211,28 @@ Parenthesized items have since been removed.
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
#ifndef _CRT_NON_CONFORMING_SWPRINTFS
|
||||
#define _CRT_NON_CONFORMING_SWPRINTFS
|
||||
#endif
|
||||
#if !defined(_MSC_VER) || _MSC_VER > 1700
|
||||
#include <intrin.h> // _BitScanReverse
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // stdlib could have min/max
|
||||
#include <stdio.h> // need FILE
|
||||
#include <string.h> // stb_define_hash needs memcpy/memset
|
||||
#include <time.h> // stb_dirtree
|
||||
#ifdef __MINGW32__
|
||||
#include <fcntl.h> // O_RDWR
|
||||
#endif
|
||||
|
||||
#ifdef STB_PERSONAL
|
||||
typedef int Bool;
|
||||
|
@ -323,7 +366,7 @@ typedef char stb__testsize2_64[sizeof(stb_uint64)==8 ? 1 : -1];
|
|||
|
||||
// add platform-specific ways of checking for sizeof(char*) == 8,
|
||||
// and make those define STB_PTR64
|
||||
#if defined(_WIN64) || defined(__x86_64__) || defined(__ia64__)
|
||||
#if defined(_WIN64) || defined(__x86_64__) || defined(__ia64__) || defined(__LP64__)
|
||||
#define STB_PTR64
|
||||
#endif
|
||||
|
||||
|
@ -682,20 +725,42 @@ STB_EXTERN char * stb_sstrdup(char *s);
|
|||
STB_EXTERN void stbprint(const char *fmt, ...);
|
||||
STB_EXTERN char *stb_sprintf(const char *fmt, ...);
|
||||
STB_EXTERN char *stb_mprintf(const char *fmt, ...);
|
||||
STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...);
|
||||
STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v);
|
||||
|
||||
#ifdef STB_DEFINE
|
||||
|
||||
int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v)
|
||||
{
|
||||
int res;
|
||||
#ifdef _WIN32
|
||||
// Could use "_vsnprintf_s(s, n, _TRUNCATE, fmt, v)" ?
|
||||
res = _vsnprintf(s,n,fmt,v);
|
||||
#else
|
||||
res = vsnprintf(s,n,fmt,v);
|
||||
#endif
|
||||
if (n) s[n-1] = 0;
|
||||
// Unix returns length output would require, Windows returns negative when truncated.
|
||||
return (res >= (int) n || res < 0) ? -1 : res;
|
||||
}
|
||||
|
||||
int stb_snprintf(char *s, size_t n, const char *fmt, ...)
|
||||
{
|
||||
int res;
|
||||
va_list v;
|
||||
va_start(v,fmt);
|
||||
res = stb_vsnprintf(s, n, fmt, v);
|
||||
va_end(v);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *stb_sprintf(const char *fmt, ...)
|
||||
{
|
||||
static char buffer[1024];
|
||||
va_list v;
|
||||
va_start(v,fmt);
|
||||
#ifdef _WIN32
|
||||
_vsnprintf(buffer, 1024, fmt, v);
|
||||
#else
|
||||
vsnprintf(buffer, 1024, fmt, v);
|
||||
#endif
|
||||
stb_vsnprintf(buffer,1024,fmt,v);
|
||||
va_end(v);
|
||||
buffer[1023] = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -704,13 +769,8 @@ char *stb_mprintf(const char *fmt, ...)
|
|||
static char buffer[1024];
|
||||
va_list v;
|
||||
va_start(v,fmt);
|
||||
#ifdef _WIN32
|
||||
_vsnprintf(buffer, 1024, fmt, v);
|
||||
#else
|
||||
vsnprintf(buffer, 1024, fmt, v);
|
||||
#endif
|
||||
stb_vsnprintf(buffer,1024,fmt,v);
|
||||
va_end(v);
|
||||
buffer[1023] = 0;
|
||||
return strdup(buffer);
|
||||
}
|
||||
|
||||
|
@ -810,9 +870,8 @@ void stbprint(const char *fmt, ...)
|
|||
va_list v;
|
||||
|
||||
va_start(v,fmt);
|
||||
res = _vsnprintf(buffer, sizeof(buffer), fmt, v);
|
||||
res = stb_vsnprintf(buffer, sizeof(buffer), fmt, v);
|
||||
va_end(v);
|
||||
buffer[sizeof(buffer)-1] = 0;
|
||||
|
||||
if (res < 0) {
|
||||
tbuf = (char *) malloc(16384);
|
||||
|
@ -1021,9 +1080,15 @@ void stb_fatal(char *s, ...)
|
|||
vfprintf(stderr, s, a);
|
||||
va_end(a);
|
||||
fputs("\n", stderr);
|
||||
#ifdef _WIN32
|
||||
#ifdef STB_DEBUG
|
||||
#ifdef _MSC_VER
|
||||
#ifndef STB_PTR64
|
||||
__asm int 3; // trap to debugger!
|
||||
#else
|
||||
__debugbreak();
|
||||
#endif
|
||||
#else
|
||||
__builtin_trap();
|
||||
#endif
|
||||
#endif
|
||||
exit(1);
|
||||
|
@ -1395,13 +1460,13 @@ int stb_is_pow2(unsigned int n)
|
|||
|
||||
// tricky use of 4-bit table to identify 5 bit positions (note the '-1')
|
||||
// 3-bit table would require another tree level; 5-bit table wouldn't save one
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4035) // disable warning about no return value
|
||||
int stb_log2_floor(unsigned int n)
|
||||
{
|
||||
#if _MSC_VER > 1700
|
||||
DWORD i;
|
||||
unsigned long i;
|
||||
_BitScanReverse(&i, n);
|
||||
return i != 0 ? i : -1;
|
||||
#else
|
||||
|
@ -1727,6 +1792,7 @@ STB_EXTERN char * stb_strichr(char *s, char t);
|
|||
STB_EXTERN char * stb_stristr(char *s, char *t);
|
||||
STB_EXTERN int stb_prefix_count(char *s, char *t);
|
||||
STB_EXTERN char * stb_plural(int n); // "s" or ""
|
||||
STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n);
|
||||
|
||||
STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count);
|
||||
STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out);
|
||||
|
@ -1741,6 +1807,17 @@ STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count);
|
|||
|
||||
#ifdef STB_DEFINE
|
||||
|
||||
size_t stb_strscpy(char *d, const char *s, size_t n)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
if (len >= n) {
|
||||
if (n) d[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
strcpy(d,s);
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
char *stb_plural(int n)
|
||||
{
|
||||
return n == 1 ? "" : "s";
|
||||
|
@ -2561,7 +2638,8 @@ void stb_malloc_validate(void *p, void *parent)
|
|||
static void * stb__try_chunk(stb__chunk *c, int size, int align, int pre_align)
|
||||
{
|
||||
char *memblock = (char *) (c+1), *q;
|
||||
int iq, start_offset;
|
||||
stb_inta iq;
|
||||
int start_offset;
|
||||
|
||||
// we going to allocate at the end of the chunk, not the start. confusing,
|
||||
// but it means we don't need both a 'limit' and a 'cur', just a 'cur'.
|
||||
|
@ -2973,8 +3051,8 @@ typedef struct
|
|||
#define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature)
|
||||
#define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature)
|
||||
#else
|
||||
#define stb_arr_check(a) 0
|
||||
#define stb_arr_check2(a) 0
|
||||
#define stb_arr_check(a) ((void) 0)
|
||||
#define stb_arr_check2(a) ((void) 0)
|
||||
#endif
|
||||
|
||||
// ARRAY LENGTH
|
||||
|
@ -3023,7 +3101,7 @@ typedef struct
|
|||
#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n))
|
||||
|
||||
// insert an element at i
|
||||
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n), ((a)[i] = v))
|
||||
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v))
|
||||
|
||||
// delete N elements from the middle starting at index 'i'
|
||||
#define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n))
|
||||
|
@ -3209,7 +3287,7 @@ void stb__arr_insertn_(void **pp, int size, int i, int n STB__PARAMS)
|
|||
}
|
||||
|
||||
z = stb_arr_len2(p);
|
||||
stb__arr_addlen_(&p, size, i STB__ARGS);
|
||||
stb__arr_addlen_(&p, size, n STB__ARGS);
|
||||
memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i));
|
||||
}
|
||||
*pp = p;
|
||||
|
@ -3219,7 +3297,7 @@ void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS)
|
|||
{
|
||||
void *p = *pp;
|
||||
if (n) {
|
||||
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-i));
|
||||
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n)));
|
||||
stb_arrhead2(p)->len -= n;
|
||||
}
|
||||
*pp = p;
|
||||
|
@ -3297,7 +3375,7 @@ unsigned int stb_hashptr(void *p)
|
|||
|
||||
unsigned int stb_rehash_improved(unsigned int v)
|
||||
{
|
||||
return stb_hashptr((void *) v);
|
||||
return stb_hashptr((void *)(size_t) v);
|
||||
}
|
||||
|
||||
unsigned int stb_hash2(char *str, unsigned int *hash2_ptr)
|
||||
|
@ -5049,7 +5127,7 @@ void stb_fwrite32(FILE *f, stb_uint32 x)
|
|||
fwrite(&x, 4, 1, f);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define stb__stat _stat
|
||||
#else
|
||||
#define stb__stat stat
|
||||
|
@ -5112,7 +5190,18 @@ int stb_filewrite(char *filename, void *data, size_t length)
|
|||
{
|
||||
FILE *f = stb_fopen(filename, "wb");
|
||||
if (f) {
|
||||
fwrite(data, 1, length, f);
|
||||
unsigned char *data_ptr = (unsigned char *) data;
|
||||
size_t remaining = length;
|
||||
while (remaining > 0) {
|
||||
size_t len2 = remaining > 65536 ? 65536 : remaining;
|
||||
size_t len3 = fwrite(data_ptr, 1, len2, f);
|
||||
if (len2 != len3) {
|
||||
fprintf(stderr, "Failed while writing %s\n", filename);
|
||||
break;
|
||||
}
|
||||
remaining -= len2;
|
||||
data_ptr += len2;
|
||||
}
|
||||
stb_fclose(f, stb_keep_if_different);
|
||||
}
|
||||
return f != NULL;
|
||||
|
@ -5389,7 +5478,11 @@ FILE * stb_fopen(char *filename, char *mode)
|
|||
#else
|
||||
{
|
||||
strcpy(temp_full+p, "stmpXXXXXX");
|
||||
int fd = mkstemp(temp_full);
|
||||
#ifdef __MINGW32__
|
||||
int fd = open(mktemp(temp_full), O_RDWR);
|
||||
#else
|
||||
int fd = mkstemp(temp_full);
|
||||
#endif
|
||||
if (fd == -1) return NULL;
|
||||
f = fdopen(fd, mode);
|
||||
if (f == NULL) {
|
||||
|
@ -5708,6 +5801,19 @@ char *stb_strip_final_slash(char *t)
|
|||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
char *stb_strip_final_slash_regardless(char *t)
|
||||
{
|
||||
if (t[0]) {
|
||||
char *z = t + strlen(t) - 1;
|
||||
// *z is the last character
|
||||
if (*z == '\\' || *z == '/')
|
||||
*z = 0;
|
||||
if (*z == '\\')
|
||||
*z = '/'; // canonicalize to make sure it matches db
|
||||
}
|
||||
return t;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5820,42 +5926,57 @@ void stb_readdir_free(char **files)
|
|||
stb_arr_free(f2);
|
||||
}
|
||||
|
||||
static int isdotdirname(char *name)
|
||||
{
|
||||
if (name[0] == '.')
|
||||
return (name[1] == '.') ? !name[2] : !name[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
STB_EXTERN int stb_wildmatchi(char *expr, char *candidate);
|
||||
static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
||||
{
|
||||
char **results = NULL;
|
||||
char buffer[512], with_slash[512];
|
||||
int n;
|
||||
char buffer[4096], with_slash[4096];
|
||||
size_t n;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
stb__wchar *ws;
|
||||
struct _wfinddata_t data;
|
||||
#ifdef _WIN64
|
||||
const intptr_t none = -1;
|
||||
intptr_t z;
|
||||
#else
|
||||
const long none = -1;
|
||||
long z;
|
||||
#else
|
||||
#endif
|
||||
#else // !_MSC_VER
|
||||
const DIR *none = NULL;
|
||||
DIR *z;
|
||||
#endif
|
||||
|
||||
strcpy(buffer,dir);
|
||||
n = stb_strscpy(buffer,dir,sizeof(buffer));
|
||||
if (!n || n >= sizeof(buffer))
|
||||
return NULL;
|
||||
stb_fixpath(buffer);
|
||||
n = strlen(buffer);
|
||||
n--;
|
||||
|
||||
if (n > 0 && (buffer[n-1] != '/')) {
|
||||
buffer[n++] = '/';
|
||||
}
|
||||
buffer[n] = 0;
|
||||
strcpy(with_slash, buffer);
|
||||
if (!stb_strscpy(with_slash,buffer,sizeof(with_slash)))
|
||||
return NULL;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
strcpy(buffer+n, "*.*");
|
||||
if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n))
|
||||
return NULL;
|
||||
ws = stb__from_utf8(buffer);
|
||||
z = _wfindfirst((const wchar_t *)ws, &data);
|
||||
#else
|
||||
z = opendir(dir);
|
||||
#endif
|
||||
|
||||
|
||||
if (z != none) {
|
||||
int nonempty = STB_TRUE;
|
||||
#ifndef _MSC_VER
|
||||
|
@ -5876,17 +5997,18 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
|
|||
is_subdir = !!(data.attrib & _A_SUBDIR);
|
||||
#else
|
||||
char *name = data->d_name;
|
||||
strcpy(buffer+n,name);
|
||||
DIR *y = opendir(buffer);
|
||||
is_subdir = (y != NULL);
|
||||
if (y != NULL) closedir(y);
|
||||
if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n))
|
||||
break;
|
||||
// Could follow DT_LNK, but would need to check for recursive links.
|
||||
is_subdir = !!(data->d_type & DT_DIR);
|
||||
#endif
|
||||
|
||||
|
||||
if (is_subdir == return_subdirs) {
|
||||
if (!is_subdir || name[0] != '.') {
|
||||
if (!is_subdir || !isdotdirname(name)) {
|
||||
if (!mask || stb_wildmatchi(mask, name)) {
|
||||
char buffer[512],*p=buffer;
|
||||
sprintf(buffer, "%s%s", with_slash, name);
|
||||
char buffer[4096],*p=buffer;
|
||||
if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 )
|
||||
break;
|
||||
if (buffer[0] == '.' && buffer[1] == '/')
|
||||
p = buffer+2;
|
||||
stb_arr_push(results, strdup(p));
|
||||
|
@ -6649,14 +6771,16 @@ typedef struct
|
|||
char * path; // full path from passed-in root
|
||||
time_t last_modified;
|
||||
int num_files;
|
||||
int flag;
|
||||
} stb_dirtree_dir;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name; // name relative to path
|
||||
int dir; // index into dirs[] array
|
||||
unsigned long size; // size, max 4GB
|
||||
stb_int64 size; // size, max 4GB
|
||||
time_t last_modified;
|
||||
int flag;
|
||||
} stb_dirtree_file;
|
||||
|
||||
typedef struct
|
||||
|
@ -6684,6 +6808,14 @@ extern stb_dirtree *stb_dirtree_get_with_file ( char *dir, char *cache_file);
|
|||
// do a call to stb_dirtree_get() with the same cache file at about the same
|
||||
// time, but I _think_ it might just work.
|
||||
|
||||
// i needed to build an identical data structure representing the state of
|
||||
// a mirrored copy WITHOUT bothering to rescan it (i.e. we're mirroring to
|
||||
// it WITHOUT scanning it, e.g. it's over the net), so this requires access
|
||||
// to all of the innards.
|
||||
extern void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last);
|
||||
extern void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last);
|
||||
extern void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir);
|
||||
extern void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir);
|
||||
|
||||
#ifdef STB_DEFINE
|
||||
static void stb__dirtree_add_dir(char *path, time_t last, stb_dirtree *active)
|
||||
|
@ -6695,7 +6827,7 @@ static void stb__dirtree_add_dir(char *path, time_t last, stb_dirtree *active)
|
|||
stb_arr_push(active->dirs, d);
|
||||
}
|
||||
|
||||
static void stb__dirtree_add_file(char *name, int dir, unsigned long size, time_t last, stb_dirtree *active)
|
||||
static void stb__dirtree_add_file(char *name, int dir, stb_int64 size, time_t last, stb_dirtree *active)
|
||||
{
|
||||
stb_dirtree_file f;
|
||||
f.dir = dir;
|
||||
|
@ -6706,23 +6838,25 @@ static void stb__dirtree_add_file(char *name, int dir, unsigned long size, time_
|
|||
stb_arr_push(active->files, f);
|
||||
}
|
||||
|
||||
static char stb__signature[12] = { 's', 'T', 'b', 'D', 'i', 'R', 't', 'R', 'e', 'E', '0', '1' };
|
||||
// version 02 supports > 4GB files
|
||||
static char stb__signature[12] = { 's', 'T', 'b', 'D', 'i', 'R', 't', 'R', 'e', 'E', '0', '2' };
|
||||
|
||||
static void stb__dirtree_save_db(char *filename, stb_dirtree *data, char *root)
|
||||
{
|
||||
int i, num_dirs_final=0, num_files_final;
|
||||
char *info = root ? root : "";
|
||||
int *remap;
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (!f) return;
|
||||
|
||||
fwrite(stb__signature, sizeof(stb__signature), 1, f);
|
||||
fwrite(root, strlen(root)+1, 1, f);
|
||||
fwrite(info, strlen(info)+1, 1, f);
|
||||
// need to be slightly tricky and not write out NULLed directories, nor the root
|
||||
|
||||
// build remapping table of all dirs we'll be writing out
|
||||
remap = (int *) malloc(sizeof(remap[0]) * stb_arr_len(data->dirs));
|
||||
for (i=0; i < stb_arr_len(data->dirs); ++i) {
|
||||
if (data->dirs[i].path == NULL || 0==stb_stricmp(data->dirs[i].path, root)) {
|
||||
if (data->dirs[i].path == NULL || (root && 0==stb_stricmp(data->dirs[i].path, root))) {
|
||||
remap[i] = -1;
|
||||
} else {
|
||||
remap[i] = num_dirs_final++;
|
||||
|
@ -6739,14 +6873,14 @@ static void stb__dirtree_save_db(char *filename, stb_dirtree *data, char *root)
|
|||
|
||||
num_files_final = 0;
|
||||
for (i=0; i < stb_arr_len(data->files); ++i)
|
||||
if (remap[data->files[i].dir] >= 0)
|
||||
if (remap[data->files[i].dir] >= 0 && data->files[i].name)
|
||||
++num_files_final;
|
||||
|
||||
fwrite(&num_files_final, 4, 1, f);
|
||||
for (i=0; i < stb_arr_len(data->files); ++i) {
|
||||
if (remap[data->files[i].dir] >= 0) {
|
||||
if (remap[data->files[i].dir] >= 0 && data->files[i].name) {
|
||||
stb_fput_ranged(f, remap[data->files[i].dir], 0, num_dirs_final);
|
||||
stb_fput_varlenu(f, data->files[i].size);
|
||||
stb_fput_varlen64(f, data->files[i].size);
|
||||
fwrite(&data->files[i].last_modified, 4, 1, f);
|
||||
stb_fput_string(f, data->files[i].name);
|
||||
}
|
||||
|
@ -6783,7 +6917,7 @@ static void stb__dirtree_load_db(char *filename, stb_dirtree *data, char *dir)
|
|||
stb_arr_setlen(data->files, n);
|
||||
for (i=0; i < stb_arr_len(data->files); ++i) {
|
||||
data->files[i].dir = stb_fget_ranged(f, 0, stb_arr_len(data->dirs));
|
||||
data->files[i].size = stb_fget_varlenu(f);
|
||||
data->files[i].size = stb_fget_varlen64(f);
|
||||
fread(&data->files[i].last_modified, 4, 1, f);
|
||||
data->files[i].name = stb_fget_string(f, data->string_pool);
|
||||
if (data->files[i].name == NULL) goto bail;
|
||||
|
@ -6797,6 +6931,7 @@ static void stb__dirtree_load_db(char *filename, stb_dirtree *data, char *dir)
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
static int stb__dircount, stb__dircount_mask, stb__showfile;
|
||||
static void stb__dirtree_scandir(char *path, time_t last_time, stb_dirtree *active)
|
||||
{
|
||||
// this is dumb depth first; theoretically it might be faster
|
||||
|
@ -6805,48 +6940,75 @@ static void stb__dirtree_scandir(char *path, time_t last_time, stb_dirtree *acti
|
|||
|
||||
int n;
|
||||
|
||||
struct _wfinddata_t c_file;
|
||||
struct _wfinddatai64_t c_file;
|
||||
long hFile;
|
||||
stb__wchar full_path[1024];
|
||||
int has_slash;
|
||||
if (stb__showfile) printf("<");
|
||||
|
||||
has_slash = (path[0] && path[strlen(path)-1] == '/');
|
||||
|
||||
// @TODO: do this concatenation without using swprintf to avoid this mess:
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1400
|
||||
if (has_slash)
|
||||
swprintf((wchar_t *)full_path, L"%s*", stb__from_utf8(path));
|
||||
swprintf(full_path, L"%s*", stb__from_utf8(path));
|
||||
else
|
||||
swprintf((wchar_t *)full_path, L"%s/*", stb__from_utf8(path));
|
||||
swprintf(full_path, L"%s/*", stb__from_utf8(path));
|
||||
#else
|
||||
if (has_slash)
|
||||
swprintf(full_path, 1024, L"%s*", stb__from_utf8(path));
|
||||
else
|
||||
swprintf(full_path, 1024, L"%s/*", stb__from_utf8(path));
|
||||
#endif
|
||||
|
||||
// it's possible this directory is already present: that means it was in the
|
||||
// cache, but its parent wasn't... in that case, we're done with it
|
||||
if (stb__showfile) printf("C[%d]", stb_arr_len(active->dirs));
|
||||
for (n=0; n < stb_arr_len(active->dirs); ++n)
|
||||
if (0 == stb_stricmp(active->dirs[n].path, path))
|
||||
if (0 == stb_stricmp(active->dirs[n].path, path)) {
|
||||
if (stb__showfile) printf("D");
|
||||
return;
|
||||
}
|
||||
if (stb__showfile) printf("E");
|
||||
|
||||
// otherwise, we need to add it
|
||||
stb__dirtree_add_dir(path, last_time, active);
|
||||
n = stb_arr_lastn(active->dirs);
|
||||
|
||||
if( (hFile = _wfindfirst((const wchar_t *)full_path, &c_file )) != -1L ) {
|
||||
if (stb__showfile) printf("[");
|
||||
if( (hFile = _wfindfirsti64( full_path, &c_file )) != -1L ) {
|
||||
do {
|
||||
if (stb__showfile) printf(")");
|
||||
if (c_file.attrib & _A_SUBDIR) {
|
||||
// ignore subdirectories starting with '.', e.g. "." and ".."
|
||||
if (c_file.name[0] != '.') {
|
||||
char *new_path = (char *) full_path;
|
||||
char *temp = stb__to_utf8((stb__wchar *)c_file.name);
|
||||
char *temp = stb__to_utf8(c_file.name);
|
||||
|
||||
if (has_slash)
|
||||
sprintf(new_path, "%s%s", path, temp);
|
||||
else
|
||||
sprintf(new_path, "%s/%s", path, temp);
|
||||
|
||||
if (stb__dircount_mask) {
|
||||
++stb__dircount;
|
||||
if (!(stb__dircount & stb__dircount_mask)) {
|
||||
printf("%s\r", new_path);
|
||||
}
|
||||
}
|
||||
|
||||
stb__dirtree_scandir(new_path, c_file.time_write, active);
|
||||
}
|
||||
} else {
|
||||
char *temp = stb__to_utf8((stb__wchar *)c_file.name);
|
||||
char *temp = stb__to_utf8(c_file.name);
|
||||
stb__dirtree_add_file(temp, n, c_file.size, c_file.time_write, active);
|
||||
}
|
||||
} while( _wfindnext( hFile, &c_file ) == 0 );
|
||||
|
||||
if (stb__showfile) printf("(");
|
||||
} while( _wfindnexti64( hFile, &c_file ) == 0 );
|
||||
if (stb__showfile) printf("]");
|
||||
_findclose( hFile );
|
||||
}
|
||||
if (stb__showfile) printf(">\n");
|
||||
}
|
||||
|
||||
// scan the database and see if it's all valid
|
||||
|
@ -6862,13 +7024,21 @@ static int stb__dirtree_update_db(stb_dirtree *db, stb_dirtree *active)
|
|||
|
||||
for (i=0; i < stb_arr_len(db->dirs); ++i) {
|
||||
struct _stat info;
|
||||
if (stb__dircount_mask) {
|
||||
++stb__dircount;
|
||||
if (!(stb__dircount & stb__dircount_mask)) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
if (0 == _stat(db->dirs[i].path, &info)) {
|
||||
if (info.st_mode & _S_IFDIR) {
|
||||
// it's still a directory, as expected
|
||||
if (info.st_mtime > db->dirs[i].last_modified) {
|
||||
int n = abs(info.st_mtime - db->dirs[i].last_modified);
|
||||
if (n > 1 && n != 3600) { // the 3600 is a hack because sometimes this jumps for no apparent reason, even when no time zone or DST issues are at play
|
||||
// it's changed! force a rescan
|
||||
// we don't want to scan it until we've stat()d its
|
||||
// subdirs, though, so we queue it
|
||||
if (stb__showfile) printf("Changed: %s - %08x:%08x\n", db->dirs[i].path, db->dirs[i].last_modified, info.st_mtime);
|
||||
stb_arr_push(rescan, i);
|
||||
// update the last_mod time
|
||||
db->dirs[i].last_modified = info.st_mtime;
|
||||
|
@ -6946,6 +7116,8 @@ stb_dirtree *stb_dirtree_get_with_file(char *dir, char *cache_file)
|
|||
|
||||
if (cache_file != NULL)
|
||||
stb__dirtree_load_db(cache_file, &db, stripped_dir);
|
||||
else if (stb__showfile)
|
||||
printf("No cache file\n");
|
||||
|
||||
active.files = NULL;
|
||||
active.dirs = NULL;
|
||||
|
@ -6960,6 +7132,9 @@ stb_dirtree *stb_dirtree_get_with_file(char *dir, char *cache_file)
|
|||
|
||||
stb__dirtree_scandir(stripped_dir, 0, &active); // no last_modified time available for root
|
||||
|
||||
if (stb__dircount_mask)
|
||||
printf(" \r");
|
||||
|
||||
// done with the DB; write it back out if any changes, i.e. either
|
||||
// 1. any inconsistency found between cached information and actual disk
|
||||
// or 2. if scanning the root found any new directories--which we detect because
|
||||
|
@ -7022,6 +7197,32 @@ void stb_dirtree_free(stb_dirtree *d)
|
|||
stb__dirtree_free_raw(d);
|
||||
free(d);
|
||||
}
|
||||
|
||||
void stb_dirtree_db_add_dir(stb_dirtree *active, char *path, time_t last)
|
||||
{
|
||||
stb__dirtree_add_dir(path, last, active);
|
||||
}
|
||||
|
||||
void stb_dirtree_db_add_file(stb_dirtree *active, char *name, int dir, stb_int64 size, time_t last)
|
||||
{
|
||||
stb__dirtree_add_file(name, dir, size, last, active);
|
||||
}
|
||||
|
||||
void stb_dirtree_db_read(stb_dirtree *target, char *filename, char *dir)
|
||||
{
|
||||
char *s = stb_strip_final_slash(strdup(dir));
|
||||
target->dirs = 0;
|
||||
target->files = 0;
|
||||
target->string_pool = 0;
|
||||
stb__dirtree_load_db(filename, target, s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
void stb_dirtree_db_write(stb_dirtree *target, char *filename, char *dir)
|
||||
{
|
||||
stb__dirtree_save_db(filename, target, 0); // don't strip out any directories
|
||||
}
|
||||
|
||||
#endif // STB_DEFINE
|
||||
|
||||
#endif // _WIN32
|
||||
|
@ -7338,7 +7539,7 @@ STB_EXTERN void ** stb_ps_fastlist(stb_ps *ps, int *count);
|
|||
// but some entries of the list may be invalid;
|
||||
// test with 'stb_ps_fastlist_valid(x)'
|
||||
|
||||
#define stb_ps_fastlist_valid(x) ((unsigned int) (x) > 1)
|
||||
#define stb_ps_fastlist_valid(x) ((stb_uinta) (x) > 1)
|
||||
|
||||
#ifdef STB_DEFINE
|
||||
|
||||
|
@ -7359,8 +7560,6 @@ typedef struct
|
|||
#define GetBucket(p) ((stb_ps_bucket *) ((char *) (p) - STB_ps_bucket))
|
||||
#define EncodeBucket(p) ((stb_ps *) ((char *) (p) + STB_ps_bucket))
|
||||
|
||||
typedef char stb__verify_bucket_heap_size[sizeof(stb_ps_bucket) == 16];
|
||||
|
||||
static void stb_bucket_free(stb_ps_bucket *b)
|
||||
{
|
||||
free(b);
|
||||
|
@ -7736,7 +7935,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
|
|||
void ** stb_ps_getlist(stb_ps *ps, int *count)
|
||||
{
|
||||
int i,n=0;
|
||||
void **p;
|
||||
void **p = NULL;
|
||||
switch (3 & (int) ps) {
|
||||
case STB_ps_direct:
|
||||
if (ps == NULL) { *count = 0; return NULL; }
|
||||
|
@ -10058,7 +10257,7 @@ char *stb_decompress_fromfile(char *filename, unsigned int *len)
|
|||
if (p == NULL) return NULL;
|
||||
if (p[0] != 0x57 || p[1] != 0xBc || p[2] || p[3]) { free(p); return NULL; }
|
||||
q = (char *) malloc(stb_decompress_length(p)+1);
|
||||
if (!q) { free(p); free(p); return NULL; }
|
||||
if (!q) { free(p); return NULL; }
|
||||
*len = stb_decompress((unsigned char *) q, p, n);
|
||||
if (*len) q[*len] = 0;
|
||||
free(p);
|
||||
|
@ -10407,15 +10606,15 @@ int stb_compress_intofile(FILE *f, char *input, unsigned int length)
|
|||
////////////////////// streaming I/O version /////////////////////
|
||||
|
||||
|
||||
static stb_uint stb_out_backpatch_id(void)
|
||||
static size_t stb_out_backpatch_id(void)
|
||||
{
|
||||
if (stb__out)
|
||||
return (stb_uint) stb__out;
|
||||
return (size_t) stb__out;
|
||||
else
|
||||
return ftell(stb__outfile);
|
||||
}
|
||||
|
||||
static void stb_out_backpatch(stb_uint id, stb_uint value)
|
||||
static void stb_out_backpatch(size_t id, stb_uint value)
|
||||
{
|
||||
stb_uchar data[4] = { value >> 24, value >> 16, value >> 8, value };
|
||||
if (stb__out) {
|
||||
|
@ -11107,7 +11306,7 @@ int stb_arith_decode_byte(stb_arith *a)
|
|||
// Threads
|
||||
//
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
#ifdef STB_THREADS
|
||||
#error "threads not implemented except for Windows"
|
||||
#endif
|
||||
|
@ -14077,10 +14276,49 @@ void stua_run_script(char *s)
|
|||
stua_gc(1);
|
||||
}
|
||||
#endif // STB_DEFINE
|
||||
|
||||
#endif // STB_STUA
|
||||
|
||||
|
||||
#undef STB_EXTERN
|
||||
#endif // STB_INCLUDE_STB_H
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
259
stb_c_lexer.h
259
stb_c_lexer.h
|
@ -1,4 +1,4 @@
|
|||
// stb_c_lexer.h - v0.06 - public domain Sean Barrett 2013
|
||||
// stb_c_lexer.h - v0.09 - public domain Sean Barrett 2013
|
||||
// lexer for making little C-like languages with recursive-descent parsers
|
||||
//
|
||||
// This file provides both the interface and the implementation.
|
||||
|
@ -10,6 +10,9 @@
|
|||
// suffixes on integer constants are not handled (you can override this).
|
||||
//
|
||||
// History:
|
||||
// 0.09 hex floats, no-stdlib fixes
|
||||
// 0.08 fix bad pointer comparison
|
||||
// 0.07 fix mishandling of hexadecimal constants parsed by strtol
|
||||
// 0.06 fix missing next character after ending quote mark (Andreas Fredriksson)
|
||||
// 0.05 refixed get_location because github version had lost the fix
|
||||
// 0.04 fix octal parsing bug
|
||||
|
@ -28,6 +31,14 @@
|
|||
// - haven't implemented octal/hex character constants
|
||||
// - haven't implemented support for unicode CLEX_char
|
||||
// - need to expand error reporting so you don't just get "CLEX_parse_error"
|
||||
//
|
||||
// Contributors:
|
||||
// Arpad Goretity (bugfix)
|
||||
// Alan Hickman (hex floats)
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
#ifndef STB_C_LEXER_DEFINITIONS
|
||||
// to change the default parsing rules, copy the following lines
|
||||
|
@ -38,7 +49,8 @@
|
|||
#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit
|
||||
#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit
|
||||
#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit
|
||||
#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE]-?[0-9]+)?) CLEX_floatlit
|
||||
#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit
|
||||
#define STB_C_LEX_C99_HEX_FLOATS N // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit
|
||||
#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id
|
||||
#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring
|
||||
#define STB_C_LEX_C_SQ_STRINGS N // single-quote-delimited strings with escapes CLEX_ssstring
|
||||
|
@ -77,7 +89,7 @@
|
|||
#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess
|
||||
// still have #line, #pragma, etc)
|
||||
|
||||
//#define STB_C_LEX_ISWHITE(str) ... // return length in bytes of first character if it is whitespace
|
||||
//#define STB_C_LEX_ISWHITE(str) ... // return length in bytes of whitespace characters if first char is whitespace
|
||||
|
||||
#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions
|
||||
// --END--
|
||||
|
@ -164,11 +176,6 @@ extern void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where,
|
|||
#define Y(x) 1
|
||||
#define N(x) 0
|
||||
|
||||
#if STB_C_LEX_USE_STDLIB(x)
|
||||
#define STB__CLEX_use_stdlib
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if STB_C_LEX_INTEGERS_AS_DOUBLES(x)
|
||||
typedef double stb__clex_int;
|
||||
#define intfield real_number
|
||||
|
@ -193,6 +200,10 @@ typedef long stb__clex_int;
|
|||
#define STB__clex_define_shifts
|
||||
#endif
|
||||
|
||||
#if STB_C_LEX_C99_HEX_FLOATS(x)
|
||||
#define STB__clex_hex_floats
|
||||
#endif
|
||||
|
||||
#if STB_C_LEX_C_HEX_INTS(x)
|
||||
#define STB__clex_hex_ints
|
||||
#endif
|
||||
|
@ -213,6 +224,11 @@ typedef long stb__clex_int;
|
|||
#define STB__clex_discard_preprocessor
|
||||
#endif
|
||||
|
||||
#if STB_C_LEX_USE_STDLIB(x) && (!defined(STB__clex_hex_floats) || __STDC_VERSION__ >= 199901L)
|
||||
#define STB__CLEX_use_stdlib
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
// Now pick a definition of Y/N that's conducive to
|
||||
// defining the enum of token names.
|
||||
#if STB_C_LEX_DEFINE_ALL_TOKEN_NAMES(x) || defined(STB_C_LEXER_SELF_TEST)
|
||||
|
@ -357,34 +373,95 @@ static int stb__clex_parse_suffixes(stb_lexer *lexer, long tokenid, char *start,
|
|||
}
|
||||
|
||||
#ifndef STB__CLEX_use_stdlib
|
||||
static double stb__clex_pow(double base, unsigned int exponent)
|
||||
{
|
||||
double value=1;
|
||||
for ( ; exponent; exponent >>= 1) {
|
||||
if (exponent & 1)
|
||||
value *= base;
|
||||
base *= base;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static double stb__clex_parse_float(char *p, char **q)
|
||||
{
|
||||
char *s = p;
|
||||
double value=0;
|
||||
while (*p >= '0' && *p <= '9')
|
||||
value = value*10 + (*p++ - '0');
|
||||
if (*p == '.') {
|
||||
double powten=1, addend = 0;
|
||||
++p;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
addend = addend + 10*(*p++ - '0');
|
||||
powten *= 10;
|
||||
int base=10;
|
||||
int exponent=0;
|
||||
|
||||
#ifdef STB__clex_hex_floats
|
||||
if (*p == '0') {
|
||||
if (p[1] == 'x' || p[1] == 'X') {
|
||||
base=16;
|
||||
p += 2;
|
||||
}
|
||||
value += addend / powten;
|
||||
}
|
||||
if (*p == 'e' || *p == 'E') {
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if (*p >= '0' && *p <= '9')
|
||||
value = value*base + (*p++ - '0');
|
||||
#ifdef STB__clex_hex_floats
|
||||
else if (base == 16 && *p >= 'a' && *p <= 'f')
|
||||
value = value*base + 10 + (*p++ - 'a');
|
||||
else if (base == 16 && *p >= 'A' && *p <= 'F')
|
||||
value = value*base + 10 + (*p++ - 'A');
|
||||
#endif
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p == '.') {
|
||||
double pow, addend = 0;
|
||||
++p;
|
||||
for (pow=1; ; pow*=base) {
|
||||
if (*p >= '0' && *p <= '9')
|
||||
addend = addend*base + (*p++ - '0');
|
||||
#ifdef STB__clex_hex_floats
|
||||
else if (base == 16 && *p >= 'a' && *p <= 'f')
|
||||
addend = addend*base + 10 + (*p++ - 'a');
|
||||
else if (base == 16 && *p >= 'A' && *p <= 'F')
|
||||
addend = addend*base + 10 + (*p++ - 'A');
|
||||
#endif
|
||||
else
|
||||
break;
|
||||
}
|
||||
value += addend / pow;
|
||||
}
|
||||
#ifdef STB__clex_hex_floats
|
||||
if (base == 16) {
|
||||
// exponent required for hex float literal
|
||||
if (*p != 'p' && *p != 'P') {
|
||||
*q = s;
|
||||
return 0;
|
||||
}
|
||||
exponent = 1;
|
||||
} else
|
||||
#endif
|
||||
exponent = (*p == 'e' || *p == 'E');
|
||||
|
||||
if (exponent) {
|
||||
int sign = p[1] == '-';
|
||||
int exponent=0;
|
||||
double pow10=1;
|
||||
p += 1+sign;
|
||||
unsigned int exponent=0;
|
||||
double power=1;
|
||||
++p;
|
||||
if (*p == '-' || *p == '+')
|
||||
++p;
|
||||
while (*p >= '0' && *p <= '9')
|
||||
exponent = exponent*10 + (*p++ - '0');
|
||||
// can't use pow() from stdlib, so do it slow way
|
||||
while (exponent-- > 0)
|
||||
pow10 *= 10;
|
||||
if (sign)
|
||||
value /= pow10;
|
||||
|
||||
#ifdef STB__clex_hex_floats
|
||||
if (base == 16)
|
||||
power = stb__clex_pow(2, exponent);
|
||||
else
|
||||
value *= pow10;
|
||||
#endif
|
||||
power = stb__clex_pow(10, exponent);
|
||||
if (sign)
|
||||
value /= power;
|
||||
else
|
||||
value *= power;
|
||||
}
|
||||
*q = p;
|
||||
return value;
|
||||
|
@ -452,7 +529,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|||
int n;
|
||||
n = STB_C_LEX_ISWHITE(p);
|
||||
if (n == 0) break;
|
||||
if (lexer->eof && lexer+n > lexer->eof)
|
||||
if (lexer->eof && lexer->eof - lexer->parse_point < n)
|
||||
return stb__clex_token(tok, CLEX_parse_error, p,lexer->eof-1);
|
||||
p += n;
|
||||
}
|
||||
|
@ -623,33 +700,57 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|||
goto single_char;
|
||||
|
||||
case '0':
|
||||
#ifdef STB__clex_hex_ints
|
||||
#if defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
|
||||
if (p+1 != lexer->eof) {
|
||||
if (p[1] == 'x' || p[1] == 'X') {
|
||||
char *q = p+2;
|
||||
#ifdef STB__CLEX_use_stdlib
|
||||
lexer->int_number = strtol((char *) p, (char **) q, 16);
|
||||
#else
|
||||
stb__clex_int n=0;
|
||||
while (q != lexer->eof) {
|
||||
if (*q >= '0' && *q <= '9')
|
||||
n = n*16 + (*q - '0');
|
||||
else if (*q >= 'a' && *q <= 'f')
|
||||
n = n*16 + (*q - 'a') + 10;
|
||||
else if (*q >= 'A' && *q <= 'F')
|
||||
n = n*16 + (*q - 'A') + 10;
|
||||
else
|
||||
break;
|
||||
++q;
|
||||
char *q;
|
||||
|
||||
#ifdef STB__clex_hex_floats
|
||||
for (q=p+2;
|
||||
q != lexer->eof && ((*q >= '0' && *q <= '9') || (*q >= 'a' && *q <= 'f') || (*q >= 'A' && *q <= 'F'));
|
||||
++q);
|
||||
if (q != lexer->eof) {
|
||||
if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'p' || *q == 'P')) {
|
||||
#ifdef STB__CLEX_use_stdlib
|
||||
lexer->real_number = strtod((char *) p, (char**) &q);
|
||||
#else
|
||||
lexer->real_number = stb__clex_parse_float(p, &q);
|
||||
#endif
|
||||
|
||||
if (p == q)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, p,q);
|
||||
return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES);
|
||||
|
||||
}
|
||||
}
|
||||
#endif // STB__CLEX_hex_floats
|
||||
|
||||
#ifdef STB__clex_hex_ints
|
||||
#ifdef STB__CLEX_use_stdlib
|
||||
lexer->int_number = strtol((char *) p, (char **) &q, 16);
|
||||
#else
|
||||
{
|
||||
stb__clex_int n=0;
|
||||
for (q=p+2; q != lexer->eof; ++q) {
|
||||
if (*q >= '0' && *q <= '9')
|
||||
n = n*16 + (*q - '0');
|
||||
else if (*q >= 'a' && *q <= 'f')
|
||||
n = n*16 + (*q - 'a') + 10;
|
||||
else if (*q >= 'A' && *q <= 'F')
|
||||
n = n*16 + (*q - 'A') + 10;
|
||||
else
|
||||
break;
|
||||
}
|
||||
lexer->int_number = n;
|
||||
}
|
||||
lexer->int_field = n; // int_field is macro that expands to real_number/int_number depending on type of n
|
||||
#endif
|
||||
if (q == p+2)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, p-2,p-1);
|
||||
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_HEX_SUFFIXES);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // STB__clex_hex_ints
|
||||
#endif // defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
|
||||
// can't test for octal because we might parse '0.0' as float or as '0' '.' '0',
|
||||
// so have to do float first
|
||||
|
||||
|
@ -685,14 +786,14 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|||
stb__clex_int n=0;
|
||||
while (q != lexer->eof) {
|
||||
if (*q >= '0' && *q <= '7')
|
||||
n = n*8 + (q - '0');
|
||||
n = n*8 + (*q - '0');
|
||||
else
|
||||
break;
|
||||
++q;
|
||||
}
|
||||
if (q != lexer->eof && (*q == '8' || *q=='9'))
|
||||
return stb__clex_token(tok, CLEX_parse_error, p, q);
|
||||
lexer->int_field = n;
|
||||
return stb__clex_token(lexer, CLEX_parse_error, p, q);
|
||||
lexer->int_number = n;
|
||||
#endif
|
||||
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
|
||||
}
|
||||
|
@ -707,12 +808,12 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|||
stb__clex_int n=0;
|
||||
while (q != lexer->eof) {
|
||||
if (*q >= '0' && *q <= '9')
|
||||
n = n*10 + (q - '0');
|
||||
n = n*10 + (*q - '0');
|
||||
else
|
||||
break;
|
||||
++q;
|
||||
}
|
||||
lexer->int_field = n;
|
||||
lexer->int_number = n;
|
||||
#endif
|
||||
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
|
||||
}
|
||||
|
@ -725,6 +826,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|||
#ifdef STB_C_LEXER_SELF_TEST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void print_token(stb_lexer *lexer)
|
||||
{
|
||||
|
@ -780,7 +882,15 @@ multiline comments */
|
|||
|
||||
void dummy(void)
|
||||
{
|
||||
printf("test",1); // https://github.com/nothings/stb/issues/13
|
||||
double some_floats[] = {
|
||||
1.0501, -10.4e12, 5E+10,
|
||||
#if 0 // not support in C++ or C-pre-99, so don't try to compile it
|
||||
0x1.0p+24, 0xff.FP-8, 0x1p-23,
|
||||
#endif
|
||||
4.
|
||||
};
|
||||
|
||||
printf("test %d",1); // https://github.com/nothings/stb/issues/13
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -791,11 +901,13 @@ int main(int argc, char **argv)
|
|||
stb_lexer lex;
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "Error opening file\n");
|
||||
free(text);
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
stb_c_lexer_init(&lex, text, text+len, (char *) malloc(1<<16), 1<<16);
|
||||
stb_c_lexer_init(&lex, text, text+len, (char *) malloc(0x10000), 0x10000);
|
||||
while (stb_c_lexer_get_token(&lex)) {
|
||||
if (lex.token == CLEX_parse_error) {
|
||||
printf("\n<<<PARSE ERROR>>>\n");
|
||||
|
@ -807,3 +919,44 @@ int main(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
File diff suppressed because it is too large
Load Diff
46
stb_divide.h
46
stb_divide.h
|
@ -75,6 +75,10 @@
|
|||
// by the euclidean division operator we define, so it's possibly not
|
||||
// always true. If any such platform turns up, we can add more cases.
|
||||
// (Possibly only stb_div_trunc currently relies on property (b).)
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
|
||||
#ifndef INCLUDE_STB_DIVIDE_H
|
||||
|
@ -371,3 +375,45 @@ int main(int argc, char **argv)
|
|||
#endif // STB_DIVIDE_TEST
|
||||
#endif // STB_DIVIDE_IMPLEMENTATION
|
||||
#endif // INCLUDE_STB_DIVIDE_H
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
81
stb_dxt.h
81
stb_dxt.h
|
@ -1,4 +1,4 @@
|
|||
// stb_dxt.h - v1.04 - DXT1/DXT5 compressor - public domain
|
||||
// stb_dxt.h - v1.06 - DXT1/DXT5 compressor - public domain
|
||||
// original by fabian "ryg" giesen - ported to C by stb
|
||||
// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation
|
||||
//
|
||||
|
@ -9,6 +9,8 @@
|
|||
// and "high quality" using mode.
|
||||
//
|
||||
// version history:
|
||||
// v1.06 - (stb) fix to known-broken 1.05
|
||||
// v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski)
|
||||
// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec);
|
||||
// single color match fix (allow for inexact color interpolation);
|
||||
// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps.
|
||||
|
@ -16,6 +18,10 @@
|
|||
// v1.02 - (stb) fix alpha encoding bug
|
||||
// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom
|
||||
// v1.00 - (stb) first release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
#ifndef STB_INCLUDE_STB_DXT_H
|
||||
#define STB_INCLUDE_STB_DXT_H
|
||||
|
@ -25,7 +31,17 @@
|
|||
#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like!
|
||||
#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower.
|
||||
|
||||
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode);
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode);
|
||||
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define STB_COMPRESS_DXT_BLOCK
|
||||
|
||||
#ifdef STB_DXT_IMPLEMENTATION
|
||||
|
@ -532,18 +548,18 @@ static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, i
|
|||
}
|
||||
|
||||
// Alpha block compression (this is easy for a change)
|
||||
static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int mode)
|
||||
static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src, int stride)
|
||||
{
|
||||
int i,dist,bias,dist4,dist2,bits,mask;
|
||||
|
||||
// find min/max color
|
||||
int mn,mx;
|
||||
mn = mx = src[3];
|
||||
mn = mx = src[0];
|
||||
|
||||
for (i=1;i<16;i++)
|
||||
{
|
||||
if (src[i*4+3] < mn) mn = src[i*4+3];
|
||||
else if (src[i*4+3] > mx) mx = src[i*4+3];
|
||||
if (src[i*stride] < mn) mn = src[i*stride];
|
||||
else if (src[i*stride] > mx) mx = src[i*stride];
|
||||
}
|
||||
|
||||
// encode them
|
||||
|
@ -562,7 +578,7 @@ static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int m
|
|||
bits = 0,mask=0;
|
||||
|
||||
for (i=0;i<16;i++) {
|
||||
int a = src[i*4+3]*7 + bias;
|
||||
int a = src[i*stride]*7 + bias;
|
||||
int ind,t;
|
||||
|
||||
// select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max).
|
||||
|
@ -613,12 +629,59 @@ void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int a
|
|||
}
|
||||
|
||||
if (alpha) {
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src,mode);
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4);
|
||||
dest += 8;
|
||||
}
|
||||
|
||||
stb__CompressColorBlock(dest,(unsigned char*) src,mode);
|
||||
}
|
||||
#endif // STB_DXT_IMPLEMENTATION
|
||||
|
||||
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src)
|
||||
{
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src,2);
|
||||
stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2);
|
||||
}
|
||||
#endif // STB_DXT_IMPLEMENTATION
|
||||
#endif // STB_INCLUDE_STB_DXT_H
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
103
stb_easy_font.h
103
stb_easy_font.h
|
@ -1,4 +1,4 @@
|
|||
// stb_easy_font.h - v0.5 - bitmap font for 3D rendering - public domain
|
||||
// stb_easy_font.h - v1.0 - bitmap font for 3D rendering - public domain
|
||||
// Sean Barrett, Feb 2015
|
||||
//
|
||||
// Easy-to-deploy,
|
||||
|
@ -16,8 +16,10 @@
|
|||
// DOCUMENTATION:
|
||||
//
|
||||
// int stb_easy_font_width(char *text)
|
||||
// int stb_easy_font_height(char *text)
|
||||
//
|
||||
// Takes a string without newlines and returns the horizontal size.
|
||||
// Takes a string and returns the horizontal size and the
|
||||
// vertical size (which can vary if 'text' has newlines).
|
||||
//
|
||||
// int stb_easy_font_print(float x, float y,
|
||||
// char *text, unsigned char color[4],
|
||||
|
@ -40,7 +42,7 @@
|
|||
//
|
||||
// You can ignore z and color if you get them from elsewhere
|
||||
// This format was chosen in the hopes it would make it
|
||||
// easier for you to reuse existing buffer-drawing code.
|
||||
// easier for you to reuse existing vertex-buffer-drawing code.
|
||||
//
|
||||
// If you pass in NULL for color, it becomes 255,255,255,255.
|
||||
//
|
||||
|
@ -63,12 +65,27 @@
|
|||
// compact to me; -0.5 is a reasonable compromise as long as
|
||||
// you're scaling the font up.
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// (2017-01-15) 1.0 space character takes same space as numbers; fix bad spacing of 'f'
|
||||
// (2016-01-22) 0.7 width() supports multiline text; add height()
|
||||
// (2015-09-13) 0.6 #include <math.h>; updated license
|
||||
// (2015-02-01) 0.5 First release
|
||||
//
|
||||
// CONTRIBUTORS
|
||||
//
|
||||
// github:vassvik -- bug report
|
||||
|
||||
#if 0
|
||||
// SAMPLE CODE:
|
||||
//
|
||||
// Here's sample code for old OpenGL; it's a lot more complicated
|
||||
// to make work on modern APIs, and that's your problem.
|
||||
//
|
||||
#if 0
|
||||
void print_string(float x, float y, char *text, float r, float g, float b)
|
||||
{
|
||||
static char buffer[99999]; // ~500 chars
|
||||
|
@ -88,13 +105,14 @@ void print_string(float x, float y, char *text, float r, float g, float b)
|
|||
#define INCLUDE_STB_EASY_FONT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
struct {
|
||||
struct stb_easy_font_info_struct {
|
||||
unsigned char advance;
|
||||
unsigned char h_seg;
|
||||
unsigned char v_seg;
|
||||
} stb_easy_font_charinfo[96] = {
|
||||
{ 5, 0, 0 }, { 3, 0, 0 }, { 5, 1, 1 }, { 7, 1, 4 },
|
||||
{ 6, 0, 0 }, { 3, 0, 0 }, { 5, 1, 1 }, { 7, 1, 4 },
|
||||
{ 7, 3, 7 }, { 7, 6, 12 }, { 7, 8, 19 }, { 4, 16, 21 },
|
||||
{ 4, 17, 22 }, { 4, 19, 23 }, { 23, 21, 24 }, { 23, 22, 31 },
|
||||
{ 20, 23, 34 }, { 22, 23, 36 }, { 19, 24, 36 }, { 21, 25, 36 },
|
||||
|
@ -111,7 +129,7 @@ struct {
|
|||
{ 7,109,165 }, { 7,118,167 }, { 6,118,172 }, { 4,120,176 },
|
||||
{ 6,122,177 }, { 4,122,181 }, { 23,124,182 }, { 22,129,182 },
|
||||
{ 4,130,182 }, { 22,131,183 }, { 6,133,187 }, { 22,135,191 },
|
||||
{ 6,137,192 }, { 22,139,196 }, { 5,144,197 }, { 22,147,198 },
|
||||
{ 6,137,192 }, { 22,139,196 }, { 6,144,197 }, { 22,147,198 },
|
||||
{ 6,150,202 }, { 19,151,206 }, { 21,152,207 }, { 6,155,209 },
|
||||
{ 3,160,210 }, { 23,160,211 }, { 22,164,216 }, { 22,165,220 },
|
||||
{ 22,167,224 }, { 22,169,228 }, { 21,171,232 }, { 21,173,233 },
|
||||
|
@ -210,11 +228,76 @@ static int stb_easy_font_print(float x, float y, char *text, unsigned char color
|
|||
static int stb_easy_font_width(char *text)
|
||||
{
|
||||
float len = 0;
|
||||
float max_len = 0;
|
||||
while (*text) {
|
||||
len += stb_easy_font_charinfo[*text-32].advance & 15;
|
||||
len += stb_easy_font_spacing_val;
|
||||
if (*text == '\n') {
|
||||
if (len > max_len) max_len = len;
|
||||
len = 0;
|
||||
} else {
|
||||
len += stb_easy_font_charinfo[*text-32].advance & 15;
|
||||
len += stb_easy_font_spacing_val;
|
||||
}
|
||||
++text;
|
||||
}
|
||||
return (int) ceil(len);
|
||||
if (len > max_len) max_len = len;
|
||||
return (int) ceil(max_len);
|
||||
}
|
||||
|
||||
static int stb_easy_font_height(char *text)
|
||||
{
|
||||
float y = 0;
|
||||
int nonempty_line=0;
|
||||
while (*text) {
|
||||
if (*text == '\n') {
|
||||
y += 12;
|
||||
nonempty_line = 0;
|
||||
} else {
|
||||
nonempty_line = 1;
|
||||
}
|
||||
++text;
|
||||
}
|
||||
return (int) ceil(y + (nonempty_line ? 12 : 0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
/* stbhw - v0.6 - http://nothings.org/gamedev/herringbone
|
||||
Herringbone Wang Tile Generator - Sean Barrett 2014 - public domain
|
||||
|
||||
This file is in the public domain. In case that declaration is ineffective,
|
||||
you are also granted a license to use and modify it without restriction.
|
||||
== LICENSE ==============================
|
||||
|
||||
This software is dual-licensed to the public domain and under the following
|
||||
license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
publish, and distribute this file as you see fit.
|
||||
|
||||
== WHAT IT IS ===========================
|
||||
|
||||
|
|
2214
stb_image.h
2214
stb_image.h
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
/* stb_image_resize - v0.90 - public domain image resizing
|
||||
/* stb_image_resize - v0.94 - public domain image resizing
|
||||
by Jorge L Rodriguez (@VinoBS) - 2014
|
||||
http://github.com/nothings/stb
|
||||
|
||||
|
@ -107,8 +107,8 @@
|
|||
industry, it is still uncommon in the videogame/real-time world.
|
||||
|
||||
If you linearly filter non-premultiplied alpha, strange effects
|
||||
occur. (For example, the average of 1% opaque bright green
|
||||
and 99% opaque black produces 50% transparent dark green when
|
||||
occur. (For example, the 50/50 average of 99% transparent bright green
|
||||
and 1% transparent black produces 50% transparent dark green when
|
||||
non-premultiplied, whereas premultiplied it produces 50%
|
||||
transparent near-black. The former introduces green energy
|
||||
that doesn't exist in the source image.)
|
||||
|
@ -152,16 +152,20 @@
|
|||
(For example, graphics hardware does not apply sRGB conversion
|
||||
to the alpha channel.)
|
||||
|
||||
ADDITIONAL CONTRIBUTORS
|
||||
CONTRIBUTORS
|
||||
Jorge L Rodriguez: Implementation
|
||||
Sean Barrett: API design, optimizations
|
||||
Aras Pranckevicius: bugfix
|
||||
|
||||
REVISIONS
|
||||
0.94 (2017-03-18) fixed warnings
|
||||
0.93 (2017-03-03) fixed bug with certain combinations of heights
|
||||
0.92 (2017-01-02) fix integer overflow on large (>2GB) images
|
||||
0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
|
||||
0.90 (2014-09-17) first released version
|
||||
|
||||
LICENSE
|
||||
This software is in the public domain. Where that dedication is not
|
||||
recognized, you are granted a perpetual, irrevocable license to copy
|
||||
and modify this file as you see fit.
|
||||
See end of file for license information.
|
||||
|
||||
TODO
|
||||
Don't decode all of the image data when only processing a partial tile
|
||||
|
@ -382,15 +386,6 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
|
|||
#define STBIR_ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
#ifdef STBIR_DEBUG
|
||||
#define STBIR__DEBUG_ASSERT STBIR_ASSERT
|
||||
#else
|
||||
#define STBIR__DEBUG_ASSERT
|
||||
#endif
|
||||
|
||||
// If you hit this it means I haven't done it yet.
|
||||
#define STBIR__UNIMPLEMENTED(x) STBIR_ASSERT(!(x))
|
||||
|
||||
// For memset
|
||||
#include <string.h>
|
||||
|
||||
|
@ -538,10 +533,11 @@ typedef struct
|
|||
int horizontal_num_contributors;
|
||||
int vertical_num_contributors;
|
||||
|
||||
int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
|
||||
int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
|
||||
int ring_buffer_num_entries; // Total number of entries in the ring buffer.
|
||||
int ring_buffer_first_scanline;
|
||||
int ring_buffer_last_scanline;
|
||||
int ring_buffer_begin_index;
|
||||
int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
|
||||
float* ring_buffer;
|
||||
|
||||
float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
|
||||
|
@ -556,16 +552,17 @@ typedef struct
|
|||
int encode_buffer_size;
|
||||
} stbir__info;
|
||||
|
||||
|
||||
static const float stbir__max_uint8_as_float = 255.0f;
|
||||
static const float stbir__max_uint16_as_float = 65535.0f;
|
||||
static const double stbir__max_uint32_as_float = 4294967295.0;
|
||||
|
||||
|
||||
static stbir__inline int stbir__min(int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static stbir__inline int stbir__max(int a, int b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
static stbir__inline float stbir__saturate(float x)
|
||||
{
|
||||
if (x < 0)
|
||||
|
@ -757,7 +754,7 @@ static float stbir__filter_trapezoid(float x, float scale)
|
|||
{
|
||||
float halfscale = scale / 2;
|
||||
float t = 0.5f + halfscale;
|
||||
STBIR__DEBUG_ASSERT(scale <= 1);
|
||||
STBIR_ASSERT(scale <= 1);
|
||||
|
||||
x = (float)fabs(x);
|
||||
|
||||
|
@ -775,7 +772,7 @@ static float stbir__filter_trapezoid(float x, float scale)
|
|||
|
||||
static float stbir__support_trapezoid(float scale)
|
||||
{
|
||||
STBIR__DEBUG_ASSERT(scale <= 1);
|
||||
STBIR_ASSERT(scale <= 1);
|
||||
return 0.5f + scale / 2;
|
||||
}
|
||||
|
||||
|
@ -989,7 +986,7 @@ static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
|
|||
return n; // NOTREACHED
|
||||
|
||||
default:
|
||||
STBIR__UNIMPLEMENTED("Unimplemented edge type");
|
||||
STBIR_ASSERT(!"Unimplemented edge type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1032,18 +1029,18 @@ static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radi
|
|||
*out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
|
||||
}
|
||||
|
||||
static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
|
||||
static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
|
||||
{
|
||||
int i;
|
||||
float total_filter = 0;
|
||||
float filter_scale;
|
||||
|
||||
STBIR__DEBUG_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
|
||||
STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
|
||||
|
||||
contributor->n0 = in_first_pixel;
|
||||
contributor->n1 = in_last_pixel;
|
||||
|
||||
STBIR__DEBUG_ASSERT(contributor->n1 >= contributor->n0);
|
||||
STBIR_ASSERT(contributor->n1 >= contributor->n0);
|
||||
|
||||
for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
|
||||
{
|
||||
|
@ -1061,10 +1058,10 @@ static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbi
|
|||
total_filter += coefficient_group[i];
|
||||
}
|
||||
|
||||
STBIR__DEBUG_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
|
||||
STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
|
||||
|
||||
STBIR__DEBUG_ASSERT(total_filter > 0.9);
|
||||
STBIR__DEBUG_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
|
||||
STBIR_ASSERT(total_filter > 0.9);
|
||||
STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
|
||||
|
||||
// Make sure the sum of all coefficients is 1.
|
||||
filter_scale = 1 / total_filter;
|
||||
|
@ -1082,16 +1079,16 @@ static void stbir__calculate_coefficients_upsample(stbir__info* stbir_info, stbi
|
|||
}
|
||||
}
|
||||
|
||||
static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
|
||||
static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
|
||||
{
|
||||
int i;
|
||||
|
||||
STBIR__DEBUG_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
|
||||
STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
|
||||
|
||||
contributor->n0 = out_first_pixel;
|
||||
contributor->n1 = out_last_pixel;
|
||||
|
||||
STBIR__DEBUG_ASSERT(contributor->n1 >= contributor->n0);
|
||||
STBIR_ASSERT(contributor->n1 >= contributor->n0);
|
||||
|
||||
for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
|
||||
{
|
||||
|
@ -1100,7 +1097,7 @@ static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, st
|
|||
coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
|
||||
}
|
||||
|
||||
STBIR__DEBUG_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
|
||||
STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
|
||||
|
||||
for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
|
||||
{
|
||||
|
@ -1112,7 +1109,7 @@ static void stbir__calculate_coefficients_downsample(stbir__info* stbir_info, st
|
|||
}
|
||||
}
|
||||
|
||||
static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
|
||||
static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
|
||||
{
|
||||
int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
|
||||
int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
|
||||
|
@ -1135,8 +1132,8 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, st
|
|||
break;
|
||||
}
|
||||
|
||||
STBIR__DEBUG_ASSERT(total > 0.9f);
|
||||
STBIR__DEBUG_ASSERT(total < 1.1f);
|
||||
STBIR_ASSERT(total > 0.9f);
|
||||
STBIR_ASSERT(total < 1.1f);
|
||||
|
||||
scale = 1 / total;
|
||||
|
||||
|
@ -1189,7 +1186,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, st
|
|||
|
||||
// Each scan line uses the same kernel values so we should calculate the kernel
|
||||
// values once and then we can use them for every scan line.
|
||||
static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
|
||||
static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
|
||||
{
|
||||
int n;
|
||||
int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
|
||||
|
@ -1206,7 +1203,7 @@ static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributor
|
|||
|
||||
stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
|
||||
|
||||
stbir__calculate_coefficients_upsample(stbir_info, filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
|
||||
stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1222,10 +1219,10 @@ static void stbir__calculate_filters(stbir__info* stbir_info, stbir__contributor
|
|||
|
||||
stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
|
||||
|
||||
stbir__calculate_coefficients_downsample(stbir_info, filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
|
||||
stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
|
||||
}
|
||||
|
||||
stbir__normalize_downsample_coefficients(stbir_info, contributors, coefficients, filter, scale_ratio, shift, input_size, output_size);
|
||||
stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1246,11 +1243,11 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
int type = stbir_info->type;
|
||||
int colorspace = stbir_info->colorspace;
|
||||
int input_w = stbir_info->input_w;
|
||||
int input_stride_bytes = stbir_info->input_stride_bytes;
|
||||
size_t input_stride_bytes = stbir_info->input_stride_bytes;
|
||||
float* decode_buffer = stbir__get_decode_buffer(stbir_info);
|
||||
stbir_edge edge_horizontal = stbir_info->edge_horizontal;
|
||||
stbir_edge edge_vertical = stbir_info->edge_vertical;
|
||||
int in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
|
||||
size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
|
||||
const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
|
||||
int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
|
||||
int decode = STBIR__DECODE(type, colorspace);
|
||||
|
@ -1275,7 +1272,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
int decode_pixel_index = x * channels;
|
||||
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
|
||||
for (c = 0; c < channels; c++)
|
||||
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / 255;
|
||||
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1288,7 +1285,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
|
||||
|
||||
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / 255;
|
||||
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1298,7 +1295,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
int decode_pixel_index = x * channels;
|
||||
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
|
||||
for (c = 0; c < channels; c++)
|
||||
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535;
|
||||
decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1308,10 +1305,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
int decode_pixel_index = x * channels;
|
||||
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
|
||||
for (c = 0; c < channels; c++)
|
||||
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / 65535);
|
||||
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
|
||||
|
||||
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / 65535;
|
||||
decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1321,7 +1318,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
int decode_pixel_index = x * channels;
|
||||
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
|
||||
for (c = 0; c < channels; c++)
|
||||
decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295);
|
||||
decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1331,10 +1328,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
int decode_pixel_index = x * channels;
|
||||
int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
|
||||
for (c = 0; c < channels; c++)
|
||||
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / 4294967295));
|
||||
decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
|
||||
|
||||
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / 4294967295);
|
||||
decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1363,7 +1360,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
|||
break;
|
||||
|
||||
default:
|
||||
STBIR__UNIMPLEMENTED("Unknown type/colorspace/channels combination.");
|
||||
STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1416,6 +1413,8 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
|
|||
int ring_buffer_index;
|
||||
float* ring_buffer;
|
||||
|
||||
stbir_info->ring_buffer_last_scanline = n;
|
||||
|
||||
if (stbir_info->ring_buffer_begin_index < 0)
|
||||
{
|
||||
ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
|
||||
|
@ -1423,24 +1422,21 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
|
|||
}
|
||||
else
|
||||
{
|
||||
ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline) + 1) % stbir_info->vertical_filter_pixel_width;
|
||||
STBIR__DEBUG_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
|
||||
ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
|
||||
STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
|
||||
}
|
||||
|
||||
ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
|
||||
memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
|
||||
|
||||
stbir_info->ring_buffer_last_scanline = n;
|
||||
|
||||
return ring_buffer;
|
||||
}
|
||||
|
||||
|
||||
static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n, float* output_buffer)
|
||||
static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
|
||||
{
|
||||
int x, k;
|
||||
int output_w = stbir_info->output_w;
|
||||
int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
|
||||
int channels = stbir_info->channels;
|
||||
float* decode_buffer = stbir__get_decode_buffer(stbir_info);
|
||||
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
|
||||
|
@ -1456,11 +1452,11 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
|
|||
int coefficient_group = coefficient_width * x;
|
||||
int coefficient_counter = 0;
|
||||
|
||||
STBIR__DEBUG_ASSERT(n1 >= n0);
|
||||
STBIR__DEBUG_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
|
||||
STBIR__DEBUG_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
|
||||
STBIR__DEBUG_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
|
||||
STBIR__DEBUG_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
|
||||
STBIR_ASSERT(n1 >= n0);
|
||||
STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
|
||||
STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
|
||||
STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
|
||||
STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
|
||||
|
||||
switch (channels) {
|
||||
case 1:
|
||||
|
@ -1468,7 +1464,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
|
|||
{
|
||||
int in_pixel_index = k * 1;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
}
|
||||
break;
|
||||
|
@ -1477,7 +1473,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
|
|||
{
|
||||
int in_pixel_index = k * 2;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
}
|
||||
|
@ -1487,7 +1483,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
|
|||
{
|
||||
int in_pixel_index = k * 3;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
|
||||
|
@ -1498,7 +1494,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
|
|||
{
|
||||
int in_pixel_index = k * 4;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
|
||||
|
@ -1511,7 +1507,7 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
|
|||
int in_pixel_index = k * channels;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
|
||||
int c;
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
for (c = 0; c < channels; c++)
|
||||
output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
|
||||
}
|
||||
|
@ -1520,12 +1516,10 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
|
|||
}
|
||||
}
|
||||
|
||||
static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n, float* output_buffer)
|
||||
static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
|
||||
{
|
||||
int x, k;
|
||||
int input_w = stbir_info->input_w;
|
||||
int output_w = stbir_info->output_w;
|
||||
int kernel_pixel_width = stbir_info->horizontal_filter_pixel_width;
|
||||
int channels = stbir_info->channels;
|
||||
float* decode_buffer = stbir__get_decode_buffer(stbir_info);
|
||||
stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
|
||||
|
@ -1534,7 +1528,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
|
|||
int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
|
||||
int max_x = input_w + filter_pixel_margin * 2;
|
||||
|
||||
STBIR__DEBUG_ASSERT(!stbir__use_width_upsampling(stbir_info));
|
||||
STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
|
||||
|
||||
switch (channels) {
|
||||
case 1:
|
||||
|
@ -1552,7 +1546,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
|
|||
{
|
||||
int out_pixel_index = k * 1;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
}
|
||||
}
|
||||
|
@ -1573,7 +1567,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
|
|||
{
|
||||
int out_pixel_index = k * 2;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
}
|
||||
|
@ -1595,7 +1589,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
|
|||
{
|
||||
int out_pixel_index = k * 3;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
|
||||
|
@ -1618,7 +1612,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
|
|||
{
|
||||
int out_pixel_index = k * 4;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
|
||||
output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
|
||||
output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
|
||||
|
@ -1643,7 +1637,7 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
|
|||
int c;
|
||||
int out_pixel_index = k * channels;
|
||||
float coefficient = horizontal_coefficients[coefficient_group + k - n0];
|
||||
STBIR__DEBUG_ASSERT(coefficient != 0);
|
||||
STBIR_ASSERT(coefficient != 0);
|
||||
for (c = 0; c < channels; c++)
|
||||
output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
|
||||
}
|
||||
|
@ -1659,9 +1653,9 @@ static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
|
|||
|
||||
// Now resample it into the ring buffer.
|
||||
if (stbir__use_width_upsampling(stbir_info))
|
||||
stbir__resample_horizontal_upsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n));
|
||||
stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
|
||||
else
|
||||
stbir__resample_horizontal_downsample(stbir_info, n, stbir__add_empty_ring_buffer_entry(stbir_info, n));
|
||||
stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
|
||||
|
||||
// Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
|
||||
}
|
||||
|
@ -1675,17 +1669,17 @@ static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n
|
|||
|
||||
// Now resample it into the horizontal buffer.
|
||||
if (stbir__use_width_upsampling(stbir_info))
|
||||
stbir__resample_horizontal_upsample(stbir_info, n, stbir_info->horizontal_buffer);
|
||||
stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
|
||||
else
|
||||
stbir__resample_horizontal_downsample(stbir_info, n, stbir_info->horizontal_buffer);
|
||||
stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
|
||||
|
||||
// Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
|
||||
}
|
||||
|
||||
// Get the specified scan line from the ring buffer.
|
||||
static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_size, int ring_buffer_length)
|
||||
static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
|
||||
{
|
||||
int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_size;
|
||||
int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
|
||||
return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
|
||||
}
|
||||
|
||||
|
@ -1720,19 +1714,23 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|||
|
||||
// build a table of all channels that need colorspace correction, so
|
||||
// we don't perform colorspace correction on channels that don't need it.
|
||||
for (x=0, num_nonalpha=0; x < channels; ++x)
|
||||
for (x = 0, num_nonalpha = 0; x < channels; ++x)
|
||||
{
|
||||
if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
nonalpha[num_nonalpha++] = x;
|
||||
{
|
||||
nonalpha[num_nonalpha++] = (stbir_uint16)x;
|
||||
}
|
||||
}
|
||||
|
||||
#define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
|
||||
#define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
|
||||
|
||||
#ifdef STBIR__SATURATE_INT
|
||||
#define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * 255 ))
|
||||
#define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * 65535))
|
||||
#define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
|
||||
#define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
|
||||
#else
|
||||
#define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * 255 )
|
||||
#define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * 65535)
|
||||
#define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
|
||||
#define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
|
||||
#endif
|
||||
|
||||
switch (decode)
|
||||
|
@ -1787,7 +1785,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|||
for (n = 0; n < num_nonalpha; n++)
|
||||
{
|
||||
int index = pixel_index + nonalpha[n];
|
||||
((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535);
|
||||
((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
|
||||
}
|
||||
|
||||
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
|
@ -1804,7 +1802,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|||
for (n = 0; n < channels; n++)
|
||||
{
|
||||
int index = pixel_index + n;
|
||||
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * 4294967295);
|
||||
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1817,11 +1815,11 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|||
for (n = 0; n < num_nonalpha; n++)
|
||||
{
|
||||
int index = pixel_index + nonalpha[n];
|
||||
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295);
|
||||
((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
|
||||
}
|
||||
|
||||
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295);
|
||||
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1855,12 +1853,12 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
|||
break;
|
||||
|
||||
default:
|
||||
STBIR__UNIMPLEMENTED("Unknown type/colorspace/channels combination.");
|
||||
STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out)
|
||||
static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
|
||||
{
|
||||
int x, k;
|
||||
int output_w = stbir_info->output_w;
|
||||
|
@ -1870,7 +1868,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
int alpha_channel = stbir_info->alpha_channel;
|
||||
int type = stbir_info->type;
|
||||
int colorspace = stbir_info->colorspace;
|
||||
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
|
||||
int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
|
||||
void* output_data = stbir_info->output_data;
|
||||
float* encode_buffer = stbir_info->encode_buffer;
|
||||
int decode = STBIR__DECODE(type, colorspace);
|
||||
|
@ -1881,7 +1879,6 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
float* ring_buffer = stbir_info->ring_buffer;
|
||||
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
|
||||
int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
|
||||
int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
|
||||
int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
|
||||
|
||||
int n0,n1, output_row_start;
|
||||
|
@ -1892,7 +1889,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
|
||||
output_row_start = n * stbir_info->output_stride_bytes;
|
||||
|
||||
STBIR__DEBUG_ASSERT(stbir__use_height_upsampling(stbir_info));
|
||||
STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
|
||||
|
||||
memset(encode_buffer, 0, output_w * sizeof(float) * channels);
|
||||
|
||||
|
@ -1905,7 +1902,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
for (k = n0; k <= n1; k++)
|
||||
{
|
||||
int coefficient_index = coefficient_counter++;
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
|
||||
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
|
||||
for (x = 0; x < output_w; ++x)
|
||||
{
|
||||
|
@ -1918,7 +1915,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
for (k = n0; k <= n1; k++)
|
||||
{
|
||||
int coefficient_index = coefficient_counter++;
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
|
||||
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
|
||||
for (x = 0; x < output_w; ++x)
|
||||
{
|
||||
|
@ -1932,7 +1929,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
for (k = n0; k <= n1; k++)
|
||||
{
|
||||
int coefficient_index = coefficient_counter++;
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
|
||||
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
|
||||
for (x = 0; x < output_w; ++x)
|
||||
{
|
||||
|
@ -1947,7 +1944,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
for (k = n0; k <= n1; k++)
|
||||
{
|
||||
int coefficient_index = coefficient_counter++;
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
|
||||
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
|
||||
for (x = 0; x < output_w; ++x)
|
||||
{
|
||||
|
@ -1963,7 +1960,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
for (k = n0; k <= n1; k++)
|
||||
{
|
||||
int coefficient_index = coefficient_counter++;
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
|
||||
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
|
||||
for (x = 0; x < output_w; ++x)
|
||||
{
|
||||
|
@ -1978,16 +1975,14 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
|
|||
stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
|
||||
}
|
||||
|
||||
static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out)
|
||||
static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
|
||||
{
|
||||
int x, k;
|
||||
int output_w = stbir_info->output_w;
|
||||
int output_h = stbir_info->output_h;
|
||||
stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
|
||||
float* vertical_coefficients = stbir_info->vertical_coefficients;
|
||||
int channels = stbir_info->channels;
|
||||
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
|
||||
void* output_data = stbir_info->output_data;
|
||||
int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
|
||||
float* horizontal_buffer = stbir_info->horizontal_buffer;
|
||||
int coefficient_width = stbir_info->vertical_coefficient_width;
|
||||
int contributor = n + stbir_info->vertical_filter_pixel_margin;
|
||||
|
@ -1995,14 +1990,13 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
|
|||
float* ring_buffer = stbir_info->ring_buffer;
|
||||
int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
|
||||
int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
|
||||
int ring_buffer_last_scanline = stbir_info->ring_buffer_last_scanline;
|
||||
int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
|
||||
int n0,n1;
|
||||
|
||||
n0 = vertical_contributors[contributor].n0;
|
||||
n1 = vertical_contributors[contributor].n1;
|
||||
|
||||
STBIR__DEBUG_ASSERT(!stbir__use_height_upsampling(stbir_info));
|
||||
STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
|
||||
|
||||
for (k = n0; k <= n1; k++)
|
||||
{
|
||||
|
@ -2010,7 +2004,7 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
|
|||
int coefficient_group = coefficient_width * contributor;
|
||||
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
|
||||
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
|
||||
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
|
||||
|
||||
switch (channels) {
|
||||
case 1:
|
||||
|
@ -2067,7 +2061,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
|
|||
float scale_ratio = stbir_info->vertical_scale;
|
||||
float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
|
||||
|
||||
STBIR__DEBUG_ASSERT(stbir__use_height_upsampling(stbir_info));
|
||||
STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
|
||||
|
||||
for (y = 0; y < stbir_info->output_h; y++)
|
||||
{
|
||||
|
@ -2076,7 +2070,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
|
|||
|
||||
stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
|
||||
|
||||
STBIR__DEBUG_ASSERT(in_last_scanline - in_first_scanline <= stbir_info->vertical_filter_pixel_width);
|
||||
STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
|
||||
|
||||
if (stbir_info->ring_buffer_begin_index >= 0)
|
||||
{
|
||||
|
@ -2095,7 +2089,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
|
|||
else
|
||||
{
|
||||
stbir_info->ring_buffer_first_scanline++;
|
||||
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
|
||||
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2108,7 +2102,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
|
|||
stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
|
||||
|
||||
// Now all buffers should be ready to write a row of vertical sampling.
|
||||
stbir__resample_vertical_upsample(stbir_info, y, in_first_scanline, in_last_scanline, in_center_of_out);
|
||||
stbir__resample_vertical_upsample(stbir_info, y);
|
||||
|
||||
STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
|
||||
}
|
||||
|
@ -2153,7 +2147,7 @@ static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessar
|
|||
else
|
||||
{
|
||||
stbir_info->ring_buffer_first_scanline++;
|
||||
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
|
||||
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2168,7 +2162,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
|
|||
int pixel_margin = stbir_info->vertical_filter_pixel_margin;
|
||||
int max_y = stbir_info->input_h + pixel_margin;
|
||||
|
||||
STBIR__DEBUG_ASSERT(!stbir__use_height_upsampling(stbir_info));
|
||||
STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
|
||||
|
||||
for (y = -pixel_margin; y < max_y; y++)
|
||||
{
|
||||
|
@ -2177,7 +2171,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
|
|||
|
||||
stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
|
||||
|
||||
STBIR__DEBUG_ASSERT(out_last_scanline - out_first_scanline <= stbir_info->vertical_filter_pixel_width);
|
||||
STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
|
||||
|
||||
if (out_last_scanline < 0 || out_first_scanline >= output_h)
|
||||
continue;
|
||||
|
@ -2194,7 +2188,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
|
|||
stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
|
||||
|
||||
// Now the horizontal buffer is ready to write to all ring buffer rows.
|
||||
stbir__resample_vertical_downsample(stbir_info, y, out_first_scanline, out_last_scanline, out_center_of_in);
|
||||
stbir__resample_vertical_downsample(stbir_info, y);
|
||||
}
|
||||
|
||||
stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
|
||||
|
@ -2228,8 +2222,8 @@ static void stbir__calculate_transform(stbir__info *info, float s0, float t0, fl
|
|||
info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
|
||||
info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
|
||||
|
||||
info->horizontal_shift = s0 * info->input_w / (s1 - s0);
|
||||
info->vertical_shift = t0 * info->input_h / (t1 - t0);
|
||||
info->horizontal_shift = s0 * info->output_w / (s1 - s0);
|
||||
info->vertical_shift = t0 * info->output_h / (t1 - t0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2251,13 +2245,16 @@ static stbir_uint32 stbir__calculate_memory(stbir__info *info)
|
|||
info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
|
||||
info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
|
||||
|
||||
// One extra entry because floating point precision problems sometimes cause an extra to be necessary.
|
||||
info->ring_buffer_num_entries = filter_height + 1;
|
||||
|
||||
info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
|
||||
info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
|
||||
info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
|
||||
info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
|
||||
info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
|
||||
info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
|
||||
info->ring_buffer_size = info->output_w * info->channels * filter_height * sizeof(float);
|
||||
info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
|
||||
info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
|
||||
|
||||
STBIR_ASSERT(info->horizontal_filter != 0);
|
||||
|
@ -2379,7 +2376,7 @@ static int stbir__resize_allocated(stbir__info *info,
|
|||
info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
|
||||
info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
|
||||
|
||||
STBIR__DEBUG_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
|
||||
STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2387,7 +2384,7 @@ static int stbir__resize_allocated(stbir__info *info,
|
|||
info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
|
||||
info->encode_buffer = NULL;
|
||||
|
||||
STBIR__DEBUG_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
|
||||
STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
|
||||
}
|
||||
|
||||
#undef STBIR__NEXT_MEMPTR
|
||||
|
@ -2395,8 +2392,8 @@ static int stbir__resize_allocated(stbir__info *info,
|
|||
// This signals that the ring buffer is empty
|
||||
info->ring_buffer_begin_index = -1;
|
||||
|
||||
stbir__calculate_filters(info, info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
|
||||
stbir__calculate_filters(info, info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
|
||||
stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
|
||||
stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
|
||||
|
||||
STBIR_PROGRESS_REPORT(0);
|
||||
|
||||
|
@ -2408,10 +2405,10 @@ static int stbir__resize_allocated(stbir__info *info,
|
|||
STBIR_PROGRESS_REPORT(1);
|
||||
|
||||
#ifdef STBIR_DEBUG_OVERWRITE_TEST
|
||||
STBIR__DEBUG_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
STBIR__DEBUG_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
STBIR__DEBUG_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
STBIR__DEBUG_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
|
@ -2583,3 +2580,45 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
|
|||
}
|
||||
|
||||
#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
/* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Before #including,
|
||||
|
||||
|
@ -18,7 +17,7 @@ ABOUT:
|
|||
|
||||
The PNG output is not optimal; it is 20-50% larger than the file
|
||||
written by a decent optimizing implementation. This library is designed
|
||||
for source code compactness and simplicitly, not optimal image file size
|
||||
for source code compactness and simplicity, not optimal image file size
|
||||
or run-time performance.
|
||||
|
||||
BUILDING:
|
||||
|
@ -35,7 +34,22 @@ USAGE:
|
|||
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
|
||||
There are also four equivalent functions that use an arbitrary write function. You are
|
||||
expected to open/close your file-equivalent before and after calling these:
|
||||
|
||||
int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||
|
||||
where the callback is:
|
||||
void stbi_write_func(void *context, void *data, int size);
|
||||
|
||||
You can define STBI_WRITE_NO_STDIO to disable the file variant of these
|
||||
functions, so the library will not use stdio.h at all. However, this will
|
||||
also disable HDR writing, because it requires stdio for formatted output.
|
||||
|
||||
Each function returns 0 on failure and non-0 on success.
|
||||
|
||||
|
@ -63,6 +77,9 @@ USAGE:
|
|||
data, alpha (if provided) is discarded, and for monochrome data it is
|
||||
replicated across all three channels.
|
||||
|
||||
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
|
||||
data, set the global variable 'stbi_write_tga_with_rle' to 0.
|
||||
|
||||
CREDITS:
|
||||
|
||||
PNG/BMP/TGA
|
||||
|
@ -73,8 +90,26 @@ CREDITS:
|
|||
Jean-Sebastien Guay
|
||||
misc enhancements:
|
||||
Tim Kelsey
|
||||
TGA RLE
|
||||
Alan Hickman
|
||||
initial file IO callback implementation
|
||||
Emmanuel Julien
|
||||
bugfixes:
|
||||
github:Chribba
|
||||
Guillaume Chereau
|
||||
github:jry2
|
||||
github:romigrou
|
||||
Sergio Gonzalez
|
||||
Jonas Karlsson
|
||||
Filip Wasil
|
||||
Thatcher Ulrich
|
||||
github:poppolopoppo
|
||||
Patrick Boettcher
|
||||
|
||||
LICENSE
|
||||
|
||||
See end of file for license information.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||
|
@ -84,10 +119,26 @@ CREDITS:
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
#ifdef STB_IMAGE_WRITE_STATIC
|
||||
#define STBIWDEF static
|
||||
#else
|
||||
#define STBIWDEF extern
|
||||
extern int stbi_write_tga_with_rle;
|
||||
#endif
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
#endif
|
||||
|
||||
typedef void stbi_write_func(void *context, void *data, int size);
|
||||
|
||||
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -97,25 +148,43 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl
|
|||
|
||||
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#endif // STBI_WRITE_NO_STDIO
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC)
|
||||
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
|
||||
// ok
|
||||
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC)
|
||||
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
|
||||
// ok
|
||||
#else
|
||||
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC."
|
||||
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
|
||||
#endif
|
||||
|
||||
#ifndef STBIW_MALLOC
|
||||
#define STBIW_MALLOC(sz) malloc(sz)
|
||||
#define STBIW_REALLOC(p,sz) realloc(p,sz)
|
||||
#define STBIW_FREE(p) free(p)
|
||||
#define STBIW_MALLOC(sz) malloc(sz)
|
||||
#define STBIW_REALLOC(p,newsz) realloc(p,newsz)
|
||||
#define STBIW_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
#ifndef STBIW_REALLOC_SIZED
|
||||
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef STBIW_MEMMOVE
|
||||
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
|
||||
#endif
|
||||
|
@ -126,22 +195,73 @@ extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const fl
|
|||
#define STBIW_ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
stbi_write_func *func;
|
||||
void *context;
|
||||
} stbi__write_context;
|
||||
|
||||
// initialize a callback-based context
|
||||
static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
|
||||
{
|
||||
s->func = c;
|
||||
s->context = context;
|
||||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
|
||||
static void stbi__stdio_write(void *context, void *data, int size)
|
||||
{
|
||||
fwrite(data,1,size,(FILE*) context);
|
||||
}
|
||||
|
||||
static int stbi__start_write_file(stbi__write_context *s, const char *filename)
|
||||
{
|
||||
FILE *f = fopen(filename, "wb");
|
||||
stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
|
||||
return f != NULL;
|
||||
}
|
||||
|
||||
static void stbi__end_write_file(stbi__write_context *s)
|
||||
{
|
||||
fclose((FILE *)s->context);
|
||||
}
|
||||
|
||||
#endif // !STBI_WRITE_NO_STDIO
|
||||
|
||||
typedef unsigned int stbiw_uint32;
|
||||
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
|
||||
|
||||
static void writefv(FILE *f, const char *fmt, va_list v)
|
||||
#ifdef STB_IMAGE_WRITE_STATIC
|
||||
static int stbi_write_tga_with_rle = 1;
|
||||
#else
|
||||
int stbi_write_tga_with_rle = 1;
|
||||
#endif
|
||||
|
||||
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
|
||||
{
|
||||
while (*fmt) {
|
||||
switch (*fmt++) {
|
||||
case ' ': break;
|
||||
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
|
||||
case '2': { int x = va_arg(v,int); unsigned char b[2];
|
||||
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
|
||||
fwrite(b,2,1,f); break; }
|
||||
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
|
||||
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
|
||||
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
|
||||
fwrite(b,4,1,f); break; }
|
||||
case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
|
||||
s->func(s->context,&x,1);
|
||||
break; }
|
||||
case '2': { int x = va_arg(v,int);
|
||||
unsigned char b[2];
|
||||
b[0] = STBIW_UCHAR(x);
|
||||
b[1] = STBIW_UCHAR(x>>8);
|
||||
s->func(s->context,b,2);
|
||||
break; }
|
||||
case '4': { stbiw_uint32 x = va_arg(v,int);
|
||||
unsigned char b[4];
|
||||
b[0]=STBIW_UCHAR(x);
|
||||
b[1]=STBIW_UCHAR(x>>8);
|
||||
b[2]=STBIW_UCHAR(x>>16);
|
||||
b[3]=STBIW_UCHAR(x>>24);
|
||||
s->func(s->context,b,4);
|
||||
break; }
|
||||
default:
|
||||
STBIW_ASSERT(0);
|
||||
return;
|
||||
|
@ -149,18 +269,58 @@ static void writefv(FILE *f, const char *fmt, va_list v)
|
|||
}
|
||||
}
|
||||
|
||||
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
|
||||
static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
|
||||
{
|
||||
va_list v;
|
||||
va_start(v, fmt);
|
||||
stbiw__writefv(s, fmt, v);
|
||||
va_end(v);
|
||||
}
|
||||
|
||||
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
|
||||
{
|
||||
unsigned char arr[3];
|
||||
arr[0] = a, arr[1] = b, arr[2] = c;
|
||||
fwrite(arr, 3, 1, f);
|
||||
s->func(s->context, arr, 3);
|
||||
}
|
||||
|
||||
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
|
||||
static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
|
||||
{
|
||||
unsigned char bg[3] = { 255, 0, 255}, px[3];
|
||||
int k;
|
||||
|
||||
if (write_alpha < 0)
|
||||
s->func(s->context, &d[comp - 1], 1);
|
||||
|
||||
switch (comp) {
|
||||
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
|
||||
case 1:
|
||||
if (expand_mono)
|
||||
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
|
||||
else
|
||||
s->func(s->context, d, 1); // monochrome TGA
|
||||
break;
|
||||
case 4:
|
||||
if (!write_alpha) {
|
||||
// composite against pink background
|
||||
for (k = 0; k < 3; ++k)
|
||||
px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
|
||||
stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
|
||||
break;
|
||||
}
|
||||
if (write_alpha > 0)
|
||||
s->func(s->context, &d[comp - 1], 1);
|
||||
}
|
||||
|
||||
static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
|
||||
{
|
||||
stbiw_uint32 zero = 0;
|
||||
int i,j,k, j_end;
|
||||
int i,j, j_end;
|
||||
|
||||
if (y <= 0)
|
||||
return;
|
||||
|
@ -173,73 +333,147 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
|
|||
for (; j != j_end; j += vdir) {
|
||||
for (i=0; i < x; ++i) {
|
||||
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
|
||||
if (write_alpha < 0)
|
||||
fwrite(&d[comp-1], 1, 1, f);
|
||||
switch (comp) {
|
||||
case 1: fwrite(d, 1, 1, f);
|
||||
break;
|
||||
case 2: if (expand_mono)
|
||||
write3(f, d[0],d[0],d[0]); // monochrome bmp
|
||||
else
|
||||
fwrite(d, 1, 1, f); // monochrome TGA
|
||||
break;
|
||||
case 4:
|
||||
if (!write_alpha) {
|
||||
// composite against pink background
|
||||
for (k=0; k < 3; ++k)
|
||||
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
|
||||
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
|
||||
break;
|
||||
}
|
||||
if (write_alpha > 0)
|
||||
fwrite(&d[comp-1], 1, 1, f);
|
||||
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
|
||||
}
|
||||
fwrite(&zero,scanline_pad,1,f);
|
||||
s->func(s->context, &zero, scanline_pad);
|
||||
}
|
||||
}
|
||||
|
||||
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
|
||||
static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
|
||||
{
|
||||
FILE *f;
|
||||
if (y < 0 || x < 0) return 0;
|
||||
f = fopen(filename, "wb");
|
||||
if (f) {
|
||||
if (y < 0 || x < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
va_list v;
|
||||
va_start(v, fmt);
|
||||
writefv(f, fmt, v);
|
||||
stbiw__writefv(s, fmt, v);
|
||||
va_end(v);
|
||||
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
|
||||
fclose(f);
|
||||
stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
|
||||
return 1;
|
||||
}
|
||||
return f != NULL;
|
||||
}
|
||||
|
||||
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
|
||||
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
|
||||
{
|
||||
int pad = (-x*3) & 3;
|
||||
return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
|
||||
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
|
||||
"11 4 22 4" "4 44 22 444444",
|
||||
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
||||
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
||||
}
|
||||
|
||||
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
|
||||
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
stbi__start_write_callbacks(&s, func, context);
|
||||
return stbi_write_bmp_core(&s, x, y, comp, data);
|
||||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
if (stbi__start_write_file(&s,filename)) {
|
||||
int r = stbi_write_bmp_core(&s, x, y, comp, data);
|
||||
stbi__end_write_file(&s);
|
||||
return r;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
#endif //!STBI_WRITE_NO_STDIO
|
||||
|
||||
static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
|
||||
{
|
||||
int has_alpha = (comp == 2 || comp == 4);
|
||||
int colorbytes = has_alpha ? comp-1 : comp;
|
||||
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
|
||||
return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
|
||||
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
|
||||
|
||||
if (y < 0 || x < 0)
|
||||
return 0;
|
||||
|
||||
if (!stbi_write_tga_with_rle) {
|
||||
return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
|
||||
"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
|
||||
} else {
|
||||
int i,j,k;
|
||||
|
||||
stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
|
||||
|
||||
for (j = y - 1; j >= 0; --j) {
|
||||
unsigned char *row = (unsigned char *) data + j * x * comp;
|
||||
int len;
|
||||
|
||||
for (i = 0; i < x; i += len) {
|
||||
unsigned char *begin = row + i * comp;
|
||||
int diff = 1;
|
||||
len = 1;
|
||||
|
||||
if (i < x - 1) {
|
||||
++len;
|
||||
diff = memcmp(begin, row + (i + 1) * comp, comp);
|
||||
if (diff) {
|
||||
const unsigned char *prev = begin;
|
||||
for (k = i + 2; k < x && len < 128; ++k) {
|
||||
if (memcmp(prev, row + k * comp, comp)) {
|
||||
prev += comp;
|
||||
++len;
|
||||
} else {
|
||||
--len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (k = i + 2; k < x && len < 128; ++k) {
|
||||
if (!memcmp(begin, row + k * comp, comp)) {
|
||||
++len;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (diff) {
|
||||
unsigned char header = STBIW_UCHAR(len - 1);
|
||||
s->func(s->context, &header, 1);
|
||||
for (k = 0; k < len; ++k) {
|
||||
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
|
||||
}
|
||||
} else {
|
||||
unsigned char header = STBIW_UCHAR(len - 129);
|
||||
s->func(s->context, &header, 1);
|
||||
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
stbi__start_write_callbacks(&s, func, context);
|
||||
return stbi_write_tga_core(&s, x, y, comp, (void *) data);
|
||||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
if (stbi__start_write_file(&s,filename)) {
|
||||
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
|
||||
stbi__end_write_file(&s);
|
||||
return r;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// *************************************************************************************************
|
||||
// Radiance RGBE HDR writer
|
||||
// by Baldur Karlsson
|
||||
|
||||
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
||||
|
@ -247,7 +481,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
|||
int exponent;
|
||||
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
|
||||
|
||||
if (maxcomp < 1e-32) {
|
||||
if (maxcomp < 1e-32f) {
|
||||
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
|
||||
} else {
|
||||
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
|
||||
|
@ -259,23 +493,23 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
|||
}
|
||||
}
|
||||
|
||||
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
|
||||
void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
|
||||
{
|
||||
unsigned char lengthbyte = (unsigned char) (length+128);
|
||||
unsigned char lengthbyte = STBIW_UCHAR(length+128);
|
||||
STBIW_ASSERT(length+128 <= 255);
|
||||
fwrite(&lengthbyte, 1, 1, f);
|
||||
fwrite(&databyte, 1, 1, f);
|
||||
s->func(s->context, &lengthbyte, 1);
|
||||
s->func(s->context, &databyte, 1);
|
||||
}
|
||||
|
||||
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
|
||||
void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
|
||||
{
|
||||
unsigned char lengthbyte = (unsigned char )(length & 0xff);
|
||||
unsigned char lengthbyte = STBIW_UCHAR(length);
|
||||
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
|
||||
fwrite(&lengthbyte, 1, 1, f);
|
||||
fwrite(data, length, 1, f);
|
||||
s->func(s->context, &lengthbyte, 1);
|
||||
s->func(s->context, data, length);
|
||||
}
|
||||
|
||||
void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
|
||||
void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
|
||||
{
|
||||
unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
|
||||
unsigned char rgbe[4];
|
||||
|
@ -288,31 +522,31 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
|
|||
/* skip RLE for images too small or large */
|
||||
if (width < 8 || width >= 32768) {
|
||||
for (x=0; x < width; x++) {
|
||||
switch (comp) {
|
||||
switch (ncomp) {
|
||||
case 4: /* fallthrough */
|
||||
case 3: linear[2] = scanline[x*comp + 2];
|
||||
linear[1] = scanline[x*comp + 1];
|
||||
linear[0] = scanline[x*comp + 0];
|
||||
case 3: linear[2] = scanline[x*ncomp + 2];
|
||||
linear[1] = scanline[x*ncomp + 1];
|
||||
linear[0] = scanline[x*ncomp + 0];
|
||||
break;
|
||||
case 2: /* fallthrough */
|
||||
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
|
||||
default:
|
||||
linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
|
||||
break;
|
||||
}
|
||||
stbiw__linear_to_rgbe(rgbe, linear);
|
||||
fwrite(rgbe, 4, 1, f);
|
||||
s->func(s->context, rgbe, 4);
|
||||
}
|
||||
} else {
|
||||
int c,r;
|
||||
/* encode into scratch buffer */
|
||||
for (x=0; x < width; x++) {
|
||||
switch(comp) {
|
||||
switch(ncomp) {
|
||||
case 4: /* fallthrough */
|
||||
case 3: linear[2] = scanline[x*comp + 2];
|
||||
linear[1] = scanline[x*comp + 1];
|
||||
linear[0] = scanline[x*comp + 0];
|
||||
case 3: linear[2] = scanline[x*ncomp + 2];
|
||||
linear[1] = scanline[x*ncomp + 1];
|
||||
linear[0] = scanline[x*ncomp + 0];
|
||||
break;
|
||||
case 2: /* fallthrough */
|
||||
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
|
||||
default:
|
||||
linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
|
||||
break;
|
||||
}
|
||||
stbiw__linear_to_rgbe(rgbe, linear);
|
||||
|
@ -322,7 +556,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
|
|||
scratch[x + width*3] = rgbe[3];
|
||||
}
|
||||
|
||||
fwrite(scanlineheader, 4, 1, f);
|
||||
s->func(s->context, scanlineheader, 4);
|
||||
|
||||
/* RLE each component separately */
|
||||
for (c=0; c < 4; c++) {
|
||||
|
@ -343,7 +577,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
|
|||
while (x < r) {
|
||||
int len = r-x;
|
||||
if (len > 128) len = 128;
|
||||
stbiw__write_dump_data(f, len, &comp[x]);
|
||||
stbiw__write_dump_data(s, len, &comp[x]);
|
||||
x += len;
|
||||
}
|
||||
// if there's a run, output it
|
||||
|
@ -355,7 +589,7 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
|
|||
while (x < r) {
|
||||
int len = r-x;
|
||||
if (len > 127) len = 127;
|
||||
stbiw__write_run_data(f, len, comp[x]);
|
||||
stbiw__write_run_data(s, len, comp[x]);
|
||||
x += len;
|
||||
}
|
||||
}
|
||||
|
@ -364,27 +598,53 @@ void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scra
|
|||
}
|
||||
}
|
||||
|
||||
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||
static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
if (y <= 0 || x <= 0 || data == NULL) return 0;
|
||||
f = fopen(filename, "wb");
|
||||
if (f) {
|
||||
/* Each component is stored separately. Allocate scratch space for full output scanline. */
|
||||
if (y <= 0 || x <= 0 || data == NULL)
|
||||
return 0;
|
||||
else {
|
||||
// Each component is stored separately. Allocate scratch space for full output scanline.
|
||||
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
|
||||
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
|
||||
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
|
||||
int i, len;
|
||||
char buffer[128];
|
||||
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
|
||||
s->func(s->context, header, sizeof(header)-1);
|
||||
|
||||
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||
s->func(s->context, buffer, len);
|
||||
|
||||
for(i=0; i < y; i++)
|
||||
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
|
||||
stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
|
||||
STBIW_FREE(scratch);
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
return f != NULL;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// PNG
|
||||
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
stbi__start_write_callbacks(&s, func, context);
|
||||
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
|
||||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
if (stbi__start_write_file(&s,filename)) {
|
||||
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
|
||||
stbi__end_write_file(&s);
|
||||
return r;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
#endif // STBI_WRITE_NO_STDIO
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PNG writer
|
||||
//
|
||||
|
||||
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
|
||||
#define stbiw__sbraw(a) ((int *) (a) - 2)
|
||||
|
@ -402,7 +662,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
|
|||
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
|
||||
{
|
||||
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
|
||||
void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
||||
void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
|
||||
STBIW_ASSERT(p);
|
||||
if (p) {
|
||||
if (!*arr) ((int *) p)[1] = 0;
|
||||
|
@ -415,7 +675,7 @@ static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
|
|||
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
|
||||
{
|
||||
while (*bitcount >= 8) {
|
||||
stbiw__sbpush(data, (unsigned char) *bitbuffer);
|
||||
stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
|
||||
*bitbuffer >>= 8;
|
||||
*bitcount -= 8;
|
||||
}
|
||||
|
@ -475,7 +735,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||
unsigned int bitbuf=0;
|
||||
int i,j, bitcount=0;
|
||||
unsigned char *out = NULL;
|
||||
unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
|
||||
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
|
||||
if (quality < 5) quality = 5;
|
||||
|
||||
stbiw__sbpush(out, 0x78); // DEFLATE 32K window
|
||||
|
@ -547,21 +807,23 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||
|
||||
for (i=0; i < stbiw__ZHASH; ++i)
|
||||
(void) stbiw__sbfree(hash_table[i]);
|
||||
STBIW_FREE(hash_table);
|
||||
|
||||
{
|
||||
// compute adler32 on input
|
||||
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
|
||||
int j=0;
|
||||
unsigned int s1=1, s2=0;
|
||||
int blocklen = (int) (data_len % 5552);
|
||||
j=0;
|
||||
while (j < data_len) {
|
||||
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
|
||||
s1 %= 65521, s2 %= 65521;
|
||||
j += blocklen;
|
||||
blocklen = 5552;
|
||||
}
|
||||
stbiw__sbpush(out, (unsigned char) (s2 >> 8));
|
||||
stbiw__sbpush(out, (unsigned char) s2);
|
||||
stbiw__sbpush(out, (unsigned char) (s1 >> 8));
|
||||
stbiw__sbpush(out, (unsigned char) s1);
|
||||
stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
|
||||
stbiw__sbpush(out, STBIW_UCHAR(s2));
|
||||
stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
|
||||
stbiw__sbpush(out, STBIW_UCHAR(s1));
|
||||
}
|
||||
*out_len = stbiw__sbn(out);
|
||||
// make returned pointer freeable
|
||||
|
@ -569,21 +831,52 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
|||
return (unsigned char *) stbiw__sbraw(out);
|
||||
}
|
||||
|
||||
unsigned int stbiw__crc32(unsigned char *buffer, int len)
|
||||
static unsigned int stbiw__crc32(unsigned char *buffer, int len)
|
||||
{
|
||||
static unsigned int crc_table[256];
|
||||
static unsigned int crc_table[256] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
unsigned int crc = ~0u;
|
||||
int i,j;
|
||||
if (crc_table[1] == 0)
|
||||
for(i=0; i < 256; i++)
|
||||
for (crc_table[i]=i, j=0; j < 8; ++j)
|
||||
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
|
||||
int i;
|
||||
for (i=0; i < len; ++i)
|
||||
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
|
||||
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
|
||||
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
|
||||
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
|
||||
|
||||
|
@ -596,11 +889,12 @@ static void stbiw__wpcrc(unsigned char **data, int len)
|
|||
static unsigned char stbiw__paeth(int a, int b, int c)
|
||||
{
|
||||
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
|
||||
if (pa <= pb && pa <= pc) return (unsigned char) a;
|
||||
if (pb <= pc) return (unsigned char) b;
|
||||
return (unsigned char) c;
|
||||
if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
|
||||
if (pb <= pc) return STBIW_UCHAR(b);
|
||||
return STBIW_UCHAR(c);
|
||||
}
|
||||
|
||||
// @OPTIMIZE: provide an option that always forces left-predict or paeth predict
|
||||
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
|
||||
{
|
||||
int ctype[5] = { -1, 0, 4, 2, 6 };
|
||||
|
@ -617,10 +911,10 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||
for (j=0; j < y; ++j) {
|
||||
static int mapping[] = { 0,1,2,3,4 };
|
||||
static int firstmap[] = { 0,1,0,5,6 };
|
||||
int *mymap = j ? mapping : firstmap;
|
||||
int *mymap = (j != 0) ? mapping : firstmap;
|
||||
int best = 0, bestval = 0x7fffffff;
|
||||
for (p=0; p < 2; ++p) {
|
||||
for (k= p?best:0; k < 5; ++k) {
|
||||
for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass
|
||||
int type = mymap[k],est=0;
|
||||
unsigned char *z = pixels + stride_bytes*j;
|
||||
for (i=0; i < n; ++i)
|
||||
|
@ -671,7 +965,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||
stbiw__wp32(o, x);
|
||||
stbiw__wp32(o, y);
|
||||
*o++ = 8;
|
||||
*o++ = (unsigned char) ctype[n];
|
||||
*o++ = STBIW_UCHAR(ctype[n]);
|
||||
*o++ = 0;
|
||||
*o++ = 0;
|
||||
*o++ = 0;
|
||||
|
@ -693,12 +987,13 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
|||
return out;
|
||||
}
|
||||
|
||||
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
|
||||
{
|
||||
FILE *f;
|
||||
int len;
|
||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||
if (!png) return 0;
|
||||
if (png == NULL) return 0;
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) { STBIW_FREE(png); return 0; }
|
||||
fwrite(png, 1, len, f);
|
||||
|
@ -706,9 +1001,34 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
|
|||
STBIW_FREE(png);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
|
||||
{
|
||||
int len;
|
||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||
if (png == NULL) return 0;
|
||||
func(context, png, len);
|
||||
STBIW_FREE(png);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
/* Revision history
|
||||
1.04 (2017-03-03)
|
||||
monochrome BMP expansion
|
||||
1.03 ???
|
||||
1.02 (2016-04-02)
|
||||
avoid allocating large structures on the stack
|
||||
1.01 (2016-01-16)
|
||||
STBIW_REALLOC_SIZED: support allocators with no realloc support
|
||||
avoid race-condition in crc initialization
|
||||
minor compile issues
|
||||
1.00 (2015-09-14)
|
||||
installable file IO function
|
||||
0.99 (2015-09-13)
|
||||
warning fixes; TGA rle support
|
||||
0.98 (2015-04-08)
|
||||
added STBIW_MALLOC, STBIW_ASSERT etc
|
||||
0.97 (2015-01-18)
|
||||
|
@ -728,3 +1048,45 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
|
|||
first public release
|
||||
0.90 first internal release
|
||||
*/
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// stb_leakcheck.h - v0.2 - quick & dirty malloc leak-checking - public domain
|
||||
// stb_leakcheck.h - v0.3 - quick & dirty malloc leak-checking - public domain
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file.
|
||||
|
||||
#ifdef STB_LEAKCHECK_IMPLEMENTATION
|
||||
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implenment more than once
|
||||
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implement more than once
|
||||
|
||||
// if we've already included leakcheck before, undefine the macros
|
||||
#ifdef malloc
|
||||
|
@ -10,6 +13,8 @@
|
|||
#undef realloc
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
@ -88,14 +93,14 @@ void stb_leakcheck_dumpmem(void)
|
|||
stb_leakcheck_malloc_info *mi = mi_head;
|
||||
while (mi) {
|
||||
if ((ptrdiff_t) mi->size >= 0)
|
||||
printf("LEAKED: %s (%4d): %8z bytes at %p\n", mi->file, mi->line, mi->size, mi+1);
|
||||
printf("LEAKED: %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) mi->size, mi+1);
|
||||
mi = mi->next;
|
||||
}
|
||||
#ifdef STB_LEAKCHECK_SHOWALL
|
||||
mi = mi_head;
|
||||
while (mi) {
|
||||
if ((ptrdiff_t) mi->size < 0)
|
||||
printf("FREED : %s (%4d): %8z bytes at %p\n", mi->file, mi->line, ~mi->size, mi+1);
|
||||
printf("FREED : %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) ~mi->size, mi+1);
|
||||
mi = mi->next;
|
||||
}
|
||||
#endif
|
||||
|
@ -115,3 +120,46 @@ extern void stb_leakcheck_free(void *ptr);
|
|||
extern void stb_leakcheck_dumpmem(void);
|
||||
|
||||
#endif // INCLUDE_STB_LEAKCHECK_H
|
||||
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
165
stb_perlin.h
165
stb_perlin.h
|
@ -1,11 +1,16 @@
|
|||
// stb_perlin.h - v0.2 - perlin noise
|
||||
// stb_perlin.h - v0.3 - perlin noise
|
||||
// public domain single-file C implementation by Sean Barrett
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file.
|
||||
//
|
||||
//
|
||||
// to create the implementation,
|
||||
// #define STB_PERLIN_IMPLEMENTATION
|
||||
// in *one* C/CPP file that includes this file.
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Documentation:
|
||||
//
|
||||
// float stb_perlin_noise3( float x,
|
||||
|
@ -26,22 +31,55 @@
|
|||
// 0 to mean "don't care". (The noise always wraps every 256 due
|
||||
// details of the implementation, even if you ask for larger or no
|
||||
// wrapping.)
|
||||
//
|
||||
// Fractal Noise:
|
||||
//
|
||||
// Three common fractal noise functions are included, which produce
|
||||
// a wide variety of nice effects depending on the parameters
|
||||
// provided. Note that each function will call stb_perlin_noise3
|
||||
// 'octaves' times, so this parameter will affect runtime.
|
||||
//
|
||||
// float stb_perlin_ridge_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, float offset, int octaves,
|
||||
// int x_wrap, int y_wrap, int z_wrap);
|
||||
//
|
||||
// float stb_perlin_fbm_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves,
|
||||
// int x_wrap, int y_wrap, int z_wrap);
|
||||
//
|
||||
// float stb_perlin_turbulence_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain,int octaves,
|
||||
// int x_wrap, int y_wrap, int z_wrap);
|
||||
//
|
||||
// Typical values to start playing with:
|
||||
// octaves = 6 -- number of "octaves" of noise3() to sum
|
||||
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
|
||||
// gain = 0.5 -- relative weighting applied to each successive octave
|
||||
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
|
||||
//
|
||||
//
|
||||
// Contributors:
|
||||
// Jack Mott - additional noise functions
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" float stb_perlin_noise3(float x, float y, float z, int x_wrap=0, int y_wrap=0, int z_wrap=0);
|
||||
#else
|
||||
extern "C" {
|
||||
#endif
|
||||
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
#include <math.h> // floor()
|
||||
|
||||
// not same permutation table as Perlin's reference to avoid copyright issues;
|
||||
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
|
||||
// @OPTIMIZE: should this be unsigned char instead of int for cache?
|
||||
static int stb__perlin_randtab[512] =
|
||||
static unsigned char stb__perlin_randtab[512] =
|
||||
{
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
|
@ -84,6 +122,12 @@ static float stb__perlin_lerp(float a, float b, float t)
|
|||
return a + (b-a) * t;
|
||||
}
|
||||
|
||||
static int stb__perlin_fastfloor(float a)
|
||||
{
|
||||
int ai = (int) a;
|
||||
return (a < ai) ? ai-1 : ai;
|
||||
}
|
||||
|
||||
// different grad function from Perlin's, but easy to modify to match reference
|
||||
static float stb__perlin_grad(int hash, float x, float y, float z)
|
||||
{
|
||||
|
@ -105,7 +149,7 @@ static float stb__perlin_grad(int hash, float x, float y, float z)
|
|||
|
||||
// perlin's gradient has 12 cases so some get used 1/16th of the time
|
||||
// and some 2/16ths. We reduce bias by changing those fractions
|
||||
// to 5/16ths and 6/16ths, and the same 4 cases get the extra weight.
|
||||
// to 5/64ths and 6/64ths, and the same 4 cases get the extra weight.
|
||||
static unsigned char indices[64] =
|
||||
{
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
|
@ -117,6 +161,7 @@ static float stb__perlin_grad(int hash, float x, float y, float z)
|
|||
};
|
||||
|
||||
// if you use reference permutation table, change 63 below to 15 to match reference
|
||||
// (this is why the ordering of the table above is funky)
|
||||
float *grad = basis[indices[hash & 63]];
|
||||
return grad[0]*x + grad[1]*y + grad[2]*z;
|
||||
}
|
||||
|
@ -131,9 +176,9 @@ float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z
|
|||
unsigned int x_mask = (x_wrap-1) & 255;
|
||||
unsigned int y_mask = (y_wrap-1) & 255;
|
||||
unsigned int z_mask = (z_wrap-1) & 255;
|
||||
int px = (int) floor(x);
|
||||
int py = (int) floor(y);
|
||||
int pz = (int) floor(z);
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x0 = px & x_mask, x1 = (px+1) & x_mask;
|
||||
int y0 = py & y_mask, y1 = (py+1) & y_mask;
|
||||
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
|
||||
|
@ -172,4 +217,100 @@ float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z
|
|||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
|
||||
float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float prev = 1.0f;
|
||||
float amplitude = 0.5f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = (float)(stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap));
|
||||
r = r<0 ? -r : r; // fabs()
|
||||
r = offset - r;
|
||||
r = r*r;
|
||||
sum += r*amplitude*prev;
|
||||
prev = r;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
sum += stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
|
||||
r = r<0 ? -r : r; // fabs()
|
||||
sum += r;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
#endif // STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
115
stb_rect_pack.h
115
stb_rect_pack.h
|
@ -1,4 +1,4 @@
|
|||
// stb_rect_pack.h - v0.06 - public domain - rectangle packing
|
||||
// stb_rect_pack.h - v0.11 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
|
@ -27,15 +27,26 @@
|
|||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// [your name could be here]
|
||||
// Jeremy Jaussaud
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -67,7 +78,7 @@ typedef int stbrp_coord;
|
|||
typedef unsigned short stbrp_coord;
|
||||
#endif
|
||||
|
||||
STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
|
@ -88,6 +99,9 @@ STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int
|
|||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
|
@ -140,7 +154,7 @@ enum
|
|||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
|
@ -190,9 +204,15 @@ struct stbrp_context
|
|||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1,
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
|
@ -265,6 +285,9 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0
|
|||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
|
@ -492,8 +515,8 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
|
|||
|
||||
static int rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
stbrp_rect *p = (stbrp_rect *) a;
|
||||
stbrp_rect *q = (stbrp_rect *) b;
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
|
@ -503,8 +526,8 @@ static int rect_height_compare(const void *a, const void *b)
|
|||
|
||||
static int rect_width_compare(const void *a, const void *b)
|
||||
{
|
||||
stbrp_rect *p = (stbrp_rect *) a;
|
||||
stbrp_rect *q = (stbrp_rect *) b;
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->w > q->w)
|
||||
return -1;
|
||||
if (p->w < q->w)
|
||||
|
@ -514,8 +537,8 @@ static int rect_width_compare(const void *a, const void *b)
|
|||
|
||||
static int rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
stbrp_rect *p = (stbrp_rect *) a;
|
||||
stbrp_rect *q = (stbrp_rect *) b;
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
|
@ -525,9 +548,9 @@ static int rect_original_order(const void *a, const void *b)
|
|||
#define STBRP__MAXVAL 0xffff
|
||||
#endif
|
||||
|
||||
STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i;
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
|
@ -541,20 +564,72 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n
|
|||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags
|
||||
for (i=0; i < num_rects; ++i)
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
File diff suppressed because it is too large
Load Diff
227
stb_textedit.h
227
stb_textedit.h
|
@ -1,4 +1,4 @@
|
|||
// stb_textedit.h - v1.6 - public domain - Sean Barrett
|
||||
// stb_textedit.h - v1.11 - public domain - Sean Barrett
|
||||
// Development of this library was sponsored by RAD Game Tools
|
||||
//
|
||||
// This C header file implements the guts of a multi-line text-editing
|
||||
|
@ -17,9 +17,7 @@
|
|||
//
|
||||
// LICENSE
|
||||
//
|
||||
// This software has been placed in the public domain by its author.
|
||||
// Where that dedication is not recognized, you are granted a perpetual,
|
||||
// irrevocable license to copy and modify this file as you see fit.
|
||||
// See end of file for license information.
|
||||
//
|
||||
//
|
||||
// DEPENDENCIES
|
||||
|
@ -31,6 +29,11 @@
|
|||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
|
||||
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
|
||||
// 1.9 (2016-08-27) customizable move-by-word
|
||||
// 1.8 (2016-04-02) better keyboard handling when mouse button is down
|
||||
// 1.7 (2015-09-13) change y range handling in case baseline is non-0
|
||||
// 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove
|
||||
// 1.5 (2014-09-10) add support for secondary keys for OS X
|
||||
// 1.4 (2014-08-17) fix signed/unsigned warnings
|
||||
|
@ -45,9 +48,14 @@
|
|||
// ADDITIONAL CONTRIBUTORS
|
||||
//
|
||||
// Ulf Winklemann: move-by-word in 1.1
|
||||
// Scott Graham: mouse selection bugfix in 1.3
|
||||
// Fabian Giesen: secondary key inputs in 1.5
|
||||
// Martins Mozeiko: STB_TEXTEDIT_memmove
|
||||
// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6
|
||||
//
|
||||
// Bugfixes:
|
||||
// Scott Graham
|
||||
// Daniel Keller
|
||||
// Omar Cornut
|
||||
// Dan Thompson
|
||||
//
|
||||
// USAGE
|
||||
//
|
||||
|
@ -142,15 +150,17 @@
|
|||
// STB_TEXTEDIT_K_REDO keyboard input to perform redo
|
||||
//
|
||||
// Optional:
|
||||
// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode
|
||||
// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'),
|
||||
// required for WORDLEFT/WORDRIGHT
|
||||
// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT
|
||||
// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT
|
||||
// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line
|
||||
// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line
|
||||
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
||||
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
||||
// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode
|
||||
// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'),
|
||||
// required for default WORDLEFT/WORDRIGHT handlers
|
||||
// STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to
|
||||
// STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to
|
||||
// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT
|
||||
// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT
|
||||
// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line
|
||||
// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line
|
||||
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
||||
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
||||
//
|
||||
// Todo:
|
||||
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
|
||||
|
@ -380,9 +390,6 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
|||
float base_y = 0, prev_x;
|
||||
int i=0, k;
|
||||
|
||||
if (y < 0)
|
||||
return 0;
|
||||
|
||||
r.x0 = r.x1 = 0;
|
||||
r.ymin = r.ymax = 0;
|
||||
r.num_chars = 0;
|
||||
|
@ -393,6 +400,9 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
|||
if (r.num_chars <= 0)
|
||||
return n;
|
||||
|
||||
if (i==0 && y < base_y + r.ymin)
|
||||
return 0;
|
||||
|
||||
if (y < base_y + r.ymax)
|
||||
break;
|
||||
|
||||
|
@ -411,10 +421,9 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
|||
// check if it's before the end of the line
|
||||
if (x < r.x1) {
|
||||
// search characters in row for one that straddles 'x'
|
||||
k = i;
|
||||
prev_x = r.x0;
|
||||
for (i=0; i < r.num_chars; ++i) {
|
||||
float w = STB_TEXTEDIT_GETWIDTH(str, k, i);
|
||||
for (k=0; k < r.num_chars; ++k) {
|
||||
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
|
||||
if (x < prev_x+w) {
|
||||
if (x < prev_x+w/2)
|
||||
return k+i;
|
||||
|
@ -436,6 +445,15 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
|||
// API click: on mouse down, move the cursor to the clicked location, and reset the selection
|
||||
static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
{
|
||||
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
||||
// goes off the top or bottom of the text
|
||||
if( state->single_line )
|
||||
{
|
||||
StbTexteditRow r;
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
y = r.ymin;
|
||||
}
|
||||
|
||||
state->cursor = stb_text_locate_coord(str, x, y);
|
||||
state->select_start = state->cursor;
|
||||
state->select_end = state->cursor;
|
||||
|
@ -445,7 +463,21 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
|||
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
|
||||
static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
{
|
||||
int p = stb_text_locate_coord(str, x, y);
|
||||
int p = 0;
|
||||
|
||||
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
||||
// goes off the top or bottom of the text
|
||||
if( state->single_line )
|
||||
{
|
||||
StbTexteditRow r;
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
y = r.ymin;
|
||||
}
|
||||
|
||||
if (state->select_start == state->select_end)
|
||||
state->select_start = state->cursor;
|
||||
|
||||
p = stb_text_locate_coord(str, x, y);
|
||||
state->cursor = state->select_end = p;
|
||||
}
|
||||
|
||||
|
@ -602,15 +634,16 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat
|
|||
}
|
||||
|
||||
#ifdef STB_TEXTEDIT_IS_SPACE
|
||||
static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx )
|
||||
static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
|
||||
{
|
||||
return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1;
|
||||
return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
|
||||
}
|
||||
|
||||
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state )
|
||||
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
||||
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
int c = _state->cursor - 1;
|
||||
while( c >= 0 && !is_word_boundary( _str, c ) )
|
||||
--c; // always move at least one character
|
||||
while( c >= 0 && !is_word_boundary( str, c ) )
|
||||
--c;
|
||||
|
||||
if( c < 0 )
|
||||
|
@ -618,12 +651,15 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_Te
|
|||
|
||||
return c;
|
||||
}
|
||||
#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous
|
||||
#endif
|
||||
|
||||
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state )
|
||||
#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
|
||||
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
const int len = STB_TEXTEDIT_STRINGLEN(_str);
|
||||
int c = _state->cursor+1;
|
||||
while( c < len && !is_word_boundary( _str, c ) )
|
||||
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
||||
++c; // always move at least one character
|
||||
while( c < len && !is_word_boundary( str, c ) )
|
||||
++c;
|
||||
|
||||
if( c > len )
|
||||
|
@ -631,6 +667,9 @@ static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_Texted
|
|||
|
||||
return c;
|
||||
}
|
||||
#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// update selection and cursor to match each other
|
||||
|
@ -654,9 +693,8 @@ static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
|||
}
|
||||
|
||||
// API paste: replace existing selection with passed-in text
|
||||
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
||||
static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
||||
{
|
||||
STB_TEXTEDIT_CHARTYPE *text = (STB_TEXTEDIT_CHARTYPE *) ctext;
|
||||
// if there's a selection, the paste should delete it
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_delete_selection(str,state);
|
||||
|
@ -752,21 +790,12 @@ retry:
|
|||
state->has_preferred_x = 0;
|
||||
break;
|
||||
|
||||
#ifdef STB_TEXTEDIT_IS_SPACE
|
||||
#ifdef STB_TEXTEDIT_MOVEWORDLEFT
|
||||
case STB_TEXTEDIT_K_WORDLEFT:
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
stb_textedit_move_to_first(state);
|
||||
else {
|
||||
state->cursor = stb_textedit_move_to_word_previous(str, state);
|
||||
stb_textedit_clamp( str, state );
|
||||
}
|
||||
break;
|
||||
|
||||
case STB_TEXTEDIT_K_WORDRIGHT:
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
stb_textedit_move_to_last(str, state);
|
||||
else {
|
||||
state->cursor = stb_textedit_move_to_word_next(str, state);
|
||||
state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
|
||||
stb_textedit_clamp( str, state );
|
||||
}
|
||||
break;
|
||||
|
@ -775,17 +804,28 @@ retry:
|
|||
if( !STB_TEXT_HAS_SELECTION( state ) )
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
|
||||
state->cursor = stb_textedit_move_to_word_previous(str, state);
|
||||
state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
|
||||
state->select_end = state->cursor;
|
||||
|
||||
stb_textedit_clamp( str, state );
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef STB_TEXTEDIT_MOVEWORDRIGHT
|
||||
case STB_TEXTEDIT_K_WORDRIGHT:
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
stb_textedit_move_to_last(str, state);
|
||||
else {
|
||||
state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
|
||||
stb_textedit_clamp( str, state );
|
||||
}
|
||||
break;
|
||||
|
||||
case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
|
||||
if( !STB_TEXT_HAS_SELECTION( state ) )
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
|
||||
state->cursor = stb_textedit_move_to_word_next(str, state);
|
||||
state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
|
||||
state->select_end = state->cursor;
|
||||
|
||||
stb_textedit_clamp( str, state );
|
||||
|
@ -968,25 +1008,27 @@ retry:
|
|||
#ifdef STB_TEXTEDIT_K_LINESTART2
|
||||
case STB_TEXTEDIT_K_LINESTART2:
|
||||
#endif
|
||||
case STB_TEXTEDIT_K_LINESTART: {
|
||||
StbFindState find;
|
||||
case STB_TEXTEDIT_K_LINESTART:
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_move_to_first(state);
|
||||
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
|
||||
state->cursor = find.first_char;
|
||||
if (state->single_line)
|
||||
state->cursor = 0;
|
||||
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
||||
--state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef STB_TEXTEDIT_K_LINEEND2
|
||||
case STB_TEXTEDIT_K_LINEEND2:
|
||||
#endif
|
||||
case STB_TEXTEDIT_K_LINEEND: {
|
||||
StbFindState find;
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_move_to_first(state);
|
||||
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
|
||||
state->cursor = find.first_char + find.length;
|
||||
if (state->single_line)
|
||||
state->cursor = n;
|
||||
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
||||
++state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -994,25 +1036,29 @@ retry:
|
|||
#ifdef STB_TEXTEDIT_K_LINESTART2
|
||||
case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
|
||||
#endif
|
||||
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: {
|
||||
StbFindState find;
|
||||
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
|
||||
state->cursor = state->select_end = find.first_char;
|
||||
if (state->single_line)
|
||||
state->cursor = 0;
|
||||
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
||||
--state->cursor;
|
||||
state->select_end = state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef STB_TEXTEDIT_K_LINEEND2
|
||||
case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
|
||||
#endif
|
||||
case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
|
||||
StbFindState find;
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
|
||||
state->cursor = state->select_end = find.first_char + find.length;
|
||||
if (state->single_line)
|
||||
state->cursor = n;
|
||||
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
||||
++state->cursor;
|
||||
state->select_end = state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -1287,4 +1333,61 @@ static void stb_textedit_initialize_state(STB_TexteditState *state, int is_singl
|
|||
{
|
||||
stb_textedit_clear_state(state, is_single_line);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
|
||||
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
||||
{
|
||||
return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif//STB_TEXTEDIT_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// stb_tilemap_editor.h - v0.35 - Sean Barrett - http://nothings.org/stb
|
||||
// stb_tilemap_editor.h - v0.38 - Sean Barrett - http://nothings.org/stb
|
||||
// placed in the public domain - not copyrighted - first released 2014-09
|
||||
//
|
||||
// Embeddable tilemap editor for C/C++
|
||||
|
@ -259,7 +259,7 @@
|
|||
// #define STBTE_MAX_CATEGORIES 100
|
||||
// #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB
|
||||
// #define STBTE_MAX_COPY 90000 // e.g. 300x300
|
||||
// #define STBTE_MAX_PROPERTIESERTIES 10 // max properties per tile
|
||||
// #define STBTE_MAX_PROPERTIES 10 // max properties per tile
|
||||
//
|
||||
// API
|
||||
//
|
||||
|
@ -275,6 +275,9 @@
|
|||
// either approach allows cut&pasting between levels.)
|
||||
//
|
||||
// REVISION HISTORY
|
||||
// 0.38 fix warning
|
||||
// 0.37 fix warning
|
||||
// 0.36 minor compiler support
|
||||
// 0.35 layername button changes
|
||||
// - layername buttons grow with the layer panel
|
||||
// - fix stbte_create_map being declared as stbte_create
|
||||
|
@ -309,13 +312,12 @@
|
|||
// Additional features:
|
||||
// Josh Huelsman
|
||||
// Bugfixes:
|
||||
// [this could be you!]
|
||||
// Ryan Whitworth
|
||||
// Eugene Opalev
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// This software has been placed in the public domain by its author.
|
||||
// Where that dedication is not recognized, you are granted a perpetual,
|
||||
// irrevocable license to copy and modify this file as you see fit.
|
||||
// See end of file for license information.
|
||||
|
||||
|
||||
|
||||
|
@ -326,6 +328,14 @@
|
|||
#ifndef STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
|
||||
#define STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
typedef struct stbte_tilemap stbte_tilemap;
|
||||
|
||||
// these are the drawmodes used in STBTE_DRAW_TILE
|
||||
|
@ -3345,7 +3355,7 @@ static void stbte__toolbar(stbte_tilemap *tm, int x0, int y0, int w, int h)
|
|||
|
||||
#define STBTE__TEXTCOLOR(n) stbte__color_table[n][STBTE__text][STBTE__idle]
|
||||
|
||||
static int stbte__info_value(char *label, int x, int y, int val, int digits, int id)
|
||||
static int stbte__info_value(const char *label, int x, int y, int val, int digits, int id)
|
||||
{
|
||||
if (stbte__ui.event == STBTE__paint) {
|
||||
int off = 9-stbte__get_char_width(label[0]);
|
||||
|
@ -4118,3 +4128,45 @@ void stbte_mouse_sdl(stbte_tilemap *tm, const void *sdl_event, float xs, float y
|
|||
}
|
||||
|
||||
#endif // STB_TILEMAP_EDITOR_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
1078
stb_truetype.h
1078
stb_truetype.h
File diff suppressed because it is too large
Load Diff
1118
stb_vorbis.c
1118
stb_vorbis.c
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
// stb_voxel_render.h - v0.81 - Sean Barrett, 2015 - public domain
|
||||
// stb_voxel_render.h - v0.85 - Sean Barrett, 2015 - public domain
|
||||
//
|
||||
// This library helps render large-scale "voxel" worlds for games,
|
||||
// in this case, one with blocks that can have textures and that
|
||||
|
@ -13,7 +13,7 @@
|
|||
// It works by creating triangle meshes. The library includes
|
||||
//
|
||||
// - converter from dense 3D arrays of block info to vertex mesh
|
||||
// - shader for the vertex mesh
|
||||
// - vertex & fragment shaders for the vertex mesh
|
||||
// - assistance in setting up shader state
|
||||
//
|
||||
// For portability, none of the library code actually accesses
|
||||
|
@ -24,8 +24,9 @@
|
|||
// yourself. However, you could also try making a game with
|
||||
// a small enough world that it's fully loaded rather than
|
||||
// streaming. Currently the preferred vertex format is 20 bytes
|
||||
// per quad. There are plans to allow much more compact formats
|
||||
// with a slight reduction in shader features.
|
||||
// per quad. There are designs to allow much more compact formats
|
||||
// with a slight reduction in shader features, but no roadmap
|
||||
// for actually implementing them.
|
||||
//
|
||||
//
|
||||
// USAGE
|
||||
|
@ -108,7 +109,7 @@
|
|||
// and avoids a potential slow path (gathering non-uniform
|
||||
// data from uniforms) on some hardware.
|
||||
//
|
||||
// In the future I hope to add additional modes that have significantly
|
||||
// In the future I might add additional modes that have significantly
|
||||
// smaller meshes but reduce features, down as small as 6 bytes per quad.
|
||||
// See elsewhere in this file for a table of candidate modes. Switching
|
||||
// to a mode will require changing some of your mesh creation code, but
|
||||
|
@ -186,11 +187,16 @@
|
|||
// Features Porting Bugfixes & Warnings
|
||||
// Sean Barrett github:r-leyh Jesus Fernandez
|
||||
// Miguel Lechon github:Arbeiterunfallversicherungsgesetz
|
||||
// Thomas Frase
|
||||
// Thomas Frase James Hofmann
|
||||
// Stephen Olsen github:guitarfreak
|
||||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 0.85 (2017-03-03) add block_selector (by guitarfreak)
|
||||
// 0.84 (2016-04-02) fix GLSL syntax error on glModelView path
|
||||
// 0.83 (2015-09-13) remove non-constant struct initializers to support more compilers
|
||||
// 0.82 (2015-08-01) added input.packed_compact to store rot, vheight & texlerp efficiently
|
||||
// fix broken tex_overlay2
|
||||
// 0.81 (2015-05-28) fix broken STBVOX_CONFIG_OPTIMIZED_VHEIGHT
|
||||
// 0.80 (2015-04-11) fix broken STBVOX_CONFIG_ROTATION_IN_LIGHTING refactoring
|
||||
// change STBVOX_MAKE_LIGHTING to STBVOX_MAKE_LIGHTING_EXT so
|
||||
|
@ -209,6 +215,11 @@
|
|||
// stb_voxel_render 20-byte quads 2015/01
|
||||
// zmc engine 32-byte quads 2013/12
|
||||
// zmc engine 96-byte quads 2011/10
|
||||
//
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
#ifndef INCLUDE_STB_VOXEL_RENDER_H
|
||||
#define INCLUDE_STB_VOXEL_RENDER_H
|
||||
|
@ -253,7 +264,7 @@ extern "C" {
|
|||
// modes 0,1,20,21, Z in the mesh can extend to 511 instead
|
||||
// of 255. However, half-height blocks cannot be used.
|
||||
//
|
||||
// All of the following just #ifdef tested so need no values, and are optional.
|
||||
// All of the following are just #ifdef tested so need no values, and are optional.
|
||||
//
|
||||
// STBVOX_CONFIG_BLOCKTYPE_SHORT
|
||||
// use unsigned 16-bit values for 'blocktype' in the input instead of 8-bit values
|
||||
|
@ -293,7 +304,7 @@ extern "C" {
|
|||
//
|
||||
// STBVOX_CONFIG_DISABLE_TEX2
|
||||
// This disables all processing of texture 2 in the shader in case
|
||||
// you don't use it. Eventually this will be replaced with a mode
|
||||
// you don't use it. Eventually this could be replaced with a mode
|
||||
// that omits the unused data entirely.
|
||||
//
|
||||
// STBVOX_CONFIG_TEX1_EDGE_CLAMP
|
||||
|
@ -1581,7 +1592,7 @@ static const char *stbvox_vertex_program =
|
|||
"uniform vec3 normal_table[32];\n"
|
||||
|
||||
#ifndef STBVOX_CONFIG_OPENGL_MODELVIEW
|
||||
"uniform mat44 model_view;\n"
|
||||
"uniform mat4x4 model_view;\n"
|
||||
#endif
|
||||
|
||||
// fragment output data
|
||||
|
@ -2891,7 +2902,9 @@ static void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, in
|
|||
|
||||
if (mm->input.selector)
|
||||
mesh = mm->input.selector[v_off];
|
||||
|
||||
else if (mm->input.block_selector)
|
||||
mesh = mm->input.block_selector[mm->input.blocktype[v_off]];
|
||||
|
||||
// check if we're going off the end
|
||||
if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
|
||||
mm->full = 1;
|
||||
|
@ -3100,7 +3113,9 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
|
|||
mesh = mm->default_mesh;
|
||||
if (mm->input.selector)
|
||||
mesh = mm->input.selector[v_off];
|
||||
|
||||
else if (mm->input.block_selector)
|
||||
mesh = mm->input.block_selector[bt];
|
||||
|
||||
if (geo <= STBVOX_GEOM_ceil_slope_north_is_bottom) {
|
||||
// this is the simple case, we can just use regular block gen with special vmesh calculated with vheight
|
||||
stbvox_mesh_vertex basevert;
|
||||
|
@ -3121,7 +3136,9 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
|
|||
basevert = stbvox_vertex_encode(pos.x, pos.y, pos.z << STBVOX_CONFIG_PRECISION_Z, 0,0);
|
||||
if (mm->input.selector) {
|
||||
mesh = mm->input.selector[v_off];
|
||||
}
|
||||
} else if (mm->input.block_selector)
|
||||
mesh = mm->input.block_selector[bt];
|
||||
|
||||
|
||||
// check if we're going off the end
|
||||
if (mm->output_cur[mesh][0] + mm->output_size[mesh][0]*6 > mm->output_end[mesh][0]) {
|
||||
|
@ -3341,6 +3358,9 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
|
|||
mesh = mm->input.selector[v_off];
|
||||
simple_rot = mesh >> 4;
|
||||
mesh &= 15;
|
||||
}
|
||||
if (mm->input.block_selector) {
|
||||
mesh = mm->input.block_selector[bt];
|
||||
}
|
||||
|
||||
// check if we're going off the end
|
||||
|
@ -3374,10 +3394,13 @@ static void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_po
|
|||
|
||||
static void stbvox_make_mesh_for_column(stbvox_mesh_maker *mm, int x, int y, int z0)
|
||||
{
|
||||
stbvox_pos pos = { x,y,0 };
|
||||
stbvox_pos pos;
|
||||
int v_off = x * mm->x_stride_in_bytes + y * mm->y_stride_in_bytes;
|
||||
int ns_off = mm->y_stride_in_bytes;
|
||||
int ew_off = mm->x_stride_in_bytes;
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = 0;
|
||||
if (mm->input.geometry) {
|
||||
unsigned char *bt = mm->input.blocktype + v_off;
|
||||
unsigned char *geo = mm->input.geometry + v_off;
|
||||
|
@ -3736,3 +3759,45 @@ int main(int argc, char **argv)
|
|||
// (v: x:2,y:2,z:2,light:2)
|
||||
|
||||
#endif // STB_VOXEL_RENDER_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// a vector<>-like dynamic array for C
|
||||
//
|
||||
// version history:
|
||||
// 1.02 - compiles as C++, but untested
|
||||
// 1.02 - tweaks to syntax for no good reason
|
||||
// 1.01 - added a "common uses" documentation section
|
||||
// 1.0 - fixed bug in the version I posted prematurely
|
||||
// 0.9 - rewrite to try to avoid strict-aliasing optimization
|
||||
|
@ -21,7 +21,7 @@
|
|||
// - the length of the "in-use" part of the array
|
||||
// - the current size of the allocated array
|
||||
//
|
||||
// I find it to be single most useful non-built-in-structure when
|
||||
// I find it to be the single most useful non-built-in-structure when
|
||||
// programming in C (hash tables a close second), but to be clear
|
||||
// it lacks many of the capabilities of C++ vector<>: there is no
|
||||
// range checking, the object address isn't stable (see next section
|
||||
|
@ -57,7 +57,7 @@
|
|||
//
|
||||
// 1. can't take long-term pointers to elements of the array
|
||||
// 2. have to return the pointer from functions which might expand it
|
||||
// (either as a return value or by passing it back)
|
||||
// (either as a return value or by storing it to a ptr-to-ptr)
|
||||
//
|
||||
// Now you can do the following things with this array:
|
||||
//
|
||||
|
@ -161,6 +161,10 @@
|
|||
// The details are trivial and implementation is straightforward;
|
||||
// the main trick is in realizing in the first place that it's
|
||||
// possible to do this in a generic, type-safe way in C.
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
#ifndef STB_STRETCHY_BUFFER_H_INCLUDED
|
||||
#define STB_STRETCHY_BUFFER_H_INCLUDED
|
||||
|
@ -208,3 +212,46 @@ static void * stb__sbgrowf(void *arr, int increment, int itemsize)
|
|||
}
|
||||
}
|
||||
#endif // STB_STRETCHY_BUFFER_H_INCLUDED
|
||||
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -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
|
|
@ -1,3 +1,50 @@
|
|||
#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit
|
||||
#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit
|
||||
#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit
|
||||
#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit
|
||||
#define STB_C_LEX_C99_HEX_FLOATS Y // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit
|
||||
#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id
|
||||
#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring
|
||||
#define STB_C_LEX_C_SQ_STRINGS Y // single-quote-delimited strings with escapes CLEX_ssstring
|
||||
#define STB_C_LEX_C_CHARS Y // single-quote-delimited character with escape CLEX_charlits
|
||||
#define STB_C_LEX_C_COMMENTS Y // "/* comment */"
|
||||
#define STB_C_LEX_CPP_COMMENTS Y // "// comment to end of line\n"
|
||||
#define STB_C_LEX_C_COMPARISONS Y // "==" CLEX_eq "!=" CLEX_noteq "<=" CLEX_lesseq ">=" CLEX_greatereq
|
||||
#define STB_C_LEX_C_LOGICAL Y // "&&" CLEX_andand "||" CLEX_oror
|
||||
#define STB_C_LEX_C_SHIFTS Y // "<<" CLEX_shl ">>" CLEX_shr
|
||||
#define STB_C_LEX_C_INCREMENTS Y // "++" CLEX_plusplus "--" CLEX_minusminus
|
||||
#define STB_C_LEX_C_ARROW Y // "->" CLEX_arrow
|
||||
#define STB_C_LEX_EQUAL_ARROW Y // "=>" CLEX_eqarrow
|
||||
#define STB_C_LEX_C_BITWISEEQ Y // "&=" CLEX_andeq "|=" CLEX_oreq "^=" CLEX_xoreq
|
||||
#define STB_C_LEX_C_ARITHEQ Y // "+=" CLEX_pluseq "-=" CLEX_minuseq
|
||||
// "*=" CLEX_muleq "/=" CLEX_diveq "%=" CLEX_modeq
|
||||
// if both STB_C_LEX_SHIFTS & STB_C_LEX_ARITHEQ:
|
||||
// "<<=" CLEX_shleq ">>=" CLEX_shreq
|
||||
|
||||
#define STB_C_LEX_PARSE_SUFFIXES Y // letters after numbers are parsed as part of those numbers, and must be in suffix list below
|
||||
#define STB_C_LEX_DECIMAL_SUFFIXES "uUlL" // decimal integer suffixes e.g. "uUlL" -- these are returned as-is in string storage
|
||||
#define STB_C_LEX_HEX_SUFFIXES "lL" // e.g. "uUlL"
|
||||
#define STB_C_LEX_OCTAL_SUFFIXES "lL" // e.g. "uUlL"
|
||||
#define STB_C_LEX_FLOAT_SUFFIXES "uulL" //
|
||||
|
||||
#define STB_C_LEX_0_IS_EOF N // if Y, ends parsing at '\0'; if N, returns '\0' as token
|
||||
#define STB_C_LEX_INTEGERS_AS_DOUBLES N // parses integers as doubles so they can be larger than 'int', but only if STB_C_LEX_STDLIB==N
|
||||
#define STB_C_LEX_MULTILINE_DSTRINGS Y // allow newlines in double-quoted strings
|
||||
#define STB_C_LEX_MULTILINE_SSTRINGS Y // allow newlines in single-quoted strings
|
||||
#define STB_C_LEX_USE_STDLIB N // use strtod,strtol for parsing #s; otherwise inaccurate hack
|
||||
#define STB_C_LEX_DOLLAR_IDENTIFIER Y // allow $ as an identifier character
|
||||
#define STB_C_LEX_FLOAT_NO_DECIMAL Y // allow floats that have no decimal point if they have an exponent
|
||||
|
||||
#define STB_C_LEX_DEFINE_ALL_TOKEN_NAMES Y // if Y, all CLEX_ token names are defined, even if never returned
|
||||
// leaving it as N should help you catch config bugs
|
||||
|
||||
#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess
|
||||
// still have #line, #pragma, etc)
|
||||
|
||||
#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions
|
||||
|
||||
|
||||
|
||||
#define STB_C_LEXER_IMPLEMENTATION
|
||||
#define STB_C_LEXER_SELF_TEST
|
||||
#include "../stb_c_lexer.h"
|
||||
|
|
|
@ -699,7 +699,7 @@ static int test_plane(plane *p, float x0, float y0, float z0, float x1, float y1
|
|||
static int is_box_in_frustum(float *bmin, float *bmax)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < 5; ++i)
|
||||
for (i=0; i < 6; ++i)
|
||||
if (!test_plane(&frustum[i], bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]))
|
||||
return 0;
|
||||
return 1;
|
||||
|
|
|
@ -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
|
|
@ -7,7 +7,7 @@
|
|||
#define STB_DEFINE
|
||||
#include "stb.h"
|
||||
|
||||
#define PNGSUITE_PRIMARY
|
||||
//#define PNGSUITE_PRIMARY
|
||||
|
||||
#if 0
|
||||
void test_ycbcr(void)
|
||||
|
@ -53,6 +53,13 @@ void test_ycbcr(void)
|
|||
|
||||
float hdr_data[200][200][3];
|
||||
|
||||
void dummy_write(void *context, void *data, int len)
|
||||
{
|
||||
static char dummy[1024];
|
||||
if (len > 1024) len = 1024;
|
||||
memcpy(dummy, data, len);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int w,h;
|
||||
|
@ -73,18 +80,28 @@ int main(int argc, char **argv)
|
|||
int i, n;
|
||||
|
||||
for (i=1; i < argc; ++i) {
|
||||
int res;
|
||||
int w2,h2,n2;
|
||||
unsigned char *data;
|
||||
printf("%s\n", argv[i]);
|
||||
res = stbi_info(argv[1], &w2, &h2, &n2);
|
||||
data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n");
|
||||
data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n");
|
||||
data = stbi_load(argv[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n");
|
||||
data = stbi_load(argv[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n");
|
||||
data = stbi_load(argv[i], &w, &h, 0, 4);
|
||||
data = stbi_load(argv[i], &w, &h, &n, 4);
|
||||
assert(data);
|
||||
assert(w == w2 && h == h2 && n == n2);
|
||||
assert(res);
|
||||
if (data) {
|
||||
char fname[512];
|
||||
stb_splitpath(fname, argv[i], STB_FILE);
|
||||
stbi_write_png(stb_sprintf("output/%s.png", fname), w, h, 4, data, w*4);
|
||||
stbi_write_bmp(stb_sprintf("output/%s.bmp", fname), w, h, 4, data);
|
||||
stbi_write_tga(stb_sprintf("output/%s.tga", fname), w, h, 4, data);
|
||||
stbi_write_png_to_func(dummy_write,0, w, h, 4, data, w*4);
|
||||
stbi_write_bmp_to_func(dummy_write,0, w, h, 4, data);
|
||||
stbi_write_tga_to_func(dummy_write,0, w, h, 4, data);
|
||||
free(data);
|
||||
} else
|
||||
printf("FAILED 4\n");
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#pragma comment(lib, "opengl32.lib")
|
||||
#pragma comment(lib, "glu32.lib")
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
#pragma comment(lib, "gdi32.lib")
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_WIN32) && _MSC_VER > 1200
|
||||
#define STBIR_ASSERT(x) \
|
||||
|
@ -69,9 +70,11 @@ void stbir_progress(float p)
|
|||
|
||||
#ifdef _WIN32
|
||||
#include <sys/timeb.h>
|
||||
#endif
|
||||
|
||||
#include <direct.h>
|
||||
#define mkdir(a, b) _mkdir(a)
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#define MT_SIZE 624
|
||||
static size_t g_aiMT[MT_SIZE];
|
||||
|
@ -356,6 +359,54 @@ void test_subpixel(const char* file, float width_percent, float height_percent,
|
|||
free(output_data);
|
||||
}
|
||||
|
||||
void test_subpixel_region(const char* file, float width_percent, float height_percent, float s0, float t0, float s1, float t1)
|
||||
{
|
||||
int w, h, n;
|
||||
unsigned char* input_data = stbi_load(file, &w, &h, &n, 0);
|
||||
|
||||
if (input_data == NULL)
|
||||
return;
|
||||
|
||||
int new_w = (int)(w * width_percent);
|
||||
int new_h = (int)(h * height_percent);
|
||||
|
||||
unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char));
|
||||
|
||||
stbir_resize_region(input_data, w, h, 0, output_data, new_w, new_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, s0, t0, s1, t1);
|
||||
|
||||
stbi_image_free(input_data);
|
||||
|
||||
char output[200];
|
||||
sprintf(output, "test-output/subpixel-region-%d-%d-%f-%f-%f-%f-%s", new_w, new_h, s0, t0, s1, t1, file);
|
||||
stbi_write_png(output, new_w, new_h, n, output_data, 0);
|
||||
|
||||
free(output_data);
|
||||
}
|
||||
|
||||
void test_subpixel_command(const char* file, float width_percent, float height_percent, float x_scale, float y_scale, float x_offset, float y_offset)
|
||||
{
|
||||
int w, h, n;
|
||||
unsigned char* input_data = stbi_load(file, &w, &h, &n, 0);
|
||||
|
||||
if (input_data == NULL)
|
||||
return;
|
||||
|
||||
int new_w = (int)(w * width_percent);
|
||||
int new_h = (int)(h * height_percent);
|
||||
|
||||
unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char));
|
||||
|
||||
stbir_resize_subpixel(input_data, w, h, 0, output_data, new_w, new_h, 0, STBIR_TYPE_UINT8, n, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, x_scale, y_scale, x_offset, y_offset);
|
||||
|
||||
stbi_image_free(input_data);
|
||||
|
||||
char output[200];
|
||||
sprintf(output, "test-output/subpixel-command-%d-%d-%f-%f-%f-%f-%s", new_w, new_h, x_scale, y_scale, x_offset, y_offset, file);
|
||||
stbi_write_png(output, new_w, new_h, n, output_data, 0);
|
||||
|
||||
free(output_data);
|
||||
}
|
||||
|
||||
unsigned int* pixel(unsigned int* buffer, int x, int y, int c, int w, int n)
|
||||
{
|
||||
return &buffer[y*w*n + x*n + c];
|
||||
|
@ -461,6 +512,18 @@ void test_subpixel_1()
|
|||
STBIR_ASSERT(output_data[y * 16 + x + 8] == output_right[y * 8 + x]);
|
||||
}
|
||||
}
|
||||
|
||||
stbir_resize_subpixel(image, 8, 8, 0, output_left, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 0, 0);
|
||||
stbir_resize_subpixel(image, 8, 8, 0, output_right, 8, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 8, 0);
|
||||
|
||||
{for (int x = 0; x < 8; x++)
|
||||
{
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
STBIR_ASSERT(output_data[y * 16 + x] == output_left[y * 8 + x]);
|
||||
STBIR_ASSERT(output_data[y * 16 + x + 8] == output_right[y * 8 + x]);
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
// test that replicating an image and using a subtile of it produces same results as wraparound
|
||||
|
@ -498,6 +561,14 @@ void test_subpixel_2()
|
|||
for (int y = 0; y < 16; y++)
|
||||
STBIR_ASSERT(output_data_1[y * 16 + x] == output_data_2[y * 16 + x]);
|
||||
}}
|
||||
|
||||
stbir_resize_subpixel(large_image, 32, 32, 0, output_data_2, 16, 16, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_WRAP, STBIR_EDGE_WRAP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context, 2, 2, 16, 16);
|
||||
|
||||
{for (int x = 0; x < 16; x++)
|
||||
{
|
||||
for (int y = 0; y < 16; y++)
|
||||
STBIR_ASSERT(output_data_1[y * 16 + x] == output_data_2[y * 16 + x]);
|
||||
}}
|
||||
}
|
||||
|
||||
// test that 0,0,1,1 subpixel produces same result as no-rect
|
||||
|
@ -521,6 +592,14 @@ void test_subpixel_3()
|
|||
for (int y = 0; y < 32; y++)
|
||||
STBIR_ASSERT(output_data_1[y * 32 + x] == output_data_2[y * 32 + x]);
|
||||
}
|
||||
|
||||
stbir_resize_subpixel(image, 8, 8, 0, output_data_1, 32, 32, 0, STBIR_TYPE_UINT8, 1, 0, STBIR_ALPHA_CHANNEL_NONE, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_LINEAR, NULL, 4, 4, 0, 0);
|
||||
|
||||
{for (int x = 0; x < 32; x++)
|
||||
{
|
||||
for (int y = 0; y < 32; y++)
|
||||
STBIR_ASSERT(output_data_1[y * 32 + x] == output_data_2[y * 32 + x]);
|
||||
}}
|
||||
}
|
||||
|
||||
// test that 1:1 resample using s,t=0,0,1,1 with bilinear produces original image
|
||||
|
@ -537,6 +616,9 @@ void test_subpixel_4()
|
|||
|
||||
stbir_resize_region(image, 8, 8, 0, output, 8, 8, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, &g_context, 0, 0, 1, 1);
|
||||
STBIR_ASSERT(memcmp(image, output, 8 * 8) == 0);
|
||||
|
||||
stbir_resize_subpixel(image, 8, 8, 0, output, 8, 8, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, &g_context, 1, 1, 0, 0);
|
||||
STBIR_ASSERT(memcmp(image, output, 8 * 8) == 0);
|
||||
}
|
||||
|
||||
static unsigned int image88_int[8][8];
|
||||
|
@ -753,7 +835,7 @@ void test_filters(void)
|
|||
|
||||
#define UMAX32 4294967295U
|
||||
|
||||
static void write32(char *filename, stbir_uint32 *output, int w, int h)
|
||||
static void write32(const char *filename, stbir_uint32 *output, int w, int h)
|
||||
{
|
||||
stbir_uint8 *data = (stbir_uint8*) malloc(w*h*3);
|
||||
for (int i=0; i < w*h*3; ++i)
|
||||
|
@ -789,9 +871,9 @@ static void test_32(void)
|
|||
void test_suite(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
char *barbara;
|
||||
const char *barbara;
|
||||
|
||||
_mkdir("test-output");
|
||||
mkdir("test-output", 777);
|
||||
|
||||
if (argc > 1)
|
||||
barbara = argv[1];
|
||||
|
@ -880,17 +962,70 @@ void test_suite(int argc, char **argv)
|
|||
stbir_resize(image88, 8, 8, 0, output88, 16, 4, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_CATMULLROM, STBIR_COLORSPACE_SRGB, &g_context);
|
||||
stbir_resize(image88, 8, 8, 0, output88, 16, 4, 0, STBIR_TYPE_UINT8, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_CATMULLROM, STBIR_FILTER_BOX, STBIR_COLORSPACE_SRGB, &g_context);
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
int barbara_width, barbara_height, barbara_channels;
|
||||
stbi_image_free(stbi_load(barbara, &barbara_width, &barbara_height, &barbara_channels, 0));
|
||||
|
||||
int res = 10;
|
||||
// Downscaling
|
||||
{for (int i = 0; i <= res; i++)
|
||||
{
|
||||
float t = (float)i/res;
|
||||
float scale = 0.5;
|
||||
float out_scale = 2.0f/3;
|
||||
float x_shift = (barbara_width*out_scale - barbara_width*scale) * t;
|
||||
float y_shift = (barbara_height*out_scale - barbara_height*scale) * t;
|
||||
|
||||
test_subpixel_command(barbara, scale, scale, out_scale, out_scale, x_shift, y_shift);
|
||||
}}
|
||||
|
||||
// Upscaling
|
||||
{for (int i = 0; i <= res; i++)
|
||||
{
|
||||
float t = (float)i/res;
|
||||
float scale = 2;
|
||||
float out_scale = 3;
|
||||
float x_shift = (barbara_width*out_scale - barbara_width*scale) * t;
|
||||
float y_shift = (barbara_height*out_scale - barbara_height*scale) * t;
|
||||
|
||||
test_subpixel_command(barbara, scale, scale, out_scale, out_scale, x_shift, y_shift);
|
||||
}}
|
||||
|
||||
// Downscaling
|
||||
{for (int i = 0; i <= res; i++)
|
||||
{
|
||||
float t = (float)i/res / 2;
|
||||
test_subpixel_region(barbara, 0.25f, 0.25f, t, t, t+0.5f, t+0.5f);
|
||||
}}
|
||||
|
||||
// No scaling
|
||||
{for (int i = 0; i <= res; i++)
|
||||
{
|
||||
float t = (float)i/res / 2;
|
||||
test_subpixel_region(barbara, 0.5f, 0.5f, t, t, t+0.5f, t+0.5f);
|
||||
}}
|
||||
|
||||
// Upscaling
|
||||
{for (int i = 0; i <= res; i++)
|
||||
{
|
||||
float t = (float)i/res / 2;
|
||||
test_subpixel_region(barbara, 1, 1, t, t, t+0.5f, t+0.5f);
|
||||
}}
|
||||
|
||||
{for (i = 0; i < 10; i++)
|
||||
test_subpixel(barbara, 0.5f, 0.5f, (float)i / 10, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{for (i = 0; i < 10; i++)
|
||||
test_subpixel(barbara, 0.5f, 0.5f, 1, (float)i / 10);
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{for (i = 0; i < 10; i++)
|
||||
test_subpixel(barbara, 2, 2, (float)i / 10, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{for (i = 0; i < 10; i++)
|
||||
test_subpixel(barbara, 2, 2, 1, (float)i / 10);
|
||||
}
|
||||
|
||||
// Channels test
|
||||
test_channels(barbara, 0.5f, 0.5f, 1);
|
||||
|
@ -916,40 +1051,40 @@ void test_suite(int argc, char **argv)
|
|||
resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_CATMULLROM , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-catmullrom.png");
|
||||
resize_image(barbara, 0.5f, 0.5f, STBIR_FILTER_MITCHELL , STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, "test-output/barbara-downsample-mitchell.png");
|
||||
|
||||
for (i = 10; i < 100; i++)
|
||||
{for (i = 10; i < 100; i++)
|
||||
{
|
||||
char outname[200];
|
||||
sprintf(outname, "test-output/barbara-width-%d.jpg", i);
|
||||
resize_image(barbara, (float)i / 100, 1, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
|
||||
}
|
||||
}}
|
||||
|
||||
for (i = 110; i < 500; i += 10)
|
||||
{for (i = 110; i < 500; i += 10)
|
||||
{
|
||||
char outname[200];
|
||||
sprintf(outname, "test-output/barbara-width-%d.jpg", i);
|
||||
resize_image(barbara, (float)i / 100, 1, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
|
||||
}
|
||||
}}
|
||||
|
||||
for (i = 10; i < 100; i++)
|
||||
{for (i = 10; i < 100; i++)
|
||||
{
|
||||
char outname[200];
|
||||
sprintf(outname, "test-output/barbara-height-%d.jpg", i);
|
||||
resize_image(barbara, 1, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
|
||||
}
|
||||
}}
|
||||
|
||||
for (i = 110; i < 500; i += 10)
|
||||
{for (i = 110; i < 500; i += 10)
|
||||
{
|
||||
char outname[200];
|
||||
sprintf(outname, "test-output/barbara-height-%d.jpg", i);
|
||||
resize_image(barbara, 1, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
|
||||
}
|
||||
}}
|
||||
|
||||
for (i = 50; i < 200; i += 10)
|
||||
{for (i = 50; i < 200; i += 10)
|
||||
{
|
||||
char outname[200];
|
||||
sprintf(outname, "test-output/barbara-width-height-%d.jpg", i);
|
||||
resize_image(barbara, 100 / (float)i, (float)i / 100, STBIR_FILTER_CATMULLROM, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB, outname);
|
||||
}
|
||||
}}
|
||||
|
||||
test_format<unsigned short>(barbara, 0.5, 2.0, STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB);
|
||||
test_format<unsigned short>(barbara, 0.5, 2.0, STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR);
|
||||
|
|
|
@ -3,3 +3,6 @@
|
|||
#include "stb_image_resize.h"
|
||||
|
||||
// Just to make sure it will build properly with a c compiler
|
||||
|
||||
int main() {
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ RSC=rc.exe
|
|||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /G6 /MT /W3 /GX /Z7 /O2 /Ob2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FD /c
|
||||
# ADD CPP /nologo /G6 /MT /W3 /GX /Z7 /O2 /Ob2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "GRID_TEST" /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
@ -66,7 +66,7 @@ LINK32=link.exe
|
|||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GRID_TEST" /FR /FD /GZ /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
|
@ -86,6 +86,10 @@ LINK32=link.exe
|
|||
# Name "stb - Win32 Debug"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\grid_reachability.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -98,6 +102,10 @@ SOURCE=..\stb_c_lexer.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_connected_components.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_divide.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -106,6 +114,10 @@ SOURCE=..\stb_dxt.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_easy_font.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_herringbone_wang_tile.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -126,14 +138,26 @@ SOURCE=..\stb_leakcheck.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_malloc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_perlin.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_pg.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_rect_pack.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_sprintf.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\stb_textedit.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -63,7 +63,19 @@ Package=<4>
|
|||
|
||||
###############################################################################
|
||||
|
||||
Project: "resize"=.\resize\resize.dsp - Package Owner=<4>
|
||||
Project: "pg_test"=.\pg_test\pg_test.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "resize"=.\resize.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
|
@ -123,6 +135,30 @@ Package=<4>
|
|||
|
||||
###############################################################################
|
||||
|
||||
Project: "unicode"=..\tools\unicode\unicode.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "vorbseek"=.\vorbseek\vorbseek.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#include "stb_sprintf.h"
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "stb_sprintf.h"
|
||||
|
||||
#define STB_PERLIN_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_DXT_IMPLEMENATION
|
||||
|
@ -8,7 +12,9 @@
|
|||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#define STB_VOXEL_RENDER_IMPLEMENTATION
|
||||
#define STB_EASY_FONT_IMPLEMENTATION
|
||||
|
||||
#include "stb_easy_font.h"
|
||||
#include "stb_herringbone_wang_tile.h"
|
||||
#include "stb_image.h"
|
||||
#include "stb_image_write.h"
|
||||
|
@ -26,3 +32,11 @@
|
|||
#define STBTE_DRAW_TILE(x,y,id,highlight,data) 0
|
||||
#define STB_TILEMAP_EDITOR_IMPLEMENTATION
|
||||
#include "stb_tilemap_editor.h"
|
||||
|
||||
|
||||
int quicktest(void)
|
||||
{
|
||||
char buffer[999];
|
||||
stbsp_sprintf(buffer, "test%%test");
|
||||
return 0;
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
#include "stb_sprintf.h"
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "stb_sprintf.h"
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#define STB_PERLIN_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
@ -8,6 +12,7 @@
|
|||
#define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#define STB_VOXEL_RENDER_IMPLEMENTATION
|
||||
#define STB_CONNECTED_COMPONENTS_IMPLEMENTATION
|
||||
|
||||
#define STBI_MALLOC my_malloc
|
||||
#define STBI_FREE my_free
|
||||
|
@ -27,6 +32,10 @@ void my_free(void *) { }
|
|||
#include "stb_divide.h"
|
||||
#include "stb_herringbone_wang_tile.h"
|
||||
|
||||
#define STBCC_GRID_COUNT_X_LOG2 10
|
||||
#define STBCC_GRID_COUNT_Y_LOG2 10
|
||||
#include "stb_connected_components.h"
|
||||
|
||||
#define STBVOX_CONFIG_MODE 1
|
||||
#include "stb_voxel_render.h"
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
#include "stb_truetype.h"
|
||||
#include "stb_image_write.h"
|
||||
|
||||
#ifdef TT_TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
char ttf_buffer[1<<25];
|
||||
unsigned char output[512*100];
|
||||
|
||||
#ifdef TT_TEST
|
||||
|
||||
void debug(void)
|
||||
{
|
||||
stbtt_fontinfo font;
|
||||
|
@ -24,6 +24,7 @@ void debug(void)
|
|||
unsigned char temp_bitmap[BITMAP_H][BITMAP_W];
|
||||
stbtt_bakedchar cdata[256*2]; // ASCII 32..126 is 95 glyphs
|
||||
stbtt_packedchar pdata[256*2];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
stbtt_fontinfo font;
|
||||
|
@ -35,6 +36,17 @@ int main(int argc, char **argv)
|
|||
// @TODO: why is minglui.ttc failing?
|
||||
fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/mingliu.ttc", "rb"));
|
||||
|
||||
//fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/x/DroidSansMono.ttf", "rb"));
|
||||
{
|
||||
static stbtt_pack_context pc;
|
||||
static stbtt_packedchar cd[256];
|
||||
static unsigned char atlas[1024*1024];
|
||||
|
||||
stbtt_PackBegin(&pc, atlas, 1024,1024,1024,1,NULL);
|
||||
stbtt_PackFontRange(&pc, ttf_buffer, 0, 32.0, 0, 256, cd);
|
||||
stbtt_PackEnd(&pc);
|
||||
}
|
||||
|
||||
#if 0
|
||||
stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits!
|
||||
stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0);
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#define STB_IMAGE_STATIC
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include "stb_vorbis.c"
|
||||
#include "stb.h"
|
||||
|
@ -8,10 +12,11 @@ extern void stb_vorbis_dumpmem(void);
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t memlen;
|
||||
unsigned char *mem = stb_fileu("c:/x/theme_03.ogg", &memlen);
|
||||
unsigned char *mem = stb_fileu("c:/x/sketch008.ogg", &memlen);
|
||||
int chan, samplerate;
|
||||
short *output;
|
||||
int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output);
|
||||
stb_filewrite("c:/x/sketch008.raw", output, samples*4);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -4,15 +4,40 @@ FAQ
|
|||
|
||||
#### What's the license?
|
||||
|
||||
These libraries are in the public domain (or the equivalent where that is not
|
||||
possible). You can do anything you want with them. You have no legal obligation
|
||||
These libraries are in the public domain. You can do anything you
|
||||
want with them. You have no legal obligation
|
||||
to do anything else, although I appreciate attribution.
|
||||
|
||||
#### If I wrap an stb library in a new library, does the new library have to be public domain?
|
||||
They are also licensed under the MIT open source license, if you have lawyers
|
||||
who are unhappy with public domain. Every source file includes an explicit
|
||||
dual-license for you to choose from.
|
||||
|
||||
No.
|
||||
#### <a name="other_libs"></a> Are there other single-file public-domain/open source libraries with minimal dependencies out there?
|
||||
|
||||
#### A lot of these libraries seem redundant to existing open source libraries. Are they better somehow?
|
||||
[Yes.](https://github.com/nothings/single_file_libs)
|
||||
|
||||
#### If I wrap an stb library in a new library, does the new library have to be public domain/MIT?
|
||||
|
||||
No, because it's public domain you can freely relicense it to whatever license your new
|
||||
library wants to be.
|
||||
|
||||
#### What's the deal with SSE support in GCC-based compilers?
|
||||
|
||||
stb_image will either use SSE2 (if you compile with -msse2) or
|
||||
will not use any SIMD at all, rather than trying to detect the
|
||||
processor at runtime and handle it correctly. As I understand it,
|
||||
the approved path in GCC for runtime-detection require
|
||||
you to use multiple source files, one for each CPU configuration.
|
||||
Because stb_image is a header-file library that compiles in only
|
||||
one source file, there's no approved way to build both an
|
||||
SSE-enabled and a non-SSE-enabled variation.
|
||||
|
||||
While we've tried to work around it, we've had multiple issues over
|
||||
the years due to specific versions of gcc breaking what we're doing,
|
||||
so we've given up on it. See https://github.com/nothings/stb/issues/280
|
||||
and https://github.com/nothings/stb/issues/410 for examples.
|
||||
|
||||
#### Some of these libraries seem redundant to existing open source libraries. Are they better somehow?
|
||||
|
||||
Generally they're only better in that they're easier to integrate,
|
||||
easier to use, and easier to release (single file; good API; no
|
||||
|
@ -20,6 +45,10 @@ attribution requirement). They may be less featureful, slower,
|
|||
and/or use more memory. If you're already using an equivalent
|
||||
library, there's probably no good reason to switch.
|
||||
|
||||
#### Can I link directly to the table of stb libraries?
|
||||
|
||||
You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list.
|
||||
|
||||
#### Why do you list "lines of code"? It's a terrible metric.
|
||||
|
||||
Just to give you some idea of the internal complexity of the library,
|
||||
|
@ -57,10 +86,10 @@ remember to attach *two* files, etc.
|
|||
#### Why "stb"? Is this something to do with Set-Top Boxes?
|
||||
|
||||
No, they are just the initials for my name, Sean T. Barrett.
|
||||
This was not chosen out of egomania, but as a semi-robust
|
||||
This was not chosen out of egomania, but as a moderately sane
|
||||
way of namespacing the filenames and source function names.
|
||||
|
||||
#### Will you add more image types to stb_image.c?
|
||||
#### Will you add more image types to stb_image.h?
|
||||
|
||||
If people submit them, I generally add them, but the goal of stb_image
|
||||
is less for applications like image viewer apps (which need to support
|
||||
|
@ -68,10 +97,6 @@ every type of image under the sun) and more for things like games which
|
|||
can choose what images to use, so I may decline to add them if they're
|
||||
too rare or if the size of implementation vs. apparent benefit is too low.
|
||||
|
||||
#### Are there other single-file public-domain libraries out there?
|
||||
|
||||
Yes. I'll put a list here when people remind me what they are.
|
||||
|
||||
#### Do you have any advice on how to create my own single-file library?
|
||||
|
||||
Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
stb
|
||||
===
|
||||
|
||||
single-file public domain libraries for C/C++
|
||||
single-file public domain (or MIT licensed) libraries for C/C++ <a name="stb_libs"></a>
|
||||
|
||||
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
|
||||
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
|
||||
|
||||
|
||||
library | lastest version | category | LoC | description
|
||||
--------------------- | ---- | -------- | --- | --------------------------------
|
||||
|
|
|
@ -4,8 +4,9 @@ stb_truetype.h | graphics | parse, decode, and rasterize ch
|
|||
stb_image_write.h | graphics | image writing to disk: PNG, TGA, BMP
|
||||
stb_image_resize.h | graphics | resize images larger/smaller with good quality
|
||||
stb_rect_pack.h | graphics | simple 2D rectangle packer with decent quality
|
||||
stb_sprintf.h | utility | fast sprintf, snprintf for C/C++
|
||||
stretchy_buffer.h | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
|
||||
stb_textedit.h | UI | guts of a text editor for games etc implementing them from scratch
|
||||
stb_textedit.h | user interface | guts of a text editor for games etc implementing them from scratch
|
||||
stb_voxel_render.h | 3D graphics | Minecraft-esque voxel rendering "engine" with many more features
|
||||
stb_dxt.h | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor
|
||||
stb_perlin.h | 3D graphics | revised Perlin noise (3D input, 1D output)
|
||||
|
@ -14,5 +15,6 @@ stb_tilemap_editor.h | game dev | embeddable tilemap editor
|
|||
stb_herringbone_wang_tile.h | game dev | herringbone Wang tile map generator
|
||||
stb_c_lexer.h | parsing | simplify writing parsers for C-like languages
|
||||
stb_divide.h | math | more useful 32-bit modulus e.g. "euclidean divide"
|
||||
stb_connected_components.h | misc | incrementally compute reachability on grids
|
||||
stb.h | misc | helper functions for C, mostly redundant in C++; basically author's personal stuff
|
||||
stb_leakcheck.h | misc | quick-and-dirty malloc/free leak-checking
|
||||
|
|
|
@ -30,15 +30,18 @@ int main(int argc, char **argv)
|
|||
if (*s1 == 'v') ++s1;
|
||||
s3 = tokens[0];
|
||||
stb_trimwhite(s3);
|
||||
fprintf(f, "**[");
|
||||
if (strlen(s3) < 21) {
|
||||
fprintf(f, "**%s** | %s", tokens[0], s1);
|
||||
fprintf(f, "%s", tokens[0]);
|
||||
} else {
|
||||
char buffer[256];
|
||||
strncpy(buffer, s3, 18);
|
||||
buffer[18] = 0;
|
||||
strcat(buffer, "...");
|
||||
fprintf(f, "**%s** | %s", buffer, s1);
|
||||
fprintf(f, "%s", buffer);
|
||||
}
|
||||
fprintf(f, "](%s)**", tokens[0]);
|
||||
fprintf(f, " | %s", s1);
|
||||
s1 = stb_trimwhite(tokens[1]); // stb_trimwhite -- advance pointer to after whitespace & delete trailing whitespace
|
||||
s2 = stb_dupreplace(s1, " ", " "); // stb_dupreplace -- search & replace string and malloc result
|
||||
fprintf(f, " | %s", s2);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue