remove stb vendored
This commit is contained in:
parent
5a3ef830a4
commit
1a3b322df4
37
source/engine/thirdparty/stb/LICENSE
vendored
37
source/engine/thirdparty/stb/LICENSE
vendored
|
@ -1,37 +0,0 @@
|
||||||
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.
|
|
181
source/engine/thirdparty/stb/README.md
vendored
181
source/engine/thirdparty/stb/README.md
vendored
|
@ -1,181 +0,0 @@
|
||||||
<!--- THIS FILE IS AUTOMATICALLY GENERATED, DO NOT CHANGE IT BY HAND --->
|
|
||||||
|
|
||||||
stb
|
|
||||||
===
|
|
||||||
|
|
||||||
single-file public domain (or MIT licensed) libraries for C/C++
|
|
||||||
|
|
||||||
Noteworthy:
|
|
||||||
|
|
||||||
* image loader: [stb_image.h](stb_image.h)
|
|
||||||
* image writer: [stb_image_write.h](stb_image_write.h)
|
|
||||||
* image resizer: [stb_image_resize.h](stb_image_resize.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, stb_image_resize
|
|
||||||
by Jorge L. "VinoBS" Rodriguez, 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.27 | graphics | 7897 | 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_resize.h](stb_image_resize.h)** | 0.97 | graphics | 2634 | 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_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: 20
|
|
||||||
Total lines of C code: 42599
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
|
@ -1 +0,0 @@
|
||||||
Moved to https://github.com/nothings/single_file_libs
|
|
185
source/engine/thirdparty/stb/docs/stb_howto.txt
vendored
185
source/engine/thirdparty/stb/docs/stb_howto.txt
vendored
|
@ -1,185 +0,0 @@
|
||||||
Lessons learned about how to make a header-file library
|
|
||||||
V1.0
|
|
||||||
September 2013 Sean Barrett
|
|
||||||
|
|
||||||
Things to do in an stb-style header-file library,
|
|
||||||
and rationales:
|
|
||||||
|
|
||||||
|
|
||||||
1. #define LIBRARYNAME_IMPLEMENTATION
|
|
||||||
|
|
||||||
Use a symbol like the above to control creating
|
|
||||||
the implementation. (I used a far-less-clear name
|
|
||||||
in my first header-file library; it became
|
|
||||||
clear that was a mistake once I had multiple
|
|
||||||
libraries.)
|
|
||||||
|
|
||||||
Include a "header-file" section with header-file
|
|
||||||
guards and declarations for all the functions,
|
|
||||||
but only guard the implementation with LIBRARYNAME_IMPLEMENTATION,
|
|
||||||
not the header-file guard. That way, if client's
|
|
||||||
header file X includes your header file for
|
|
||||||
declarations, they can still include header file X
|
|
||||||
in the source file that creates the implementation;
|
|
||||||
if you guard the implementation too, then the first
|
|
||||||
include (before the #define) creates the declarations,
|
|
||||||
and the second one (after the #define) does nothing.
|
|
||||||
|
|
||||||
|
|
||||||
2. AVOID DEPENDENCIES
|
|
||||||
|
|
||||||
Don't rely on anything other than the C standard libraries.
|
|
||||||
|
|
||||||
(If you're creating a library specifically to leverage/wrap
|
|
||||||
some other library, then obviously you can rely on that
|
|
||||||
library. But if that library is public domain, you might
|
|
||||||
be better off directly embedding the source, to reduce
|
|
||||||
dependencies for your clients. But of course now you have
|
|
||||||
to update whenever that library updates.)
|
|
||||||
|
|
||||||
If you use stdlib, consider wrapping all stdlib calls in
|
|
||||||
macros, and then conditionally define those macros to the
|
|
||||||
stdlib function, allowing the user to replace them.
|
|
||||||
|
|
||||||
For functions with side effects, like memory allocations,
|
|
||||||
consider letting the user pass in a context and pass
|
|
||||||
that in to the macros. (The stdlib versions will ignore
|
|
||||||
the parameter.) Otherwise, users may have to use global
|
|
||||||
or thread-local variables to achieve the same effect.
|
|
||||||
|
|
||||||
|
|
||||||
3. AVOID MALLOC
|
|
||||||
|
|
||||||
You can't always do this, but when you can, embedded developers
|
|
||||||
will appreciate it. I almost never bother avoiding, as it's
|
|
||||||
too much work (and in some cases is pretty infeasible;
|
|
||||||
see http://nothings.org/gamedev/font_rendering_malloc.txt ).
|
|
||||||
But it's definitely something one of the things I've gotten
|
|
||||||
the most pushback on from potential users.
|
|
||||||
|
|
||||||
|
|
||||||
4. ALLOW STATIC IMPLEMENTATION
|
|
||||||
|
|
||||||
Have a #define which makes function declarations and
|
|
||||||
function definitions static. This makes the implementation
|
|
||||||
private to the source file that creates it. This allows
|
|
||||||
people to use your library multiple times in their project
|
|
||||||
without collision. (This is only necessary if your library
|
|
||||||
has configuration macros or global state, or if your
|
|
||||||
library has multiple versions that are not backwards
|
|
||||||
compatible. I've run into both of those cases.)
|
|
||||||
|
|
||||||
|
|
||||||
5. MAKE ACCESSIBLE FROM C
|
|
||||||
|
|
||||||
Making your code accessible from C instead of C++ (i.e.
|
|
||||||
either coding in C, or using extern "C") makes it more
|
|
||||||
straightforward to be used in C and in other languages,
|
|
||||||
which often only have support for C bindings, not C++.
|
|
||||||
(One of the earliest results I found in googling for
|
|
||||||
stb_image was a Haskell wrapper.) Otherwise, people
|
|
||||||
have to wrap it in another set of function calls, and
|
|
||||||
the whole point here is to make it convenient for people
|
|
||||||
to use, isn't it? (See below.)
|
|
||||||
|
|
||||||
I prefer to code entirely in C, so the source file that
|
|
||||||
instantiates the implementation can be C itself, for
|
|
||||||
those crazy people out there who are programming in C.
|
|
||||||
But it's probably not a big hardship for a C programmer
|
|
||||||
to create a single C++ source file to instantiate your
|
|
||||||
library.
|
|
||||||
|
|
||||||
|
|
||||||
6. NAMESPACE PRIVATE FUNCTIONS
|
|
||||||
|
|
||||||
Try to avoid having names in your source code that
|
|
||||||
will cause conflicts with identical names in client
|
|
||||||
code. You can do this either by namespacing in C++,
|
|
||||||
or prefixing with your library name in C.
|
|
||||||
|
|
||||||
In C, generally, I use the same prefix for API
|
|
||||||
functions and private symbols, such as "stbtt_"
|
|
||||||
for stb_truetype; but private functions (and
|
|
||||||
static globals) use a second underscore as
|
|
||||||
in "stbtt__" to further minimize the chance of
|
|
||||||
additional collisions in the unlikely but not
|
|
||||||
impossible event that users write wrapper
|
|
||||||
functions that have names of the form "stbtt_".
|
|
||||||
(Consider the user that has used "stbtt_foo"
|
|
||||||
*successfully*, and then upgrades to a new
|
|
||||||
version of your library which has a new private
|
|
||||||
function named either "stbtt_foo" or "stbtt__foo".)
|
|
||||||
|
|
||||||
Note that the double-underscore is reserved for
|
|
||||||
use by the compiler, but (1) there is nothing
|
|
||||||
reserved for "middleware", i.e. libraries
|
|
||||||
desiring to avoid conflicts with user symbols
|
|
||||||
have no other good options, and (2) in practice
|
|
||||||
no compilers use double-underscore in the middle
|
|
||||||
rather than the beginning/end. (Unfortunately,
|
|
||||||
there is at least one videogame-console compiler that
|
|
||||||
will warn about double-underscores by default.)
|
|
||||||
|
|
||||||
|
|
||||||
7. EASY-TO-COMPLY LICENSE
|
|
||||||
|
|
||||||
I make my libraries public domain. You don't have to.
|
|
||||||
But my goal in releasing stb-style libraries is to
|
|
||||||
reduce friction for potential users as much as
|
|
||||||
possible. That means:
|
|
||||||
|
|
||||||
a. easy to build (what this file is mostly about)
|
|
||||||
b. easy to invoke (which requires good API design)
|
|
||||||
c. easy to deploy (which is about licensing)
|
|
||||||
|
|
||||||
I choose to place all my libraries in the public
|
|
||||||
domain, abjuring copyright, rather than license
|
|
||||||
the libraries. This has some benefits and some
|
|
||||||
drawbacks.
|
|
||||||
|
|
||||||
Any license which is "viral" to modifications
|
|
||||||
causes worries for lawyers, even if their programmers
|
|
||||||
aren't modifying it.
|
|
||||||
|
|
||||||
Any license which requires crediting in documentation
|
|
||||||
adds friction which can add up. Valve used to have
|
|
||||||
a page with a list of all of these on their web site,
|
|
||||||
and it was insane, and obviously nobody ever looked
|
|
||||||
at it so why would you care whether your credit appeared
|
|
||||||
there?
|
|
||||||
|
|
||||||
Permissive licenses like zlib and BSD license are
|
|
||||||
perfectly reasonable, but they are very wordy and
|
|
||||||
have only two benefits over public domain: legally-mandated
|
|
||||||
attribution and liability-control. I do not believe these
|
|
||||||
are worth the excessive verbosity and user-unfriendliness
|
|
||||||
these licenses induce, especially in the single-file
|
|
||||||
case where those licenses tend to be at the top of
|
|
||||||
the file, the first thing you see. (To the specific
|
|
||||||
points, I have had no trouble receiving attribution
|
|
||||||
for my libraries; liability in the face of no explicit
|
|
||||||
disclaimer of liability is an open question.)
|
|
||||||
|
|
||||||
However, public domain has frictions of its own, because
|
|
||||||
public domain declarations aren't necessary recognized
|
|
||||||
in the USA and some other locations. For that reason,
|
|
||||||
I recommend a declaration along these lines:
|
|
||||||
|
|
||||||
// This software is dual-licensed to the public domain and under the following
|
|
||||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
|
||||||
// publish, and distribute this file as you see fit.
|
|
||||||
|
|
||||||
I typically place this declaration at the end of the initial
|
|
||||||
comment block of the file and just say 'public domain'
|
|
||||||
at the top.
|
|
||||||
|
|
||||||
I have had people say they couldn't use one of my
|
|
||||||
libraries because it was only "public domain" and didn't
|
|
||||||
have the additional fallback clause, who asked if
|
|
||||||
I could dual-license it under a traditional license.
|
|
||||||
|
|
||||||
My answer: they can create a derivative work by
|
|
||||||
modifying one character, and then license that however
|
|
||||||
they like. (Indeed, *adding* the zlib or BSD license
|
|
||||||
would be such a modification!) Unfortunately, their
|
|
||||||
lawyers reportedly didn't like that answer. :(
|
|
|
@ -1,173 +0,0 @@
|
||||||
# An interview with STB about stb_voxel_render.h
|
|
||||||
|
|
||||||
**Q:**
|
|
||||||
I suppose you really like Minecraft?
|
|
||||||
|
|
||||||
**A:**
|
|
||||||
Not really. I mean, I do own it and play it some, and
|
|
||||||
I do watch YouTube videos of other people playing it
|
|
||||||
once in a while, but I'm not saying it's that great.
|
|
||||||
|
|
||||||
But I do love voxels. I've been playing with voxel rendering
|
|
||||||
since the mid-late 90's when we were still doing software
|
|
||||||
rendering and thinking maybe polygons weren't the answer.
|
|
||||||
Once GPUs came along that kind of died off, at least until
|
|
||||||
Minecraft brought it back to attention.
|
|
||||||
|
|
||||||
**Q:**
|
|
||||||
Do you expect people will make a lot of Minecraft clones
|
|
||||||
with this?
|
|
||||||
|
|
||||||
**A:**
|
|
||||||
I hope not!
|
|
||||||
|
|
||||||
For one thing, it's a terrible idea for the
|
|
||||||
developer. Remember before Minecraft was on the Xbox 360,
|
|
||||||
there were a ton of "indie" clones (some maybe making
|
|
||||||
decent money even), but then the real Minecraft came out
|
|
||||||
and just crushed them (as far as I know). It's just not
|
|
||||||
something you really want to compete with.
|
|
||||||
|
|
||||||
The reason I made this library is because I'd like
|
|
||||||
to see more games with Minecraft's *art style*, not
|
|
||||||
necessary its *gameplay*.
|
|
||||||
|
|
||||||
I can understand the urge to clone the gameplay. When
|
|
||||||
you have a world made of voxels/blocks, there are a
|
|
||||||
few things that become incredibly easy to do that would
|
|
||||||
otherwise be very hard (at least for an indie) to do in 3D.
|
|
||||||
One thing is that procedural generation becomes much easier.
|
|
||||||
Another is that destructible environments are easy. Another
|
|
||||||
is that you have a world where your average user can build
|
|
||||||
stuff that they find satisfactory.
|
|
||||||
|
|
||||||
Minecraft is at a sort of local maximum, a sweet spot, where
|
|
||||||
it leverages all of those easy-to-dos. And so I'm sure it's
|
|
||||||
hard to look at the space of 'games using voxels' and move
|
|
||||||
away from that local maximum, to give up some of that.
|
|
||||||
But I think that's what people should do.
|
|
||||||
|
|
||||||
**Q:**
|
|
||||||
So what else can people do with stb_voxel_render?
|
|
||||||
|
|
||||||
**A:**
|
|
||||||
All of those benefits I mentioned above are still valid even
|
|
||||||
if you stay away from the sweet spot. You can make a 3D roguelike
|
|
||||||
without player-creation/destruction that uses procedural generation.
|
|
||||||
You could make a shooter with pre-designed maps but destructible
|
|
||||||
environments.
|
|
||||||
|
|
||||||
And I'm sure there are other possible benefits to using voxels/blocks.
|
|
||||||
Hopefully this will make it easier for people to explore the space.
|
|
||||||
|
|
||||||
The library has a pretty wide range of features to allow
|
|
||||||
people to come up with some distinctive looks. For example,
|
|
||||||
the art style of Continue?9876543210 was one of the inspirations
|
|
||||||
for trying to make the multitexturing capabilities flexible.
|
|
||||||
I'm terrible at art, so this isn't really something I can
|
|
||||||
come up with myself, but I tried to put in flexible
|
|
||||||
technology that could be used multiple ways.
|
|
||||||
|
|
||||||
One thing I did intentionally was try to make it possible to
|
|
||||||
make nicer looking ground terrain, using the half-height
|
|
||||||
slopes and "weird slopes". There are Minecraft mods with
|
|
||||||
drivable cars and they just go up these blocky slopes and,
|
|
||||||
like, what? So I wanted you to be able to make smoother
|
|
||||||
terrain, either just for the look, or for vehicles etc.
|
|
||||||
Also, you can spatially cross-fade between two ground textures for
|
|
||||||
that classic bad dirt/grass transition that has shipped
|
|
||||||
in plenty of professional games. Of course, you could
|
|
||||||
just use a separate non-voxel ground renderer for all of
|
|
||||||
this. But this way, you can seamlessly integrate everything
|
|
||||||
else with it. E.g. in your authoring tool (or procedural
|
|
||||||
generation) you can make smooth ground and then cut a
|
|
||||||
sharp-edged hole in it for a building's basement or whatever.
|
|
||||||
|
|
||||||
Another thing you can do is work at a very different scale.
|
|
||||||
In Minecraft, a person is just under 2 blocks tall. In
|
|
||||||
Ace of Spades, a person is just under 3 blocks tall. Why
|
|
||||||
not 4 or 6? Well, partly because you just need a lot more
|
|
||||||
voxels; if a meter is 2 voxels in Mineraft and 4 voxels in
|
|
||||||
your game, and you draw the same number of voxels due to
|
|
||||||
hardware limits, then your game has half the view distance
|
|
||||||
of Minecraft. Since stb_voxel_render is designed to keep
|
|
||||||
the meshes small and render efficiently, you can push the
|
|
||||||
view distance out further than Minecraft--or use a similar
|
|
||||||
view distance and a higher voxel resolution. You could also
|
|
||||||
stop making infinite worlds and work at entirely different
|
|
||||||
scales; where Minecraft is 1 voxel per meter, you could
|
|
||||||
have 20 voxels per meter and make a small arena that's
|
|
||||||
50 meters wide and 5 meters tall.
|
|
||||||
|
|
||||||
Back when the voxel game Voxatron was announced, the weekend
|
|
||||||
after the trailer came out I wrote my own little GPU-accelerated
|
|
||||||
version of the engine and thought that was pretty cool. I've
|
|
||||||
been tempted many times to extract that and release it
|
|
||||||
as a library, but
|
|
||||||
I don't want to steal Voxatron's thunder so I've avoided
|
|
||||||
it. You could use this engine to do the same kind of thing,
|
|
||||||
although it won't be as efficient as an engine dedicated to
|
|
||||||
that style of thing would be.
|
|
||||||
|
|
||||||
**Q:**
|
|
||||||
What one thing would you really like to see somebody do?
|
|
||||||
|
|
||||||
**A:**
|
|
||||||
Before Unity, 3D has seemed deeply problematic in the indie
|
|
||||||
space. Software like GameMaker has tried to support 3D but
|
|
||||||
it seems like little of note has been done with it.
|
|
||||||
|
|
||||||
Minecraft has shown that people can build worlds with the
|
|
||||||
Minecraft toolset far more easily than we've ever seen from those
|
|
||||||
other tools. Obviously people have done great things with
|
|
||||||
Unity, but those people are much closer to professional
|
|
||||||
developers; typically they still need real 3D modelling
|
|
||||||
and all of that stuff.
|
|
||||||
|
|
||||||
So what I'd really like to see is someone build some kind
|
|
||||||
of voxel-game-construction-set. Start with stb_voxel_render,
|
|
||||||
maybe expose all the flexibility of stb_voxel_render (so
|
|
||||||
people can do different things). Thrown in lua or something
|
|
||||||
else for scripting, make some kind of editor that feels
|
|
||||||
at least as good as Minecraft and Infinifactory, and see
|
|
||||||
where that gets you.
|
|
||||||
|
|
||||||
**Q:**
|
|
||||||
Why'd you make this library?
|
|
||||||
|
|
||||||
**A:**
|
|
||||||
Mainly as a way of releasing this technology I've been working
|
|
||||||
on since 2011 and seemed unlikely to ever ship myself. In 2011
|
|
||||||
I was playing the voxel shooter Ace of Spades. One of the maps
|
|
||||||
that we played on was a partial port of Broville (which is the
|
|
||||||
first Minecraft map in stb_voxel_render release trailer). I'd
|
|
||||||
made a bunch of procedural level generators for the game, and
|
|
||||||
I started trying to make a city generator inspired by Broville.
|
|
||||||
|
|
||||||
But I realized it would be a lot of work, and of very little
|
|
||||||
value (most of my maps didn't get much play because people
|
|
||||||
preferred to play on maps where they could charge straight
|
|
||||||
at the enemies and shoot them as fast as possible). So I
|
|
||||||
wrote my own voxel engine and started working on a procedural
|
|
||||||
city game. But I got bogged down after I finally got the road
|
|
||||||
generator working and never got anywhere with building
|
|
||||||
generation or gameplay.
|
|
||||||
|
|
||||||
stb_voxel_render is actually a complete rewrite from scratch,
|
|
||||||
but it's based a lot on what I learned from that previous work.
|
|
||||||
|
|
||||||
**Q:**
|
|
||||||
About the release video... how long did that take to edit?
|
|
||||||
|
|
||||||
**A:**
|
|
||||||
About seven or eight hours. I had the first version done in
|
|
||||||
maybe six or seven hours, but then I realized I'd left out
|
|
||||||
one clip, and when I went back to add it I also gussied up
|
|
||||||
a couple other moments in the video. But there was something
|
|
||||||
basically identical to it that was done in around six.
|
|
||||||
|
|
||||||
**Q:**
|
|
||||||
Ok, that's it. Thanks, me.
|
|
||||||
|
|
||||||
**A:**
|
|
||||||
Thanks *me!*
|
|
|
@ -1,117 +0,0 @@
|
||||||
My collected rationales for placing these libraries
|
|
||||||
in the public domain:
|
|
||||||
|
|
||||||
1. Public domain vs. viral licenses
|
|
||||||
|
|
||||||
Why is this library public domain?
|
|
||||||
Because more people will use it. Because it's not viral, people are
|
|
||||||
not obligated to give back, so you could argue that it hurts the
|
|
||||||
development of it, and then because it doesn't develop as well it's
|
|
||||||
not as good, and then because it's not as good, in the long run
|
|
||||||
maybe fewer people will use it. I have total respect for that
|
|
||||||
opinion, but I just don't believe it myself for most software.
|
|
||||||
|
|
||||||
2. Public domain vs. attribution-required licenses
|
|
||||||
|
|
||||||
The primary difference between public domain and, say, a Creative Commons
|
|
||||||
commercial / non-share-alike / attribution license is solely the
|
|
||||||
requirement for attribution. (Similarly the BSD license and such.)
|
|
||||||
While I would *appreciate* acknowledgement and attribution, I believe
|
|
||||||
that it is foolish to place a legal encumberment (i.e. a license) on
|
|
||||||
the software *solely* to get attribution.
|
|
||||||
|
|
||||||
In other words, I'm arguing that PD is superior to the BSD license and
|
|
||||||
the Creative Commons 'Attribution' license. If the license offers
|
|
||||||
anything besides attribution -- as does, e.g., CC NonCommercial-ShareAlike,
|
|
||||||
or the GPL -- that's a separate discussion.
|
|
||||||
|
|
||||||
3. Other aspects of BSD-style licenses besides attribution
|
|
||||||
|
|
||||||
Permissive licenses like zlib and BSD license are perfectly reasonable
|
|
||||||
in their requirements, but they are very wordy and
|
|
||||||
have only two benefits over public domain: legally-mandated
|
|
||||||
attribution and liability-control. I do not believe these
|
|
||||||
are worth the excessive verbosity and user-unfriendliness
|
|
||||||
these licenses induce, especially in the single-file
|
|
||||||
case where those licenses tend to be at the top of
|
|
||||||
the file, the first thing you see.
|
|
||||||
|
|
||||||
To the specific points, I have had no trouble receiving
|
|
||||||
attribution for my libraries; liability in the face of
|
|
||||||
no explicit disclaimer of liability is an open question,
|
|
||||||
but one I have a lot of difficulty imagining there being
|
|
||||||
any actual doubt about in court. Sometimes I explicitly
|
|
||||||
note in my libraries that I make no guarantees about them
|
|
||||||
being fit for purpose, but it's pretty absurd to do this;
|
|
||||||
as a whole, it comes across as "here is a library to decode
|
|
||||||
vorbis audio files, but it may not actually work and if
|
|
||||||
you have problems it's not my fault, but also please
|
|
||||||
report bugs so I can fix them"--so dumb!
|
|
||||||
|
|
||||||
4. full discussion from stb_howto.txt on what YOU should do for YOUR libs
|
|
||||||
|
|
||||||
```
|
|
||||||
EASY-TO-COMPLY LICENSE
|
|
||||||
|
|
||||||
I make my libraries public domain. You don't have to.
|
|
||||||
But my goal in releasing stb-style libraries is to
|
|
||||||
reduce friction for potential users as much as
|
|
||||||
possible. That means:
|
|
||||||
|
|
||||||
a. easy to build (what this file is mostly about)
|
|
||||||
b. easy to invoke (which requires good API design)
|
|
||||||
c. easy to deploy (which is about licensing)
|
|
||||||
|
|
||||||
I choose to place all my libraries in the public
|
|
||||||
domain, abjuring copyright, rather than license
|
|
||||||
the libraries. This has some benefits and some
|
|
||||||
drawbacks.
|
|
||||||
|
|
||||||
Any license which is "viral" to modifications
|
|
||||||
causes worries for lawyers, even if their programmers
|
|
||||||
aren't modifying it.
|
|
||||||
|
|
||||||
Any license which requires crediting in documentation
|
|
||||||
adds friction which can add up. Valve has a huge list
|
|
||||||
(http://nothings.org/remote/ThirdPartyLegalNotices_steam_2019.html)
|
|
||||||
of all of these included in each game they ship,
|
|
||||||
and it's insane, and obviously nobody ever looks
|
|
||||||
at it so why would you care whether your credit
|
|
||||||
appeared there?
|
|
||||||
|
|
||||||
Permissive licenses like zlib and BSD license are
|
|
||||||
perfectly reasonable, but they are very wordy and
|
|
||||||
have only two benefits over public domain: legally-mandated
|
|
||||||
attribution and liability-control. I do not believe these
|
|
||||||
are worth the excessive verbosity and user-unfriendliness
|
|
||||||
these licenses induce, especially in the single-file
|
|
||||||
case where those licenses tend to be at the top of
|
|
||||||
the file, the first thing you see. (To the specific
|
|
||||||
points, I have had no trouble receiving attribution
|
|
||||||
for my libraries; liability in the face of no explicit
|
|
||||||
disclaimer of liability is an open question.)
|
|
||||||
|
|
||||||
However, public domain has frictions of its own, because
|
|
||||||
public domain declarations aren't necessary recognized
|
|
||||||
in the USA and some other locations. For that reason,
|
|
||||||
I recommend a declaration along these lines:
|
|
||||||
|
|
||||||
// This software is dual-licensed to the public domain and under the following
|
|
||||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
|
||||||
// publish, and distribute this file as you see fit.
|
|
||||||
|
|
||||||
I typically place this declaration at the end of the initial
|
|
||||||
comment block of the file and just say 'public domain'
|
|
||||||
at the top.
|
|
||||||
|
|
||||||
I have had people say they couldn't use one of my
|
|
||||||
libraries because it was only "public domain" and didn't
|
|
||||||
have the additional fallback clause, who asked if
|
|
||||||
I could dual-license it under a traditional license.
|
|
||||||
|
|
||||||
My answer: they can create a derivative work by
|
|
||||||
modifying one character, and then license that however
|
|
||||||
they like. (Indeed, *adding* the zlib or BSD license
|
|
||||||
would be such a modification!) Unfortunately, their
|
|
||||||
lawyers reportedly didn't like that answer. :(
|
|
||||||
```
|
|
940
source/engine/thirdparty/stb/include/stb_c_lexer.h
vendored
940
source/engine/thirdparty/stb/include/stb_c_lexer.h
vendored
|
@ -1,940 +0,0 @@
|
||||||
// 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.
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
*/
|
|
File diff suppressed because it is too large
Load diff
433
source/engine/thirdparty/stb/include/stb_divide.h
vendored
433
source/engine/thirdparty/stb/include/stb_divide.h
vendored
|
@ -1,433 +0,0 @@
|
||||||
// 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
source/engine/thirdparty/stb/include/stb_ds.h
vendored
1895
source/engine/thirdparty/stb/include/stb_ds.h
vendored
File diff suppressed because it is too large
Load diff
719
source/engine/thirdparty/stb/include/stb_dxt.h
vendored
719
source/engine/thirdparty/stb/include/stb_dxt.h
vendored
|
@ -1,719 +0,0 @@
|
||||||
// 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
source/engine/thirdparty/stb/include/stb_easy_font.h
vendored
305
source/engine/thirdparty/stb/include/stb_easy_font.h
vendored
|
@ -1,305 +0,0 @@
|
||||||
// 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.
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
*/
|
|
File diff suppressed because it is too large
Load diff
680
source/engine/thirdparty/stb/include/stb_hexwave.h
vendored
680
source/engine/thirdparty/stb/include/stb_hexwave.h
vendored
|
@ -1,680 +0,0 @@
|
||||||
// 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.
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
*/
|
|
7987
source/engine/thirdparty/stb/include/stb_image.h
vendored
7987
source/engine/thirdparty/stb/include/stb_image.h
vendored
File diff suppressed because it is too large
Load diff
2634
source/engine/thirdparty/stb/include/stb_image_resize.h
vendored
2634
source/engine/thirdparty/stb/include/stb_image_resize.h
vendored
File diff suppressed because it is too large
Load diff
1724
source/engine/thirdparty/stb/include/stb_image_write.h
vendored
1724
source/engine/thirdparty/stb/include/stb_image_write.h
vendored
File diff suppressed because it is too large
Load diff
295
source/engine/thirdparty/stb/include/stb_include.h
vendored
295
source/engine/thirdparty/stb/include/stb_include.h
vendored
|
@ -1,295 +0,0 @@
|
||||||
// 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
source/engine/thirdparty/stb/include/stb_leakcheck.h
vendored
194
source/engine/thirdparty/stb/include/stb_leakcheck.h
vendored
|
@ -1,194 +0,0 @@
|
||||||
// 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.
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
*/
|
|
623
source/engine/thirdparty/stb/include/stb_rect_pack.h
vendored
623
source/engine/thirdparty/stb/include/stb_rect_pack.h
vendored
|
@ -1,623 +0,0 @@
|
||||||
// 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.
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
*/
|
|
1906
source/engine/thirdparty/stb/include/stb_sprintf.h
vendored
1906
source/engine/thirdparty/stb/include/stb_sprintf.h
vendored
File diff suppressed because it is too large
Load diff
1429
source/engine/thirdparty/stb/include/stb_textedit.h
vendored
1429
source/engine/thirdparty/stb/include/stb_textedit.h
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
5077
source/engine/thirdparty/stb/include/stb_truetype.h
vendored
5077
source/engine/thirdparty/stb/include/stb_truetype.h
vendored
File diff suppressed because it is too large
Load diff
5584
source/engine/thirdparty/stb/include/stb_vorbis.h
vendored
5584
source/engine/thirdparty/stb/include/stb_vorbis.h
vendored
File diff suppressed because it is too large
Load diff
3807
source/engine/thirdparty/stb/include/stb_voxel_render.h
vendored
3807
source/engine/thirdparty/stb/include/stb_voxel_render.h
vendored
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue