cleanup and refactoring
This commit is contained in:
parent
2302158928
commit
76f6bf62a4
1285 changed files with 757994 additions and 8 deletions
37
raytracer/nvpro_core/third_party/stb/LICENSE
vendored
Normal file
37
raytracer/nvpro_core/third_party/stb/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
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.
|
||||
184
raytracer/nvpro_core/third_party/stb/README.md
vendored
Normal file
184
raytracer/nvpro_core/third_party/stb/README.md
vendored
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
<!--- THIS FILE IS AUTOMATICALLY GENERATED, DO NOT CHANGE IT BY HAND --->
|
||||
|
||||
stb
|
||||
===
|
||||
|
||||
single-file public domain (or MIT licensed) libraries for C/C++
|
||||
|
||||
# This project discusses security-relevant bugs in public in Github Issues and Pull Requests, and it may take significant time for security fixes to be implemented or merged. If this poses an unreasonable risk to your project, do not use stb libraries.
|
||||
|
||||
Noteworthy:
|
||||
|
||||
* image loader: [stb_image.h](stb_image.h)
|
||||
* image writer: [stb_image_write.h](stb_image_write.h)
|
||||
* image resizer: [stb_image_resize2.h](stb_image_resize2.h)
|
||||
* font text rasterizer: [stb_truetype.h](stb_truetype.h)
|
||||
* typesafe containers: [stb_ds.h](stb_ds.h)
|
||||
|
||||
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, original stb_image_resize
|
||||
by Jorge L. "VinoBS" Rodriguez, and stb_image_resize2 and stb_sprintf by Jeff Roberts.
|
||||
|
||||
<a name="stb_libs"></a>
|
||||
|
||||
library | lastest version | category | LoC | description
|
||||
--------------------- | ---- | -------- | --- | --------------------------------
|
||||
**[stb_vorbis.c](stb_vorbis.c)** | 1.22 | audio | 5584 | decode ogg vorbis files from file/memory to float/16-bit signed output
|
||||
**[stb_hexwave.h](stb_hexwave.h)** | 0.5 | audio | 680 | audio waveform synthesizer
|
||||
**[stb_image.h](stb_image.h)** | 2.29 | graphics | 7985 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
|
||||
**[stb_truetype.h](stb_truetype.h)** | 1.26 | graphics | 5077 | parse, decode, and rasterize characters from truetype fonts
|
||||
**[stb_image_write.h](stb_image_write.h)** | 1.16 | graphics | 1724 | image writing to disk: PNG, TGA, BMP
|
||||
**[stb_image_resize2.h](stb_image_resize2.h)** | 2.04 | graphics | 10325 | resize images larger/smaller with good quality
|
||||
**[stb_rect_pack.h](stb_rect_pack.h)** | 1.01 | graphics | 623 | simple 2D rectangle packer with decent quality
|
||||
**[stb_perlin.h](stb_perlin.h)** | 0.5 | graphics | 428 | perlin's revised simplex noise w/ different seeds
|
||||
**[stb_ds.h](stb_ds.h)** | 0.67 | utility | 1895 | typesafe dynamic array and hash tables for C, will compile in C++
|
||||
**[stb_sprintf.h](stb_sprintf.h)** | 1.10 | utility | 1906 | fast sprintf, snprintf for C/C++
|
||||
**[stb_textedit.h](stb_textedit.h)** | 1.14 | user interface | 1429 | guts of a text editor for games etc implementing them from scratch
|
||||
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.89 | 3D graphics | 3807 | Minecraft-esque voxel rendering "engine" with many more features
|
||||
**[stb_dxt.h](stb_dxt.h)** | 1.12 | 3D graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor
|
||||
**[stb_easy_font.h](stb_easy_font.h)** | 1.1 | 3D graphics | 305 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
|
||||
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.42 | game dev | 4187 | embeddable tilemap editor
|
||||
**[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.7 | game dev | 1221 | herringbone Wang tile map generator
|
||||
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.12 | parsing | 940 | simplify writing parsers for C-like languages
|
||||
**[stb_divide.h](stb_divide.h)** | 0.94 | math | 433 | more useful 32-bit modulus e.g. "euclidean divide"
|
||||
**[stb_connected_comp...](stb_connected_components.h)** | 0.96 | misc | 1049 | incrementally compute reachability on grids
|
||||
**[stb_leakcheck.h](stb_leakcheck.h)** | 0.6 | misc | 194 | quick-and-dirty malloc/free leak-checking
|
||||
**[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL
|
||||
|
||||
Total libraries: 21
|
||||
Total lines of C code: 50806
|
||||
|
||||
|
||||
FAQ
|
||||
---
|
||||
|
||||
#### What's the license?
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
#### How do I use these libraries?
|
||||
|
||||
The idea behind single-header file libraries is that they're easy to distribute and deploy
|
||||
because all the code is contained in a single file. By default, the .h files in here act as
|
||||
their own header files, i.e. they declare the functions contained in the file but don't
|
||||
actually result in any code getting compiled.
|
||||
|
||||
So in addition, you should select _exactly one_ C/C++ source file that actually instantiates
|
||||
the code, preferably a file you're not editing frequently. This file should define a
|
||||
specific macro (this is documented per-library) to actually enable the function definitions.
|
||||
For example, to use stb_image, you should have exactly one C/C++ file that doesn't
|
||||
include stb_image.h regularly, but instead does
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
The right macro to define is pointed out right at the top of each of these libraries.
|
||||
|
||||
#### <a name="other_libs"></a> Are there other single-file public-domain/open source libraries with minimal dependencies out there?
|
||||
|
||||
[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
|
||||
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,
|
||||
to help you manage your expectations, or to let you know what you're
|
||||
getting into. While not all the libraries are written in the same
|
||||
style, they're certainly similar styles, and so comparisons between
|
||||
the libraries are probably still meaningful.
|
||||
|
||||
Note though that the lines do include both the implementation, the
|
||||
part that corresponds to a header file, and the documentation.
|
||||
|
||||
#### Why single-file headers?
|
||||
|
||||
Windows doesn't have standard directories where libraries
|
||||
live. That makes deploying libraries in Windows a lot more
|
||||
painful than open source developers on Unix-derivates generally
|
||||
realize. (It also makes library dependencies a lot worse in Windows.)
|
||||
|
||||
There's also a common problem in Windows where a library was built
|
||||
against a different version of the runtime library, which causes
|
||||
link conflicts and confusion. Shipping the libs as headers means
|
||||
you normally just compile them straight into your project without
|
||||
making libraries, thus sidestepping that problem.
|
||||
|
||||
Making them a single file makes it very easy to just
|
||||
drop them into a project that needs them. (Of course you can
|
||||
still put them in a proper shared library tree if you want.)
|
||||
|
||||
Why not two files, one a header and one an implementation?
|
||||
The difference between 10 files and 9 files is not a big deal,
|
||||
but the difference between 2 files and 1 file is a big deal.
|
||||
You don't need to zip or tar the files up, you don't have to
|
||||
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 moderately sane
|
||||
way of namespacing the filenames and source function names.
|
||||
|
||||
#### Will you add more image types to stb_image.h?
|
||||
|
||||
No. As stb_image use has grown, it has become more important
|
||||
for us to focus on security of the codebase. Adding new image
|
||||
formats increases the amount of code we need to secure, so it
|
||||
is no longer worth adding new formats.
|
||||
|
||||
#### 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
|
||||
|
||||
#### Why public domain?
|
||||
|
||||
I prefer it over GPL, LGPL, BSD, zlib, etc. for many reasons.
|
||||
Some of them are listed here:
|
||||
https://github.com/nothings/stb/blob/master/docs/why_public_domain.md
|
||||
|
||||
#### Why C?
|
||||
|
||||
Primarily, because I use C, not C++. But it does also make it easier
|
||||
for other people to use them from other languages.
|
||||
|
||||
#### Why not C99? stdint.h, declare-anywhere, etc.
|
||||
|
||||
I still use MSVC 6 (1998) as my IDE because it has better human factors
|
||||
for me than later versions of MSVC.
|
||||
940
raytracer/nvpro_core/third_party/stb/stb_c_lexer.h
vendored
Normal file
940
raytracer/nvpro_core/third_party/stb/stb_c_lexer.h
vendored
Normal file
|
|
@ -0,0 +1,940 @@
|
|||
// stb_c_lexer.h - v0.12 - 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.
|
||||
// To instantiate the implementation,
|
||||
// #define STB_C_LEXER_IMPLEMENTATION
|
||||
// in *ONE* source file, before #including this file.
|
||||
//
|
||||
// The default configuration is fairly close to a C lexer, although
|
||||
// suffixes on integer constants are not handled (you can override this).
|
||||
//
|
||||
// History:
|
||||
// 0.12 fix compilation bug for NUL support; better support separate inclusion
|
||||
// 0.11 fix clang static analysis warning
|
||||
// 0.10 fix warnings
|
||||
// 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
|
||||
// 0.03 added STB_C_LEX_DISCARD_PREPROCESSOR option
|
||||
// refactor API to simplify (only one struct instead of two)
|
||||
// change literal enum names to have 'lit' at the end
|
||||
// 0.02 first public release
|
||||
//
|
||||
// Status:
|
||||
// - haven't tested compiling as C++
|
||||
// - haven't tested the float parsing path
|
||||
// - haven't tested the non-default-config paths (e.g. non-stdlib)
|
||||
// - only tested default-config paths by eyeballing output of self-parse
|
||||
//
|
||||
// - haven't implemented multiline strings
|
||||
// - 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.
|
||||
|
||||
#ifdef STB_C_LEXER_IMPLEMENTATION
|
||||
#ifndef STB_C_LEXER_DEFINITIONS
|
||||
// to change the default parsing rules, copy the following lines
|
||||
// into your C/C++ file *before* including this, and then replace
|
||||
// the Y's with N's for the ones you don't want. This needs to be
|
||||
// set to the same values for every place in your program where
|
||||
// stb_c_lexer.h is included.
|
||||
// --BEGIN--
|
||||
|
||||
#if defined(Y) || defined(N)
|
||||
#error "Can only use stb_c_lexer in contexts where the preprocessor symbols 'Y' and 'N' are not defined"
|
||||
#endif
|
||||
|
||||
#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 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
|
||||
#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 N // "=>" 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 N // letters after numbers are parsed as part of those numbers, and must be in suffix list below
|
||||
#define STB_C_LEX_DECIMAL_SUFFIXES "" // decimal integer suffixes e.g. "uUlL" -- these are returned as-is in string storage
|
||||
#define STB_C_LEX_HEX_SUFFIXES "" // e.g. "uUlL"
|
||||
#define STB_C_LEX_OCTAL_SUFFIXES "" // e.g. "uUlL"
|
||||
#define STB_C_LEX_FLOAT_SUFFIXES "" //
|
||||
|
||||
#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 N // allow newlines in double-quoted strings
|
||||
#define STB_C_LEX_MULTILINE_SSTRINGS N // allow newlines in single-quoted strings
|
||||
#define STB_C_LEX_USE_STDLIB Y // 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 N // 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_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--
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef INCLUDE_STB_C_LEXER_H
|
||||
#define INCLUDE_STB_C_LEXER_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// lexer variables
|
||||
char *input_stream;
|
||||
char *eof;
|
||||
char *parse_point;
|
||||
char *string_storage;
|
||||
int string_storage_len;
|
||||
|
||||
// lexer parse location for error messages
|
||||
char *where_firstchar;
|
||||
char *where_lastchar;
|
||||
|
||||
// lexer token variables
|
||||
long token;
|
||||
double real_number;
|
||||
long int_number;
|
||||
char *string;
|
||||
int string_len;
|
||||
} stb_lexer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int line_number;
|
||||
int line_offset;
|
||||
} stb_lex_location;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void stb_c_lexer_init(stb_lexer *lexer, const char *input_stream, const char *input_stream_end, char *string_store, int store_length);
|
||||
// this function initialize the 'lexer' structure
|
||||
// Input:
|
||||
// - input_stream points to the file to parse, loaded into memory
|
||||
// - input_stream_end points to the end of the file, or NULL if you use 0-for-EOF
|
||||
// - string_store is storage the lexer can use for storing parsed strings and identifiers
|
||||
// - store_length is the length of that storage
|
||||
|
||||
extern int stb_c_lexer_get_token(stb_lexer *lexer);
|
||||
// this function returns non-zero if a token is parsed, or 0 if at EOF
|
||||
// Output:
|
||||
// - lexer->token is the token ID, which is unicode code point for a single-char token, < 0 for a multichar or eof or error
|
||||
// - lexer->real_number is a double constant value for CLEX_floatlit, or CLEX_intlit if STB_C_LEX_INTEGERS_AS_DOUBLES
|
||||
// - lexer->int_number is an integer constant for CLEX_intlit if !STB_C_LEX_INTEGERS_AS_DOUBLES, or character for CLEX_charlit
|
||||
// - lexer->string is a 0-terminated string for CLEX_dqstring or CLEX_sqstring or CLEX_identifier
|
||||
// - lexer->string_len is the byte length of lexer->string
|
||||
|
||||
extern void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where, stb_lex_location *loc);
|
||||
// this inefficient function returns the line number and character offset of a
|
||||
// given location in the file as returned by stb_lex_token. Because it's inefficient,
|
||||
// you should only call it for errors, not for every token.
|
||||
// For error messages of invalid tokens, you typically want the location of the start
|
||||
// of the token (which caused the token to be invalid). For bugs involving legit
|
||||
// tokens, you can report the first or the range.
|
||||
// Output:
|
||||
// - loc->line_number is the line number in the file, counting from 1, of the location
|
||||
// - loc->line_offset is the char-offset in the line, counting from 0, of the location
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
CLEX_eof = 256,
|
||||
CLEX_parse_error,
|
||||
CLEX_intlit ,
|
||||
CLEX_floatlit ,
|
||||
CLEX_id ,
|
||||
CLEX_dqstring ,
|
||||
CLEX_sqstring ,
|
||||
CLEX_charlit ,
|
||||
CLEX_eq ,
|
||||
CLEX_noteq ,
|
||||
CLEX_lesseq ,
|
||||
CLEX_greatereq ,
|
||||
CLEX_andand ,
|
||||
CLEX_oror ,
|
||||
CLEX_shl ,
|
||||
CLEX_shr ,
|
||||
CLEX_plusplus ,
|
||||
CLEX_minusminus ,
|
||||
CLEX_pluseq ,
|
||||
CLEX_minuseq ,
|
||||
CLEX_muleq ,
|
||||
CLEX_diveq ,
|
||||
CLEX_modeq ,
|
||||
CLEX_andeq ,
|
||||
CLEX_oreq ,
|
||||
CLEX_xoreq ,
|
||||
CLEX_arrow ,
|
||||
CLEX_eqarrow ,
|
||||
CLEX_shleq, CLEX_shreq,
|
||||
|
||||
CLEX_first_unused_token
|
||||
|
||||
};
|
||||
#endif // INCLUDE_STB_C_LEXER_H
|
||||
|
||||
#ifdef STB_C_LEXER_IMPLEMENTATION
|
||||
|
||||
// Hacky definitions so we can easily #if on them
|
||||
#define Y(x) 1
|
||||
#define N(x) 0
|
||||
|
||||
#if STB_C_LEX_INTEGERS_AS_DOUBLES(x)
|
||||
typedef double stb__clex_int;
|
||||
#define intfield real_number
|
||||
#define STB__clex_int_as_double
|
||||
#else
|
||||
typedef long stb__clex_int;
|
||||
#define intfield int_number
|
||||
#endif
|
||||
|
||||
// Convert these config options to simple conditional #defines so we can more
|
||||
// easily test them once we've change the meaning of Y/N
|
||||
|
||||
#if STB_C_LEX_PARSE_SUFFIXES(x)
|
||||
#define STB__clex_parse_suffixes
|
||||
#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
|
||||
|
||||
#if STB_C_LEX_C_DECIMAL_INTS(x)
|
||||
#define STB__clex_decimal_ints
|
||||
#endif
|
||||
|
||||
#if STB_C_LEX_C_OCTAL_INTS(x)
|
||||
#define STB__clex_octal_ints
|
||||
#endif
|
||||
|
||||
#if STB_C_LEX_C_DECIMAL_FLOATS(x)
|
||||
#define STB__clex_decimal_floats
|
||||
#endif
|
||||
|
||||
#if STB_C_LEX_DISCARD_PREPROCESSOR(x)
|
||||
#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 for the rest of the file we'll use the basic definition where
|
||||
// where Y expands to its contents and N expands to nothing
|
||||
#undef Y
|
||||
#define Y(a) a
|
||||
#undef N
|
||||
#define N(a)
|
||||
|
||||
// API function
|
||||
void stb_c_lexer_init(stb_lexer *lexer, const char *input_stream, const char *input_stream_end, char *string_store, int store_length)
|
||||
{
|
||||
lexer->input_stream = (char *) input_stream;
|
||||
lexer->eof = (char *) input_stream_end;
|
||||
lexer->parse_point = (char *) input_stream;
|
||||
lexer->string_storage = string_store;
|
||||
lexer->string_storage_len = store_length;
|
||||
}
|
||||
|
||||
// API function
|
||||
void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where, stb_lex_location *loc)
|
||||
{
|
||||
char *p = lexer->input_stream;
|
||||
int line_number = 1;
|
||||
int char_offset = 0;
|
||||
while (*p && p < where) {
|
||||
if (*p == '\n' || *p == '\r') {
|
||||
p += (p[0]+p[1] == '\r'+'\n' ? 2 : 1); // skip newline
|
||||
line_number += 1;
|
||||
char_offset = 0;
|
||||
} else {
|
||||
++p;
|
||||
++char_offset;
|
||||
}
|
||||
}
|
||||
loc->line_number = line_number;
|
||||
loc->line_offset = char_offset;
|
||||
}
|
||||
|
||||
// main helper function for returning a parsed token
|
||||
static int stb__clex_token(stb_lexer *lexer, int token, char *start, char *end)
|
||||
{
|
||||
lexer->token = token;
|
||||
lexer->where_firstchar = start;
|
||||
lexer->where_lastchar = end;
|
||||
lexer->parse_point = end+1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// helper function for returning eof
|
||||
static int stb__clex_eof(stb_lexer *lexer)
|
||||
{
|
||||
lexer->token = CLEX_eof;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb__clex_iswhite(int x)
|
||||
{
|
||||
return x == ' ' || x == '\t' || x == '\r' || x == '\n' || x == '\f';
|
||||
}
|
||||
|
||||
static const char *stb__strchr(const char *str, int ch)
|
||||
{
|
||||
for (; *str; ++str)
|
||||
if (*str == ch)
|
||||
return str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// parse suffixes at the end of a number
|
||||
static int stb__clex_parse_suffixes(stb_lexer *lexer, long tokenid, char *start, char *cur, const char *suffixes)
|
||||
{
|
||||
#ifdef STB__clex_parse_suffixes
|
||||
lexer->string = lexer->string_storage;
|
||||
lexer->string_len = 0;
|
||||
|
||||
while ((*cur >= 'a' && *cur <= 'z') || (*cur >= 'A' && *cur <= 'Z')) {
|
||||
if (stb__strchr(suffixes, *cur) == 0)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, start, cur);
|
||||
if (lexer->string_len+1 >= lexer->string_storage_len)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, start, cur);
|
||||
lexer->string[lexer->string_len++] = *cur++;
|
||||
}
|
||||
#else
|
||||
suffixes = suffixes; // attempt to suppress warnings
|
||||
#endif
|
||||
return stb__clex_token(lexer, tokenid, start, cur-1);
|
||||
}
|
||||
|
||||
#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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
#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] == '-';
|
||||
unsigned int exponent=0;
|
||||
double power=1;
|
||||
++p;
|
||||
if (*p == '-' || *p == '+')
|
||||
++p;
|
||||
while (*p >= '0' && *p <= '9')
|
||||
exponent = exponent*10 + (*p++ - '0');
|
||||
|
||||
#ifdef STB__clex_hex_floats
|
||||
if (base == 16)
|
||||
power = stb__clex_pow(2, exponent);
|
||||
else
|
||||
#endif
|
||||
power = stb__clex_pow(10, exponent);
|
||||
if (sign)
|
||||
value /= power;
|
||||
else
|
||||
value *= power;
|
||||
}
|
||||
*q = p;
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int stb__clex_parse_char(char *p, char **q)
|
||||
{
|
||||
if (*p == '\\') {
|
||||
*q = p+2; // tentatively guess we'll parse two characters
|
||||
switch(p[1]) {
|
||||
case '\\': return '\\';
|
||||
case '\'': return '\'';
|
||||
case '"': return '"';
|
||||
case 't': return '\t';
|
||||
case 'f': return '\f';
|
||||
case 'n': return '\n';
|
||||
case 'r': return '\r';
|
||||
case '0': return '\0'; // @TODO ocatal constants
|
||||
case 'x': case 'X': return -1; // @TODO hex constants
|
||||
case 'u': return -1; // @TODO unicode constants
|
||||
}
|
||||
}
|
||||
*q = p+1;
|
||||
return (unsigned char) *p;
|
||||
}
|
||||
|
||||
static int stb__clex_parse_string(stb_lexer *lexer, char *p, int type)
|
||||
{
|
||||
char *start = p;
|
||||
char delim = *p++; // grab the " or ' for later matching
|
||||
char *out = lexer->string_storage;
|
||||
char *outend = lexer->string_storage + lexer->string_storage_len;
|
||||
while (*p != delim) {
|
||||
int n;
|
||||
if (*p == '\\') {
|
||||
char *q;
|
||||
n = stb__clex_parse_char(p, &q);
|
||||
if (n < 0)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, start, q);
|
||||
p = q;
|
||||
} else {
|
||||
// @OPTIMIZE: could speed this up by looping-while-not-backslash
|
||||
n = (unsigned char) *p++;
|
||||
}
|
||||
if (out+1 > outend)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, start, p);
|
||||
// @TODO expand unicode escapes to UTF8
|
||||
*out++ = (char) n;
|
||||
}
|
||||
*out = 0;
|
||||
lexer->string = lexer->string_storage;
|
||||
lexer->string_len = (int) (out - lexer->string_storage);
|
||||
return stb__clex_token(lexer, type, start, p);
|
||||
}
|
||||
|
||||
int stb_c_lexer_get_token(stb_lexer *lexer)
|
||||
{
|
||||
char *p = lexer->parse_point;
|
||||
|
||||
// skip whitespace and comments
|
||||
for (;;) {
|
||||
#ifdef STB_C_LEX_ISWHITE
|
||||
while (p != lexer->stream_end) {
|
||||
int n;
|
||||
n = STB_C_LEX_ISWHITE(p);
|
||||
if (n == 0) break;
|
||||
if (lexer->eof && lexer->eof - lexer->parse_point < n)
|
||||
return stb__clex_token(tok, CLEX_parse_error, p,lexer->eof-1);
|
||||
p += n;
|
||||
}
|
||||
#else
|
||||
while (p != lexer->eof && stb__clex_iswhite(*p))
|
||||
++p;
|
||||
#endif
|
||||
|
||||
STB_C_LEX_CPP_COMMENTS(
|
||||
if (p != lexer->eof && p[0] == '/' && p[1] == '/') {
|
||||
while (p != lexer->eof && *p != '\r' && *p != '\n')
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
)
|
||||
|
||||
STB_C_LEX_C_COMMENTS(
|
||||
if (p != lexer->eof && p[0] == '/' && p[1] == '*') {
|
||||
char *start = p;
|
||||
p += 2;
|
||||
while (p != lexer->eof && (p[0] != '*' || p[1] != '/'))
|
||||
++p;
|
||||
if (p == lexer->eof)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, start, p-1);
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
)
|
||||
|
||||
#ifdef STB__clex_discard_preprocessor
|
||||
// @TODO this discards everything after a '#', regardless
|
||||
// of where in the line the # is, rather than requiring it
|
||||
// be at the start. (because this parser doesn't otherwise
|
||||
// check for line breaks!)
|
||||
if (p != lexer->eof && p[0] == '#') {
|
||||
while (p != lexer->eof && *p != '\r' && *p != '\n')
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == lexer->eof)
|
||||
return stb__clex_eof(lexer);
|
||||
|
||||
switch (*p) {
|
||||
default:
|
||||
if ( (*p >= 'a' && *p <= 'z')
|
||||
|| (*p >= 'A' && *p <= 'Z')
|
||||
|| *p == '_' || (unsigned char) *p >= 128 // >= 128 is UTF8 char
|
||||
STB_C_LEX_DOLLAR_IDENTIFIER( || *p == '$' ) )
|
||||
{
|
||||
int n = 0;
|
||||
lexer->string = lexer->string_storage;
|
||||
lexer->string_len = n;
|
||||
do {
|
||||
if (n+1 >= lexer->string_storage_len)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, p, p+n);
|
||||
lexer->string[n] = p[n];
|
||||
++n;
|
||||
} while (
|
||||
(p[n] >= 'a' && p[n] <= 'z')
|
||||
|| (p[n] >= 'A' && p[n] <= 'Z')
|
||||
|| (p[n] >= '0' && p[n] <= '9') // allow digits in middle of identifier
|
||||
|| p[n] == '_' || (unsigned char) p[n] >= 128
|
||||
STB_C_LEX_DOLLAR_IDENTIFIER( || p[n] == '$' )
|
||||
);
|
||||
lexer->string[n] = 0;
|
||||
return stb__clex_token(lexer, CLEX_id, p, p+n-1);
|
||||
}
|
||||
|
||||
// check for EOF
|
||||
STB_C_LEX_0_IS_EOF(
|
||||
if (*p == 0)
|
||||
return stb__clex_eof(lexer);
|
||||
)
|
||||
|
||||
single_char:
|
||||
// not an identifier, return the character as itself
|
||||
return stb__clex_token(lexer, *p, p, p);
|
||||
|
||||
case '+':
|
||||
if (p+1 != lexer->eof) {
|
||||
STB_C_LEX_C_INCREMENTS(if (p[1] == '+') return stb__clex_token(lexer, CLEX_plusplus, p,p+1);)
|
||||
STB_C_LEX_C_ARITHEQ( if (p[1] == '=') return stb__clex_token(lexer, CLEX_pluseq , p,p+1);)
|
||||
}
|
||||
goto single_char;
|
||||
case '-':
|
||||
if (p+1 != lexer->eof) {
|
||||
STB_C_LEX_C_INCREMENTS(if (p[1] == '-') return stb__clex_token(lexer, CLEX_minusminus, p,p+1);)
|
||||
STB_C_LEX_C_ARITHEQ( if (p[1] == '=') return stb__clex_token(lexer, CLEX_minuseq , p,p+1);)
|
||||
STB_C_LEX_C_ARROW( if (p[1] == '>') return stb__clex_token(lexer, CLEX_arrow , p,p+1);)
|
||||
}
|
||||
goto single_char;
|
||||
case '&':
|
||||
if (p+1 != lexer->eof) {
|
||||
STB_C_LEX_C_LOGICAL( if (p[1] == '&') return stb__clex_token(lexer, CLEX_andand, p,p+1);)
|
||||
STB_C_LEX_C_BITWISEEQ(if (p[1] == '=') return stb__clex_token(lexer, CLEX_andeq , p,p+1);)
|
||||
}
|
||||
goto single_char;
|
||||
case '|':
|
||||
if (p+1 != lexer->eof) {
|
||||
STB_C_LEX_C_LOGICAL( if (p[1] == '|') return stb__clex_token(lexer, CLEX_oror, p,p+1);)
|
||||
STB_C_LEX_C_BITWISEEQ(if (p[1] == '=') return stb__clex_token(lexer, CLEX_oreq, p,p+1);)
|
||||
}
|
||||
goto single_char;
|
||||
case '=':
|
||||
if (p+1 != lexer->eof) {
|
||||
STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_eq, p,p+1);)
|
||||
STB_C_LEX_EQUAL_ARROW( if (p[1] == '>') return stb__clex_token(lexer, CLEX_eqarrow, p,p+1);)
|
||||
}
|
||||
goto single_char;
|
||||
case '!':
|
||||
STB_C_LEX_C_COMPARISONS(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_noteq, p,p+1);)
|
||||
goto single_char;
|
||||
case '^':
|
||||
STB_C_LEX_C_BITWISEEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_xoreq, p,p+1));
|
||||
goto single_char;
|
||||
case '%':
|
||||
STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_modeq, p,p+1));
|
||||
goto single_char;
|
||||
case '*':
|
||||
STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_muleq, p,p+1));
|
||||
goto single_char;
|
||||
case '/':
|
||||
STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_diveq, p,p+1));
|
||||
goto single_char;
|
||||
case '<':
|
||||
if (p+1 != lexer->eof) {
|
||||
STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_lesseq, p,p+1);)
|
||||
STB_C_LEX_C_SHIFTS( if (p[1] == '<') {
|
||||
STB_C_LEX_C_ARITHEQ(if (p+2 != lexer->eof && p[2] == '=')
|
||||
return stb__clex_token(lexer, CLEX_shleq, p,p+2);)
|
||||
return stb__clex_token(lexer, CLEX_shl, p,p+1);
|
||||
}
|
||||
)
|
||||
}
|
||||
goto single_char;
|
||||
case '>':
|
||||
if (p+1 != lexer->eof) {
|
||||
STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_greatereq, p,p+1);)
|
||||
STB_C_LEX_C_SHIFTS( if (p[1] == '>') {
|
||||
STB_C_LEX_C_ARITHEQ(if (p+2 != lexer->eof && p[2] == '=')
|
||||
return stb__clex_token(lexer, CLEX_shreq, p,p+2);)
|
||||
return stb__clex_token(lexer, CLEX_shr, p,p+1);
|
||||
}
|
||||
)
|
||||
}
|
||||
goto single_char;
|
||||
|
||||
case '"':
|
||||
STB_C_LEX_C_DQ_STRINGS(return stb__clex_parse_string(lexer, p, CLEX_dqstring);)
|
||||
goto single_char;
|
||||
case '\'':
|
||||
STB_C_LEX_C_SQ_STRINGS(return stb__clex_parse_string(lexer, p, CLEX_sqstring);)
|
||||
STB_C_LEX_C_CHARS(
|
||||
{
|
||||
char *start = p;
|
||||
lexer->int_number = stb__clex_parse_char(p+1, &p);
|
||||
if (lexer->int_number < 0)
|
||||
return stb__clex_token(lexer, CLEX_parse_error, start,start);
|
||||
if (p == lexer->eof || *p != '\'')
|
||||
return stb__clex_token(lexer, CLEX_parse_error, start,p);
|
||||
return stb__clex_token(lexer, CLEX_charlit, start, p+1);
|
||||
})
|
||||
goto single_char;
|
||||
|
||||
case '0':
|
||||
#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;
|
||||
|
||||
#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;
|
||||
}
|
||||
#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 // 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
|
||||
|
||||
/* FALL THROUGH */
|
||||
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
|
||||
#ifdef STB__clex_decimal_floats
|
||||
{
|
||||
char *q = p;
|
||||
while (q != lexer->eof && (*q >= '0' && *q <= '9'))
|
||||
++q;
|
||||
if (q != lexer->eof) {
|
||||
if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'e' || *q == 'E')) {
|
||||
#ifdef STB__CLEX_use_stdlib
|
||||
lexer->real_number = strtod((char *) p, (char**) &q);
|
||||
#else
|
||||
lexer->real_number = stb__clex_parse_float(p, &q);
|
||||
#endif
|
||||
|
||||
return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // STB__clex_decimal_floats
|
||||
|
||||
#ifdef STB__clex_octal_ints
|
||||
if (p[0] == '0') {
|
||||
char *q = p;
|
||||
#ifdef STB__CLEX_use_stdlib
|
||||
lexer->int_number = strtol((char *) p, (char **) &q, 8);
|
||||
#else
|
||||
stb__clex_int n=0;
|
||||
while (q != lexer->eof) {
|
||||
if (*q >= '0' && *q <= '7')
|
||||
n = n*8 + (*q - '0');
|
||||
else
|
||||
break;
|
||||
++q;
|
||||
}
|
||||
if (q != lexer->eof && (*q == '8' || *q=='9'))
|
||||
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);
|
||||
}
|
||||
#endif // STB__clex_octal_ints
|
||||
|
||||
#ifdef STB__clex_decimal_ints
|
||||
{
|
||||
char *q = p;
|
||||
#ifdef STB__CLEX_use_stdlib
|
||||
lexer->int_number = strtol((char *) p, (char **) &q, 10);
|
||||
#else
|
||||
stb__clex_int n=0;
|
||||
while (q != lexer->eof) {
|
||||
if (*q >= '0' && *q <= '9')
|
||||
n = n*10 + (*q - '0');
|
||||
else
|
||||
break;
|
||||
++q;
|
||||
}
|
||||
lexer->int_number = n;
|
||||
#endif
|
||||
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
|
||||
}
|
||||
#endif // STB__clex_decimal_ints
|
||||
goto single_char;
|
||||
}
|
||||
}
|
||||
#endif // STB_C_LEXER_IMPLEMENTATION
|
||||
|
||||
#ifdef STB_C_LEXER_SELF_TEST
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void print_token(stb_lexer *lexer)
|
||||
{
|
||||
switch (lexer->token) {
|
||||
case CLEX_id : printf("_%s", lexer->string); break;
|
||||
case CLEX_eq : printf("=="); break;
|
||||
case CLEX_noteq : printf("!="); break;
|
||||
case CLEX_lesseq : printf("<="); break;
|
||||
case CLEX_greatereq : printf(">="); break;
|
||||
case CLEX_andand : printf("&&"); break;
|
||||
case CLEX_oror : printf("||"); break;
|
||||
case CLEX_shl : printf("<<"); break;
|
||||
case CLEX_shr : printf(">>"); break;
|
||||
case CLEX_plusplus : printf("++"); break;
|
||||
case CLEX_minusminus: printf("--"); break;
|
||||
case CLEX_arrow : printf("->"); break;
|
||||
case CLEX_andeq : printf("&="); break;
|
||||
case CLEX_oreq : printf("|="); break;
|
||||
case CLEX_xoreq : printf("^="); break;
|
||||
case CLEX_pluseq : printf("+="); break;
|
||||
case CLEX_minuseq : printf("-="); break;
|
||||
case CLEX_muleq : printf("*="); break;
|
||||
case CLEX_diveq : printf("/="); break;
|
||||
case CLEX_modeq : printf("%%="); break;
|
||||
case CLEX_shleq : printf("<<="); break;
|
||||
case CLEX_shreq : printf(">>="); break;
|
||||
case CLEX_eqarrow : printf("=>"); break;
|
||||
case CLEX_dqstring : printf("\"%s\"", lexer->string); break;
|
||||
case CLEX_sqstring : printf("'\"%s\"'", lexer->string); break;
|
||||
case CLEX_charlit : printf("'%s'", lexer->string); break;
|
||||
#if defined(STB__clex_int_as_double) && !defined(STB__CLEX_use_stdlib)
|
||||
case CLEX_intlit : printf("#%g", lexer->real_number); break;
|
||||
#else
|
||||
case CLEX_intlit : printf("#%ld", lexer->int_number); break;
|
||||
#endif
|
||||
case CLEX_floatlit : printf("%g", lexer->real_number); break;
|
||||
default:
|
||||
if (lexer->token >= 0 && lexer->token < 256)
|
||||
printf("%c", (int) lexer->token);
|
||||
else {
|
||||
printf("<<<UNKNOWN TOKEN %ld >>>\n", lexer->token);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Force a test
|
||||
of parsing
|
||||
multiline comments */
|
||||
|
||||
/*/ comment /*/
|
||||
/**/ extern /**/
|
||||
|
||||
void dummy(void)
|
||||
{
|
||||
double some_floats[] = {
|
||||
1.0501, -10.4e12, 5E+10,
|
||||
#if 0 // not supported in C++ or C-pre-99, so don't try to compile it, but let our parser test it
|
||||
0x1.0p+24, 0xff.FP-8, 0x1p-23,
|
||||
#endif
|
||||
4.
|
||||
};
|
||||
(void) sizeof(some_floats);
|
||||
(void) some_floats[1];
|
||||
|
||||
printf("test %d",1); // https://github.com/nothings/stb/issues/13
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *f = fopen("stb_c_lexer.h","rb");
|
||||
char *text = (char *) malloc(1 << 20);
|
||||
int len = f ? (int) fread(text, 1, 1<<20, f) : -1;
|
||||
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(0x10000), 0x10000);
|
||||
while (stb_c_lexer_get_token(&lex)) {
|
||||
if (lex.token == CLEX_parse_error) {
|
||||
printf("\n<<<PARSE ERROR>>>\n");
|
||||
break;
|
||||
}
|
||||
print_token(&lex);
|
||||
printf(" ");
|
||||
}
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
1049
raytracer/nvpro_core/third_party/stb/stb_connected_components.h
vendored
Normal file
1049
raytracer/nvpro_core/third_party/stb/stb_connected_components.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
433
raytracer/nvpro_core/third_party/stb/stb_divide.h
vendored
Normal file
433
raytracer/nvpro_core/third_party/stb/stb_divide.h
vendored
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
// stb_divide.h - v0.94 - public domain - Sean Barrett, Feb 2010
|
||||
// Three kinds of divide/modulus of signed integers.
|
||||
//
|
||||
// HISTORY
|
||||
//
|
||||
// v0.94 Fix integer overflow issues
|
||||
// v0.93 2020-02-02 Write useful exit() value from main()
|
||||
// v0.92 2019-02-25 Fix warning
|
||||
// v0.91 2010-02-27 Fix euclidean division by INT_MIN for non-truncating C
|
||||
// Check result with 64-bit math to catch such cases
|
||||
// v0.90 2010-02-24 First public release
|
||||
//
|
||||
// USAGE
|
||||
//
|
||||
// In *ONE* source file, put:
|
||||
//
|
||||
// #define STB_DIVIDE_IMPLEMENTATION
|
||||
// // #define C_INTEGER_DIVISION_TRUNCATES // see Note 1
|
||||
// // #define C_INTEGER_DIVISION_FLOORS // see Note 2
|
||||
// #include "stb_divide.h"
|
||||
//
|
||||
// Other source files should just include stb_divide.h
|
||||
//
|
||||
// Note 1: On platforms/compilers that you know signed C division
|
||||
// truncates, you can #define C_INTEGER_DIVISION_TRUNCATES.
|
||||
//
|
||||
// Note 2: On platforms/compilers that you know signed C division
|
||||
// floors (rounds to negative infinity), you can #define
|
||||
// C_INTEGER_DIVISION_FLOORS.
|
||||
//
|
||||
// You can #define STB_DIVIDE_TEST in which case the implementation
|
||||
// will generate a main() and compiling the result will create a
|
||||
// program that tests the implementation. Run it with no arguments
|
||||
// and any output indicates an error; run it with any argument and
|
||||
// it will also print the test results. Define STB_DIVIDE_TEST_64
|
||||
// to a 64-bit integer type to avoid overflows in the result-checking
|
||||
// which give false negatives.
|
||||
//
|
||||
// ABOUT
|
||||
//
|
||||
// This file provides three different consistent divide/mod pairs
|
||||
// implemented on top of arbitrary C/C++ division, including correct
|
||||
// handling of overflow of intermediate calculations:
|
||||
//
|
||||
// trunc: a/b truncates to 0, a%b has same sign as a
|
||||
// floor: a/b truncates to -inf, a%b has same sign as b
|
||||
// eucl: a/b truncates to sign(b)*inf, a%b is non-negative
|
||||
//
|
||||
// Not necessarily optimal; I tried to keep it generally efficient,
|
||||
// but there may be better ways.
|
||||
//
|
||||
// Briefly, for those who are not familiar with the problem, we note
|
||||
// the reason these divides exist and are interesting:
|
||||
//
|
||||
// 'trunc' is easy to implement in hardware (strip the signs,
|
||||
// compute, reapply the signs), thus is commonly defined
|
||||
// by many languages (including C99)
|
||||
//
|
||||
// 'floor' is simple to define and better behaved than trunc;
|
||||
// for example it divides integers into fixed-size buckets
|
||||
// without an extra-wide bucket at 0, and for a fixed
|
||||
// divisor N there are only |N| possible moduli.
|
||||
//
|
||||
// 'eucl' guarantees fixed-sized buckets *and* a non-negative
|
||||
// modulus and defines division to be whatever is needed
|
||||
// to achieve that result.
|
||||
//
|
||||
// See "The Euclidean definition of the functions div and mod"
|
||||
// by Raymond Boute (1992), or "Division and Modulus for Computer
|
||||
// Scientists" by Daan Leijen (2001)
|
||||
//
|
||||
// We assume of the built-in C division:
|
||||
// (a) modulus is the remainder for the corresponding division
|
||||
// (b) a/b truncates if a and b are the same sign
|
||||
//
|
||||
// Property (a) requires (a/b)*b + (a%b)==a, and is required by C.
|
||||
// Property (b) seems to be true of all hardware but is *not* satisfied
|
||||
// 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
|
||||
#define INCLUDE_STB_DIVIDE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int stb_div_trunc(int value_to_be_divided, int value_to_divide_by);
|
||||
extern int stb_div_floor(int value_to_be_divided, int value_to_divide_by);
|
||||
extern int stb_div_eucl (int value_to_be_divided, int value_to_divide_by);
|
||||
extern int stb_mod_trunc(int value_to_be_divided, int value_to_divide_by);
|
||||
extern int stb_mod_floor(int value_to_be_divided, int value_to_divide_by);
|
||||
extern int stb_mod_eucl (int value_to_be_divided, int value_to_divide_by);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STB_DIVIDE_IMPLEMENTATION
|
||||
|
||||
#if defined(__STDC_VERSION) && __STDC_VERSION__ >= 19901
|
||||
#ifndef C_INTEGER_DIVISION_TRUNCATES
|
||||
#define C_INTEGER_DIVISION_TRUNCATES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef INT_MIN
|
||||
#include <limits.h> // if you have no limits.h, #define INT_MIN yourself
|
||||
#endif
|
||||
|
||||
// the following macros are designed to allow testing
|
||||
// other platforms by simulating them
|
||||
#ifndef STB_DIVIDE_TEST_FLOOR
|
||||
#define stb__div(a,b) ((a)/(b))
|
||||
#define stb__mod(a,b) ((a)%(b))
|
||||
#else
|
||||
// implement floor-style divide on trunc platform
|
||||
#ifndef C_INTEGER_DIVISION_TRUNCATES
|
||||
#error "floor test requires truncating division"
|
||||
#endif
|
||||
#undef C_INTEGER_DIVISION_TRUNCATES
|
||||
int stb__div(int v1, int v2)
|
||||
{
|
||||
int q = v1/v2, r = v1%v2;
|
||||
if ((r > 0 && v2 < 0) || (r < 0 && v2 > 0))
|
||||
return q-1;
|
||||
else
|
||||
return q;
|
||||
}
|
||||
|
||||
int stb__mod(int v1, int v2)
|
||||
{
|
||||
int r = v1%v2;
|
||||
if ((r > 0 && v2 < 0) || (r < 0 && v2 > 0))
|
||||
return r+v2;
|
||||
else
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
int stb_div_trunc(int v1, int v2)
|
||||
{
|
||||
#ifdef C_INTEGER_DIVISION_TRUNCATES
|
||||
return v1/v2;
|
||||
#else
|
||||
if (v1 >= 0 && v2 <= 0)
|
||||
return -stb__div(-v1,v2); // both negative to avoid overflow
|
||||
if (v1 <= 0 && v2 >= 0)
|
||||
if (v1 != INT_MIN)
|
||||
return -stb__div(v1,-v2); // both negative to avoid overflow
|
||||
else
|
||||
return -stb__div(v1+v2,-v2)-1; // push v1 away from wrap point
|
||||
else
|
||||
return v1/v2; // same sign, so expect truncation
|
||||
#endif
|
||||
}
|
||||
|
||||
int stb_div_floor(int v1, int v2)
|
||||
{
|
||||
#ifdef C_INTEGER_DIVISION_FLOORS
|
||||
return v1/v2;
|
||||
#else
|
||||
if (v1 >= 0 && v2 < 0) {
|
||||
if (v2 + 1 >= INT_MIN + v1) // check if increasing v1's magnitude overflows
|
||||
return -stb__div((v2+1)-v1,v2); // nope, so just compute it
|
||||
else
|
||||
return -stb__div(-v1,v2) + ((-v1)%v2 ? -1 : 0);
|
||||
}
|
||||
if (v1 < 0 && v2 >= 0) {
|
||||
if (v1 != INT_MIN) {
|
||||
if (v1 + 1 >= INT_MIN + v2) // check if increasing v1's magnitude overflows
|
||||
return -stb__div((v1+1)-v2,-v2); // nope, so just compute it
|
||||
else
|
||||
return -stb__div(-v1,v2) + (stb__mod(v1,-v2) ? -1 : 0);
|
||||
} else // it must be possible to compute -(v1+v2) without overflowing
|
||||
return -stb__div(-(v1+v2),v2) + (stb__mod(-(v1+v2),v2) ? -2 : -1);
|
||||
} else
|
||||
return v1/v2; // same sign, so expect truncation
|
||||
#endif
|
||||
}
|
||||
|
||||
int stb_div_eucl(int v1, int v2)
|
||||
{
|
||||
int q,r;
|
||||
#ifdef C_INTEGER_DIVISION_TRUNCATES
|
||||
q = v1/v2;
|
||||
r = v1%v2;
|
||||
#else
|
||||
// handle every quadrant separately, since we can't rely on q and r flor
|
||||
if (v1 >= 0)
|
||||
if (v2 >= 0)
|
||||
return stb__div(v1,v2);
|
||||
else if (v2 != INT_MIN)
|
||||
q = -stb__div(v1,-v2), r = stb__mod(v1,-v2);
|
||||
else
|
||||
q = 0, r = v1;
|
||||
else if (v1 != INT_MIN)
|
||||
if (v2 >= 0)
|
||||
q = -stb__div(-v1,v2), r = -stb__mod(-v1,v2);
|
||||
else if (v2 != INT_MIN)
|
||||
q = stb__div(-v1,-v2), r = -stb__mod(-v1,-v2);
|
||||
else // if v2 is INT_MIN, then we can't use -v2, but we can't divide by v2
|
||||
q = 1, r = v1-q*v2;
|
||||
else // if v1 is INT_MIN, we have to move away from overflow place
|
||||
if (v2 >= 0)
|
||||
q = -stb__div(-(v1+v2),v2)-1, r = -stb__mod(-(v1+v2),v2);
|
||||
else if (v2 != INT_MIN)
|
||||
q = stb__div(-(v1-v2),-v2)+1, r = -stb__mod(-(v1-v2),-v2);
|
||||
else // for INT_MIN / INT_MIN, we need to be extra-careful to avoid overflow
|
||||
q = 1, r = 0;
|
||||
#endif
|
||||
if (r >= 0)
|
||||
return q;
|
||||
else
|
||||
return q + (v2 > 0 ? -1 : 1);
|
||||
}
|
||||
|
||||
int stb_mod_trunc(int v1, int v2)
|
||||
{
|
||||
#ifdef C_INTEGER_DIVISION_TRUNCATES
|
||||
return v1%v2;
|
||||
#else
|
||||
if (v1 >= 0) { // modulus result should always be positive
|
||||
int r = stb__mod(v1,v2);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
else
|
||||
return r - (v2 < 0 ? v2 : -v2);
|
||||
} else { // modulus result should always be negative
|
||||
int r = stb__mod(v1,v2);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
else
|
||||
return r + (v2 < 0 ? v2 : -v2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int stb_mod_floor(int v1, int v2)
|
||||
{
|
||||
#ifdef C_INTEGER_DIVISION_FLOORS
|
||||
return v1%v2;
|
||||
#else
|
||||
if (v2 >= 0) { // result should always be positive
|
||||
int r = stb__mod(v1,v2);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
else
|
||||
return r + v2;
|
||||
} else { // result should always be negative
|
||||
int r = stb__mod(v1,v2);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
else
|
||||
return r + v2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int stb_mod_eucl(int v1, int v2)
|
||||
{
|
||||
int r = stb__mod(v1,v2);
|
||||
|
||||
if (r >= 0)
|
||||
return r;
|
||||
else
|
||||
return r - (v2 < 0 ? v2 : -v2); // negative abs() [to avoid overflow]
|
||||
}
|
||||
|
||||
#ifdef STB_DIVIDE_TEST
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
int show=0;
|
||||
int err=0;
|
||||
|
||||
void stbdiv_check(int q, int r, int a, int b, char *type, int dir)
|
||||
{
|
||||
if ((dir > 0 && r < 0) || (dir < 0 && r > 0)) {
|
||||
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d in wrong direction\n", type,a,b,r);
|
||||
err++;
|
||||
} else
|
||||
if (b != INT_MIN) // can't compute abs(), but if b==INT_MIN all remainders are valid
|
||||
if (r <= -abs(b) || r >= abs(b)) {
|
||||
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d out of range\n", type,a,b,r);
|
||||
err++;
|
||||
}
|
||||
#ifdef STB_DIVIDE_TEST_64
|
||||
{
|
||||
STB_DIVIDE_TEST_64 q64 = q, r64=r, a64=a, b64=b;
|
||||
if (q64*b64+r64 != a64) {
|
||||
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d doesn't match quotient %d\n", type,a,b,r,q);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (q*b+r != a) {
|
||||
fprintf(stderr, "FAILED: %s(%d,%d) remainder %d doesn't match quotient %d\n", type,a,b,r,q);
|
||||
err++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void test(int a, int b)
|
||||
{
|
||||
int q,r;
|
||||
if (show) printf("(%+11d,%+d) | ", a,b);
|
||||
q = stb_div_trunc(a,b), r = stb_mod_trunc(a,b);
|
||||
if (show) printf("(%+11d,%+2d) ", q,r); stbdiv_check(q,r,a,b, "trunc",a);
|
||||
q = stb_div_floor(a,b), r = stb_mod_floor(a,b);
|
||||
if (show) printf("(%+11d,%+2d) ", q,r); stbdiv_check(q,r,a,b, "floor",b);
|
||||
q = stb_div_eucl (a,b), r = stb_mod_eucl (a,b);
|
||||
if (show) printf("(%+11d,%+2d)\n", q,r); stbdiv_check(q,r,a,b, "euclidean",1);
|
||||
}
|
||||
|
||||
void testh(int a, int b)
|
||||
{
|
||||
int q,r;
|
||||
if (show) printf("(%08x,%08x) |\n", a,b);
|
||||
q = stb_div_trunc(a,b), r = stb_mod_trunc(a,b); stbdiv_check(q,r,a,b, "trunc",a);
|
||||
if (show) printf(" (%08x,%08x)", q,r);
|
||||
q = stb_div_floor(a,b), r = stb_mod_floor(a,b); stbdiv_check(q,r,a,b, "floor",b);
|
||||
if (show) printf(" (%08x,%08x)", q,r);
|
||||
q = stb_div_eucl (a,b), r = stb_mod_eucl (a,b); stbdiv_check(q,r,a,b, "euclidean",1);
|
||||
if (show) printf(" (%08x,%08x)\n ", q,r);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc > 1) show=1;
|
||||
|
||||
test(8,3);
|
||||
test(8,-3);
|
||||
test(-8,3);
|
||||
test(-8,-3);
|
||||
test(1,2);
|
||||
test(1,-2);
|
||||
test(-1,2);
|
||||
test(-1,-2);
|
||||
test(8,4);
|
||||
test(8,-4);
|
||||
test(-8,4);
|
||||
test(-8,-4);
|
||||
|
||||
test(INT_MAX,1);
|
||||
test(INT_MIN,1);
|
||||
test(INT_MIN+1,1);
|
||||
test(INT_MAX,-1);
|
||||
//test(INT_MIN,-1); // this traps in MSVC, so we leave it untested
|
||||
test(INT_MIN+1,-1);
|
||||
test(INT_MIN,-2);
|
||||
test(INT_MIN+1,2);
|
||||
test(INT_MIN+1,-2);
|
||||
test(INT_MAX,2);
|
||||
test(INT_MAX,-2);
|
||||
test(INT_MIN+1,2);
|
||||
test(INT_MIN+1,-2);
|
||||
test(INT_MIN,2);
|
||||
test(INT_MIN,-2);
|
||||
test(INT_MIN,7);
|
||||
test(INT_MIN,-7);
|
||||
test(INT_MIN+1,4);
|
||||
test(INT_MIN+1,-4);
|
||||
|
||||
testh(-7, INT_MIN);
|
||||
testh(-1, INT_MIN);
|
||||
testh(1, INT_MIN);
|
||||
testh(7, INT_MIN);
|
||||
|
||||
testh(INT_MAX-1, INT_MIN);
|
||||
testh(INT_MAX, INT_MIN);
|
||||
testh(INT_MIN, INT_MIN);
|
||||
testh(INT_MIN+1, INT_MIN);
|
||||
|
||||
testh(INT_MAX-1, INT_MAX);
|
||||
testh(INT_MAX , INT_MAX);
|
||||
testh(INT_MIN , INT_MAX);
|
||||
testh(INT_MIN+1, INT_MAX);
|
||||
|
||||
return err > 0 ? 1 : 0;
|
||||
}
|
||||
#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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
1895
raytracer/nvpro_core/third_party/stb/stb_ds.h
vendored
Normal file
1895
raytracer/nvpro_core/third_party/stb/stb_ds.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
719
raytracer/nvpro_core/third_party/stb/stb_dxt.h
vendored
Normal file
719
raytracer/nvpro_core/third_party/stb/stb_dxt.h
vendored
Normal file
|
|
@ -0,0 +1,719 @@
|
|||
// stb_dxt.h - v1.12 - 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
|
||||
//
|
||||
// USAGE:
|
||||
// call stb_compress_dxt_block() for every block (you must pad)
|
||||
// source should be a 4x4 block of RGBA data in row-major order;
|
||||
// Alpha channel is not stored if you specify alpha=0 (but you
|
||||
// must supply some constant alpha in the alpha channel).
|
||||
// You can turn on dithering and "high quality" using mode.
|
||||
//
|
||||
// version history:
|
||||
// v1.12 - (ryg) fix bug in single-color table generator
|
||||
// v1.11 - (ryg) avoid racy global init, better single-color tables, remove dither
|
||||
// v1.10 - (i.c) various small quality improvements
|
||||
// v1.09 - (stb) update documentation re: surprising alpha channel requirement
|
||||
// v1.08 - (stb) fix bug in dxt-with-alpha block
|
||||
// v1.07 - (stb) bc4; allow not using libc; add STB_DXT_STATIC
|
||||
// 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.
|
||||
// v1.03 - (stb) endianness support
|
||||
// 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
|
||||
//
|
||||
// contributors:
|
||||
// Rich Geldreich (more accurate index selection)
|
||||
// Kevin Schmidt (#defines for "freestanding" compilation)
|
||||
// github:ppiastucki (BC4 support)
|
||||
// Ignacio Castano - improve DXT endpoint quantization
|
||||
// Alan Hickman - static table initialization
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
#ifndef STB_INCLUDE_STB_DXT_H
|
||||
#define STB_INCLUDE_STB_DXT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef STB_DXT_STATIC
|
||||
#define STBDDEF static
|
||||
#else
|
||||
#define STBDDEF extern
|
||||
#endif
|
||||
|
||||
// compression mode (bitflags)
|
||||
#define STB_DXT_NORMAL 0
|
||||
#define STB_DXT_DITHER 1 // use dithering. was always dubious, now deprecated. does nothing!
|
||||
#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower.
|
||||
|
||||
STBDDEF void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode);
|
||||
STBDDEF void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src_r_one_byte_per_pixel);
|
||||
STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel);
|
||||
|
||||
#define STB_COMPRESS_DXT_BLOCK
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // STB_INCLUDE_STB_DXT_H
|
||||
|
||||
#ifdef STB_DXT_IMPLEMENTATION
|
||||
|
||||
// configuration options for DXT encoder. set them in the project/makefile or just define
|
||||
// them at the top.
|
||||
|
||||
// STB_DXT_USE_ROUNDING_BIAS
|
||||
// use a rounding bias during color interpolation. this is closer to what "ideal"
|
||||
// interpolation would do but doesn't match the S3TC/DX10 spec. old versions (pre-1.03)
|
||||
// implicitly had this turned on.
|
||||
//
|
||||
// in case you're targeting a specific type of hardware (e.g. console programmers):
|
||||
// NVidia and Intel GPUs (as of 2010) as well as DX9 ref use DXT decoders that are closer
|
||||
// to STB_DXT_USE_ROUNDING_BIAS. AMD/ATI, S3 and DX10 ref are closer to rounding with no bias.
|
||||
// you also see "(a*5 + b*3) / 8" on some old GPU designs.
|
||||
// #define STB_DXT_USE_ROUNDING_BIAS
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(STBD_FABS)
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#ifndef STBD_FABS
|
||||
#define STBD_FABS(x) fabs(x)
|
||||
#endif
|
||||
|
||||
static const unsigned char stb__OMatch5[256][2] = {
|
||||
{ 0, 0 }, { 0, 0 }, { 0, 1 }, { 0, 1 }, { 1, 0 }, { 1, 0 }, { 1, 0 }, { 1, 1 },
|
||||
{ 1, 1 }, { 1, 1 }, { 1, 2 }, { 0, 4 }, { 2, 1 }, { 2, 1 }, { 2, 1 }, { 2, 2 },
|
||||
{ 2, 2 }, { 2, 2 }, { 2, 3 }, { 1, 5 }, { 3, 2 }, { 3, 2 }, { 4, 0 }, { 3, 3 },
|
||||
{ 3, 3 }, { 3, 3 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, { 3, 5 }, { 4, 3 }, { 4, 3 },
|
||||
{ 5, 2 }, { 4, 4 }, { 4, 4 }, { 4, 5 }, { 4, 5 }, { 5, 4 }, { 5, 4 }, { 5, 4 },
|
||||
{ 6, 3 }, { 5, 5 }, { 5, 5 }, { 5, 6 }, { 4, 8 }, { 6, 5 }, { 6, 5 }, { 6, 5 },
|
||||
{ 6, 6 }, { 6, 6 }, { 6, 6 }, { 6, 7 }, { 5, 9 }, { 7, 6 }, { 7, 6 }, { 8, 4 },
|
||||
{ 7, 7 }, { 7, 7 }, { 7, 7 }, { 7, 8 }, { 7, 8 }, { 7, 8 }, { 7, 9 }, { 8, 7 },
|
||||
{ 8, 7 }, { 9, 6 }, { 8, 8 }, { 8, 8 }, { 8, 9 }, { 8, 9 }, { 9, 8 }, { 9, 8 },
|
||||
{ 9, 8 }, { 10, 7 }, { 9, 9 }, { 9, 9 }, { 9, 10 }, { 8, 12 }, { 10, 9 }, { 10, 9 },
|
||||
{ 10, 9 }, { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 11 }, { 9, 13 }, { 11, 10 }, { 11, 10 },
|
||||
{ 12, 8 }, { 11, 11 }, { 11, 11 }, { 11, 11 }, { 11, 12 }, { 11, 12 }, { 11, 12 }, { 11, 13 },
|
||||
{ 12, 11 }, { 12, 11 }, { 13, 10 }, { 12, 12 }, { 12, 12 }, { 12, 13 }, { 12, 13 }, { 13, 12 },
|
||||
{ 13, 12 }, { 13, 12 }, { 14, 11 }, { 13, 13 }, { 13, 13 }, { 13, 14 }, { 12, 16 }, { 14, 13 },
|
||||
{ 14, 13 }, { 14, 13 }, { 14, 14 }, { 14, 14 }, { 14, 14 }, { 14, 15 }, { 13, 17 }, { 15, 14 },
|
||||
{ 15, 14 }, { 16, 12 }, { 15, 15 }, { 15, 15 }, { 15, 15 }, { 15, 16 }, { 15, 16 }, { 15, 16 },
|
||||
{ 15, 17 }, { 16, 15 }, { 16, 15 }, { 17, 14 }, { 16, 16 }, { 16, 16 }, { 16, 17 }, { 16, 17 },
|
||||
{ 17, 16 }, { 17, 16 }, { 17, 16 }, { 18, 15 }, { 17, 17 }, { 17, 17 }, { 17, 18 }, { 16, 20 },
|
||||
{ 18, 17 }, { 18, 17 }, { 18, 17 }, { 18, 18 }, { 18, 18 }, { 18, 18 }, { 18, 19 }, { 17, 21 },
|
||||
{ 19, 18 }, { 19, 18 }, { 20, 16 }, { 19, 19 }, { 19, 19 }, { 19, 19 }, { 19, 20 }, { 19, 20 },
|
||||
{ 19, 20 }, { 19, 21 }, { 20, 19 }, { 20, 19 }, { 21, 18 }, { 20, 20 }, { 20, 20 }, { 20, 21 },
|
||||
{ 20, 21 }, { 21, 20 }, { 21, 20 }, { 21, 20 }, { 22, 19 }, { 21, 21 }, { 21, 21 }, { 21, 22 },
|
||||
{ 20, 24 }, { 22, 21 }, { 22, 21 }, { 22, 21 }, { 22, 22 }, { 22, 22 }, { 22, 22 }, { 22, 23 },
|
||||
{ 21, 25 }, { 23, 22 }, { 23, 22 }, { 24, 20 }, { 23, 23 }, { 23, 23 }, { 23, 23 }, { 23, 24 },
|
||||
{ 23, 24 }, { 23, 24 }, { 23, 25 }, { 24, 23 }, { 24, 23 }, { 25, 22 }, { 24, 24 }, { 24, 24 },
|
||||
{ 24, 25 }, { 24, 25 }, { 25, 24 }, { 25, 24 }, { 25, 24 }, { 26, 23 }, { 25, 25 }, { 25, 25 },
|
||||
{ 25, 26 }, { 24, 28 }, { 26, 25 }, { 26, 25 }, { 26, 25 }, { 26, 26 }, { 26, 26 }, { 26, 26 },
|
||||
{ 26, 27 }, { 25, 29 }, { 27, 26 }, { 27, 26 }, { 28, 24 }, { 27, 27 }, { 27, 27 }, { 27, 27 },
|
||||
{ 27, 28 }, { 27, 28 }, { 27, 28 }, { 27, 29 }, { 28, 27 }, { 28, 27 }, { 29, 26 }, { 28, 28 },
|
||||
{ 28, 28 }, { 28, 29 }, { 28, 29 }, { 29, 28 }, { 29, 28 }, { 29, 28 }, { 30, 27 }, { 29, 29 },
|
||||
{ 29, 29 }, { 29, 30 }, { 29, 30 }, { 30, 29 }, { 30, 29 }, { 30, 29 }, { 30, 30 }, { 30, 30 },
|
||||
{ 30, 30 }, { 30, 31 }, { 30, 31 }, { 31, 30 }, { 31, 30 }, { 31, 30 }, { 31, 31 }, { 31, 31 },
|
||||
};
|
||||
static const unsigned char stb__OMatch6[256][2] = {
|
||||
{ 0, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 }, { 1, 1 }, { 1, 2 }, { 2, 1 }, { 2, 2 },
|
||||
{ 2, 2 }, { 2, 3 }, { 3, 2 }, { 3, 3 }, { 3, 3 }, { 3, 4 }, { 4, 3 }, { 4, 4 },
|
||||
{ 4, 4 }, { 4, 5 }, { 5, 4 }, { 5, 5 }, { 5, 5 }, { 5, 6 }, { 6, 5 }, { 6, 6 },
|
||||
{ 6, 6 }, { 6, 7 }, { 7, 6 }, { 7, 7 }, { 7, 7 }, { 7, 8 }, { 8, 7 }, { 8, 8 },
|
||||
{ 8, 8 }, { 8, 9 }, { 9, 8 }, { 9, 9 }, { 9, 9 }, { 9, 10 }, { 10, 9 }, { 10, 10 },
|
||||
{ 10, 10 }, { 10, 11 }, { 11, 10 }, { 8, 16 }, { 11, 11 }, { 11, 12 }, { 12, 11 }, { 9, 17 },
|
||||
{ 12, 12 }, { 12, 13 }, { 13, 12 }, { 11, 16 }, { 13, 13 }, { 13, 14 }, { 14, 13 }, { 12, 17 },
|
||||
{ 14, 14 }, { 14, 15 }, { 15, 14 }, { 14, 16 }, { 15, 15 }, { 15, 16 }, { 16, 14 }, { 16, 15 },
|
||||
{ 17, 14 }, { 16, 16 }, { 16, 17 }, { 17, 16 }, { 18, 15 }, { 17, 17 }, { 17, 18 }, { 18, 17 },
|
||||
{ 20, 14 }, { 18, 18 }, { 18, 19 }, { 19, 18 }, { 21, 15 }, { 19, 19 }, { 19, 20 }, { 20, 19 },
|
||||
{ 20, 20 }, { 20, 20 }, { 20, 21 }, { 21, 20 }, { 21, 21 }, { 21, 21 }, { 21, 22 }, { 22, 21 },
|
||||
{ 22, 22 }, { 22, 22 }, { 22, 23 }, { 23, 22 }, { 23, 23 }, { 23, 23 }, { 23, 24 }, { 24, 23 },
|
||||
{ 24, 24 }, { 24, 24 }, { 24, 25 }, { 25, 24 }, { 25, 25 }, { 25, 25 }, { 25, 26 }, { 26, 25 },
|
||||
{ 26, 26 }, { 26, 26 }, { 26, 27 }, { 27, 26 }, { 24, 32 }, { 27, 27 }, { 27, 28 }, { 28, 27 },
|
||||
{ 25, 33 }, { 28, 28 }, { 28, 29 }, { 29, 28 }, { 27, 32 }, { 29, 29 }, { 29, 30 }, { 30, 29 },
|
||||
{ 28, 33 }, { 30, 30 }, { 30, 31 }, { 31, 30 }, { 30, 32 }, { 31, 31 }, { 31, 32 }, { 32, 30 },
|
||||
{ 32, 31 }, { 33, 30 }, { 32, 32 }, { 32, 33 }, { 33, 32 }, { 34, 31 }, { 33, 33 }, { 33, 34 },
|
||||
{ 34, 33 }, { 36, 30 }, { 34, 34 }, { 34, 35 }, { 35, 34 }, { 37, 31 }, { 35, 35 }, { 35, 36 },
|
||||
{ 36, 35 }, { 36, 36 }, { 36, 36 }, { 36, 37 }, { 37, 36 }, { 37, 37 }, { 37, 37 }, { 37, 38 },
|
||||
{ 38, 37 }, { 38, 38 }, { 38, 38 }, { 38, 39 }, { 39, 38 }, { 39, 39 }, { 39, 39 }, { 39, 40 },
|
||||
{ 40, 39 }, { 40, 40 }, { 40, 40 }, { 40, 41 }, { 41, 40 }, { 41, 41 }, { 41, 41 }, { 41, 42 },
|
||||
{ 42, 41 }, { 42, 42 }, { 42, 42 }, { 42, 43 }, { 43, 42 }, { 40, 48 }, { 43, 43 }, { 43, 44 },
|
||||
{ 44, 43 }, { 41, 49 }, { 44, 44 }, { 44, 45 }, { 45, 44 }, { 43, 48 }, { 45, 45 }, { 45, 46 },
|
||||
{ 46, 45 }, { 44, 49 }, { 46, 46 }, { 46, 47 }, { 47, 46 }, { 46, 48 }, { 47, 47 }, { 47, 48 },
|
||||
{ 48, 46 }, { 48, 47 }, { 49, 46 }, { 48, 48 }, { 48, 49 }, { 49, 48 }, { 50, 47 }, { 49, 49 },
|
||||
{ 49, 50 }, { 50, 49 }, { 52, 46 }, { 50, 50 }, { 50, 51 }, { 51, 50 }, { 53, 47 }, { 51, 51 },
|
||||
{ 51, 52 }, { 52, 51 }, { 52, 52 }, { 52, 52 }, { 52, 53 }, { 53, 52 }, { 53, 53 }, { 53, 53 },
|
||||
{ 53, 54 }, { 54, 53 }, { 54, 54 }, { 54, 54 }, { 54, 55 }, { 55, 54 }, { 55, 55 }, { 55, 55 },
|
||||
{ 55, 56 }, { 56, 55 }, { 56, 56 }, { 56, 56 }, { 56, 57 }, { 57, 56 }, { 57, 57 }, { 57, 57 },
|
||||
{ 57, 58 }, { 58, 57 }, { 58, 58 }, { 58, 58 }, { 58, 59 }, { 59, 58 }, { 59, 59 }, { 59, 59 },
|
||||
{ 59, 60 }, { 60, 59 }, { 60, 60 }, { 60, 60 }, { 60, 61 }, { 61, 60 }, { 61, 61 }, { 61, 61 },
|
||||
{ 61, 62 }, { 62, 61 }, { 62, 62 }, { 62, 62 }, { 62, 63 }, { 63, 62 }, { 63, 63 }, { 63, 63 },
|
||||
};
|
||||
|
||||
static int stb__Mul8Bit(int a, int b)
|
||||
{
|
||||
int t = a*b + 128;
|
||||
return (t + (t >> 8)) >> 8;
|
||||
}
|
||||
|
||||
static void stb__From16Bit(unsigned char *out, unsigned short v)
|
||||
{
|
||||
int rv = (v & 0xf800) >> 11;
|
||||
int gv = (v & 0x07e0) >> 5;
|
||||
int bv = (v & 0x001f) >> 0;
|
||||
|
||||
// expand to 8 bits via bit replication
|
||||
out[0] = (rv * 33) >> 2;
|
||||
out[1] = (gv * 65) >> 4;
|
||||
out[2] = (bv * 33) >> 2;
|
||||
out[3] = 0;
|
||||
}
|
||||
|
||||
static unsigned short stb__As16Bit(int r, int g, int b)
|
||||
{
|
||||
return (unsigned short)((stb__Mul8Bit(r,31) << 11) + (stb__Mul8Bit(g,63) << 5) + stb__Mul8Bit(b,31));
|
||||
}
|
||||
|
||||
// linear interpolation at 1/3 point between a and b, using desired rounding type
|
||||
static int stb__Lerp13(int a, int b)
|
||||
{
|
||||
#ifdef STB_DXT_USE_ROUNDING_BIAS
|
||||
// with rounding bias
|
||||
return a + stb__Mul8Bit(b-a, 0x55);
|
||||
#else
|
||||
// without rounding bias
|
||||
// replace "/ 3" by "* 0xaaab) >> 17" if your compiler sucks or you really need every ounce of speed.
|
||||
return (2*a + b) / 3;
|
||||
#endif
|
||||
}
|
||||
|
||||
// lerp RGB color
|
||||
static void stb__Lerp13RGB(unsigned char *out, unsigned char *p1, unsigned char *p2)
|
||||
{
|
||||
out[0] = (unsigned char)stb__Lerp13(p1[0], p2[0]);
|
||||
out[1] = (unsigned char)stb__Lerp13(p1[1], p2[1]);
|
||||
out[2] = (unsigned char)stb__Lerp13(p1[2], p2[2]);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static void stb__EvalColors(unsigned char *color,unsigned short c0,unsigned short c1)
|
||||
{
|
||||
stb__From16Bit(color+ 0, c0);
|
||||
stb__From16Bit(color+ 4, c1);
|
||||
stb__Lerp13RGB(color+ 8, color+0, color+4);
|
||||
stb__Lerp13RGB(color+12, color+4, color+0);
|
||||
}
|
||||
|
||||
// The color matching function
|
||||
static unsigned int stb__MatchColorsBlock(unsigned char *block, unsigned char *color)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
int dirr = color[0*4+0] - color[1*4+0];
|
||||
int dirg = color[0*4+1] - color[1*4+1];
|
||||
int dirb = color[0*4+2] - color[1*4+2];
|
||||
int dots[16];
|
||||
int stops[4];
|
||||
int i;
|
||||
int c0Point, halfPoint, c3Point;
|
||||
|
||||
for(i=0;i<16;i++)
|
||||
dots[i] = block[i*4+0]*dirr + block[i*4+1]*dirg + block[i*4+2]*dirb;
|
||||
|
||||
for(i=0;i<4;i++)
|
||||
stops[i] = color[i*4+0]*dirr + color[i*4+1]*dirg + color[i*4+2]*dirb;
|
||||
|
||||
// think of the colors as arranged on a line; project point onto that line, then choose
|
||||
// next color out of available ones. we compute the crossover points for "best color in top
|
||||
// half"/"best in bottom half" and then the same inside that subinterval.
|
||||
//
|
||||
// relying on this 1d approximation isn't always optimal in terms of euclidean distance,
|
||||
// but it's very close and a lot faster.
|
||||
// http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html
|
||||
|
||||
c0Point = (stops[1] + stops[3]);
|
||||
halfPoint = (stops[3] + stops[2]);
|
||||
c3Point = (stops[2] + stops[0]);
|
||||
|
||||
for (i=15;i>=0;i--) {
|
||||
int dot = dots[i]*2;
|
||||
mask <<= 2;
|
||||
|
||||
if(dot < halfPoint)
|
||||
mask |= (dot < c0Point) ? 1 : 3;
|
||||
else
|
||||
mask |= (dot < c3Point) ? 2 : 0;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
// The color optimization function. (Clever code, part 1)
|
||||
static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16)
|
||||
{
|
||||
int mind,maxd;
|
||||
unsigned char *minp, *maxp;
|
||||
double magn;
|
||||
int v_r,v_g,v_b;
|
||||
static const int nIterPower = 4;
|
||||
float covf[6],vfr,vfg,vfb;
|
||||
|
||||
// determine color distribution
|
||||
int cov[6];
|
||||
int mu[3],min[3],max[3];
|
||||
int ch,i,iter;
|
||||
|
||||
for(ch=0;ch<3;ch++)
|
||||
{
|
||||
const unsigned char *bp = ((const unsigned char *) block) + ch;
|
||||
int muv,minv,maxv;
|
||||
|
||||
muv = minv = maxv = bp[0];
|
||||
for(i=4;i<64;i+=4)
|
||||
{
|
||||
muv += bp[i];
|
||||
if (bp[i] < minv) minv = bp[i];
|
||||
else if (bp[i] > maxv) maxv = bp[i];
|
||||
}
|
||||
|
||||
mu[ch] = (muv + 8) >> 4;
|
||||
min[ch] = minv;
|
||||
max[ch] = maxv;
|
||||
}
|
||||
|
||||
// determine covariance matrix
|
||||
for (i=0;i<6;i++)
|
||||
cov[i] = 0;
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
{
|
||||
int r = block[i*4+0] - mu[0];
|
||||
int g = block[i*4+1] - mu[1];
|
||||
int b = block[i*4+2] - mu[2];
|
||||
|
||||
cov[0] += r*r;
|
||||
cov[1] += r*g;
|
||||
cov[2] += r*b;
|
||||
cov[3] += g*g;
|
||||
cov[4] += g*b;
|
||||
cov[5] += b*b;
|
||||
}
|
||||
|
||||
// convert covariance matrix to float, find principal axis via power iter
|
||||
for(i=0;i<6;i++)
|
||||
covf[i] = cov[i] / 255.0f;
|
||||
|
||||
vfr = (float) (max[0] - min[0]);
|
||||
vfg = (float) (max[1] - min[1]);
|
||||
vfb = (float) (max[2] - min[2]);
|
||||
|
||||
for(iter=0;iter<nIterPower;iter++)
|
||||
{
|
||||
float r = vfr*covf[0] + vfg*covf[1] + vfb*covf[2];
|
||||
float g = vfr*covf[1] + vfg*covf[3] + vfb*covf[4];
|
||||
float b = vfr*covf[2] + vfg*covf[4] + vfb*covf[5];
|
||||
|
||||
vfr = r;
|
||||
vfg = g;
|
||||
vfb = b;
|
||||
}
|
||||
|
||||
magn = STBD_FABS(vfr);
|
||||
if (STBD_FABS(vfg) > magn) magn = STBD_FABS(vfg);
|
||||
if (STBD_FABS(vfb) > magn) magn = STBD_FABS(vfb);
|
||||
|
||||
if(magn < 4.0f) { // too small, default to luminance
|
||||
v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000.
|
||||
v_g = 587;
|
||||
v_b = 114;
|
||||
} else {
|
||||
magn = 512.0 / magn;
|
||||
v_r = (int) (vfr * magn);
|
||||
v_g = (int) (vfg * magn);
|
||||
v_b = (int) (vfb * magn);
|
||||
}
|
||||
|
||||
minp = maxp = block;
|
||||
mind = maxd = block[0]*v_r + block[1]*v_g + block[2]*v_b;
|
||||
// Pick colors at extreme points
|
||||
for(i=1;i<16;i++)
|
||||
{
|
||||
int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b;
|
||||
|
||||
if (dot < mind) {
|
||||
mind = dot;
|
||||
minp = block+i*4;
|
||||
}
|
||||
|
||||
if (dot > maxd) {
|
||||
maxd = dot;
|
||||
maxp = block+i*4;
|
||||
}
|
||||
}
|
||||
|
||||
*pmax16 = stb__As16Bit(maxp[0],maxp[1],maxp[2]);
|
||||
*pmin16 = stb__As16Bit(minp[0],minp[1],minp[2]);
|
||||
}
|
||||
|
||||
static const float stb__midpoints5[32] = {
|
||||
0.015686f, 0.047059f, 0.078431f, 0.111765f, 0.145098f, 0.176471f, 0.207843f, 0.241176f, 0.274510f, 0.305882f, 0.337255f, 0.370588f, 0.403922f, 0.435294f, 0.466667f, 0.5f,
|
||||
0.533333f, 0.564706f, 0.596078f, 0.629412f, 0.662745f, 0.694118f, 0.725490f, 0.758824f, 0.792157f, 0.823529f, 0.854902f, 0.888235f, 0.921569f, 0.952941f, 0.984314f, 1.0f
|
||||
};
|
||||
|
||||
static const float stb__midpoints6[64] = {
|
||||
0.007843f, 0.023529f, 0.039216f, 0.054902f, 0.070588f, 0.086275f, 0.101961f, 0.117647f, 0.133333f, 0.149020f, 0.164706f, 0.180392f, 0.196078f, 0.211765f, 0.227451f, 0.245098f,
|
||||
0.262745f, 0.278431f, 0.294118f, 0.309804f, 0.325490f, 0.341176f, 0.356863f, 0.372549f, 0.388235f, 0.403922f, 0.419608f, 0.435294f, 0.450980f, 0.466667f, 0.482353f, 0.500000f,
|
||||
0.517647f, 0.533333f, 0.549020f, 0.564706f, 0.580392f, 0.596078f, 0.611765f, 0.627451f, 0.643137f, 0.658824f, 0.674510f, 0.690196f, 0.705882f, 0.721569f, 0.737255f, 0.754902f,
|
||||
0.772549f, 0.788235f, 0.803922f, 0.819608f, 0.835294f, 0.850980f, 0.866667f, 0.882353f, 0.898039f, 0.913725f, 0.929412f, 0.945098f, 0.960784f, 0.976471f, 0.992157f, 1.0f
|
||||
};
|
||||
|
||||
static unsigned short stb__Quantize5(float x)
|
||||
{
|
||||
unsigned short q;
|
||||
x = x < 0 ? 0 : x > 1 ? 1 : x; // saturate
|
||||
q = (unsigned short)(x * 31);
|
||||
q += (x > stb__midpoints5[q]);
|
||||
return q;
|
||||
}
|
||||
|
||||
static unsigned short stb__Quantize6(float x)
|
||||
{
|
||||
unsigned short q;
|
||||
x = x < 0 ? 0 : x > 1 ? 1 : x; // saturate
|
||||
q = (unsigned short)(x * 63);
|
||||
q += (x > stb__midpoints6[q]);
|
||||
return q;
|
||||
}
|
||||
|
||||
// The refinement function. (Clever code, part 2)
|
||||
// Tries to optimize colors to suit block contents better.
|
||||
// (By solving a least squares system via normal equations+Cramer's rule)
|
||||
static int stb__RefineBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16, unsigned int mask)
|
||||
{
|
||||
static const int w1Tab[4] = { 3,0,2,1 };
|
||||
static const int prods[4] = { 0x090000,0x000900,0x040102,0x010402 };
|
||||
// ^some magic to save a lot of multiplies in the accumulating loop...
|
||||
// (precomputed products of weights for least squares system, accumulated inside one 32-bit register)
|
||||
|
||||
float f;
|
||||
unsigned short oldMin, oldMax, min16, max16;
|
||||
int i, akku = 0, xx,xy,yy;
|
||||
int At1_r,At1_g,At1_b;
|
||||
int At2_r,At2_g,At2_b;
|
||||
unsigned int cm = mask;
|
||||
|
||||
oldMin = *pmin16;
|
||||
oldMax = *pmax16;
|
||||
|
||||
if((mask ^ (mask<<2)) < 4) // all pixels have the same index?
|
||||
{
|
||||
// yes, linear system would be singular; solve using optimal
|
||||
// single-color match on average color
|
||||
int r = 8, g = 8, b = 8;
|
||||
for (i=0;i<16;++i) {
|
||||
r += block[i*4+0];
|
||||
g += block[i*4+1];
|
||||
b += block[i*4+2];
|
||||
}
|
||||
|
||||
r >>= 4; g >>= 4; b >>= 4;
|
||||
|
||||
max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0];
|
||||
min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1];
|
||||
} else {
|
||||
At1_r = At1_g = At1_b = 0;
|
||||
At2_r = At2_g = At2_b = 0;
|
||||
for (i=0;i<16;++i,cm>>=2) {
|
||||
int step = cm&3;
|
||||
int w1 = w1Tab[step];
|
||||
int r = block[i*4+0];
|
||||
int g = block[i*4+1];
|
||||
int b = block[i*4+2];
|
||||
|
||||
akku += prods[step];
|
||||
At1_r += w1*r;
|
||||
At1_g += w1*g;
|
||||
At1_b += w1*b;
|
||||
At2_r += r;
|
||||
At2_g += g;
|
||||
At2_b += b;
|
||||
}
|
||||
|
||||
At2_r = 3*At2_r - At1_r;
|
||||
At2_g = 3*At2_g - At1_g;
|
||||
At2_b = 3*At2_b - At1_b;
|
||||
|
||||
// extract solutions and decide solvability
|
||||
xx = akku >> 16;
|
||||
yy = (akku >> 8) & 0xff;
|
||||
xy = (akku >> 0) & 0xff;
|
||||
|
||||
f = 3.0f / 255.0f / (xx*yy - xy*xy);
|
||||
|
||||
max16 = stb__Quantize5((At1_r*yy - At2_r * xy) * f) << 11;
|
||||
max16 |= stb__Quantize6((At1_g*yy - At2_g * xy) * f) << 5;
|
||||
max16 |= stb__Quantize5((At1_b*yy - At2_b * xy) * f) << 0;
|
||||
|
||||
min16 = stb__Quantize5((At2_r*xx - At1_r * xy) * f) << 11;
|
||||
min16 |= stb__Quantize6((At2_g*xx - At1_g * xy) * f) << 5;
|
||||
min16 |= stb__Quantize5((At2_b*xx - At1_b * xy) * f) << 0;
|
||||
}
|
||||
|
||||
*pmin16 = min16;
|
||||
*pmax16 = max16;
|
||||
return oldMin != min16 || oldMax != max16;
|
||||
}
|
||||
|
||||
// Color block compression
|
||||
static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, int mode)
|
||||
{
|
||||
unsigned int mask;
|
||||
int i;
|
||||
int refinecount;
|
||||
unsigned short max16, min16;
|
||||
unsigned char color[4*4];
|
||||
|
||||
refinecount = (mode & STB_DXT_HIGHQUAL) ? 2 : 1;
|
||||
|
||||
// check if block is constant
|
||||
for (i=1;i<16;i++)
|
||||
if (((unsigned int *) block)[i] != ((unsigned int *) block)[0])
|
||||
break;
|
||||
|
||||
if(i == 16) { // constant color
|
||||
int r = block[0], g = block[1], b = block[2];
|
||||
mask = 0xaaaaaaaa;
|
||||
max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0];
|
||||
min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1];
|
||||
} else {
|
||||
// first step: PCA+map along principal axis
|
||||
stb__OptimizeColorsBlock(block,&max16,&min16);
|
||||
if (max16 != min16) {
|
||||
stb__EvalColors(color,max16,min16);
|
||||
mask = stb__MatchColorsBlock(block,color);
|
||||
} else
|
||||
mask = 0;
|
||||
|
||||
// third step: refine (multiple times if requested)
|
||||
for (i=0;i<refinecount;i++) {
|
||||
unsigned int lastmask = mask;
|
||||
|
||||
if (stb__RefineBlock(block,&max16,&min16,mask)) {
|
||||
if (max16 != min16) {
|
||||
stb__EvalColors(color,max16,min16);
|
||||
mask = stb__MatchColorsBlock(block,color);
|
||||
} else {
|
||||
mask = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(mask == lastmask)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write the color block
|
||||
if(max16 < min16)
|
||||
{
|
||||
unsigned short t = min16;
|
||||
min16 = max16;
|
||||
max16 = t;
|
||||
mask ^= 0x55555555;
|
||||
}
|
||||
|
||||
dest[0] = (unsigned char) (max16);
|
||||
dest[1] = (unsigned char) (max16 >> 8);
|
||||
dest[2] = (unsigned char) (min16);
|
||||
dest[3] = (unsigned char) (min16 >> 8);
|
||||
dest[4] = (unsigned char) (mask);
|
||||
dest[5] = (unsigned char) (mask >> 8);
|
||||
dest[6] = (unsigned char) (mask >> 16);
|
||||
dest[7] = (unsigned char) (mask >> 24);
|
||||
}
|
||||
|
||||
// Alpha block compression (this is easy for a change)
|
||||
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[0];
|
||||
|
||||
for (i=1;i<16;i++)
|
||||
{
|
||||
if (src[i*stride] < mn) mn = src[i*stride];
|
||||
else if (src[i*stride] > mx) mx = src[i*stride];
|
||||
}
|
||||
|
||||
// encode them
|
||||
dest[0] = (unsigned char)mx;
|
||||
dest[1] = (unsigned char)mn;
|
||||
dest += 2;
|
||||
|
||||
// determine bias and emit color indices
|
||||
// given the choice of mx/mn, these indices are optimal:
|
||||
// http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/
|
||||
dist = mx-mn;
|
||||
dist4 = dist*4;
|
||||
dist2 = dist*2;
|
||||
bias = (dist < 8) ? (dist - 1) : (dist/2 + 2);
|
||||
bias -= mn * 7;
|
||||
bits = 0,mask=0;
|
||||
|
||||
for (i=0;i<16;i++) {
|
||||
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).
|
||||
t = (a >= dist4) ? -1 : 0; ind = t & 4; a -= dist4 & t;
|
||||
t = (a >= dist2) ? -1 : 0; ind += t & 2; a -= dist2 & t;
|
||||
ind += (a >= dist);
|
||||
|
||||
// turn linear scale into DXT index (0/1 are extremal pts)
|
||||
ind = -ind & 7;
|
||||
ind ^= (2 > ind);
|
||||
|
||||
// write index
|
||||
mask |= ind << bits;
|
||||
if((bits += 3) >= 8) {
|
||||
*dest++ = (unsigned char)mask;
|
||||
mask >>= 8;
|
||||
bits -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode)
|
||||
{
|
||||
unsigned char data[16][4];
|
||||
if (alpha) {
|
||||
int i;
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4);
|
||||
dest += 8;
|
||||
// make a new copy of the data in which alpha is opaque,
|
||||
// because code uses a fast test for color constancy
|
||||
memcpy(data, src, 4*16);
|
||||
for (i=0; i < 16; ++i)
|
||||
data[i][3] = 255;
|
||||
src = &data[0][0];
|
||||
}
|
||||
|
||||
stb__CompressColorBlock(dest,(unsigned char*) src,mode);
|
||||
}
|
||||
|
||||
void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src)
|
||||
{
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src, 1);
|
||||
}
|
||||
|
||||
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src)
|
||||
{
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src,2);
|
||||
stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2);
|
||||
}
|
||||
#endif // STB_DXT_IMPLEMENTATION
|
||||
|
||||
// Compile with STB_DXT_IMPLEMENTATION and STB_DXT_GENERATE_TABLES
|
||||
// defined to generate the tables above.
|
||||
#ifdef STB_DXT_GENERATE_TABLES
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int i, j;
|
||||
const char *omatch_names[] = { "stb__OMatch5", "stb__OMatch6" };
|
||||
int dequant_mults[2] = { 33*4, 65 }; // .4 fixed-point dequant multipliers
|
||||
|
||||
// optimal endpoint tables
|
||||
for (i = 0; i < 2; ++i) {
|
||||
int dequant = dequant_mults[i];
|
||||
int size = i ? 64 : 32;
|
||||
printf("static const unsigned char %s[256][2] = {\n", omatch_names[i]);
|
||||
for (int j = 0; j < 256; ++j) {
|
||||
int mn, mx;
|
||||
int best_mn = 0, best_mx = 0;
|
||||
int best_err = 256 * 100;
|
||||
for (mn=0;mn<size;mn++) {
|
||||
for (mx=0;mx<size;mx++) {
|
||||
int mine = (mn * dequant) >> 4;
|
||||
int maxe = (mx * dequant) >> 4;
|
||||
int err = abs(stb__Lerp13(maxe, mine) - j) * 100;
|
||||
|
||||
// DX10 spec says that interpolation must be within 3% of "correct" result,
|
||||
// add this as error term. Normally we'd expect a random distribution of
|
||||
// +-1.5% error, but nowhere in the spec does it say that the error has to be
|
||||
// unbiased - better safe than sorry.
|
||||
err += abs(maxe - mine) * 3;
|
||||
|
||||
if(err < best_err) {
|
||||
best_mn = mn;
|
||||
best_mx = mx;
|
||||
best_err = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((j % 8) == 0) printf(" "); // 2 spaces, third is done below
|
||||
printf(" { %2d, %2d },", best_mx, best_mn);
|
||||
if ((j % 8) == 7) printf("\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
305
raytracer/nvpro_core/third_party/stb/stb_easy_font.h
vendored
Normal file
305
raytracer/nvpro_core/third_party/stb/stb_easy_font.h
vendored
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
// stb_easy_font.h - v1.1 - bitmap font for 3D rendering - public domain
|
||||
// Sean Barrett, Feb 2015
|
||||
//
|
||||
// Easy-to-deploy,
|
||||
// reasonably compact,
|
||||
// extremely inefficient performance-wise,
|
||||
// crappy-looking,
|
||||
// ASCII-only,
|
||||
// bitmap font for use in 3D APIs.
|
||||
//
|
||||
// Intended for when you just want to get some text displaying
|
||||
// in a 3D app as quickly as possible.
|
||||
//
|
||||
// Doesn't use any textures, instead builds characters out of quads.
|
||||
//
|
||||
// DOCUMENTATION:
|
||||
//
|
||||
// int stb_easy_font_width(char *text)
|
||||
// int stb_easy_font_height(char *text)
|
||||
//
|
||||
// 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],
|
||||
// void *vertex_buffer, int vbuf_size)
|
||||
//
|
||||
// Takes a string (which can contain '\n') and fills out a
|
||||
// vertex buffer with renderable data to draw the string.
|
||||
// Output data assumes increasing x is rightwards, increasing y
|
||||
// is downwards.
|
||||
//
|
||||
// The vertex data is divided into quads, i.e. there are four
|
||||
// vertices in the vertex buffer for each quad.
|
||||
//
|
||||
// The vertices are stored in an interleaved format:
|
||||
//
|
||||
// x:float
|
||||
// y:float
|
||||
// z:float
|
||||
// color:uint8[4]
|
||||
//
|
||||
// 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 vertex-buffer-drawing code.
|
||||
//
|
||||
// If you pass in NULL for color, it becomes 255,255,255,255.
|
||||
//
|
||||
// Returns the number of quads.
|
||||
//
|
||||
// If the buffer isn't large enough, it will truncate.
|
||||
// Expect it to use an average of ~270 bytes per character.
|
||||
//
|
||||
// If your API doesn't draw quads, build a reusable index
|
||||
// list that allows you to render quads as indexed triangles.
|
||||
//
|
||||
// void stb_easy_font_spacing(float spacing)
|
||||
//
|
||||
// Use positive values to expand the space between characters,
|
||||
// and small negative values (no smaller than -1.5) to contract
|
||||
// the space between characters.
|
||||
//
|
||||
// E.g. spacing = 1 adds one "pixel" of spacing between the
|
||||
// characters. spacing = -1 is reasonable but feels a bit too
|
||||
// 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
|
||||
//
|
||||
// (2020-02-02) 1.1 make everything static so can compile it in more than one src file
|
||||
// (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
|
||||
// github:podsvirov -- fix multiple definition errors
|
||||
|
||||
#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.
|
||||
//
|
||||
void print_string(float x, float y, char *text, float r, float g, float b)
|
||||
{
|
||||
static char buffer[99999]; // ~500 chars
|
||||
int num_quads;
|
||||
|
||||
num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer));
|
||||
|
||||
glColor3f(r,g,b);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 16, buffer);
|
||||
glDrawArrays(GL_QUADS, 0, num_quads*4);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef INCLUDE_STB_EASY_FONT_H
|
||||
#define INCLUDE_STB_EASY_FONT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
static struct stb_easy_font_info_struct {
|
||||
unsigned char advance;
|
||||
unsigned char h_seg;
|
||||
unsigned char v_seg;
|
||||
} stb_easy_font_charinfo[96] = {
|
||||
{ 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 },
|
||||
{ 6, 25, 39 }, { 6, 27, 43 }, { 6, 28, 45 }, { 6, 30, 49 },
|
||||
{ 6, 33, 53 }, { 6, 34, 57 }, { 6, 40, 58 }, { 6, 46, 59 },
|
||||
{ 6, 47, 62 }, { 6, 55, 64 }, { 19, 57, 68 }, { 20, 59, 68 },
|
||||
{ 21, 61, 69 }, { 22, 66, 69 }, { 21, 68, 69 }, { 7, 73, 69 },
|
||||
{ 9, 75, 74 }, { 6, 78, 81 }, { 6, 80, 85 }, { 6, 83, 90 },
|
||||
{ 6, 85, 91 }, { 6, 87, 95 }, { 6, 90, 96 }, { 7, 92, 97 },
|
||||
{ 6, 96,102 }, { 5, 97,106 }, { 6, 99,107 }, { 6,100,110 },
|
||||
{ 6,100,115 }, { 7,101,116 }, { 6,101,121 }, { 6,101,125 },
|
||||
{ 6,102,129 }, { 7,103,133 }, { 6,104,140 }, { 6,105,145 },
|
||||
{ 7,107,149 }, { 6,108,151 }, { 7,109,155 }, { 7,109,160 },
|
||||
{ 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 }, { 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 },
|
||||
{ 5,178,233 }, { 22,179,234 }, { 23,180,238 }, { 23,180,243 },
|
||||
{ 23,180,248 }, { 22,189,248 }, { 22,191,252 }, { 5,196,252 },
|
||||
{ 3,203,252 }, { 5,203,253 }, { 22,210,253 }, { 0,214,253 },
|
||||
};
|
||||
|
||||
static unsigned char stb_easy_font_hseg[214] = {
|
||||
97,37,69,84,28,51,2,18,10,49,98,41,65,25,81,105,33,9,97,1,97,37,37,36,
|
||||
81,10,98,107,3,100,3,99,58,51,4,99,58,8,73,81,10,50,98,8,73,81,4,10,50,
|
||||
98,8,25,33,65,81,10,50,17,65,97,25,33,25,49,9,65,20,68,1,65,25,49,41,
|
||||
11,105,13,101,76,10,50,10,50,98,11,99,10,98,11,50,99,11,50,11,99,8,57,
|
||||
58,3,99,99,107,10,10,11,10,99,11,5,100,41,65,57,41,65,9,17,81,97,3,107,
|
||||
9,97,1,97,33,25,9,25,41,100,41,26,82,42,98,27,83,42,98,26,51,82,8,41,
|
||||
35,8,10,26,82,114,42,1,114,8,9,73,57,81,41,97,18,8,8,25,26,26,82,26,82,
|
||||
26,82,41,25,33,82,26,49,73,35,90,17,81,41,65,57,41,65,25,81,90,114,20,
|
||||
84,73,57,41,49,25,33,65,81,9,97,1,97,25,33,65,81,57,33,25,41,25,
|
||||
};
|
||||
|
||||
static unsigned char stb_easy_font_vseg[253] = {
|
||||
4,2,8,10,15,8,15,33,8,15,8,73,82,73,57,41,82,10,82,18,66,10,21,29,1,65,
|
||||
27,8,27,9,65,8,10,50,97,74,66,42,10,21,57,41,29,25,14,81,73,57,26,8,8,
|
||||
26,66,3,8,8,15,19,21,90,58,26,18,66,18,105,89,28,74,17,8,73,57,26,21,
|
||||
8,42,41,42,8,28,22,8,8,30,7,8,8,26,66,21,7,8,8,29,7,7,21,8,8,8,59,7,8,
|
||||
8,15,29,8,8,14,7,57,43,10,82,7,7,25,42,25,15,7,25,41,15,21,105,105,29,
|
||||
7,57,57,26,21,105,73,97,89,28,97,7,57,58,26,82,18,57,57,74,8,30,6,8,8,
|
||||
14,3,58,90,58,11,7,74,43,74,15,2,82,2,42,75,42,10,67,57,41,10,7,2,42,
|
||||
74,106,15,2,35,8,8,29,7,8,8,59,35,51,8,8,15,35,30,35,8,8,30,7,8,8,60,
|
||||
36,8,45,7,7,36,8,43,8,44,21,8,8,44,35,8,8,43,23,8,8,43,35,8,8,31,21,15,
|
||||
20,8,8,28,18,58,89,58,26,21,89,73,89,29,20,8,8,30,7,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char c[4];
|
||||
} stb_easy_font_color;
|
||||
|
||||
static int stb_easy_font_draw_segs(float x, float y, unsigned char *segs, int num_segs, int vertical, stb_easy_font_color c, char *vbuf, int vbuf_size, int offset)
|
||||
{
|
||||
int i,j;
|
||||
for (i=0; i < num_segs; ++i) {
|
||||
int len = segs[i] & 7;
|
||||
x += (float) ((segs[i] >> 3) & 1);
|
||||
if (len && offset+64 <= vbuf_size) {
|
||||
float y0 = y + (float) (segs[i]>>4);
|
||||
for (j=0; j < 4; ++j) {
|
||||
* (float *) (vbuf+offset+0) = x + (j==1 || j==2 ? (vertical ? 1 : len) : 0);
|
||||
* (float *) (vbuf+offset+4) = y0 + ( j >= 2 ? (vertical ? len : 1) : 0);
|
||||
* (float *) (vbuf+offset+8) = 0.f;
|
||||
* (stb_easy_font_color *) (vbuf+offset+12) = c;
|
||||
offset += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static float stb_easy_font_spacing_val = 0;
|
||||
static void stb_easy_font_spacing(float spacing)
|
||||
{
|
||||
stb_easy_font_spacing_val = spacing;
|
||||
}
|
||||
|
||||
static int stb_easy_font_print(float x, float y, char *text, unsigned char color[4], void *vertex_buffer, int vbuf_size)
|
||||
{
|
||||
char *vbuf = (char *) vertex_buffer;
|
||||
float start_x = x;
|
||||
int offset = 0;
|
||||
|
||||
stb_easy_font_color c = { 255,255,255,255 }; // use structure copying to avoid needing depending on memcpy()
|
||||
if (color) { c.c[0] = color[0]; c.c[1] = color[1]; c.c[2] = color[2]; c.c[3] = color[3]; }
|
||||
|
||||
while (*text && offset < vbuf_size) {
|
||||
if (*text == '\n') {
|
||||
y += 12;
|
||||
x = start_x;
|
||||
} else {
|
||||
unsigned char advance = stb_easy_font_charinfo[*text-32].advance;
|
||||
float y_ch = advance & 16 ? y+1 : y;
|
||||
int h_seg, v_seg, num_h, num_v;
|
||||
h_seg = stb_easy_font_charinfo[*text-32 ].h_seg;
|
||||
v_seg = stb_easy_font_charinfo[*text-32 ].v_seg;
|
||||
num_h = stb_easy_font_charinfo[*text-32+1].h_seg - h_seg;
|
||||
num_v = stb_easy_font_charinfo[*text-32+1].v_seg - v_seg;
|
||||
offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_hseg[h_seg], num_h, 0, c, vbuf, vbuf_size, offset);
|
||||
offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_vseg[v_seg], num_v, 1, c, vbuf, vbuf_size, offset);
|
||||
x += advance & 15;
|
||||
x += stb_easy_font_spacing_val;
|
||||
}
|
||||
++text;
|
||||
}
|
||||
return (unsigned) offset/64;
|
||||
}
|
||||
|
||||
static int stb_easy_font_width(char *text)
|
||||
{
|
||||
float len = 0;
|
||||
float max_len = 0;
|
||||
while (*text) {
|
||||
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;
|
||||
}
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
1221
raytracer/nvpro_core/third_party/stb/stb_herringbone_wang_tile.h
vendored
Normal file
1221
raytracer/nvpro_core/third_party/stb/stb_herringbone_wang_tile.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
680
raytracer/nvpro_core/third_party/stb/stb_hexwave.h
vendored
Normal file
680
raytracer/nvpro_core/third_party/stb/stb_hexwave.h
vendored
Normal file
|
|
@ -0,0 +1,680 @@
|
|||
// stb_hexwave - v0.5 - public domain, initial release 2021-04-01
|
||||
//
|
||||
// A flexible anti-aliased (bandlimited) digital audio oscillator.
|
||||
//
|
||||
// This library generates waveforms of a variety of shapes made of
|
||||
// line segments. It does not do envelopes, LFO effects, etc.; it
|
||||
// merely tries to solve the problem of generating an artifact-free
|
||||
// morphable digital waveform with a variety of spectra, and leaves
|
||||
// it to the user to rescale the waveform and mix multiple voices, etc.
|
||||
//
|
||||
// Compiling:
|
||||
//
|
||||
// In one C/C++ file that #includes this file, do
|
||||
//
|
||||
// #define STB_HEXWAVE_IMPLEMENTATION
|
||||
// #include "stb_hexwave.h"
|
||||
//
|
||||
// Optionally, #define STB_HEXWAVE_STATIC before including
|
||||
// the header to cause the definitions to be private to the
|
||||
// implementation file (i.e. to be "static" instead of "extern").
|
||||
//
|
||||
// Notes:
|
||||
//
|
||||
// Optionally performs memory allocation during initialization,
|
||||
// never allocates otherwise.
|
||||
//
|
||||
// License:
|
||||
//
|
||||
// See end of file for license information.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// Initialization:
|
||||
//
|
||||
// hexwave_init(32,16,NULL); // read "header section" for alternatives
|
||||
//
|
||||
// Create oscillator:
|
||||
//
|
||||
// HexWave *osc = malloc(sizeof(*osc)); // or "new HexWave", or declare globally or on stack
|
||||
// hexwave_create(osc, reflect_flag, peak_time, half_height, zero_wait);
|
||||
// see "Waveform shapes" below for the meaning of these parameters
|
||||
//
|
||||
// Generate audio:
|
||||
//
|
||||
// hexwave_generate_samples(output, number_of_samples, osc, oscillator_freq)
|
||||
// where:
|
||||
// output is a buffer where the library will store floating point audio samples
|
||||
// number_of_samples is the number of audio samples to generate
|
||||
// osc is a pointer to a Hexwave
|
||||
// oscillator_freq is the frequency of the oscillator divided by the sample rate
|
||||
//
|
||||
// The output samples will continue from where the samples generated by the
|
||||
// previous hexwave_generate_samples() on this oscillator ended.
|
||||
//
|
||||
// Change oscillator waveform:
|
||||
//
|
||||
// hexwave_change(osc, reflect_flag, peak_time, half_height, zero_wait);
|
||||
// can call in between calls to hexwave_generate_samples
|
||||
//
|
||||
// Waveform shapes:
|
||||
//
|
||||
// All waveforms generated by hexwave are constructed from six line segments
|
||||
// characterized by 3 parameters.
|
||||
//
|
||||
// See demonstration: https://www.youtube.com/watch?v=hsUCrAsDN-M
|
||||
//
|
||||
// reflect=0 reflect=1
|
||||
//
|
||||
// 0-----P---1 0-----P---1 peak_time = P
|
||||
// . 1 . 1
|
||||
// /\_ : /\_ :
|
||||
// / \_ : / \_ :
|
||||
// / \.H / \.H half_height = H
|
||||
// / | : / | :
|
||||
// _____/ |_:___ _____/ | : _____
|
||||
// . : \ | . | : /
|
||||
// . : \ | . | : /
|
||||
// . : \ _/ . \_: /
|
||||
// . : \ _/ . :_ /
|
||||
// . -1 \/ . -1 \/
|
||||
// 0 - Z - - - - 1 0 - Z - - - - 1 zero_wait = Z
|
||||
//
|
||||
// Classic waveforms:
|
||||
// peak half zero
|
||||
// reflect time height wait
|
||||
// Sawtooth 1 0 0 0
|
||||
// Square 1 0 1 0
|
||||
// Triangle 1 0.5 0 0
|
||||
//
|
||||
// Some waveforms can be produced in multiple ways, which is useful when morphing
|
||||
// into other waveforms, and there are a few more notable shapes:
|
||||
//
|
||||
// peak half zero
|
||||
// reflect time height wait
|
||||
// Sawtooth 1 1 any 0
|
||||
// Sawtooth (8va) 1 0 -1 0
|
||||
// Triangle 1 0.5 0 0
|
||||
// Square 1 0 1 0
|
||||
// Square 0 0 1 0
|
||||
// Triangle 0 0.5 0 0
|
||||
// Triangle 0 0 -1 0
|
||||
// AlternatingSaw 0 0 0 0
|
||||
// AlternatingSaw 0 1 any 0
|
||||
// Stairs 0 0 1 0.5
|
||||
//
|
||||
// The "Sawtooth (8va)" waveform is identical to a sawtooth wave with 2x the
|
||||
// frequency, but when morphed with other values, it becomes an overtone of
|
||||
// the base frequency.
|
||||
//
|
||||
// Morphing waveforms:
|
||||
//
|
||||
// Sweeping peak_time morphs the waveform while producing various spectra.
|
||||
// Sweeping half_height effectively crossfades between two waveforms; useful, but less exciting.
|
||||
// Sweeping zero_wait produces a similar effect no matter the reset of the waveform,
|
||||
// a sort of high-pass/PWM effect where the wave becomes silent at zero_wait=1.
|
||||
//
|
||||
// You can trivially morph between any two waveforms from the above table
|
||||
// which only differ in one column.
|
||||
//
|
||||
// Crossfade between classic waveforms:
|
||||
// peak half zero
|
||||
// Start End reflect time height wait
|
||||
// ----- --- ------- ---- ------ ----
|
||||
// Triangle Square 0 0 -1..1 0
|
||||
// Saw Square 1 0 0..1 0
|
||||
// Triangle Saw 1 0.5 0..2 0
|
||||
//
|
||||
// The last morph uses uses half-height values larger than 1, which means it will
|
||||
// be louder and the output should be scaled down by half to compensate, or better
|
||||
// by dynamically tracking the morph: volume_scale = 1 - half_height/4
|
||||
//
|
||||
// Non-crossfade morph between classic waveforms, most require changing
|
||||
// two parameters at the same time:
|
||||
// peak half zero
|
||||
// Start End reflect time height wait
|
||||
// ----- --- ------- ---- ------ ----
|
||||
// Square Triangle any 0..0.5 1..0 0
|
||||
// Square Saw 1 0..1 1..any 0
|
||||
// Triangle Saw 1 0.5..1 0..-1 0
|
||||
//
|
||||
// Other noteworthy morphs between simple shapes:
|
||||
// peak half zero
|
||||
// Start Halfway End reflect time height wait
|
||||
// ----- --------- --- ------- ---- ------ ----
|
||||
// Saw (8va,neg) Saw (pos) 1 0..1 -1 0
|
||||
// Saw (neg) Saw (pos) 1 0..1 0 0
|
||||
// Triangle AlternatingSaw 0 0..1 -1 0
|
||||
// AlternatingSaw Triangle AlternatingSaw 0 0..1 0 0
|
||||
// Square AlternatingSaw 0 0..1 1 0
|
||||
// Triangle Triangle AlternatingSaw 0 0..1 -1..1 0
|
||||
// Square AlternatingSaw 0 0..1 1..0 0
|
||||
// Saw (8va) Triangle Saw 1 0..1 -1..1 0
|
||||
// Saw (neg) Saw (pos) 1 0..1 0..1 0
|
||||
// AlternatingSaw AlternatingSaw 0 0..1 0..any 0
|
||||
//
|
||||
// The last entry is noteworthy because the morph from the halfway point to either
|
||||
// endpoint sounds very different. For example, an LFO sweeping back and forth over
|
||||
// the whole range will morph between the middle timbre and the AlternatingSaw
|
||||
// timbre in two different ways, alternating.
|
||||
//
|
||||
// Entries with "any" for half_height are whole families of morphs, as you can pick
|
||||
// any value you want as the endpoint for half_height.
|
||||
//
|
||||
// You can always morph between any two waveforms with the same value of 'reflect'
|
||||
// by just sweeping the parameters simultaneously. There will never be artifacts
|
||||
// and the result will always be useful, if not necessarily what you want.
|
||||
//
|
||||
// You can vary the sound of two-parameter morphs by ramping them differently,
|
||||
// e.g. if the morph goes from t=0..1, then square-to-triangle looks like:
|
||||
// peak_time = lerp(t, 0, 0.5)
|
||||
// half_height = lerp(t, 1, 0 )
|
||||
// but you can also do things like:
|
||||
// peak_time = lerp(smoothstep(t), 0, 0.5)
|
||||
// half_height = cos(PI/2 * t)
|
||||
//
|
||||
// How it works:
|
||||
//
|
||||
// hexwave use BLEP to bandlimit discontinuities and BLAMP
|
||||
// to bandlimit C1 discontinuities. This is not polyBLEP
|
||||
// (polynomial BLEP), it is table-driven BLEP. It is
|
||||
// also not minBLEP (minimum-phase BLEP), as that complicates
|
||||
// things for little benefit once BLAMP is involved.
|
||||
//
|
||||
// The previous oscillator frequency is remembered, and when
|
||||
// the frequency changes, a BLAMP is generated to remove the
|
||||
// C1 discontinuity, which reduces artifacts for sweeps/LFO.
|
||||
//
|
||||
// Changes to an oscillator timbre using hexwave_change() actually
|
||||
// wait until the oscillator finishes its current cycle. All
|
||||
// waveforms with non-zero "zero_wait" settings pass through 0
|
||||
// and have 0-slope at the start of a cycle, which means changing
|
||||
// the settings is artifact free at that time. (If zero_wait is 0,
|
||||
// the code still treats it as passing through 0 with 0-slope; it'll
|
||||
// apply the necessary fixups to make it artifact free as if it does
|
||||
// transition to 0 with 0-slope vs. the waveform at the end of
|
||||
// the cycle, then adds the fixups for a non-0 and non-0 slope
|
||||
// at the start of the cycle, which cancels out if zero_wait is 0,
|
||||
// and still does the right thing if zero_wait is 0 when the
|
||||
// settings are updated.)
|
||||
//
|
||||
// BLEP/BLAMP normally requires overlapping buffers, but this
|
||||
// is hidden from the user by generating the waveform to a
|
||||
// temporary buffer and saving the overlap regions internally
|
||||
// between calls. (It is slightly more complicated; see code.)
|
||||
//
|
||||
// By design all shapes have 0 DC offset; this is one reason
|
||||
// hexwave uses zero_wait instead of standard PWM.
|
||||
//
|
||||
// The internals of hexwave could support any arbitrary shape
|
||||
// made of line segments, but I chose not to expose this
|
||||
// generality in favor of a simple, easy-to-use API.
|
||||
|
||||
#ifndef STB_INCLUDE_STB_HEXWAVE_H
|
||||
#define STB_INCLUDE_STB_HEXWAVE_H
|
||||
|
||||
#ifndef STB_HEXWAVE_MAX_BLEP_LENGTH
|
||||
#define STB_HEXWAVE_MAX_BLEP_LENGTH 64 // good enough for anybody
|
||||
#endif
|
||||
|
||||
#ifdef STB_HEXWAVE_STATIC
|
||||
#define STB_HEXWAVE_DEF static
|
||||
#else
|
||||
#define STB_HEXWAVE_DEF extern
|
||||
#endif
|
||||
|
||||
typedef struct HexWave HexWave;
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_init(int width, int oversample, float *user_buffer);
|
||||
// width: size of BLEP, from 4..64, larger is slower & more memory but less aliasing
|
||||
// oversample: 2+, number of subsample positions, larger uses more memory but less noise
|
||||
// user_buffer: optional, if provided the library will perform no allocations.
|
||||
// 16*width*(oversample+1) bytes, must stay allocated as long as library is used
|
||||
// technically it only needs: 8*( width * (oversample + 1))
|
||||
// + 8*((width * oversample) + 1) bytes
|
||||
//
|
||||
// width can be larger than 64 if you define STB_HEXWAVE_MAX_BLEP_LENGTH to a larger value
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_shutdown(float *user_buffer);
|
||||
// user_buffer: pass in same parameter as passed to hexwave_init
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_create(HexWave *hex, int reflect, float peak_time, float half_height, float zero_wait);
|
||||
// see docs above for description
|
||||
//
|
||||
// reflect is tested as 0 or non-zero
|
||||
// peak_time is clamped to 0..1
|
||||
// half_height is not clamped
|
||||
// zero_wait is clamped to 0..1
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_change(HexWave *hex, int reflect, float peak_time, float half_height, float zero_wait);
|
||||
// see docs
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_generate_samples(float *output, int num_samples, HexWave *hex, float freq);
|
||||
// output: buffer where the library will store generated floating point audio samples
|
||||
// number_of_samples: the number of audio samples to generate
|
||||
// osc: pointer to a Hexwave initialized with 'hexwave_create'
|
||||
// oscillator_freq: frequency of the oscillator divided by the sample rate
|
||||
|
||||
// private:
|
||||
typedef struct
|
||||
{
|
||||
int reflect;
|
||||
float peak_time;
|
||||
float zero_wait;
|
||||
float half_height;
|
||||
} HexWaveParameters;
|
||||
|
||||
struct HexWave
|
||||
{
|
||||
float t, prev_dt;
|
||||
HexWaveParameters current, pending;
|
||||
int have_pending;
|
||||
float buffer[STB_HEXWAVE_MAX_BLEP_LENGTH];
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef STB_HEXWAVE_IMPLEMENTATION
|
||||
|
||||
#ifndef STB_HEXWAVE_NO_ALLOCATION
|
||||
#include <stdlib.h> // malloc,free
|
||||
#endif
|
||||
|
||||
#include <string.h> // memset,memcpy,memmove
|
||||
#include <math.h> // sin,cos,fabs
|
||||
|
||||
#define hexwave_clamp(v,a,b) ((v) < (a) ? (a) : (v) > (b) ? (b) : (v))
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_change(HexWave *hex, int reflect, float peak_time, float half_height, float zero_wait)
|
||||
{
|
||||
hex->pending.reflect = reflect;
|
||||
hex->pending.peak_time = hexwave_clamp(peak_time,0,1);
|
||||
hex->pending.half_height = half_height;
|
||||
hex->pending.zero_wait = hexwave_clamp(zero_wait,0,1);
|
||||
// put a barrier here to allow changing from a different thread than the generator
|
||||
hex->have_pending = 1;
|
||||
}
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_create(HexWave *hex, int reflect, float peak_time, float half_height, float zero_wait)
|
||||
{
|
||||
memset(hex, 0, sizeof(*hex));
|
||||
hexwave_change(hex, reflect, peak_time, half_height, zero_wait);
|
||||
hex->current = hex->pending;
|
||||
hex->have_pending = 0;
|
||||
hex->t = 0;
|
||||
hex->prev_dt = 0;
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
int width; // width of fixup in samples
|
||||
int oversample; // number of oversampled versions (there's actually one more to allow lerpign)
|
||||
float *blep;
|
||||
float *blamp;
|
||||
} hexblep;
|
||||
|
||||
static void hex_add_oversampled_bleplike(float *output, float time_since_transition, float scale, float *data)
|
||||
{
|
||||
float *d1,*d2;
|
||||
float lerpweight;
|
||||
int i, bw = hexblep.width;
|
||||
|
||||
int slot = (int) (time_since_transition * hexblep.oversample);
|
||||
if (slot >= hexblep.oversample)
|
||||
slot = hexblep.oversample-1; // clamp in case the floats overshoot
|
||||
|
||||
d1 = &data[ slot *bw];
|
||||
d2 = &data[(slot+1)*bw];
|
||||
|
||||
lerpweight = time_since_transition * hexblep.oversample - slot;
|
||||
for (i=0; i < bw; ++i)
|
||||
output[i] += scale * (d1[i] + (d2[i]-d1[i])*lerpweight);
|
||||
}
|
||||
|
||||
static void hex_blep (float *output, float time_since_transition, float scale)
|
||||
{
|
||||
hex_add_oversampled_bleplike(output, time_since_transition, scale, hexblep.blep);
|
||||
}
|
||||
|
||||
static void hex_blamp(float *output, float time_since_transition, float scale)
|
||||
{
|
||||
hex_add_oversampled_bleplike(output, time_since_transition, scale, hexblep.blamp);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float t,v,s; // time, value, slope
|
||||
} hexvert;
|
||||
|
||||
// each half of the waveform needs 4 vertices to represent 3 line
|
||||
// segments, plus 1 more for wraparound
|
||||
static void hexwave_generate_linesegs(hexvert vert[9], HexWave *hex, float dt)
|
||||
{
|
||||
int j;
|
||||
float min_len = dt / 256.0f;
|
||||
|
||||
vert[0].t = 0;
|
||||
vert[0].v = 0;
|
||||
vert[1].t = hex->current.zero_wait*0.5f;
|
||||
vert[1].v = 0;
|
||||
vert[2].t = 0.5f*hex->current.peak_time + vert[1].t*(1-hex->current.peak_time);
|
||||
vert[2].v = 1;
|
||||
vert[3].t = 0.5f;
|
||||
vert[3].v = hex->current.half_height;
|
||||
|
||||
if (hex->current.reflect) {
|
||||
for (j=4; j <= 7; ++j) {
|
||||
vert[j].t = 1 - vert[7-j].t;
|
||||
vert[j].v = - vert[7-j].v;
|
||||
}
|
||||
} else {
|
||||
for (j=4; j <= 7; ++j) {
|
||||
vert[j].t = 0.5f + vert[j-4].t;
|
||||
vert[j].v = - vert[j-4].v;
|
||||
}
|
||||
}
|
||||
vert[8].t = 1;
|
||||
vert[8].v = 0;
|
||||
|
||||
for (j=0; j < 8; ++j) {
|
||||
if (vert[j+1].t <= vert[j].t + min_len) {
|
||||
// if change takes place over less than a fraction of a sample treat as discontinuity
|
||||
//
|
||||
// otherwise the slope computation can blow up to arbitrarily large and we
|
||||
// try to generate a huge BLAMP and the result is wrong.
|
||||
//
|
||||
// why does this happen if the math is right? i believe if done perfectly,
|
||||
// the two BLAMPs on either side of the slope would cancel out, but our
|
||||
// BLAMPs have only limited sub-sample precision and limited integration
|
||||
// accuracy. or maybe it's just the math blowing up w/ floating point precision
|
||||
// limits as we try to make x * (1/x) cancel out
|
||||
//
|
||||
// min_len verified artifact-free even near nyquist with only oversample=4
|
||||
vert[j+1].t = vert[j].t;
|
||||
}
|
||||
}
|
||||
|
||||
if (vert[8].t != 1.0f) {
|
||||
// if the above fixup moved the endpoint away from 1.0, move it back,
|
||||
// along with any other vertices that got moved to the same time
|
||||
float t = vert[8].t;
|
||||
for (j=5; j <= 8; ++j)
|
||||
if (vert[j].t == t)
|
||||
vert[j].t = 1.0f;
|
||||
}
|
||||
|
||||
// compute the exact slopes from the final fixed-up positions
|
||||
for (j=0; j < 8; ++j)
|
||||
if (vert[j+1].t == vert[j].t)
|
||||
vert[j].s = 0;
|
||||
else
|
||||
vert[j].s = (vert[j+1].v - vert[j].v) / (vert[j+1].t - vert[j].t);
|
||||
|
||||
// wraparound at end
|
||||
vert[8].t = 1;
|
||||
vert[8].v = vert[0].v;
|
||||
vert[8].s = vert[0].s;
|
||||
}
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_generate_samples(float *output, int num_samples, HexWave *hex, float freq)
|
||||
{
|
||||
hexvert vert[9];
|
||||
int pass,i,j;
|
||||
float t = hex->t;
|
||||
float temp_output[2*STB_HEXWAVE_MAX_BLEP_LENGTH];
|
||||
int buffered_length = sizeof(float)*hexblep.width;
|
||||
float dt = (float) fabs(freq);
|
||||
float recip_dt = (dt == 0.0f) ? 0.0f : 1.0f / dt;
|
||||
|
||||
int halfw = hexblep.width/2;
|
||||
// all sample times are biased by halfw to leave room for BLEP/BLAMP to go back in time
|
||||
|
||||
if (num_samples <= 0)
|
||||
return;
|
||||
|
||||
// convert parameters to times and slopes
|
||||
hexwave_generate_linesegs(vert, hex, dt);
|
||||
|
||||
if (hex->prev_dt != dt) {
|
||||
// if frequency changes, add a fixup at the derivative discontinuity starting at now
|
||||
float slope;
|
||||
for (j=1; j < 6; ++j)
|
||||
if (t < vert[j].t)
|
||||
break;
|
||||
slope = vert[j].s;
|
||||
if (slope != 0)
|
||||
hex_blamp(output, 0, (dt - hex->prev_dt)*slope);
|
||||
hex->prev_dt = dt;
|
||||
}
|
||||
|
||||
// copy the buffered data from last call and clear the rest of the output array
|
||||
memset(output, 0, sizeof(float)*num_samples);
|
||||
memset(temp_output, 0, 2*hexblep.width*sizeof(float));
|
||||
|
||||
if (num_samples >= hexblep.width) {
|
||||
memcpy(output, hex->buffer, buffered_length);
|
||||
} else {
|
||||
// if the output is shorter than hexblep.width, we do all synthesis to temp_output
|
||||
memcpy(temp_output, hex->buffer, buffered_length);
|
||||
}
|
||||
|
||||
for (pass=0; pass < 2; ++pass) {
|
||||
int i0,i1;
|
||||
float *out;
|
||||
|
||||
// we want to simulate having one buffer that is num_output + hexblep.width
|
||||
// samples long, without putting that requirement on the user, and without
|
||||
// allocating a temp buffer that's as long as the whole thing. so we use two
|
||||
// overlapping buffers, one the user's buffer and one a fixed-length temp
|
||||
// buffer.
|
||||
|
||||
if (pass == 0) {
|
||||
if (num_samples < hexblep.width)
|
||||
continue;
|
||||
// run as far as we can without overwriting the end of the user's buffer
|
||||
out = output;
|
||||
i0 = 0;
|
||||
i1 = num_samples - hexblep.width;
|
||||
} else {
|
||||
// generate the rest into a temp buffer
|
||||
out = temp_output;
|
||||
i0 = 0;
|
||||
if (num_samples >= hexblep.width)
|
||||
i1 = hexblep.width;
|
||||
else
|
||||
i1 = num_samples;
|
||||
}
|
||||
|
||||
// determine current segment
|
||||
for (j=0; j < 8; ++j)
|
||||
if (t < vert[j+1].t)
|
||||
break;
|
||||
|
||||
i = i0;
|
||||
for(;;) {
|
||||
while (t < vert[j+1].t) {
|
||||
if (i == i1)
|
||||
goto done;
|
||||
out[i+halfw] += vert[j].v + vert[j].s*(t - vert[j].t);
|
||||
t += dt;
|
||||
++i;
|
||||
}
|
||||
// transition from lineseg starting at j to lineseg starting at j+1
|
||||
|
||||
if (vert[j].t == vert[j+1].t)
|
||||
hex_blep(out+i, recip_dt*(t-vert[j+1].t), (vert[j+1].v - vert[j].v));
|
||||
hex_blamp(out+i, recip_dt*(t-vert[j+1].t), dt*(vert[j+1].s - vert[j].s));
|
||||
++j;
|
||||
|
||||
if (j == 8) {
|
||||
// change to different waveform if there's a change pending
|
||||
j = 0;
|
||||
t -= 1.0; // t was >= 1.f if j==8
|
||||
if (hex->have_pending) {
|
||||
float prev_s0 = vert[j].s;
|
||||
float prev_v0 = vert[j].v;
|
||||
hex->current = hex->pending;
|
||||
hex->have_pending = 0;
|
||||
hexwave_generate_linesegs(vert, hex, dt);
|
||||
// the following never occurs with this oscillator, but it makes
|
||||
// the code work in more general cases
|
||||
if (vert[j].v != prev_v0)
|
||||
hex_blep (out+i, recip_dt*t, (vert[j].v - prev_v0));
|
||||
if (vert[j].s != prev_s0)
|
||||
hex_blamp(out+i, recip_dt*t, dt*(vert[j].s - prev_s0));
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
// at this point, we've written output[] and temp_output[]
|
||||
if (num_samples >= hexblep.width) {
|
||||
// the first half of temp[] overlaps the end of output, the second half will be the new start overlap
|
||||
for (i=0; i < hexblep.width; ++i)
|
||||
output[num_samples-hexblep.width + i] += temp_output[i];
|
||||
memcpy(hex->buffer, temp_output+hexblep.width, buffered_length);
|
||||
} else {
|
||||
for (i=0; i < num_samples; ++i)
|
||||
output[i] = temp_output[i];
|
||||
memcpy(hex->buffer, temp_output+num_samples, buffered_length);
|
||||
}
|
||||
|
||||
hex->t = t;
|
||||
}
|
||||
|
||||
STB_HEXWAVE_DEF void hexwave_shutdown(float *user_buffer)
|
||||
{
|
||||
#ifndef STB_HEXWAVE_NO_ALLOCATION
|
||||
if (user_buffer != 0) {
|
||||
free(hexblep.blep);
|
||||
free(hexblep.blamp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// buffer should be NULL or must be 4*(width*(oversample+1)*2 +
|
||||
STB_HEXWAVE_DEF void hexwave_init(int width, int oversample, float *user_buffer)
|
||||
{
|
||||
int halfwidth = width/2;
|
||||
int half = halfwidth*oversample;
|
||||
int blep_buffer_count = width*(oversample+1);
|
||||
int n = 2*half+1;
|
||||
#ifdef STB_HEXWAVE_NO_ALLOCATION
|
||||
float *buffers = user_buffer;
|
||||
#else
|
||||
float *buffers = user_buffer ? user_buffer : (float *) malloc(sizeof(float) * n * 2);
|
||||
#endif
|
||||
float *step = buffers+0*n;
|
||||
float *ramp = buffers+1*n;
|
||||
float *blep_buffer, *blamp_buffer;
|
||||
double integrate_impulse=0, integrate_step=0;
|
||||
int i,j;
|
||||
|
||||
if (width > STB_HEXWAVE_MAX_BLEP_LENGTH)
|
||||
width = STB_HEXWAVE_MAX_BLEP_LENGTH;
|
||||
|
||||
if (user_buffer == 0) {
|
||||
#ifndef STB_HEXWAVE_NO_ALLOCATION
|
||||
blep_buffer = (float *) malloc(sizeof(float)*blep_buffer_count);
|
||||
blamp_buffer = (float *) malloc(sizeof(float)*blep_buffer_count);
|
||||
#endif
|
||||
} else {
|
||||
blep_buffer = ramp+n;
|
||||
blamp_buffer = blep_buffer + blep_buffer_count;
|
||||
}
|
||||
|
||||
// compute BLEP and BLAMP by integerating windowed sinc
|
||||
for (i=0; i < n; ++i) {
|
||||
for (j=0; j < 16; ++j) {
|
||||
float sinc_t = 3.141592f* (i-half) / oversample;
|
||||
float sinc = (i==half) ? 1.0f : (float) sin(sinc_t) / (sinc_t);
|
||||
float wt = 2.0f*3.1415926f * i / (n-1);
|
||||
float window = (float) (0.355768 - 0.487396*cos(wt) + 0.144232*cos(2*wt) - 0.012604*cos(3*wt)); // Nuttall
|
||||
double value = window * sinc;
|
||||
integrate_impulse += value/16;
|
||||
integrate_step += integrate_impulse/16;
|
||||
}
|
||||
step[i] = (float) integrate_impulse;
|
||||
ramp[i] = (float) integrate_step;
|
||||
}
|
||||
|
||||
// renormalize
|
||||
for (i=0; i < n; ++i) {
|
||||
step[i] = step[i] * (float) (1.0 / step[n-1]); // step needs to reach to 1.0
|
||||
ramp[i] = ramp[i] * (float) (halfwidth / ramp[n-1]); // ramp needs to become a slope of 1.0 after oversampling
|
||||
}
|
||||
|
||||
// deinterleave to allow efficient interpolation e.g. w/SIMD
|
||||
for (j=0; j <= oversample; ++j) {
|
||||
for (i=0; i < width; ++i) {
|
||||
blep_buffer [j*width+i] = step[j+i*oversample];
|
||||
blamp_buffer[j*width+i] = ramp[j+i*oversample];
|
||||
}
|
||||
}
|
||||
|
||||
// subtract out the naive waveform; note we can't do this to the raw data
|
||||
// above, because we want the discontinuity to be in a different locations
|
||||
// for j=0 and j=oversample (which exists to provide something to interpolate against)
|
||||
for (j=0; j <= oversample; ++j) {
|
||||
// subtract step
|
||||
for (i=halfwidth; i < width; ++i)
|
||||
blep_buffer [j*width+i] -= 1.0f;
|
||||
// subtract ramp
|
||||
for (i=halfwidth; i < width; ++i)
|
||||
blamp_buffer[j*width+i] -= (j+i*oversample-half)*(1.0f/oversample);
|
||||
}
|
||||
|
||||
hexblep.blep = blep_buffer;
|
||||
hexblep.blamp = blamp_buffer;
|
||||
hexblep.width = width;
|
||||
hexblep.oversample = oversample;
|
||||
|
||||
#ifndef STB_HEXWAVE_NO_ALLOCATION
|
||||
if (user_buffer == 0)
|
||||
free(buffers);
|
||||
#endif
|
||||
}
|
||||
#endif // STB_HEXWAVE_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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
8033
raytracer/nvpro_core/third_party/stb/stb_image.h
vendored
Normal file
8033
raytracer/nvpro_core/third_party/stb/stb_image.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
10325
raytracer/nvpro_core/third_party/stb/stb_image_resize2.h
vendored
Normal file
10325
raytracer/nvpro_core/third_party/stb/stb_image_resize2.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
224
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/dotimings.c
vendored
Normal file
224
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/dotimings.c
vendored
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define stop() __debugbreak()
|
||||
#include <windows.h>
|
||||
#define int64 __int64
|
||||
#pragma warning(disable:4127)
|
||||
|
||||
#define get_milliseconds GetTickCount
|
||||
|
||||
#else
|
||||
|
||||
#define stop() __builtin_trap()
|
||||
#define int64 long long
|
||||
|
||||
typedef unsigned int U32;
|
||||
typedef unsigned long long U64;
|
||||
|
||||
#include <time.h>
|
||||
static int get_milliseconds()
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime( CLOCK_MONOTONIC, &ts );
|
||||
return (U32) ( ( ((U64)(U32)ts.tv_sec) * 1000LL ) + (U64)(((U32)ts.tv_nsec+500000)/1000000) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(TIME_SIMD)
|
||||
// default for most platforms
|
||||
#elif defined(TIME_SCALAR)
|
||||
#define STBIR_NO_SIMD
|
||||
#else
|
||||
#error You must define TIME_SIMD or TIME_SCALAR when compiling this file.
|
||||
#endif
|
||||
|
||||
#define STBIR_PROFILE
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#define STBIR__V_FIRST_INFO_BUFFER v_info
|
||||
#include "stb_image_resize2.h" // new one!
|
||||
|
||||
#if defined(TIME_SIMD) && !defined(STBIR_SIMD)
|
||||
#error Timing SIMD, but scalar was ON!
|
||||
#endif
|
||||
|
||||
#if defined(TIME_SCALAR) && defined(STBIR_SIMD)
|
||||
#error Timing scalar, but SIMD was ON!
|
||||
#endif
|
||||
|
||||
#define HEADER 32
|
||||
|
||||
|
||||
static int file_write( const char *filename, void * buffer, size_t size )
|
||||
{
|
||||
FILE * f = fopen( filename, "wb" );
|
||||
if ( f == 0 ) return 0;
|
||||
if ( fwrite( buffer, 1, size, f) != size ) return 0;
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int64 nresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt )
|
||||
{
|
||||
STBIR_RESIZE resize;
|
||||
int t;
|
||||
int64 b;
|
||||
|
||||
stbir_resize_init( &resize, i, ix, iy, ip, o, ox, oy, op, buf, type );
|
||||
stbir_set_edgemodes( &resize, edg, edg );
|
||||
stbir_set_filters( &resize, flt, flt );
|
||||
|
||||
stbir_build_samplers_with_splits( &resize, 1 );
|
||||
|
||||
b = 0x7fffffffffffffffULL;
|
||||
for( t = 0 ; t < 16 ; t++ )
|
||||
{
|
||||
STBIR_PROFILE_INFO profile;
|
||||
int64 v;
|
||||
if(!stbir_resize_extended( &resize ) )
|
||||
stop();
|
||||
stbir_resize_extended_profile_info( &profile, &resize );
|
||||
v = profile.clocks[1]+profile.clocks[2];
|
||||
if ( v < b )
|
||||
{
|
||||
b = v;
|
||||
t = 0;
|
||||
}
|
||||
}
|
||||
|
||||
stbir_free_samplers( &resize );
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
#define INSIZES 5
|
||||
#define TYPESCOUNT 5
|
||||
#define NUM 64
|
||||
|
||||
static const int sizes[INSIZES]={63,126,252,520,772};
|
||||
static const int types[TYPESCOUNT]={STBIR_1CHANNEL,STBIR_2CHANNEL,STBIR_RGB,STBIR_4CHANNEL,STBIR_RGBA};
|
||||
static const int effective[TYPESCOUNT]={1,2,3,4,7};
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
unsigned char * input;
|
||||
unsigned char * output;
|
||||
int dimensionx, dimensiony;
|
||||
int scalex, scaley;
|
||||
int totalms;
|
||||
int timing_count;
|
||||
int ir;
|
||||
int * file;
|
||||
int * ts;
|
||||
int64 totalcycles;
|
||||
|
||||
if ( argc != 6 )
|
||||
{
|
||||
printf("command: dotimings x_samps y_samps x_scale y_scale outfilename\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
input = malloc( 4*1200*1200 );
|
||||
memset( input, 0x80, 4*1200*1200 );
|
||||
output = malloc( 4*10000*10000ULL );
|
||||
|
||||
dimensionx = atoi( argv[1] );
|
||||
dimensiony = atoi( argv[2] );
|
||||
scalex = atoi( argv[3] );
|
||||
scaley = atoi( argv[4] );
|
||||
|
||||
timing_count = dimensionx * dimensiony * INSIZES * TYPESCOUNT;
|
||||
|
||||
file = malloc( sizeof(int) * ( 2 * timing_count + HEADER ) );
|
||||
ts = file + HEADER;
|
||||
|
||||
totalms = get_milliseconds();
|
||||
totalcycles = STBIR_PROFILE_FUNC();
|
||||
for( ir = 0 ; ir < INSIZES ; ir++ )
|
||||
{
|
||||
int ix, iy, ty;
|
||||
ix = iy = sizes[ir];
|
||||
|
||||
for( ty = 0 ; ty < TYPESCOUNT ; ty++ )
|
||||
{
|
||||
int h, hh;
|
||||
|
||||
h = 1;
|
||||
for( hh = 0 ; hh < dimensiony; hh++ )
|
||||
{
|
||||
int ww, w = 1;
|
||||
for( ww = 0 ; ww < dimensionx; ww++ )
|
||||
{
|
||||
int64 VF, HF;
|
||||
int good;
|
||||
|
||||
v_info.control_v_first = 2; // vertical first
|
||||
VF = nresize( output, w, h, (w*4*1)&~3, input, ix, iy, ix*4*1, types[ty], STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL );
|
||||
v_info.control_v_first = 1; // horizonal first
|
||||
HF = nresize( output, w, h, (w*4*1)&~3, input, ix, iy, ix*4*1, types[ty], STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL );
|
||||
|
||||
good = ( ((HF<=VF) && (!v_info.v_first)) || ((VF<=HF) && (v_info.v_first)));
|
||||
|
||||
// printf("\r%d,%d, %d,%d, %d, %I64d,%I64d, // Good: %c(%c-%d) CompEst: %.1f %.1f\n", ix, iy, w, h, ty, VF, HF, good?'y':'n', v_info.v_first?'v':'h', v_info.v_resize_classification, v_info.v_cost,v_info.h_cost );
|
||||
ts[0] = (int)VF;
|
||||
ts[1] = (int)HF;
|
||||
|
||||
ts += 2;
|
||||
|
||||
w += scalex;
|
||||
}
|
||||
printf(".");
|
||||
h += scaley;
|
||||
}
|
||||
}
|
||||
}
|
||||
totalms = get_milliseconds() - totalms;
|
||||
totalcycles = STBIR_PROFILE_FUNC() - totalcycles;
|
||||
|
||||
printf("\n");
|
||||
|
||||
file[0] = 'VFT1';
|
||||
|
||||
#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ )
|
||||
file[1] = 1; // x64
|
||||
#elif defined( _M_AMD64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__arm__) || defined( _M_ARM )
|
||||
file[1] = 2; // arm
|
||||
#else
|
||||
file[1] = 99; // who knows???
|
||||
#endif
|
||||
|
||||
#ifdef STBIR_SIMD8
|
||||
file[2] = 2; // simd-8
|
||||
#elif defined( STBIR_SIMD )
|
||||
file[2] = 1; // simd-4
|
||||
#else
|
||||
file[2] = 0; // nosimd
|
||||
#endif
|
||||
|
||||
file[3] = dimensionx; // dimx
|
||||
file[4] = dimensiony; // dimy
|
||||
file[5] = TYPESCOUNT; // channel types
|
||||
file[ 6] = types[0]; file[7] = types[1]; file[8] = types[2]; file[9] = types[3]; file[10] = types[4]; // buffer_type
|
||||
file[11] = effective[0]; file[12] = effective[1]; file[13] = effective[2]; file[14] = effective[3]; file[15] = effective[4]; // effective channels
|
||||
file[16] = INSIZES; // resizes
|
||||
file[17] = sizes[0]; file[18] = sizes[0]; // input sizes (w x h)
|
||||
file[19] = sizes[1]; file[20] = sizes[1];
|
||||
file[21] = sizes[2]; file[22] = sizes[2];
|
||||
file[23] = sizes[3]; file[24] = sizes[3];
|
||||
file[25] = sizes[4]; file[26] = sizes[4];
|
||||
file[27] = scalex; file[28] = scaley; // scale the dimx and dimy amount ( for(i=0;i<dimx) outputx = 1 + i*scalex; )
|
||||
file[29] = totalms;
|
||||
((int64*)(file+30))[0] = totalcycles;
|
||||
|
||||
if ( !file_write( argv[5], file, sizeof(int) * ( 2 * timing_count + HEADER ) ) )
|
||||
printf( "Error writing file: %s\n", argv[5] );
|
||||
else
|
||||
printf( "Successfully wrote timing file: %s\n", argv[5] );
|
||||
|
||||
return 0;
|
||||
}
|
||||
2738
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/old_image_resize.h
vendored
Normal file
2738
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/old_image_resize.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
56
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/oldir.c
vendored
Normal file
56
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/oldir.c
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define stop() __debugbreak()
|
||||
#else
|
||||
#define stop() __builtin_trap()
|
||||
#endif
|
||||
|
||||
//#define HEAVYTM
|
||||
#include "tm.h"
|
||||
|
||||
#define STBIR_SATURATE_INT
|
||||
#define STB_IMAGE_RESIZE_STATIC
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "old_image_resize.h"
|
||||
|
||||
|
||||
static int types[4] = { STBIR_TYPE_UINT8, STBIR_TYPE_UINT8, STBIR_TYPE_UINT16, STBIR_TYPE_FLOAT };
|
||||
static int edges[4] = { STBIR_EDGE_CLAMP, STBIR_EDGE_REFLECT, STBIR_EDGE_ZERO, STBIR_EDGE_WRAP };
|
||||
static int flts[5] = { STBIR_FILTER_BOX, STBIR_FILTER_TRIANGLE, STBIR_FILTER_CUBICBSPLINE, STBIR_FILTER_CATMULLROM, STBIR_FILTER_MITCHELL };
|
||||
static int channels[20] = { 1, 2, 3, 4, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2 };
|
||||
static int alphapos[20] = { -1, -1, -1, -1, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0 };
|
||||
|
||||
|
||||
void oresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt )
|
||||
{
|
||||
int t = types[type];
|
||||
int ic = channels[buf];
|
||||
int alpha = alphapos[buf];
|
||||
int e = edges[edg];
|
||||
int f = flts[flt];
|
||||
int space = ( type == 1 ) ? STBIR_COLORSPACE_SRGB : 0;
|
||||
int flags = ( buf >= 16 ) ? STBIR_FLAG_ALPHA_PREMULTIPLIED : ( ( buf >= 12 ) ? STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED : ( ( buf >= 8 ) ? (STBIR_FLAG_ALPHA_PREMULTIPLIED|STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED) : 0 ) );
|
||||
stbir_uint64 start;
|
||||
|
||||
ENTER( "Resize (old)" );
|
||||
start = tmGetAccumulationStart( tm_mask );
|
||||
|
||||
if(!stbir_resize( i, ix, iy, ip, o, ox, oy, op, t, ic, alpha, flags, e, e, f, f, space, 0 ) )
|
||||
stop();
|
||||
|
||||
#ifdef STBIR_PROFILE
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.setup, "Setup (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.filters, "Filters (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.looping, "Looping (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.vertical, "Vertical (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.horizontal, "Horizontal (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.decode, "Scanline input (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.encode, "Scanline output (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.alpha, "Alpha weighting (old)" );
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.unalpha, "Alpha unweighting (old)" );
|
||||
#endif
|
||||
|
||||
LEAVE();
|
||||
}
|
||||
992
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/stbirtest.c
vendored
Normal file
992
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/stbirtest.c
vendored
Normal file
|
|
@ -0,0 +1,992 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define HEAVYTM
|
||||
#include "tm.h"
|
||||
|
||||
#ifdef RADUSETM3
|
||||
tm_api * g_tm_api;
|
||||
//#define PROFILE_MODE
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define stop() __debugbreak()
|
||||
#include <windows.h>
|
||||
#define int64 __int64
|
||||
#define uint64 unsigned __int64
|
||||
#else
|
||||
#define stop() __builtin_trap()
|
||||
#define int64 long long
|
||||
#define uint64 unsigned long long
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
|
||||
//#define NOCOMP
|
||||
|
||||
|
||||
//#define PROFILE_NEW_ONLY
|
||||
//#define PROFILE_MODE
|
||||
|
||||
|
||||
#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ )
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
uint64 __rdtsc();
|
||||
#define __cycles() __rdtsc()
|
||||
|
||||
#else // non msvc
|
||||
|
||||
static inline uint64 __cycles()
|
||||
{
|
||||
unsigned int lo, hi;
|
||||
asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) );
|
||||
return ( ( (uint64) hi ) << 32 ) | ( (uint64) lo );
|
||||
}
|
||||
|
||||
#endif // msvc
|
||||
|
||||
#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define __cycles() _ReadStatusReg(ARM64_CNTVCT)
|
||||
|
||||
#else
|
||||
|
||||
static inline uint64 __cycles()
|
||||
{
|
||||
uint64 tsc;
|
||||
asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));
|
||||
return tsc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else // x64, arm
|
||||
|
||||
#error Unknown platform for timing.
|
||||
|
||||
#endif //x64 and
|
||||
|
||||
|
||||
#ifdef PROFILE_MODE
|
||||
|
||||
#define STBIR_ASSERT(cond)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#undef STBIR_ASSERT
|
||||
#define STBIR_ASSERT(cond) { if (!(cond)) stop(); }
|
||||
#endif
|
||||
|
||||
|
||||
#define SHRINKBYW 2
|
||||
#define ZOOMBYW 2
|
||||
#define SHRINKBYH 2
|
||||
#define ZOOMBYH 2
|
||||
|
||||
|
||||
int mem_count = 0;
|
||||
|
||||
#ifdef TEST_WITH_VALLOC
|
||||
|
||||
#define STBIR__SEPARATE_ALLOCATIONS
|
||||
|
||||
#if TEST_WITH_LIMIT_AT_FRONT
|
||||
|
||||
void * wmalloc(SIZE_T size)
|
||||
{
|
||||
static unsigned int pagesize=0;
|
||||
void* p;
|
||||
SIZE_T s;
|
||||
|
||||
// get the page size, if we haven't yet
|
||||
if (pagesize==0)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
pagesize=si.dwPageSize;
|
||||
}
|
||||
|
||||
// we need room for the size, 8 bytes to hide the original pointer and a
|
||||
// validation dword, and enough data to completely fill one page
|
||||
s=(size+(pagesize-1))&~(pagesize-1);
|
||||
|
||||
// allocate the size plus a page (for the guard)
|
||||
p=VirtualAlloc(0,(SIZE_T)s,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void wfree(void * ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
if ( ((ptrdiff_t)ptr) & 4095 ) stop();
|
||||
if ( VirtualFree(ptr,0,MEM_RELEASE) == 0 ) stop();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void * wmalloc(SIZE_T size)
|
||||
{
|
||||
static unsigned int pagesize=0;
|
||||
void* p;
|
||||
SIZE_T s;
|
||||
|
||||
// get the page size, if we haven't yet
|
||||
if (pagesize==0)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
pagesize=si.dwPageSize;
|
||||
}
|
||||
|
||||
// we need room for the size, 8 bytes to hide the original pointer and a
|
||||
// validation dword, and enough data to completely fill one page
|
||||
s=(size+16+(pagesize-1))&~(pagesize-1);
|
||||
|
||||
// allocate the size plus a page (for the guard)
|
||||
p=VirtualAlloc(0,(SIZE_T)(s+pagesize+pagesize),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
|
||||
|
||||
if (p)
|
||||
{
|
||||
DWORD oldprot;
|
||||
void* orig=p;
|
||||
|
||||
// protect the first page
|
||||
VirtualProtect(((char*)p),pagesize,PAGE_NOACCESS,&oldprot);
|
||||
|
||||
// protect the final page
|
||||
VirtualProtect(((char*)p)+s+pagesize,pagesize,PAGE_NOACCESS,&oldprot);
|
||||
|
||||
// now move the returned pointer so that it bumps right up against the
|
||||
// the next (protected) page (this may result in unaligned return
|
||||
// addresses - pre-align the sizes if you always want aligned ptrs)
|
||||
//#define ERROR_ON_FRONT
|
||||
#ifdef ERROR_ON_FRONT
|
||||
p=((char*)p)+pagesize+16;
|
||||
#else
|
||||
p=((char*)p)+(s-size)+pagesize;
|
||||
#endif
|
||||
|
||||
// hide the validation value and the original pointer (which we'll
|
||||
// need used for freeing) right behind the returned pointer
|
||||
((unsigned int*)p)[-1]=0x98765432;
|
||||
((void**)p)[-2]=orig;
|
||||
++mem_count;
|
||||
//printf("aloc: %p bytes: %d\n",p,(int)size);
|
||||
return(p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wfree(void * ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
int err=0;
|
||||
|
||||
// is this one of our allocations?
|
||||
if (((((unsigned int*)ptr)[-1])!=0x98765432) || ((((void**)ptr)[-2])==0))
|
||||
{
|
||||
err=1;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// back up to find the original pointer
|
||||
void* p=((void**)ptr)[-2];
|
||||
|
||||
// clear the validation value and the original pointer
|
||||
((unsigned int*)ptr)[-1]=0;
|
||||
((void**)ptr)[-2]=0;
|
||||
|
||||
//printf("free: %p\n",ptr);
|
||||
|
||||
--mem_count;
|
||||
|
||||
// now free the pages
|
||||
if (p)
|
||||
VirtualFree(p,0,MEM_RELEASE);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define STBIR_MALLOC(size,user_data) ((void)(user_data), wmalloc(size))
|
||||
#define STBIR_FREE(ptr,user_data) ((void)(user_data), wfree(ptr))
|
||||
|
||||
#endif
|
||||
|
||||
#define STBIR_PROFILE
|
||||
//#define STBIR_NO_SIMD
|
||||
//#define STBIR_AVX
|
||||
//#define STBIR_AVX2
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "stb_image_resize2.h" // new one!
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
int tsizes[5] = { 1, 1, 2, 4, 2 };
|
||||
int ttypes[5] = { STBIR_TYPE_UINT8, STBIR_TYPE_UINT8_SRGB, STBIR_TYPE_UINT16, STBIR_TYPE_FLOAT, STBIR_TYPE_HALF_FLOAT };
|
||||
|
||||
int cedges[4] = { STBIR_EDGE_CLAMP, STBIR_EDGE_REFLECT, STBIR_EDGE_ZERO, STBIR_EDGE_WRAP };
|
||||
int flts[5] = { STBIR_FILTER_BOX, STBIR_FILTER_TRIANGLE, STBIR_FILTER_CUBICBSPLINE, STBIR_FILTER_CATMULLROM, STBIR_FILTER_MITCHELL };
|
||||
int buffers[20] = { STBIR_1CHANNEL, STBIR_2CHANNEL, STBIR_RGB, STBIR_4CHANNEL,
|
||||
STBIR_BGRA, STBIR_ARGB, STBIR_RA, STBIR_AR,
|
||||
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
|
||||
STBIR_RGBA, STBIR_ARGB, STBIR_RA, STBIR_AR,
|
||||
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
|
||||
};
|
||||
int obuffers[20] = { STBIR_1CHANNEL, STBIR_2CHANNEL, STBIR_RGB, STBIR_4CHANNEL,
|
||||
STBIR_BGRA, STBIR_ARGB, STBIR_RA, STBIR_AR,
|
||||
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
|
||||
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
|
||||
STBIR_RGBA, STBIR_ARGB, STBIR_RA, STBIR_AR,
|
||||
};
|
||||
|
||||
int bchannels[20] = { 1, 2, 3, 4, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2 };
|
||||
int alphapos[20] = { -1, -1, -1, -1, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0,3,0, 1,0 };
|
||||
|
||||
|
||||
char const * buffstrs[20] = { "1ch", "2ch", "3ch", "4ch", "RGBA", "ARGB", "RA", "AR", "RGBA_both_pre", "ARGB_both_pre", "RA_both_pre", "AR_both_pre", "RGBA_out_pre", "ARGB_out_pre", "RA_out_pre", "AR_out_pre", "RGBA_in_pre", "ARGB_in_pre", "RA_in_pre", "AR_in_pre" };
|
||||
char const * typestrs[5] = { "Bytes", "BytesSRGB", "Shorts", "Floats", "Half Floats"};
|
||||
char const * edgestrs[4] = { "Clamp", "Reflect", "Zero", "Wrap" };
|
||||
char const * fltstrs[5] = { "Box", "Triangle", "Cubic", "Catmullrom", "Mitchell" };
|
||||
|
||||
#ifdef STBIR_PROFILE
|
||||
static void do_acc_zones( STBIR_PROFILE_INFO * profile )
|
||||
{
|
||||
stbir_uint32 j;
|
||||
stbir_uint64 start = tmGetAccumulationStart( tm_mask ); start=start;
|
||||
|
||||
for( j = 0 ; j < profile->count ; j++ )
|
||||
{
|
||||
if ( profile->clocks[j] )
|
||||
tmEmitAccumulationZone( 0, 0, (tm_uint64*)&start, 0, profile->clocks[j], profile->descriptions[j] );
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define do_acc_zones(...)
|
||||
#endif
|
||||
|
||||
int64 vert;
|
||||
|
||||
//#define WINTHREADTEST
|
||||
#ifdef WINTHREADTEST
|
||||
|
||||
static STBIR_RESIZE * thread_resize;
|
||||
static LONG which;
|
||||
static int threads_started = 0;
|
||||
static HANDLE threads[32];
|
||||
static HANDLE starts,stops;
|
||||
|
||||
static DWORD resize_shim( LPVOID p )
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
LONG wh;
|
||||
|
||||
WaitForSingleObject( starts, INFINITE );
|
||||
|
||||
wh = InterlockedAdd( &which, 1 ) - 1;
|
||||
|
||||
ENTER( "Split %d", wh );
|
||||
stbir_resize_split( thread_resize, wh, 1 );
|
||||
#ifdef STBIR_PROFILE
|
||||
{ STBIR_PROFILE_INFO profile; stbir_resize_split_profile_info( &profile, thread_resize, wh, 1 ); do_acc_zones( &profile ); vert = profile.clocks[1]; }
|
||||
#endif
|
||||
LEAVE();
|
||||
|
||||
ReleaseSemaphore( stops, 1, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void nresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt )
|
||||
{
|
||||
STBIR_RESIZE resize;
|
||||
|
||||
stbir_resize_init( &resize, i, ix, iy, ip, o, ox, oy, op, buffers[buf], ttypes[type] );
|
||||
stbir_set_pixel_layouts( &resize, buffers[buf], obuffers[buf] );
|
||||
stbir_set_edgemodes( &resize, cedges[edg], cedges[edg] );
|
||||
stbir_set_filters( &resize, flts[flt], /*STBIR_FILTER_POINT_SAMPLE */ flts[flt] );
|
||||
//stbir_set_input_subrect( &resize, 0.55f,0.333f,0.75f,0.50f);
|
||||
//stbir_set_output_pixel_subrect( &resize, 00, 00, ox/2,oy/2);
|
||||
//stbir_set_pixel_subrect(&resize, 1430,1361,30,30);
|
||||
|
||||
ENTER( "Resize" );
|
||||
|
||||
#ifndef WINTHREADTEST
|
||||
|
||||
ENTER( "Filters" );
|
||||
stbir_build_samplers_with_splits( &resize, 1 );
|
||||
#ifdef STBIR_PROFILE
|
||||
{ STBIR_PROFILE_INFO profile; stbir_resize_build_profile_info( &profile, &resize ); do_acc_zones( &profile ); }
|
||||
#endif
|
||||
LEAVE();
|
||||
|
||||
ENTER( "Resize" );
|
||||
if(!stbir_resize_extended( &resize ) )
|
||||
stop();
|
||||
#ifdef STBIR_PROFILE
|
||||
{ STBIR_PROFILE_INFO profile; stbir_resize_extended_profile_info( &profile, &resize ); do_acc_zones( &profile ); vert = profile.clocks[1]; }
|
||||
#endif
|
||||
LEAVE();
|
||||
|
||||
#else
|
||||
{
|
||||
int c, cnt;
|
||||
|
||||
ENTER( "Filters" );
|
||||
cnt = stbir_build_samplers_with_splits( &resize, 4 );
|
||||
#ifdef STBIR_PROFILE
|
||||
{ STBIR_PROFILE_INFO profile; stbir_resize_build_profile_info( &profile, &resize ); do_acc_zones( &profile ); }
|
||||
#endif
|
||||
LEAVE();
|
||||
|
||||
ENTER( "Thread start" );
|
||||
if ( threads_started == 0 )
|
||||
{
|
||||
starts = CreateSemaphore( 0, 0, 32, 0 );
|
||||
stops = CreateSemaphore( 0, 0, 32, 0 );
|
||||
}
|
||||
for( c = threads_started ; c < cnt ; c++ )
|
||||
threads[ c ] = CreateThread( 0, 2048*1024, resize_shim, 0, 0, 0 );
|
||||
|
||||
threads_started = cnt;
|
||||
thread_resize = &resize;
|
||||
which = 0;
|
||||
LEAVE();
|
||||
|
||||
// starts the threads
|
||||
ReleaseSemaphore( starts, cnt, 0 );
|
||||
|
||||
ENTER( "Wait" );
|
||||
for( c = 0 ; c < cnt; c++ )
|
||||
WaitForSingleObject( stops, INFINITE );
|
||||
LEAVE();
|
||||
}
|
||||
#endif
|
||||
|
||||
ENTER( "Free" );
|
||||
stbir_free_samplers( &resize );
|
||||
LEAVE();
|
||||
LEAVE();
|
||||
}
|
||||
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
extern void oresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt );
|
||||
|
||||
|
||||
|
||||
#define TYPESTART 0
|
||||
#define TYPEEND 4
|
||||
|
||||
#define LAYOUTSTART 0
|
||||
#define LAYOUTEND 19
|
||||
|
||||
#define SIZEWSTART 0
|
||||
#define SIZEWEND 2
|
||||
|
||||
#define SIZEHSTART 0
|
||||
#define SIZEHEND 2
|
||||
|
||||
#define EDGESTART 0
|
||||
#define EDGEEND 3
|
||||
|
||||
#define FILTERSTART 0
|
||||
#define FILTEREND 4
|
||||
|
||||
#define HEIGHTSTART 0
|
||||
#define HEIGHTEND 2
|
||||
|
||||
#define WIDTHSTART 0
|
||||
#define WIDTHEND 2
|
||||
|
||||
|
||||
|
||||
|
||||
static void * convert8to16( unsigned char * i, int w, int h, int c )
|
||||
{
|
||||
unsigned short * ret;
|
||||
int p;
|
||||
|
||||
ret = malloc( w*h*c*sizeof(short) );
|
||||
for(p = 0 ; p < (w*h*c) ; p++ )
|
||||
{
|
||||
ret[p]=(short)((((int)i[p])<<8)+i[p]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void * convert8tof( unsigned char * i, int w, int h, int c )
|
||||
{
|
||||
float * ret;
|
||||
int p;
|
||||
|
||||
ret = malloc( w*h*c*sizeof(float) );
|
||||
for(p = 0 ; p < (w*h*c) ; p++ )
|
||||
{
|
||||
ret[p]=((float)i[p])*(1.0f/255.0f);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void * convert8tohf( unsigned char * i, int w, int h, int c )
|
||||
{
|
||||
stbir__FP16 * ret;
|
||||
int p;
|
||||
|
||||
ret = malloc( w*h*c*sizeof(stbir__FP16) );
|
||||
for(p = 0 ; p < (w*h*c) ; p++ )
|
||||
{
|
||||
ret[p]=stbir__float_to_half(((float)i[p])*(1.0f/255.0f));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void * convert8tohff( unsigned char * i, int w, int h, int c )
|
||||
{
|
||||
float * ret;
|
||||
int p;
|
||||
|
||||
ret = malloc( w*h*c*sizeof(float) );
|
||||
for(p = 0 ; p < (w*h*c) ; p++ )
|
||||
{
|
||||
ret[p]=stbir__half_to_float(stbir__float_to_half(((float)i[p])*(1.0f/255.0f)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isprime( int v )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( v <= 3 )
|
||||
return ( v > 1 );
|
||||
if ( ( v & 1 ) == 0 )
|
||||
return 0;
|
||||
if ( ( v % 3 ) == 0 )
|
||||
return 0;
|
||||
i = 5;
|
||||
while ( (i*i) <= v )
|
||||
{
|
||||
if ( ( v % i ) == 0 )
|
||||
return 0;
|
||||
if ( ( v % ( i + 2 ) ) == 0 )
|
||||
return 0;
|
||||
i += 6;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getprime( int v )
|
||||
{
|
||||
int i;
|
||||
i = 0;
|
||||
for(;;)
|
||||
{
|
||||
if ( i >= v )
|
||||
return v; // can't find any, just return orig
|
||||
if (isprime(v - i))
|
||||
return v - i;
|
||||
if (isprime(v + i))
|
||||
return v + i;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
int ix, iy, ic;
|
||||
unsigned char * input[6];
|
||||
char * ir1;
|
||||
char * ir2;
|
||||
int szhs[3];
|
||||
int szws[3];
|
||||
int aw, ah, ac;
|
||||
unsigned char * correctalpha;
|
||||
int layouts, types, heights, widths, edges, filters;
|
||||
|
||||
if ( argc != 2 )
|
||||
{
|
||||
printf("command: stbirtest [imagefile]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SetupTM( "127.0.0.1" );
|
||||
|
||||
correctalpha = stbi_load( "correctalpha.png", &aw, &ah, &ac, 0 );
|
||||
|
||||
input[0] = stbi_load( argv[1], &ix, &iy, &ic, 0 );
|
||||
input[1] = input[0];
|
||||
input[2] = convert8to16( input[0], ix, iy, ic );
|
||||
input[3] = convert8tof( input[0], ix, iy, ic );
|
||||
input[4] = convert8tohf( input[0], ix, iy, ic );
|
||||
input[5] = convert8tohff( input[0], ix, iy, ic );
|
||||
|
||||
printf("Input %dx%d (%d channels)\n",ix,iy,ic);
|
||||
|
||||
ir1 = malloc( 4 * 4 * 3000 * 3000ULL );
|
||||
ir2 = malloc( 4 * 4 * 3000 * 3000ULL );
|
||||
|
||||
szhs[0] = getprime( iy/SHRINKBYH );
|
||||
szhs[1] = iy;
|
||||
szhs[2] = getprime( iy*ZOOMBYH );
|
||||
|
||||
szws[0] = getprime( ix/SHRINKBYW );
|
||||
szws[1] = ix;
|
||||
szws[2] = getprime( ix*ZOOMBYW );
|
||||
|
||||
#if 1
|
||||
for( types = TYPESTART ; types <= TYPEEND ; types++ )
|
||||
#else
|
||||
for( types = 1 ; types <= 1 ; types++ )
|
||||
#endif
|
||||
{
|
||||
ENTER( "Test type: %s",typestrs[types]);
|
||||
#if 1
|
||||
for( layouts = LAYOUTSTART ; layouts <= LAYOUTEND ; layouts++ )
|
||||
#else
|
||||
for( layouts = 16; layouts <= 16 ; layouts++ )
|
||||
#endif
|
||||
{
|
||||
ENTER( "Test layout: %s",buffstrs[layouts]);
|
||||
|
||||
#if 0
|
||||
for( heights = HEIGHTSTART ; heights <= HEIGHTEND ; heights++ )
|
||||
{
|
||||
int w, h = szhs[heights];
|
||||
#else
|
||||
for( heights = 0 ; heights <= 11 ; heights++ )
|
||||
{
|
||||
static int szhsz[12]={32, 200, 350, 400, 450, 509, 532, 624, 700, 824, 1023, 2053 };
|
||||
int w, h = szhsz[heights];
|
||||
#endif
|
||||
|
||||
ENTER( "Test height: %d %s %d",iy,(h<iy)?"Down":((h>iy)?"Up":"Same"),h);
|
||||
|
||||
#if 0
|
||||
for( widths = WIDTHSTART ; widths <= WIDTHEND ; widths++ )
|
||||
{
|
||||
w = szws[widths];
|
||||
#else
|
||||
for( widths = 0 ; widths <= 12 ; widths++ )
|
||||
{
|
||||
static int szwsz[13]={2, 32, 200, 350, 400, 450, 509, 532, 624, 700, 824, 1023, 2053 };
|
||||
w = szwsz[widths];
|
||||
#endif
|
||||
|
||||
ENTER( "Test width: %d %s %d",ix, (w<ix)?"Down":((w>ix)?"Up":"Same"), w);
|
||||
|
||||
#if 0
|
||||
for( edges = EDGESTART ; edges <= EDGEEND ; edges++ )
|
||||
#else
|
||||
for( edges = 0 ; edges <= 0 ; edges++ )
|
||||
#endif
|
||||
{
|
||||
ENTER( "Test edge: %s",edgestrs[edges]);
|
||||
#if 0
|
||||
for( filters = FILTERSTART ; filters <= FILTEREND ; filters++ )
|
||||
#else
|
||||
for( filters = 3 ; filters <= 3 ; filters++ )
|
||||
#endif
|
||||
{
|
||||
int op, opw, np,npw, c, a;
|
||||
#ifdef COMPARE_SAME
|
||||
int oldtypes = types;
|
||||
#else
|
||||
int oldtypes = (types==4)?3:types;
|
||||
#endif
|
||||
|
||||
ENTER( "Test filter: %s",fltstrs[filters]);
|
||||
{
|
||||
c = bchannels[layouts];
|
||||
a = alphapos[layouts];
|
||||
|
||||
op = w*tsizes[oldtypes]*c + 60;
|
||||
opw = w*tsizes[oldtypes]*c;
|
||||
|
||||
np = w*tsizes[types]*c + 60;
|
||||
npw = w*tsizes[types]*c;
|
||||
|
||||
printf( "%s:layout: %s w: %d h: %d edge: %s filt: %s\n", typestrs[types],buffstrs[layouts], w, h, edgestrs[edges], fltstrs[filters] );
|
||||
|
||||
|
||||
// clear pixel area to different, right edge to zero
|
||||
#ifndef NOCLEAR
|
||||
ENTER( "Test clear padding" );
|
||||
{
|
||||
int d;
|
||||
for( d = 0 ; d < h ; d++ )
|
||||
{
|
||||
int oofs = d * op;
|
||||
int nofs = d * np;
|
||||
memset( ir1 + oofs, 192, opw );
|
||||
memset( ir1 + oofs+opw, 79, op-opw );
|
||||
memset( ir2 + nofs, 255, npw );
|
||||
memset( ir2 + nofs+npw, 79, np-npw );
|
||||
}
|
||||
}
|
||||
LEAVE();
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef COMPARE_SAME
|
||||
#define TIMINGS 1
|
||||
#else
|
||||
#define TIMINGS 1
|
||||
#endif
|
||||
ENTER( "Test both" );
|
||||
{
|
||||
#ifndef PROFILE_NEW_ONLY
|
||||
{
|
||||
int ttt, max = 0x7fffffff;
|
||||
ENTER( "Test old" );
|
||||
for( ttt = 0 ; ttt < TIMINGS ; ttt++ )
|
||||
{
|
||||
int64 m = __cycles();
|
||||
|
||||
oresize( ir1, w, h, op,
|
||||
#ifdef COMPARE_SAME
|
||||
input[types],
|
||||
#else
|
||||
input[(types==4)?5:types],
|
||||
#endif
|
||||
ix, iy, ix*ic*tsizes[oldtypes], layouts, oldtypes, edges, filters );
|
||||
|
||||
m = __cycles() - m;
|
||||
if ( ( (int)m ) < max )
|
||||
max = (int) m;
|
||||
}
|
||||
LEAVE();
|
||||
printf("old: %d\n", max );
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
int ttt, max = 0x7fffffff, maxv = 0x7fffffff;
|
||||
ENTER( "Test new" );
|
||||
for( ttt = 0 ; ttt < TIMINGS ; ttt++ )
|
||||
{
|
||||
int64 m = __cycles();
|
||||
|
||||
nresize( ir2, w, h, np, input[types], ix, iy, ix*ic*tsizes[types], layouts, types, edges, filters );
|
||||
|
||||
m = __cycles() - m;
|
||||
if ( ( (int)m ) < max )
|
||||
max = (int) m;
|
||||
if ( ( (int)vert ) < maxv )
|
||||
maxv = (int) vert;
|
||||
}
|
||||
LEAVE(); // test new
|
||||
printf("new: %d (v: %d)\n", max, maxv );
|
||||
}
|
||||
}
|
||||
LEAVE(); // test both
|
||||
|
||||
if ( mem_count!= 0 )
|
||||
stop();
|
||||
|
||||
#ifndef NOCOMP
|
||||
ENTER( "Test compare" );
|
||||
{
|
||||
int x,y,ch;
|
||||
int nums = 0;
|
||||
for( y = 0 ; y < h ; y++ )
|
||||
{
|
||||
for( x = 0 ; x < w ; x++ )
|
||||
{
|
||||
switch(types)
|
||||
{
|
||||
case 0:
|
||||
case 1: //SRGB
|
||||
{
|
||||
unsigned char * p1 = (unsigned char *)&ir1[y*op+x*c];
|
||||
unsigned char * p2 = (unsigned char *)&ir2[y*np+x*c];
|
||||
for( ch = 0 ; ch < c ; ch++ )
|
||||
{
|
||||
float pp1,pp2,d;
|
||||
float av = (a==-1)?1.0f:((float)p1[a]/255.0f);
|
||||
|
||||
pp1 = p1[ch];
|
||||
pp2 = p2[ch];
|
||||
|
||||
// compare in premult space
|
||||
#ifndef COMPARE_SAME
|
||||
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >=16 ) && ( layouts <= 19 ) ) )
|
||||
{
|
||||
pp1 *= av;
|
||||
pp2 *= av;
|
||||
}
|
||||
#endif
|
||||
|
||||
d = pp1 - pp2;
|
||||
if ( d < 0 ) d = -d;
|
||||
|
||||
#ifdef COMPARE_SAME
|
||||
if ( d > 0 )
|
||||
#else
|
||||
if ( d > 1 )
|
||||
#endif
|
||||
{
|
||||
printf("Error at %d x %d (chan %d) (d: %g a: %g) [%d %d %d %d] [%d %d %d %d]\n",x,y,ch, d,av, p1[0],p1[1],p1[2],p1[3], p2[0],p2[1],p2[2],p2[3]);
|
||||
++nums;
|
||||
if ( nums > 16 ) goto ex;
|
||||
//if (d) exit(1);
|
||||
//goto ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
unsigned short * p1 = (unsigned short *)&ir1[y*op+x*c*sizeof(short)];
|
||||
unsigned short * p2 = (unsigned short *)&ir2[y*np+x*c*sizeof(short)];
|
||||
for( ch = 0 ; ch < c ; ch++ )
|
||||
{
|
||||
float thres,pp1,pp2,d;
|
||||
float av = (a==-1)?1.0f:((float)p1[a]/65535.0f);
|
||||
|
||||
pp1 = p1[ch];
|
||||
pp2 = p2[ch];
|
||||
|
||||
// compare in premult space
|
||||
#ifndef COMPARE_SAME
|
||||
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) )
|
||||
{
|
||||
pp1 *= av;
|
||||
pp2 *= av;
|
||||
}
|
||||
#endif
|
||||
|
||||
d = pp1 - pp2;
|
||||
if ( d < 0 ) d = -d;
|
||||
|
||||
thres=((float)p1[ch]*0.007f)+2.0f;
|
||||
if (thres<4) thres = 4;
|
||||
|
||||
#ifdef COMPARE_SAME
|
||||
if ( d > 0 )
|
||||
#else
|
||||
if ( d > thres)
|
||||
#endif
|
||||
{
|
||||
printf("Error at %d x %d (chan %d) %d %d [df: %g th: %g al: %g] (%d %d %d %d) (%d %d %d %d)\n",x,y,ch, p1[ch],p2[ch],d,thres,av,p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3]);
|
||||
++nums;
|
||||
if ( nums > 16 ) goto ex;
|
||||
//if (d) exit(1);
|
||||
//goto ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
float * p1 = (float *)&ir1[y*op+x*c*sizeof(float)];
|
||||
float * p2 = (float *)&ir2[y*np+x*c*sizeof(float)];
|
||||
for( ch = 0 ; ch < c ; ch++ )
|
||||
{
|
||||
float pp1 = p1[ch], pp2 = p2[ch];
|
||||
float av = (a==-1)?1.0f:p1[a];
|
||||
float thres, d;
|
||||
|
||||
// clamp
|
||||
if (pp1<=0.0f) pp1 = 0;
|
||||
if (pp2<=0.0f) pp2 = 0;
|
||||
if (av<=0.0f) av = 0;
|
||||
if (pp1>1.0f) pp1 = 1.0f;
|
||||
if (pp2>1.0f) pp2 = 1.0f;
|
||||
if (av>1.0f) av = 1.0f;
|
||||
|
||||
// compare in premult space
|
||||
#ifndef COMPARE_SAME
|
||||
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) )
|
||||
{
|
||||
pp1 *= av;
|
||||
pp2 *= av;
|
||||
}
|
||||
#endif
|
||||
|
||||
d = pp1 - pp2;
|
||||
if ( d < 0 ) d = -d;
|
||||
|
||||
thres=(p1[ch]*0.002f)+0.0002f;
|
||||
if ( thres < 0 ) thres = -thres;
|
||||
|
||||
#ifdef COMPARE_SAME
|
||||
if ( d != 0.0f )
|
||||
#else
|
||||
if ( d > thres )
|
||||
#endif
|
||||
{
|
||||
printf("Error at %d x %d (chan %d) %g %g [df: %g th: %g al: %g] (%g %g %g %g) (%g %g %g %g)\n",x,y,ch, p1[ch],p2[ch],d,thres,av,p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3]);
|
||||
++nums;
|
||||
if ( nums > 16 ) goto ex;
|
||||
//if (d) exit(1);
|
||||
//goto ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
#ifdef COMPARE_SAME
|
||||
stbir__FP16 * p1 = (stbir__FP16 *)&ir1[y*op+x*c*sizeof(stbir__FP16)];
|
||||
#else
|
||||
float * p1 = (float *)&ir1[y*op+x*c*sizeof(float)];
|
||||
#endif
|
||||
stbir__FP16 * p2 = (stbir__FP16 *)&ir2[y*np+x*c*sizeof(stbir__FP16)];
|
||||
for( ch = 0 ; ch < c ; ch++ )
|
||||
{
|
||||
#ifdef COMPARE_SAME
|
||||
float pp1 = stbir__half_to_float(p1[ch]);
|
||||
float av = (a==-1)?1.0f:stbir__half_to_float(p1[a]);
|
||||
#else
|
||||
float pp1 = stbir__half_to_float(stbir__float_to_half(p1[ch]));
|
||||
float av = (a==-1)?1.0f:stbir__half_to_float(stbir__float_to_half(p1[a]));
|
||||
#endif
|
||||
float pp2 = stbir__half_to_float(p2[ch]);
|
||||
float d, thres;
|
||||
|
||||
// clamp
|
||||
if (pp1<=0.0f) pp1 = 0;
|
||||
if (pp2<=0.0f) pp2 = 0;
|
||||
if (av<=0.0f) av = 0;
|
||||
if (pp1>1.0f) pp1 = 1.0f;
|
||||
if (pp2>1.0f) pp2 = 1.0f;
|
||||
if (av>1.0f) av = 1.0f;
|
||||
|
||||
thres=(pp1*0.002f)+0.0002f;
|
||||
|
||||
// compare in premult space
|
||||
#ifndef COMPARE_SAME
|
||||
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) )
|
||||
{
|
||||
pp1 *= av;
|
||||
pp2 *= av;
|
||||
}
|
||||
#endif
|
||||
|
||||
d = pp1 - pp2;
|
||||
if ( d < 0 ) d = -d;
|
||||
|
||||
|
||||
#ifdef COMPARE_SAME
|
||||
if ( d != 0.0f )
|
||||
#else
|
||||
if ( d > thres )
|
||||
#endif
|
||||
{
|
||||
printf("Error at %d x %d (chan %d) %g %g [df: %g th: %g al: %g] (%g %g %g %g) (%g %g %g %g)\n",x,y,ch,
|
||||
#ifdef COMPARE_SAME
|
||||
stbir__half_to_float(p1[ch]),
|
||||
#else
|
||||
p1[ch],
|
||||
#endif
|
||||
stbir__half_to_float(p2[ch]),
|
||||
d,thres,av,
|
||||
#ifdef COMPARE_SAME
|
||||
stbir__half_to_float(p1[0]),stbir__half_to_float(p1[1]),stbir__half_to_float(p1[2]),stbir__half_to_float(p1[3]),
|
||||
#else
|
||||
p1[0],p1[1],p1[2],p1[3],
|
||||
#endif
|
||||
stbir__half_to_float(p2[0]),stbir__half_to_float(p2[1]),stbir__half_to_float(p2[2]),stbir__half_to_float(p2[3]) );
|
||||
++nums;
|
||||
if ( nums > 16 ) goto ex;
|
||||
//if (d) exit(1);
|
||||
//goto ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( x = (w*c)*tsizes[oldtypes]; x < op; x++ )
|
||||
{
|
||||
if ( ir1[y*op+x] != 79 )
|
||||
{
|
||||
printf("Margin error at %d x %d %d (should be 79) OLD!\n",x,y,(unsigned char)ir1[y*op+x]);
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
|
||||
for( x = (w*c)*tsizes[types]; x < np; x++ )
|
||||
{
|
||||
if ( ir2[y*np+x] != 79 )
|
||||
{
|
||||
printf("Margin error at %d x %d %d (should be 79) NEW\n",x,y,(unsigned char)ir2[y*np+x]);
|
||||
goto ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ex:
|
||||
ENTER( "OUTPUT IMAGES" );
|
||||
printf(" tot pix: %d, errs: %d\n", w*h*c,nums );
|
||||
|
||||
if (nums)
|
||||
{
|
||||
stbi_write_png("old.png", w, h, c, ir1, op);
|
||||
stbi_write_png("new.png", w, h, c, ir2, np);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
LEAVE(); // output images
|
||||
}
|
||||
LEAVE(); //test compare
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
LEAVE(); // test filter
|
||||
}
|
||||
LEAVE(); // test edge
|
||||
}
|
||||
LEAVE(); // test width
|
||||
}
|
||||
LEAVE(); // test height
|
||||
}
|
||||
LEAVE(); // test type
|
||||
}
|
||||
LEAVE(); // test layout
|
||||
}
|
||||
|
||||
CloseTM();
|
||||
return 0;
|
||||
}
|
||||
999
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/vf_train.c
vendored
Normal file
999
raytracer/nvpro_core/third_party/stb/stb_image_resize_test/vf_train.c
vendored
Normal file
|
|
@ -0,0 +1,999 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define stop() __debugbreak()
|
||||
#include <windows.h>
|
||||
#define int64 __int64
|
||||
|
||||
#pragma warning(disable:4127)
|
||||
|
||||
#define STBIR__WEIGHT_TABLES
|
||||
#define STBIR_PROFILE
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "stb_image_resize2.h"
|
||||
|
||||
static int * file_read( char const * filename )
|
||||
{
|
||||
size_t s;
|
||||
int * m;
|
||||
FILE * f = fopen( filename, "rb" );
|
||||
if ( f == 0 ) return 0;
|
||||
|
||||
fseek( f, 0, SEEK_END);
|
||||
s = ftell( f );
|
||||
fseek( f, 0, SEEK_SET);
|
||||
m = malloc( s + 4 );
|
||||
m[0] = (int)s;
|
||||
fread( m+1, 1, s, f);
|
||||
fclose(f);
|
||||
|
||||
return( m );
|
||||
}
|
||||
|
||||
typedef struct fileinfo
|
||||
{
|
||||
int * timings;
|
||||
int timing_count;
|
||||
int dimensionx, dimensiony;
|
||||
int numtypes;
|
||||
int * types;
|
||||
int * effective;
|
||||
int cpu;
|
||||
int simd;
|
||||
int numinputrects;
|
||||
int * inputrects;
|
||||
int outputscalex, outputscaley;
|
||||
int milliseconds;
|
||||
int64 cycles;
|
||||
double scale_time;
|
||||
int bitmapx, bitmapy;
|
||||
char const * filename;
|
||||
} fileinfo;
|
||||
|
||||
int numfileinfo;
|
||||
fileinfo fi[256];
|
||||
unsigned char * bitmap;
|
||||
int bitmapw, bitmaph, bitmapp;
|
||||
|
||||
static int use_timing_file( char const * filename, int index )
|
||||
{
|
||||
int * base = file_read( filename );
|
||||
int * file = base;
|
||||
|
||||
if ( base == 0 ) return 0;
|
||||
|
||||
++file; // skip file image size;
|
||||
if ( *file++ != 'VFT1' ) return 0;
|
||||
fi[index].cpu = *file++;
|
||||
fi[index].simd = *file++;
|
||||
fi[index].dimensionx = *file++;
|
||||
fi[index].dimensiony = *file++;
|
||||
fi[index].numtypes = *file++;
|
||||
fi[index].types = file; file += fi[index].numtypes;
|
||||
fi[index].effective = file; file += fi[index].numtypes;
|
||||
fi[index].numinputrects = *file++;
|
||||
fi[index].inputrects = file; file += fi[index].numinputrects * 2;
|
||||
fi[index].outputscalex = *file++;
|
||||
fi[index].outputscaley = *file++;
|
||||
fi[index].milliseconds = *file++;
|
||||
fi[index].cycles = ((int64*)file)[0]; file += 2;
|
||||
fi[index].filename = filename;
|
||||
|
||||
fi[index].timings = file;
|
||||
fi[index].timing_count = (int) ( ( base[0] - ( ((char*)file - (char*)base - sizeof(int) ) ) ) / (sizeof(int)*2) );
|
||||
|
||||
fi[index].scale_time = (double)fi[index].milliseconds / (double)fi[index].cycles;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vert_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int ox, int oy, int ix, int iy, int filter, STBIR__V_FIRST_INFO * v_info )
|
||||
{
|
||||
float h_scale=(float)ox/(float)(ix);
|
||||
float v_scale=(float)oy/(float)(iy);
|
||||
stbir__support_callback * support = stbir__builtin_supports[filter];
|
||||
int vertical_filter_width = stbir__get_filter_pixel_width(support,v_scale,0);
|
||||
int vertical_gather = ( v_scale >= ( 1.0f - stbir__small_float ) ) || ( vertical_filter_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT );
|
||||
|
||||
return stbir__should_do_vertical_first( weights_table, stbir__get_filter_pixel_width(support,h_scale,0), h_scale, ox, vertical_filter_width, v_scale, oy, vertical_gather, v_info );
|
||||
}
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
static void alloc_bitmap()
|
||||
{
|
||||
int findex;
|
||||
int x = 0, y = 0;
|
||||
int w = 0, h = 0;
|
||||
|
||||
for( findex = 0 ; findex < numfileinfo ; findex++ )
|
||||
{
|
||||
int nx, ny;
|
||||
int thisw, thish;
|
||||
|
||||
thisw = ( fi[findex].dimensionx * fi[findex].numtypes ) + ( fi[findex].numtypes - 1 );
|
||||
thish = ( fi[findex].dimensiony * fi[findex].numinputrects ) + ( fi[findex].numinputrects - 1 );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
nx = x + ((x)?4:0) + thisw;
|
||||
ny = y + ((y)?4:0) + thish;
|
||||
if ( ( nx <= 3600 ) || ( x == 0 ) )
|
||||
{
|
||||
fi[findex].bitmapx = x + ((x)?4:0);
|
||||
fi[findex].bitmapy = y + ((y)?4:0);
|
||||
x = nx;
|
||||
if ( x > w ) w = x;
|
||||
if ( ny > h ) h = ny;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0;
|
||||
y = h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w = (w+3) & ~3;
|
||||
bitmapw = w;
|
||||
bitmaph = h;
|
||||
bitmapp = w * 3; // RGB
|
||||
bitmap = malloc( bitmapp * bitmaph );
|
||||
|
||||
memset( bitmap, 0, bitmapp * bitmaph );
|
||||
}
|
||||
|
||||
static void build_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index, int findex )
|
||||
{
|
||||
static int colors[STBIR_RESIZE_CLASSIFICATIONS];
|
||||
STBIR__V_FIRST_INFO v_info = {0};
|
||||
|
||||
int * ts;
|
||||
int ir;
|
||||
unsigned char * bitm = bitmap + ( fi[findex].bitmapx*3 ) + ( fi[findex].bitmapy*bitmapp) ;
|
||||
|
||||
for( ir = 0; ir < STBIR_RESIZE_CLASSIFICATIONS ; ir++ ) colors[ ir ] = 127*ir/STBIR_RESIZE_CLASSIFICATIONS+128;
|
||||
|
||||
ts = fi[findex].timings;
|
||||
|
||||
for( ir = 0 ; ir < fi[findex].numinputrects ; ir++ )
|
||||
{
|
||||
int ix, iy, chanind;
|
||||
ix = fi[findex].inputrects[ir*2];
|
||||
iy = fi[findex].inputrects[ir*2+1];
|
||||
|
||||
for( chanind = 0 ; chanind < fi[findex].numtypes ; chanind++ )
|
||||
{
|
||||
int ofs, h, hh;
|
||||
|
||||
// just do the type that we're on
|
||||
if ( chanind != do_channel_count_index )
|
||||
{
|
||||
ts += 2 * fi[findex].dimensionx * fi[findex].dimensiony;
|
||||
continue;
|
||||
}
|
||||
|
||||
// bitmap offset
|
||||
ofs=chanind*(fi[findex].dimensionx+1)*3+ir*(fi[findex].dimensiony+1)*bitmapp;
|
||||
|
||||
h = 1;
|
||||
for( hh = 0 ; hh < fi[findex].dimensiony; hh++ )
|
||||
{
|
||||
int ww, w = 1;
|
||||
for( ww = 0 ; ww < fi[findex].dimensionx; ww++ )
|
||||
{
|
||||
int good, v_first, VF, HF;
|
||||
|
||||
VF = ts[0];
|
||||
HF = ts[1];
|
||||
|
||||
v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
|
||||
|
||||
good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first)));
|
||||
|
||||
if ( good )
|
||||
{
|
||||
bitm[ofs+2] = 0;
|
||||
bitm[ofs+1] = (unsigned char)colors[v_info.v_resize_classification];
|
||||
}
|
||||
else
|
||||
{
|
||||
double r;
|
||||
|
||||
if ( HF < VF )
|
||||
r = (double)(VF-HF)/(double)HF;
|
||||
else
|
||||
r = (double)(HF-VF)/(double)VF;
|
||||
|
||||
if ( r > 0.4f) r = 0.4;
|
||||
r *= 1.0f/0.4f;
|
||||
|
||||
bitm[ofs+2] = (char)(255.0f*r);
|
||||
bitm[ofs+1] = (char)(((float)colors[v_info.v_resize_classification])*(1.0f-r));
|
||||
}
|
||||
bitm[ofs] = 0;
|
||||
|
||||
ofs += 3;
|
||||
ts += 2;
|
||||
w += fi[findex].outputscalex;
|
||||
}
|
||||
ofs += bitmapp - fi[findex].dimensionx*3;
|
||||
h += fi[findex].outputscaley;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void build_comp_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index )
|
||||
{
|
||||
int * ts0;
|
||||
int * ts1;
|
||||
int ir;
|
||||
unsigned char * bitm = bitmap + ( fi[0].bitmapx*3 ) + ( fi[0].bitmapy*bitmapp) ;
|
||||
|
||||
ts0 = fi[0].timings;
|
||||
ts1 = fi[1].timings;
|
||||
|
||||
for( ir = 0 ; ir < fi[0].numinputrects ; ir++ )
|
||||
{
|
||||
int ix, iy, chanind;
|
||||
ix = fi[0].inputrects[ir*2];
|
||||
iy = fi[0].inputrects[ir*2+1];
|
||||
|
||||
for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ )
|
||||
{
|
||||
int ofs, h, hh;
|
||||
|
||||
// just do the type that we're on
|
||||
if ( chanind != do_channel_count_index )
|
||||
{
|
||||
ts0 += 2 * fi[0].dimensionx * fi[0].dimensiony;
|
||||
ts1 += 2 * fi[0].dimensionx * fi[0].dimensiony;
|
||||
continue;
|
||||
}
|
||||
|
||||
// bitmap offset
|
||||
ofs=chanind*(fi[0].dimensionx+1)*3+ir*(fi[0].dimensiony+1)*bitmapp;
|
||||
|
||||
h = 1;
|
||||
for( hh = 0 ; hh < fi[0].dimensiony; hh++ )
|
||||
{
|
||||
int ww, w = 1;
|
||||
for( ww = 0 ; ww < fi[0].dimensionx; ww++ )
|
||||
{
|
||||
int v_first, time0, time1;
|
||||
|
||||
v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, 0 );
|
||||
|
||||
time0 = ( v_first ) ? ts0[0] : ts0[1];
|
||||
time1 = ( v_first ) ? ts1[0] : ts1[1];
|
||||
|
||||
if ( time0 < time1 )
|
||||
{
|
||||
double r = (double)(time1-time0)/(double)time0;
|
||||
if ( r > 0.4f) r = 0.4;
|
||||
r *= 1.0f/0.4f;
|
||||
bitm[ofs+2] = 0;
|
||||
bitm[ofs+1] = (char)(255.0f*r);
|
||||
bitm[ofs] = (char)(64.0f*(1.0f-r));
|
||||
}
|
||||
else
|
||||
{
|
||||
double r = (double)(time0-time1)/(double)time1;
|
||||
if ( r > 0.4f) r = 0.4;
|
||||
r *= 1.0f/0.4f;
|
||||
bitm[ofs+2] = (char)(255.0f*r);
|
||||
bitm[ofs+1] = 0;
|
||||
bitm[ofs] = (char)(64.0f*(1.0f-r));
|
||||
}
|
||||
ofs += 3;
|
||||
ts0 += 2;
|
||||
ts1 += 2;
|
||||
w += fi[0].outputscalex;
|
||||
}
|
||||
ofs += bitmapp - fi[0].dimensionx*3;
|
||||
h += fi[0].outputscaley;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_bitmap()
|
||||
{
|
||||
stbi_write_png( "results.png", bitmapp / 3, bitmaph, 3|STB_IMAGE_BGR, bitmap, bitmapp );
|
||||
}
|
||||
|
||||
|
||||
static void calc_errors( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int * curtot, double * curerr, int do_channel_count_index )
|
||||
{
|
||||
int th, findex;
|
||||
STBIR__V_FIRST_INFO v_info = {0};
|
||||
|
||||
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
|
||||
{
|
||||
curerr[th]=0;
|
||||
curtot[th]=0;
|
||||
}
|
||||
|
||||
for( findex = 0 ; findex < numfileinfo ; findex++ )
|
||||
{
|
||||
int * ts;
|
||||
int ir;
|
||||
ts = fi[findex].timings;
|
||||
|
||||
for( ir = 0 ; ir < fi[findex].numinputrects ; ir++ )
|
||||
{
|
||||
int ix, iy, chanind;
|
||||
ix = fi[findex].inputrects[ir*2];
|
||||
iy = fi[findex].inputrects[ir*2+1];
|
||||
|
||||
for( chanind = 0 ; chanind < fi[findex].numtypes ; chanind++ )
|
||||
{
|
||||
int h, hh;
|
||||
|
||||
// just do the type that we're on
|
||||
if ( chanind != do_channel_count_index )
|
||||
{
|
||||
ts += 2 * fi[findex].dimensionx * fi[findex].dimensiony;
|
||||
continue;
|
||||
}
|
||||
|
||||
h = 1;
|
||||
for( hh = 0 ; hh < fi[findex].dimensiony; hh++ )
|
||||
{
|
||||
int ww, w = 1;
|
||||
for( ww = 0 ; ww < fi[findex].dimensionx; ww++ )
|
||||
{
|
||||
int good, v_first, VF, HF;
|
||||
|
||||
VF = ts[0];
|
||||
HF = ts[1];
|
||||
|
||||
v_first = vert_first( weights_table, w, h, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
|
||||
|
||||
good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first)));
|
||||
|
||||
if ( !good )
|
||||
{
|
||||
double diff;
|
||||
if ( VF < HF )
|
||||
diff = ((double)HF-(double)VF) * fi[findex].scale_time;
|
||||
else
|
||||
diff = ((double)VF-(double)HF) * fi[findex].scale_time;
|
||||
|
||||
curtot[v_info.v_resize_classification] += 1;
|
||||
curerr[v_info.v_resize_classification] += diff;
|
||||
}
|
||||
|
||||
ts += 2;
|
||||
w += fi[findex].outputscalex;
|
||||
}
|
||||
h += fi[findex].outputscaley;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define TRIESPERWEIGHT 32
|
||||
#define MAXRANGE ((TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) - 1)
|
||||
|
||||
static void expand_to_floats( float * weights, int range )
|
||||
{
|
||||
weights[0] = (float)( range % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
|
||||
weights[1] = (float)( range/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
|
||||
weights[2] = (float)( range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
|
||||
weights[3] = (float)( range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
|
||||
}
|
||||
|
||||
static char const * expand_to_string( int range )
|
||||
{
|
||||
static char str[128];
|
||||
int w0,w1,w2,w3;
|
||||
w0 = range % (TRIESPERWEIGHT+1);
|
||||
w1 = range/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1);
|
||||
w2 = range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1);
|
||||
w3 = range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1);
|
||||
sprintf( str, "[ %2d/%d %2d/%d %2d/%d %2d/%d ]",w0,TRIESPERWEIGHT,w1,TRIESPERWEIGHT,w2,TRIESPERWEIGHT,w3,TRIESPERWEIGHT );
|
||||
return str;
|
||||
}
|
||||
|
||||
static void print_weights( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int channel_count_index, int * tots, double * errs )
|
||||
{
|
||||
int th;
|
||||
printf("ChInd: %d Weights:\n",channel_count_index);
|
||||
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
|
||||
{
|
||||
float * w = weights[th];
|
||||
printf(" %d: [%1.5f %1.5f %1.5f %1.5f] (%d %.4f)\n",th, w[0], w[1], w[2], w[3], tots[th], errs[th] );
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int windowranges[ 16 ];
|
||||
static int windowstatus = 0;
|
||||
static DWORD trainstart = 0;
|
||||
|
||||
static void opt_channel( float best_output_weights[STBIR_RESIZE_CLASSIFICATIONS][4], int channel_count_index )
|
||||
{
|
||||
int newbest = 0;
|
||||
float weights[STBIR_RESIZE_CLASSIFICATIONS][4] = {0};
|
||||
double besterr[STBIR_RESIZE_CLASSIFICATIONS];
|
||||
int besttot[STBIR_RESIZE_CLASSIFICATIONS];
|
||||
int best[STBIR_RESIZE_CLASSIFICATIONS]={0};
|
||||
|
||||
double curerr[STBIR_RESIZE_CLASSIFICATIONS];
|
||||
int curtot[STBIR_RESIZE_CLASSIFICATIONS];
|
||||
int th, range;
|
||||
DWORD lasttick = 0;
|
||||
|
||||
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
|
||||
{
|
||||
besterr[th]=1000000000000.0;
|
||||
besttot[th]=0x7fffffff;
|
||||
}
|
||||
|
||||
newbest = 0;
|
||||
|
||||
// try the whole range
|
||||
range = MAXRANGE;
|
||||
do
|
||||
{
|
||||
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
|
||||
expand_to_floats( weights[th], range );
|
||||
|
||||
calc_errors( weights, curtot, curerr, channel_count_index );
|
||||
|
||||
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
|
||||
{
|
||||
if ( curerr[th] < besterr[th] )
|
||||
{
|
||||
besterr[th] = curerr[th];
|
||||
besttot[th] = curtot[th];
|
||||
best[th] = range;
|
||||
expand_to_floats( best_output_weights[th], best[th] );
|
||||
newbest = 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
DWORD t = GetTickCount();
|
||||
if ( range == 0 )
|
||||
goto do_bitmap;
|
||||
|
||||
if ( newbest )
|
||||
{
|
||||
if ( ( GetTickCount() - lasttick ) > 200 )
|
||||
{
|
||||
int findex;
|
||||
|
||||
do_bitmap:
|
||||
lasttick = t;
|
||||
newbest = 0;
|
||||
|
||||
for( findex = 0 ; findex < numfileinfo ; findex++ )
|
||||
build_bitmap( best_output_weights, channel_count_index, findex );
|
||||
|
||||
lasttick = GetTickCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
windowranges[ channel_count_index ] = range;
|
||||
|
||||
// advance all the weights and loop
|
||||
--range;
|
||||
} while( ( range >= 0 ) && ( !windowstatus ) );
|
||||
|
||||
// if we hit here, then we tried all weights for this opt, so save them
|
||||
}
|
||||
|
||||
static void print_struct( float weight[5][STBIR_RESIZE_CLASSIFICATIONS][4], char const * name )
|
||||
{
|
||||
printf("\n\nstatic float %s[5][STBIR_RESIZE_CLASSIFICATIONS][4]=\n{", name );
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<5;i++)
|
||||
{
|
||||
int th;
|
||||
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
|
||||
{
|
||||
int j;
|
||||
printf("\n ");
|
||||
for(j=0;j<4;j++)
|
||||
printf("%1.5ff, ", weight[i][th][j] );
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n};\n");
|
||||
}
|
||||
}
|
||||
|
||||
static float retrain_weights[5][STBIR_RESIZE_CLASSIFICATIONS][4];
|
||||
|
||||
static DWORD __stdcall retrain_shim( LPVOID p )
|
||||
{
|
||||
int chanind = (int) (size_t)p;
|
||||
opt_channel( retrain_weights[chanind], chanind );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char const * gettime( int ms )
|
||||
{
|
||||
static char time[32];
|
||||
if (ms > 60000)
|
||||
sprintf( time, "%dm %ds",ms/60000, (ms/1000)%60 );
|
||||
else
|
||||
sprintf( time, "%ds",ms/1000 );
|
||||
return time;
|
||||
}
|
||||
|
||||
static BITMAPINFOHEADER bmiHeader;
|
||||
static DWORD extrawindoww, extrawindowh;
|
||||
static HINSTANCE instance;
|
||||
static int curzoom = 1;
|
||||
|
||||
static LRESULT WINAPI WindowProc( HWND window,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam )
|
||||
{
|
||||
switch( message )
|
||||
{
|
||||
case WM_CHAR:
|
||||
if ( wparam != 27 )
|
||||
break;
|
||||
// falls through
|
||||
|
||||
case WM_CLOSE:
|
||||
{
|
||||
int i;
|
||||
int max = 0;
|
||||
|
||||
for( i = 0 ; i < fi[0].numtypes ; i++ )
|
||||
if( windowranges[i] > max ) max = windowranges[i];
|
||||
|
||||
if ( ( max == 0 ) || ( MessageBox( window, "Cancel before training is finished?", "Vertical First Training", MB_OKCANCEL|MB_ICONSTOP ) == IDOK ) )
|
||||
{
|
||||
for( i = 0 ; i < fi[0].numtypes ; i++ )
|
||||
if( windowranges[i] > max ) max = windowranges[i];
|
||||
if ( max )
|
||||
windowstatus = 1;
|
||||
DestroyWindow( window );
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC dc;
|
||||
|
||||
dc = BeginPaint( window, &ps );
|
||||
StretchDIBits( dc,
|
||||
0, 0, bitmapw*curzoom, bitmaph*curzoom,
|
||||
0, 0, bitmapw, bitmaph,
|
||||
bitmap, (BITMAPINFO*)&bmiHeader, DIB_RGB_COLORS, SRCCOPY );
|
||||
|
||||
PatBlt( dc, bitmapw*curzoom, 0, 4096, 4096, WHITENESS );
|
||||
PatBlt( dc, 0, bitmaph*curzoom, 4096, 4096, WHITENESS );
|
||||
|
||||
SetTextColor( dc, RGB(0,0,0) );
|
||||
SetBkColor( dc, RGB(255,255,255) );
|
||||
SetBkMode( dc, OPAQUE );
|
||||
|
||||
{
|
||||
int i, l = 0, max = 0;
|
||||
char buf[1024];
|
||||
RECT rc;
|
||||
POINT p;
|
||||
|
||||
for( i = 0 ; i < fi[0].numtypes ; i++ )
|
||||
{
|
||||
l += sprintf( buf + l, "channels: %d %s\n", fi[0].effective[i], windowranges[i] ? expand_to_string( windowranges[i] ) : "Done." );
|
||||
if ( windowranges[i] > max ) max = windowranges[i];
|
||||
}
|
||||
|
||||
rc.left = 32; rc.top = bitmaph*curzoom+10;
|
||||
rc.right = 512; rc.bottom = rc.top + 512;
|
||||
DrawText( dc, buf, -1, &rc, DT_TOP );
|
||||
|
||||
l = 0;
|
||||
if ( max == 0 )
|
||||
{
|
||||
static DWORD traindone = 0;
|
||||
if ( traindone == 0 ) traindone = GetTickCount();
|
||||
l = sprintf( buf, "Finished in %s.", gettime( traindone - trainstart ) );
|
||||
}
|
||||
else if ( max != MAXRANGE )
|
||||
l = sprintf( buf, "Done in %s...", gettime( (int) ( ( ( (int64)max * ( (int64)GetTickCount() - (int64)trainstart ) ) ) / (int64) ( MAXRANGE - max ) ) ) );
|
||||
|
||||
GetCursorPos( &p );
|
||||
ScreenToClient( window, &p );
|
||||
|
||||
if ( ( p.x >= 0 ) && ( p.y >= 0 ) && ( p.x < (bitmapw*curzoom) ) && ( p.y < (bitmaph*curzoom) ) )
|
||||
{
|
||||
int findex;
|
||||
int x, y, w, h, sx, sy, ix, iy, ox, oy;
|
||||
int ir, chanind;
|
||||
int * ts;
|
||||
char badstr[64];
|
||||
STBIR__V_FIRST_INFO v_info={0};
|
||||
|
||||
p.x /= curzoom;
|
||||
p.y /= curzoom;
|
||||
|
||||
for( findex = 0 ; findex < numfileinfo ; findex++ )
|
||||
{
|
||||
x = fi[findex].bitmapx;
|
||||
y = fi[findex].bitmapy;
|
||||
w = x + ( fi[findex].dimensionx + 1 ) * fi[findex].numtypes;
|
||||
h = y + ( fi[findex].dimensiony + 1 ) * fi[findex].numinputrects;
|
||||
|
||||
if ( ( p.x >= x ) && ( p.y >= y ) && ( p.x < w ) && ( p.y < h ) )
|
||||
goto found;
|
||||
}
|
||||
goto nope;
|
||||
|
||||
found:
|
||||
|
||||
ir = ( p.y - y ) / ( fi[findex].dimensiony + 1 );
|
||||
sy = ( p.y - y ) % ( fi[findex].dimensiony + 1 );
|
||||
if ( sy >= fi[findex].dimensiony ) goto nope;
|
||||
|
||||
chanind = ( p.x - x ) / ( fi[findex].dimensionx + 1 );
|
||||
sx = ( p.x - x ) % ( fi[findex].dimensionx + 1 );
|
||||
if ( sx >= fi[findex].dimensionx ) goto nope;
|
||||
|
||||
ix = fi[findex].inputrects[ir*2];
|
||||
iy = fi[findex].inputrects[ir*2+1];
|
||||
|
||||
ts = fi[findex].timings + ( ( fi[findex].dimensionx * fi[findex].dimensiony * fi[findex].numtypes * ir ) + ( fi[findex].dimensionx * fi[findex].dimensiony * chanind ) + ( fi[findex].dimensionx * sy ) + sx ) * 2;
|
||||
|
||||
ox = 1+fi[findex].outputscalex*sx;
|
||||
oy = 1+fi[findex].outputscaley*sy;
|
||||
|
||||
if ( windowstatus != 2 )
|
||||
{
|
||||
int VF, HF, v_first, good;
|
||||
VF = ts[0];
|
||||
HF = ts[1];
|
||||
|
||||
v_first = vert_first( retrain_weights[chanind], ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
|
||||
|
||||
good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first)));
|
||||
|
||||
if ( good )
|
||||
badstr[0] = 0;
|
||||
else
|
||||
{
|
||||
double r;
|
||||
|
||||
if ( HF < VF )
|
||||
r = (double)(VF-HF)/(double)HF;
|
||||
else
|
||||
r = (double)(HF-VF)/(double)VF;
|
||||
sprintf( badstr, " %.1f%% off", r*100 );
|
||||
}
|
||||
sprintf( buf + l, "\n\n%s\nCh: %d Resize: %dx%d to %dx%d\nV: %d H: %d Order: %c (%s%s)\nClass: %d Scale: %.2f %s", fi[findex].filename,fi[findex].effective[chanind], ix,iy,ox,oy, VF, HF, v_first?'V':'H', good?"Good":"Wrong", badstr, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter" );
|
||||
}
|
||||
else
|
||||
{
|
||||
int v_first, time0, time1;
|
||||
float (* weights)[4] = stbir__compute_weights[chanind];
|
||||
int * ts1;
|
||||
char b0[32], b1[32];
|
||||
|
||||
ts1 = fi[1].timings + ( ts - fi[0].timings );
|
||||
|
||||
v_first = vert_first( weights, ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
|
||||
|
||||
time0 = ( v_first ) ? ts[0] : ts[1];
|
||||
time1 = ( v_first ) ? ts1[0] : ts1[1];
|
||||
|
||||
b0[0] = b1[0] = 0;
|
||||
if ( time0 < time1 )
|
||||
sprintf( b0," (%.f%% better)", ((double)time1-(double)time0)*100.0f/(double)time0);
|
||||
else
|
||||
sprintf( b1," (%.f%% better)", ((double)time0-(double)time1)*100.0f/(double)time1);
|
||||
|
||||
sprintf( buf + l, "\n\n0: %s\n1: %s\nCh: %d Resize: %dx%d to %dx%d\nClass: %d Scale: %.2f %s\nTime0: %d%s\nTime1: %d%s", fi[0].filename, fi[1].filename, fi[0].effective[chanind], ix,iy,ox,oy, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter", time0, b0, time1, b1 );
|
||||
}
|
||||
}
|
||||
nope:
|
||||
|
||||
rc.left = 32+320; rc.right = 512+320;
|
||||
SetTextColor( dc, RGB(0,0,128) );
|
||||
DrawText( dc, buf, -1, &rc, DT_TOP );
|
||||
|
||||
}
|
||||
EndPaint( window, &ps );
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_TIMER:
|
||||
InvalidateRect( window, 0, 0 );
|
||||
return 0;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return DefWindowProc( window, message, wparam, lparam );
|
||||
}
|
||||
|
||||
static void SetHighDPI(void)
|
||||
{
|
||||
typedef HRESULT WINAPI setdpitype(int v);
|
||||
HMODULE h=LoadLibrary("Shcore.dll");
|
||||
if (h)
|
||||
{
|
||||
setdpitype * sd = (setdpitype*)GetProcAddress(h,"SetProcessDpiAwareness");
|
||||
if (sd )
|
||||
sd(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_window()
|
||||
{
|
||||
WNDCLASS wc;
|
||||
HWND w;
|
||||
MSG msg;
|
||||
|
||||
instance = GetModuleHandle(NULL);
|
||||
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = WindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = instance;
|
||||
wc.hIcon = 0;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = 0;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.lpszClassName = "WHTrain";
|
||||
|
||||
if ( !RegisterClass( &wc ) )
|
||||
exit(1);
|
||||
|
||||
SetHighDPI();
|
||||
|
||||
bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmiHeader.biWidth = bitmapp/3;
|
||||
bmiHeader.biHeight = -bitmaph;
|
||||
bmiHeader.biPlanes = 1;
|
||||
bmiHeader.biBitCount = 24;
|
||||
bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
w = CreateWindow( "WHTrain",
|
||||
"Vertical First Training",
|
||||
WS_CAPTION | WS_POPUP| WS_CLIPCHILDREN |
|
||||
WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX,
|
||||
CW_USEDEFAULT,CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,CW_USEDEFAULT,
|
||||
0, 0, instance, 0 );
|
||||
|
||||
{
|
||||
RECT r, c;
|
||||
GetWindowRect( w, &r );
|
||||
GetClientRect( w, &c );
|
||||
extrawindoww = ( r.right - r.left ) - ( c.right - c.left );
|
||||
extrawindowh = ( r.bottom - r.top ) - ( c.bottom - c.top );
|
||||
SetWindowPos( w, 0, 0, 0, bitmapw * curzoom + extrawindoww, bitmaph * curzoom + extrawindowh + 164, SWP_NOMOVE );
|
||||
}
|
||||
|
||||
ShowWindow( w, SW_SHOWNORMAL );
|
||||
SetTimer( w, 1, 250, 0 );
|
||||
|
||||
{
|
||||
BOOL ret;
|
||||
while( ( ret = GetMessage( &msg, w, 0, 0 ) ) != 0 )
|
||||
{
|
||||
if ( ret == -1 )
|
||||
break;
|
||||
TranslateMessage( &msg );
|
||||
DispatchMessage( &msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void retrain()
|
||||
{
|
||||
HANDLE threads[ 16 ];
|
||||
int chanind;
|
||||
|
||||
trainstart = GetTickCount();
|
||||
for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ )
|
||||
threads[ chanind ] = CreateThread( 0, 2048*1024, retrain_shim, (LPVOID)(size_t)chanind, 0, 0 );
|
||||
|
||||
draw_window();
|
||||
|
||||
for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ )
|
||||
{
|
||||
WaitForSingleObject( threads[ chanind ], INFINITE );
|
||||
CloseHandle( threads[ chanind ] );
|
||||
}
|
||||
|
||||
write_bitmap();
|
||||
|
||||
print_struct( retrain_weights, "retained_weights" );
|
||||
if ( windowstatus ) printf( "CANCELLED!\n" );
|
||||
}
|
||||
|
||||
static void info()
|
||||
{
|
||||
int findex;
|
||||
|
||||
// display info about each input file
|
||||
for( findex = 0 ; findex < numfileinfo ; findex++ )
|
||||
{
|
||||
int i, h,m,s;
|
||||
if ( findex ) printf( "\n" );
|
||||
printf( "Timing file: %s\n", fi[findex].filename );
|
||||
printf( "CPU type: %d %s\n", fi[findex].cpu, fi[findex].simd?(fi[findex].simd==2?"SIMD8":"SIMD4"):"Scalar" );
|
||||
h = fi[findex].milliseconds/3600000;
|
||||
m = (fi[findex].milliseconds-h*3600000)/60000;
|
||||
s = (fi[findex].milliseconds-h*3600000-m*60000)/1000;
|
||||
printf( "Total time in test: %dh %dm %ds Cycles/sec: %.f\n", h,m,s, 1000.0/fi[findex].scale_time );
|
||||
printf( "Each tile of samples is %dx%d, and is scaled by %dx%d.\n", fi[findex].dimensionx,fi[findex].dimensiony, fi[findex].outputscalex,fi[findex].outputscaley );
|
||||
printf( "So the x coords are: " );
|
||||
for( i=0; i < fi[findex].dimensionx ; i++ ) printf( "%d ",1+i*fi[findex].outputscalex );
|
||||
printf( "\n" );
|
||||
printf( "And the y coords are: " );
|
||||
for( i=0; i < fi[findex].dimensiony ; i++ ) printf( "%d ",1+i*fi[findex].outputscaley );
|
||||
printf( "\n" );
|
||||
printf( "There are %d channel counts and they are: ", fi[findex].numtypes );
|
||||
for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%d ",fi[findex].effective[i] );
|
||||
printf( "\n" );
|
||||
printf( "There are %d input rect sizes and they are: ", fi[findex].numinputrects );
|
||||
for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%dx%d ",fi[findex].inputrects[i*2],fi[findex].inputrects[i*2+1] );
|
||||
printf( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
static void current( int do_win, int do_bitmap )
|
||||
{
|
||||
int i, findex;
|
||||
|
||||
trainstart = GetTickCount();
|
||||
|
||||
// clear progress
|
||||
memset( windowranges, 0, sizeof( windowranges ) );
|
||||
// copy in appropriate weights
|
||||
memcpy( retrain_weights, stbir__compute_weights, sizeof( retrain_weights ) );
|
||||
|
||||
// build and print current errors and build current bitmap
|
||||
for( i = 0 ; i < fi[0].numtypes ; i++ )
|
||||
{
|
||||
double curerr[STBIR_RESIZE_CLASSIFICATIONS];
|
||||
int curtot[STBIR_RESIZE_CLASSIFICATIONS];
|
||||
float (* weights)[4] = retrain_weights[i];
|
||||
|
||||
calc_errors( weights, curtot, curerr, i );
|
||||
if ( !do_bitmap )
|
||||
print_weights( weights, i, curtot, curerr );
|
||||
|
||||
for( findex = 0 ; findex < numfileinfo ; findex++ )
|
||||
build_bitmap( weights, i, findex );
|
||||
}
|
||||
|
||||
if ( do_win )
|
||||
draw_window();
|
||||
|
||||
if ( do_bitmap )
|
||||
write_bitmap();
|
||||
}
|
||||
|
||||
static void compare()
|
||||
{
|
||||
int i;
|
||||
|
||||
trainstart = GetTickCount();
|
||||
windowstatus = 2; // comp mode
|
||||
|
||||
// clear progress
|
||||
memset( windowranges, 0, sizeof( windowranges ) );
|
||||
|
||||
if ( ( fi[0].numtypes != fi[1].numtypes ) || ( fi[0].numinputrects != fi[1].numinputrects ) ||
|
||||
( fi[0].dimensionx != fi[1].dimensionx ) || ( fi[0].dimensiony != fi[1].dimensiony ) ||
|
||||
( fi[0].outputscalex != fi[1].outputscalex ) || ( fi[0].outputscaley != fi[1].outputscaley ) )
|
||||
{
|
||||
err:
|
||||
printf( "Timing files don't match.\n" );
|
||||
exit(5);
|
||||
}
|
||||
|
||||
for( i=0; i < fi[0].numtypes ; i++ )
|
||||
{
|
||||
if ( fi[0].effective[i] != fi[1].effective[i] ) goto err;
|
||||
if ( fi[0].inputrects[i*2] != fi[1].inputrects[i*2] ) goto err;
|
||||
if ( fi[0].inputrects[i*2+1] != fi[1].inputrects[i*2+1] ) goto err;
|
||||
}
|
||||
|
||||
alloc_bitmap( 1 );
|
||||
|
||||
for( i = 0 ; i < fi[0].numtypes ; i++ )
|
||||
{
|
||||
float (* weights)[4] = stbir__compute_weights[i];
|
||||
build_comp_bitmap( weights, i );
|
||||
}
|
||||
|
||||
draw_window();
|
||||
}
|
||||
|
||||
static void load_files( char ** args, int count )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( count == 0 )
|
||||
{
|
||||
printf( "No timing files listed!" );
|
||||
exit(3);
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < count ; i++ )
|
||||
{
|
||||
if ( !use_timing_file( args[i], i ) )
|
||||
{
|
||||
printf( "Bad timing file %s\n", args[i] );
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
numfileinfo = count;
|
||||
}
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
int check;
|
||||
if ( argc < 3 )
|
||||
{
|
||||
err:
|
||||
printf( "vf_train retrain [timing_filenames....] - recalcs weights for all the files on the command line.\n");
|
||||
printf( "vf_train info [timing_filenames....] - shows info about each timing file.\n");
|
||||
printf( "vf_train check [timing_filenames...] - show results for the current weights for all files listed.\n");
|
||||
printf( "vf_train compare <timing file1> <timing file2> - compare two timing files (must only be two files and same resolution).\n");
|
||||
printf( "vf_train bitmap [timing_filenames...] - write out results.png, comparing against the current weights for all files listed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
check = ( strcmp( argv[1], "check" ) == 0 );
|
||||
if ( ( check ) || ( strcmp( argv[1], "bitmap" ) == 0 ) )
|
||||
{
|
||||
load_files( argv + 2, argc - 2 );
|
||||
alloc_bitmap( numfileinfo );
|
||||
current( check, !check );
|
||||
}
|
||||
else if ( strcmp( argv[1], "info" ) == 0 )
|
||||
{
|
||||
load_files( argv + 2, argc - 2 );
|
||||
info();
|
||||
}
|
||||
else if ( strcmp( argv[1], "compare" ) == 0 )
|
||||
{
|
||||
if ( argc != 4 )
|
||||
{
|
||||
printf( "You must specify two files to compare.\n" );
|
||||
exit(4);
|
||||
}
|
||||
|
||||
load_files( argv + 2, argc - 2 );
|
||||
compare();
|
||||
}
|
||||
else if ( strcmp( argv[1], "retrain" ) == 0 )
|
||||
{
|
||||
load_files( argv + 2, argc - 2 );
|
||||
alloc_bitmap( numfileinfo );
|
||||
retrain();
|
||||
}
|
||||
else
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1724
raytracer/nvpro_core/third_party/stb/stb_image_write.h
vendored
Normal file
1724
raytracer/nvpro_core/third_party/stb/stb_image_write.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
295
raytracer/nvpro_core/third_party/stb/stb_include.h
vendored
Normal file
295
raytracer/nvpro_core/third_party/stb/stb_include.h
vendored
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
// stb_include.h - v0.02 - parse and process #include directives - public domain
|
||||
//
|
||||
// To build this, in one source file that includes this file do
|
||||
// #define STB_INCLUDE_IMPLEMENTATION
|
||||
//
|
||||
// This program parses a string and replaces lines of the form
|
||||
// #include "foo"
|
||||
// with the contents of a file named "foo". It also embeds the
|
||||
// appropriate #line directives. Note that all include files must
|
||||
// reside in the location specified in the path passed to the API;
|
||||
// it does not check multiple directories.
|
||||
//
|
||||
// If the string contains a line of the form
|
||||
// #inject
|
||||
// then it will be replaced with the contents of the string 'inject' passed to the API.
|
||||
//
|
||||
// Options:
|
||||
//
|
||||
// Define STB_INCLUDE_LINE_GLSL to get GLSL-style #line directives
|
||||
// which use numbers instead of filenames.
|
||||
//
|
||||
// Define STB_INCLUDE_LINE_NONE to disable output of #line directives.
|
||||
//
|
||||
// Standard libraries:
|
||||
//
|
||||
// stdio.h FILE, fopen, fclose, fseek, ftell
|
||||
// stdlib.h malloc, realloc, free
|
||||
// string.h strcpy, strncmp, memcpy
|
||||
//
|
||||
// Credits:
|
||||
//
|
||||
// Written by Sean Barrett.
|
||||
//
|
||||
// Fixes:
|
||||
// Michal Klos
|
||||
|
||||
#ifndef STB_INCLUDE_STB_INCLUDE_H
|
||||
#define STB_INCLUDE_STB_INCLUDE_H
|
||||
|
||||
// Do include-processing on the string 'str'. To free the return value, pass it to free()
|
||||
char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]);
|
||||
|
||||
// Concatenate the strings 'strs' and do include-processing on the result. To free the return value, pass it to free()
|
||||
char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename_for_line_directive, char error[256]);
|
||||
|
||||
// Load the file 'filename' and do include-processing on the string therein. note that
|
||||
// 'filename' is opened directly; 'path_to_includes' is not used. To free the return value, pass it to free()
|
||||
char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256]);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef STB_INCLUDE_IMPLEMENTATION
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static char *stb_include_load_file(char *filename, size_t *plen)
|
||||
{
|
||||
char *text;
|
||||
size_t len;
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (f == 0) return 0;
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = (size_t) ftell(f);
|
||||
if (plen) *plen = len;
|
||||
text = (char *) malloc(len+1);
|
||||
if (text == 0) return 0;
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(text, 1, len, f);
|
||||
fclose(f);
|
||||
text[len] = 0;
|
||||
return text;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int offset;
|
||||
int end;
|
||||
char *filename;
|
||||
int next_line_after;
|
||||
} include_info;
|
||||
|
||||
static include_info *stb_include_append_include(include_info *array, int len, int offset, int end, char *filename, int next_line)
|
||||
{
|
||||
include_info *z = (include_info *) realloc(array, sizeof(*z) * (len+1));
|
||||
z[len].offset = offset;
|
||||
z[len].end = end;
|
||||
z[len].filename = filename;
|
||||
z[len].next_line_after = next_line;
|
||||
return z;
|
||||
}
|
||||
|
||||
static void stb_include_free_includes(include_info *array, int len)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < len; ++i)
|
||||
free(array[i].filename);
|
||||
free(array);
|
||||
}
|
||||
|
||||
static int stb_include_isspace(int ch)
|
||||
{
|
||||
return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
|
||||
}
|
||||
|
||||
// find location of all #include and #inject
|
||||
static int stb_include_find_includes(char *text, include_info **plist)
|
||||
{
|
||||
int line_count = 1;
|
||||
int inc_count = 0;
|
||||
char *s = text, *start;
|
||||
include_info *list = NULL;
|
||||
while (*s) {
|
||||
// parse is always at start of line when we reach here
|
||||
start = s;
|
||||
while (*s == ' ' || *s == '\t')
|
||||
++s;
|
||||
if (*s == '#') {
|
||||
++s;
|
||||
while (*s == ' ' || *s == '\t')
|
||||
++s;
|
||||
if (0==strncmp(s, "include", 7) && stb_include_isspace(s[7])) {
|
||||
s += 7;
|
||||
while (*s == ' ' || *s == '\t')
|
||||
++s;
|
||||
if (*s == '"') {
|
||||
char *t = ++s;
|
||||
while (*t != '"' && *t != '\n' && *t != '\r' && *t != 0)
|
||||
++t;
|
||||
if (*t == '"') {
|
||||
char *filename = (char *) malloc(t-s+1);
|
||||
memcpy(filename, s, t-s);
|
||||
filename[t-s] = 0;
|
||||
s=t;
|
||||
while (*s != '\r' && *s != '\n' && *s != 0)
|
||||
++s;
|
||||
// s points to the newline, so s-start is everything except the newline
|
||||
list = stb_include_append_include(list, inc_count++, start-text, s-text, filename, line_count+1);
|
||||
}
|
||||
}
|
||||
} else if (0==strncmp(s, "inject", 6) && (stb_include_isspace(s[6]) || s[6]==0)) {
|
||||
while (*s != '\r' && *s != '\n' && *s != 0)
|
||||
++s;
|
||||
list = stb_include_append_include(list, inc_count++, start-text, s-text, NULL, line_count+1);
|
||||
}
|
||||
}
|
||||
while (*s != '\r' && *s != '\n' && *s != 0)
|
||||
++s;
|
||||
if (*s == '\r' || *s == '\n') {
|
||||
s = s + (s[0] + s[1] == '\r' + '\n' ? 2 : 1);
|
||||
}
|
||||
++line_count;
|
||||
}
|
||||
*plist = list;
|
||||
return inc_count;
|
||||
}
|
||||
|
||||
// avoid dependency on sprintf()
|
||||
static void stb_include_itoa(char str[9], int n)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < 8; ++i)
|
||||
str[i] = ' ';
|
||||
str[i] = 0;
|
||||
|
||||
for (i=1; i < 8; ++i) {
|
||||
str[7-i] = '0' + (n % 10);
|
||||
n /= 10;
|
||||
if (n == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *stb_include_append(char *str, size_t *curlen, char *addstr, size_t addlen)
|
||||
{
|
||||
str = (char *) realloc(str, *curlen + addlen);
|
||||
memcpy(str + *curlen, addstr, addlen);
|
||||
*curlen += addlen;
|
||||
return str;
|
||||
}
|
||||
|
||||
char *stb_include_string(char *str, char *inject, char *path_to_includes, char *filename, char error[256])
|
||||
{
|
||||
char temp[4096];
|
||||
include_info *inc_list;
|
||||
int i, num = stb_include_find_includes(str, &inc_list);
|
||||
size_t source_len = strlen(str);
|
||||
char *text=0;
|
||||
size_t textlen=0, last=0;
|
||||
for (i=0; i < num; ++i) {
|
||||
text = stb_include_append(text, &textlen, str+last, inc_list[i].offset - last);
|
||||
// write out line directive for the include
|
||||
#ifndef STB_INCLUDE_LINE_NONE
|
||||
#ifdef STB_INCLUDE_LINE_GLSL
|
||||
if (textlen != 0) // GLSL #version must appear first, so don't put a #line at the top
|
||||
#endif
|
||||
{
|
||||
strcpy(temp, "#line ");
|
||||
stb_include_itoa(temp+6, 1);
|
||||
strcat(temp, " ");
|
||||
#ifdef STB_INCLUDE_LINE_GLSL
|
||||
stb_include_itoa(temp+15, i+1);
|
||||
#else
|
||||
strcat(temp, "\"");
|
||||
if (inc_list[i].filename == 0)
|
||||
strcmp(temp, "INJECT");
|
||||
else
|
||||
strcat(temp, inc_list[i].filename);
|
||||
strcat(temp, "\"");
|
||||
#endif
|
||||
strcat(temp, "\n");
|
||||
text = stb_include_append(text, &textlen, temp, strlen(temp));
|
||||
}
|
||||
#endif
|
||||
if (inc_list[i].filename == 0) {
|
||||
if (inject != 0)
|
||||
text = stb_include_append(text, &textlen, inject, strlen(inject));
|
||||
} else {
|
||||
char *inc;
|
||||
strcpy(temp, path_to_includes);
|
||||
strcat(temp, "/");
|
||||
strcat(temp, inc_list[i].filename);
|
||||
inc = stb_include_file(temp, inject, path_to_includes, error);
|
||||
if (inc == NULL) {
|
||||
stb_include_free_includes(inc_list, num);
|
||||
return NULL;
|
||||
}
|
||||
text = stb_include_append(text, &textlen, inc, strlen(inc));
|
||||
free(inc);
|
||||
}
|
||||
// write out line directive
|
||||
#ifndef STB_INCLUDE_LINE_NONE
|
||||
strcpy(temp, "\n#line ");
|
||||
stb_include_itoa(temp+6, inc_list[i].next_line_after);
|
||||
strcat(temp, " ");
|
||||
#ifdef STB_INCLUDE_LINE_GLSL
|
||||
stb_include_itoa(temp+15, 0);
|
||||
#else
|
||||
strcat(temp, filename != 0 ? filename : "source-file");
|
||||
#endif
|
||||
text = stb_include_append(text, &textlen, temp, strlen(temp));
|
||||
// no newlines, because we kept the #include newlines, which will get appended next
|
||||
#endif
|
||||
last = inc_list[i].end;
|
||||
}
|
||||
text = stb_include_append(text, &textlen, str+last, source_len - last + 1); // append '\0'
|
||||
stb_include_free_includes(inc_list, num);
|
||||
return text;
|
||||
}
|
||||
|
||||
char *stb_include_strings(char **strs, int count, char *inject, char *path_to_includes, char *filename, char error[256])
|
||||
{
|
||||
char *text;
|
||||
char *result;
|
||||
int i;
|
||||
size_t length=0;
|
||||
for (i=0; i < count; ++i)
|
||||
length += strlen(strs[i]);
|
||||
text = (char *) malloc(length+1);
|
||||
length = 0;
|
||||
for (i=0; i < count; ++i) {
|
||||
strcpy(text + length, strs[i]);
|
||||
length += strlen(strs[i]);
|
||||
}
|
||||
result = stb_include_string(text, inject, path_to_includes, filename, error);
|
||||
free(text);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *stb_include_file(char *filename, char *inject, char *path_to_includes, char error[256])
|
||||
{
|
||||
size_t len;
|
||||
char *result;
|
||||
char *text = stb_include_load_file(filename, &len);
|
||||
if (text == NULL) {
|
||||
strcpy(error, "Error: couldn't load '");
|
||||
strcat(error, filename);
|
||||
strcat(error, "'");
|
||||
return 0;
|
||||
}
|
||||
result = stb_include_string(text, inject, path_to_includes, filename, error);
|
||||
free(text);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0 // @TODO, GL_ARB_shader_language_include-style system that doesn't touch filesystem
|
||||
char *stb_include_preloaded(char *str, char *inject, char *includes[][2], char error[256])
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // STB_INCLUDE_IMPLEMENTATION
|
||||
194
raytracer/nvpro_core/third_party/stb/stb_leakcheck.h
vendored
Normal file
194
raytracer/nvpro_core/third_party/stb/stb_leakcheck.h
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
// stb_leakcheck.h - v0.6 - quick & dirty malloc leak-checking - public domain
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file.
|
||||
|
||||
#ifdef STB_LEAKCHECK_IMPLEMENTATION
|
||||
#undef STB_LEAKCHECK_IMPLEMENTATION // don't implement more than once
|
||||
|
||||
// if we've already included leakcheck before, undefine the macros
|
||||
#ifdef malloc
|
||||
#undef malloc
|
||||
#undef free
|
||||
#undef realloc
|
||||
#endif
|
||||
|
||||
#ifndef STB_LEAKCHECK_OUTPUT_PIPE
|
||||
#define STB_LEAKCHECK_OUTPUT_PIPE stdout
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
typedef struct malloc_info stb_leakcheck_malloc_info;
|
||||
|
||||
struct malloc_info
|
||||
{
|
||||
const char *file;
|
||||
int line;
|
||||
size_t size;
|
||||
stb_leakcheck_malloc_info *next,*prev;
|
||||
};
|
||||
|
||||
static stb_leakcheck_malloc_info *mi_head;
|
||||
|
||||
void *stb_leakcheck_malloc(size_t sz, const char *file, int line)
|
||||
{
|
||||
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi));
|
||||
if (mi == NULL) return mi;
|
||||
mi->file = file;
|
||||
mi->line = line;
|
||||
mi->next = mi_head;
|
||||
if (mi_head)
|
||||
mi->next->prev = mi;
|
||||
mi->prev = NULL;
|
||||
mi->size = (int) sz;
|
||||
mi_head = mi;
|
||||
return mi+1;
|
||||
}
|
||||
|
||||
void stb_leakcheck_free(void *ptr)
|
||||
{
|
||||
if (ptr != NULL) {
|
||||
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
|
||||
mi->size = ~mi->size;
|
||||
#ifndef STB_LEAKCHECK_SHOWALL
|
||||
if (mi->prev == NULL) {
|
||||
assert(mi_head == mi);
|
||||
mi_head = mi->next;
|
||||
} else
|
||||
mi->prev->next = mi->next;
|
||||
if (mi->next)
|
||||
mi->next->prev = mi->prev;
|
||||
free(mi);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void *stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
return stb_leakcheck_malloc(sz, file, line);
|
||||
} else if (sz == 0) {
|
||||
stb_leakcheck_free(ptr);
|
||||
return NULL;
|
||||
} else {
|
||||
stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1;
|
||||
if (sz <= mi->size)
|
||||
return ptr;
|
||||
else {
|
||||
#ifdef STB_LEAKCHECK_REALLOC_PRESERVE_MALLOC_FILELINE
|
||||
void *q = stb_leakcheck_malloc(sz, mi->file, mi->line);
|
||||
#else
|
||||
void *q = stb_leakcheck_malloc(sz, file, line);
|
||||
#endif
|
||||
if (q) {
|
||||
memcpy(q, ptr, mi->size);
|
||||
stb_leakcheck_free(ptr);
|
||||
}
|
||||
return q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stblkck_internal_print(const char *reason, stb_leakcheck_malloc_info *mi)
|
||||
{
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900 // 1900=VS 2015
|
||||
// Compilers that use the old MS C runtime library don't have %zd
|
||||
// and the older ones don't even have %lld either... however, the old compilers
|
||||
// without "long long" don't support 64-bit targets either, so here's the
|
||||
// compromise:
|
||||
#if _MSC_VER < 1400 // before VS 2005
|
||||
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %8d bytes at %p\n", reason, mi->file, mi->line, (int)mi->size, (void*)(mi+1));
|
||||
#else
|
||||
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %16lld bytes at %p\n", reason, mi->file, mi->line, (long long)mi->size, (void*)(mi+1));
|
||||
#endif
|
||||
#else
|
||||
// Assume we have %zd on other targets.
|
||||
#ifdef __MINGW32__
|
||||
__mingw_fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
|
||||
#else
|
||||
fprintf(STB_LEAKCHECK_OUTPUT_PIPE, "%s: %s (%4d): %zd bytes at %p\n", reason, mi->file, mi->line, mi->size, (void*)(mi+1));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void stb_leakcheck_dumpmem(void)
|
||||
{
|
||||
stb_leakcheck_malloc_info *mi = mi_head;
|
||||
while (mi) {
|
||||
if ((ptrdiff_t) mi->size >= 0)
|
||||
stblkck_internal_print("LEAKED", mi);
|
||||
mi = mi->next;
|
||||
}
|
||||
#ifdef STB_LEAKCHECK_SHOWALL
|
||||
mi = mi_head;
|
||||
while (mi) {
|
||||
if ((ptrdiff_t) mi->size < 0)
|
||||
stblkck_internal_print("FREED ", mi);
|
||||
mi = mi->next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // STB_LEAKCHECK_IMPLEMENTATION
|
||||
|
||||
#if !defined(INCLUDE_STB_LEAKCHECK_H) || !defined(malloc)
|
||||
#define INCLUDE_STB_LEAKCHECK_H
|
||||
|
||||
#include <stdlib.h> // we want to define the macros *after* stdlib to avoid a slew of errors
|
||||
|
||||
#define malloc(sz) stb_leakcheck_malloc(sz, __FILE__, __LINE__)
|
||||
#define free(p) stb_leakcheck_free(p)
|
||||
#define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__)
|
||||
|
||||
extern void * stb_leakcheck_malloc(size_t sz, const char *file, int line);
|
||||
extern void * stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line);
|
||||
extern void stb_leakcheck_free(void *ptr);
|
||||
extern void stb_leakcheck_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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
428
raytracer/nvpro_core/third_party/stb/stb_perlin.h
vendored
Normal file
428
raytracer/nvpro_core/third_party/stb/stb_perlin.h
vendored
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
// stb_perlin.h - v0.5 - 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,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0)
|
||||
//
|
||||
// This function computes a random value at the coordinate (x,y,z).
|
||||
// Adjacent random values are continuous but the noise fluctuates
|
||||
// its randomness with period 1, i.e. takes on wholly unrelated values
|
||||
// at integer points. Specifically, this implements Ken Perlin's
|
||||
// revised noise function from 2002.
|
||||
//
|
||||
// The "wrap" parameters can be used to create wraparound noise that
|
||||
// wraps at powers of two. The numbers MUST be powers of two. Specify
|
||||
// 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.)
|
||||
//
|
||||
// float stb_perlin_noise3_seed( float x,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0,
|
||||
// int seed)
|
||||
//
|
||||
// As above, but 'seed' selects from multiple different variations of the
|
||||
// noise function. The current implementation only uses the bottom 8 bits
|
||||
// of 'seed', but possibly in the future more bits will be used.
|
||||
//
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// float stb_perlin_fbm_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves)
|
||||
//
|
||||
// float stb_perlin_turbulence_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves)
|
||||
//
|
||||
// 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
|
||||
// Jordan Peck - seeded noise
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
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_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed);
|
||||
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
|
||||
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
|
||||
extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
#include <math.h> // fabs()
|
||||
|
||||
// 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/
|
||||
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,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
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,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
};
|
||||
|
||||
|
||||
// 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/64ths and 6/64ths
|
||||
|
||||
// this array is designed to match the previous implementation
|
||||
// of gradient hash: indices[stb__perlin_randtab[i]&63]
|
||||
static unsigned char stb__perlin_randtab_grad_idx[512] =
|
||||
{
|
||||
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
|
||||
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
|
||||
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
|
||||
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
|
||||
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
|
||||
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
|
||||
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
|
||||
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
|
||||
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
|
||||
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
|
||||
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
|
||||
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
|
||||
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
|
||||
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
|
||||
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
|
||||
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7,
|
||||
8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8,
|
||||
7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8,
|
||||
8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5,
|
||||
5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1,
|
||||
2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4,
|
||||
9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11,
|
||||
1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6,
|
||||
10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0,
|
||||
6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2,
|
||||
4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3,
|
||||
11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11,
|
||||
10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1,
|
||||
3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10,
|
||||
11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7,
|
||||
9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5,
|
||||
};
|
||||
|
||||
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 grad_idx, float x, float y, float z)
|
||||
{
|
||||
static float basis[12][4] =
|
||||
{
|
||||
{ 1, 1, 0 },
|
||||
{ -1, 1, 0 },
|
||||
{ 1,-1, 0 },
|
||||
{ -1,-1, 0 },
|
||||
{ 1, 0, 1 },
|
||||
{ -1, 0, 1 },
|
||||
{ 1, 0,-1 },
|
||||
{ -1, 0,-1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0,-1, 1 },
|
||||
{ 0, 1,-1 },
|
||||
{ 0,-1,-1 },
|
||||
};
|
||||
|
||||
float *grad = basis[grad_idx];
|
||||
return grad[0]*x + grad[1]*y + grad[2]*z;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_internal(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
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 = 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;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0+seed];
|
||||
r1 = stb__perlin_randtab[x1+seed];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
|
||||
float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap,0);
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed)
|
||||
{
|
||||
return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap, (unsigned char) seed);
|
||||
}
|
||||
|
||||
float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves)
|
||||
{
|
||||
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 = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i);
|
||||
r = offset - (float) fabs(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 i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*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 i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
|
||||
sum += (float) fabs(r);
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x_wrap2 = (x_wrap ? x_wrap : 256);
|
||||
int y_wrap2 = (y_wrap ? y_wrap : 256);
|
||||
int z_wrap2 = (z_wrap ? z_wrap : 256);
|
||||
int x0 = px % x_wrap2, x1;
|
||||
int y0 = py % y_wrap2, y1;
|
||||
int z0 = pz % z_wrap2, z1;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
if (x0 < 0) x0 += x_wrap2;
|
||||
if (y0 < 0) y0 += y_wrap2;
|
||||
if (z0 < 0) z0 += z_wrap2;
|
||||
x1 = (x0+1) % x_wrap2;
|
||||
y1 = (y0+1) % y_wrap2;
|
||||
z1 = (z0+1) % z_wrap2;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0];
|
||||
r0 = stb__perlin_randtab[r0+seed];
|
||||
r1 = stb__perlin_randtab[x1];
|
||||
r1 = stb__perlin_randtab[r1+seed];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
#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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
623
raytracer/nvpro_core/third_party/stb/stb_rect_pack.h
vendored
Normal file
623
raytracer/nvpro_core/third_party/stb/stb_rect_pack.h
vendored
Normal file
|
|
@ -0,0 +1,623 @@
|
|||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 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.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
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.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// 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
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
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
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
STBRP_ASSERT(y <= best_y);
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *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);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
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 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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
1913
raytracer/nvpro_core/third_party/stb/stb_sprintf.h
vendored
Normal file
1913
raytracer/nvpro_core/third_party/stb/stb_sprintf.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1429
raytracer/nvpro_core/third_party/stb/stb_textedit.h
vendored
Normal file
1429
raytracer/nvpro_core/third_party/stb/stb_textedit.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
4187
raytracer/nvpro_core/third_party/stb/stb_tilemap_editor.h
vendored
Normal file
4187
raytracer/nvpro_core/third_party/stb/stb_tilemap_editor.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
5077
raytracer/nvpro_core/third_party/stb/stb_truetype.h
vendored
Normal file
5077
raytracer/nvpro_core/third_party/stb/stb_truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
5674
raytracer/nvpro_core/third_party/stb/stb_vorbis.c
vendored
Normal file
5674
raytracer/nvpro_core/third_party/stb/stb_vorbis.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
3807
raytracer/nvpro_core/third_party/stb/stb_voxel_render.h
vendored
Normal file
3807
raytracer/nvpro_core/third_party/stb/stb_voxel_render.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue