This commit is contained in:
Jorge Rodriguez 2016-02-09 19:37:07 -08:00
commit ff862a2a46
13 changed files with 871 additions and 537 deletions

View File

@ -7,10 +7,10 @@ single-file public domain libraries for C/C++ <a name="stb_libs"></a>
library | lastest version | category | LoC | description library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | -------------------------------- --------------------- | ---- | -------- | --- | --------------------------------
**stb_vorbis.c** | 1.06 | audio | 5441 | decode ogg vorbis files from file/memory to float/16-bit signed output **stb_vorbis.c** | 1.07 | audio | 5462 | decode ogg vorbis files from file/memory to float/16-bit signed output
**stb_image.h** | 2.08 | graphics | 6509 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **stb_image.h** | 2.10 | graphics | 6614 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**stb_truetype.h** | 1.08 | graphics | 3235 | parse, decode, and rasterize characters from truetype fonts **stb_truetype.h** | 1.09 | graphics | 3249 | parse, decode, and rasterize characters from truetype fonts
**stb_image_write.h** | 1.00 | graphics | 993 | image writing to disk: PNG, TGA, BMP **stb_image_write.h** | 1.01 | graphics | 1044 | image writing to disk: PNG, TGA, BMP
**stb_image_resize.h** | 0.90 | graphics | 2586 | resize images larger/smaller with good quality **stb_image_resize.h** | 0.90 | graphics | 2586 | resize images larger/smaller with good quality
**stb_rect_pack.h** | 0.08 | graphics | 572 | simple 2D rectangle packer with decent quality **stb_rect_pack.h** | 0.08 | graphics | 572 | simple 2D rectangle packer with decent quality
**stretchy_buffer.h** | 1.02 | utility | 216 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ **stretchy_buffer.h** | 1.02 | utility | 216 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
@ -18,16 +18,16 @@ library | lastest version | category | LoC | description
**stb_voxel_render.h** | 0.83 | 3D&nbsp;graphics | 3750 | Minecraft-esque voxel rendering "engine" with many more features **stb_voxel_render.h** | 0.83 | 3D&nbsp;graphics | 3750 | Minecraft-esque voxel rendering "engine" with many more features
**stb_dxt.h** | 1.04 | 3D&nbsp;graphics | 630 | Fabian "ryg" Giesen's real-time DXT compressor **stb_dxt.h** | 1.04 | 3D&nbsp;graphics | 630 | Fabian "ryg" Giesen's real-time DXT compressor
**stb_perlin.h** | 0.2 | 3D&nbsp;graphics | 182 | revised Perlin noise (3D input, 1D output) **stb_perlin.h** | 0.2 | 3D&nbsp;graphics | 182 | revised Perlin noise (3D input, 1D output)
**stb_easy_font.h** | 0.6 | 3D&nbsp;graphics | 232 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc **stb_easy_font.h** | 0.7 | 3D&nbsp;graphics | 258 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
**stb_tilemap_editor.h** | 0.36 | game&nbsp;dev | 4127 | embeddable tilemap editor **stb_tilemap_editor.h** | 0.37 | game&nbsp;dev | 4131 | embeddable tilemap editor
**stb_herringbone_wa...** | 0.6 | game&nbsp;dev | 1220 | herringbone Wang tile map generator **stb_herringbone_wa...** | 0.6 | game&nbsp;dev | 1220 | herringbone Wang tile map generator
**stb_c_lexer.h** | 0.06 | parsing | 815 | simplify writing parsers for C-like languages **stb_c_lexer.h** | 0.07 | parsing | 816 | simplify writing parsers for C-like languages
**stb_divide.h** | 0.91 | math | 379 | more useful 32-bit modulus e.g. "euclidean divide" **stb_divide.h** | 0.91 | math | 379 | more useful 32-bit modulus e.g. "euclidean divide"
**stb.h** | 2.25 | misc | 14136 | helper functions for C, mostly redundant in C++; basically author's personal stuff **stb.h** | 2.26 | misc | 14184 | helper functions for C, mostly redundant in C++; basically author's personal stuff
**stb_leakcheck.h** | 0.2 | misc | 124 | quick-and-dirty malloc/free leak-checking **stb_leakcheck.h** | 0.2 | misc | 124 | quick-and-dirty malloc/free leak-checking
Total libraries: 18 Total libraries: 18
Total lines of C code: 46448 Total lines of C code: 46718
FAQ FAQ

View File

@ -2,95 +2,148 @@
In addition to all of [my libraries](https://github.com/nothings/stb), there are other, similar libraries. In addition to all of [my libraries](https://github.com/nothings/stb), there are other, similar libraries.
People have told me about quite a few of these. However, I haven't used most of these libraries The following is a list of small, easy-to-integrate, portable libraries
and can't comment on their quality. (If you use them and aren't their author, feel which are usable from C and/or C++, and should be able to be compiled on both
free to tell me about their quality.) _Newest additions are in italics._ 32-bit and 64-bit platforms.
- **images** [jo_gif.cpp](http://www.jonolick.com/home/gif-writer): animated GIF writer (public domain) ### Rules
- **images** [gif.h](https://github.com/ginsweater/gif-h): animated GIF writer (public domain)
- **images** [tiny_jpeg.h](https://github.com/serge-rgb/TinyJPEG/blob/master/tiny_jpeg.h): JPEG encoder (public domain)
- **images** [miniexr](https://github.com/aras-p/miniexr): OpenEXR writer (public domain)
- **geometry** [nv_voronoi.h](http://www.icculus.org/~mordred/nvlib/): find voronoi regions on lattice w/ integer inputs (public domain)
- _**geometry** [sobol.h](https://github.com/Marc-B-Reynolds/Stand-alone-junk/blob/master/src/SFH/Sobol.h): sobol & stratified sampling sequences (public domain)_
- **network** [zed_net](https://github.com/ZedZull/zed_net): cross-platform socket wrapper (public domain)
- **strings**; **files & filenames** [DG_misc.h](https://github.com/DanielGibson/Snippets/): Daniel Gibson's stb.h-esque cross-platform helpers: path/file, strings (public domain)
- **strings** [utf8](https://github.com/sheredom/utf8.h): utf8 string library (public domain)
- **misc** [MakeID.h](http://www.humus.name/3D/MakeID.h): allocate/deallocate small integer IDs efficiently (public domain)
- **misc** [gb_string.h](https://github.com/gingerBill/gb): dynamic strings for C (public domain)
- _**misc** [loguru](https://github.com/emilk/loguru): flexible logging for C++ (public domain)
- _**hardware** [EasyTab](https://github.com/ApoorvaJ/EasyTab): multi-platform tablet input (public domain)_
Not public domain: - Libraries must be usable from C or C++, ideally both
- Libraries should be usable from more than one platform (ideally, all major desktops and/or all major mobile)
- Libraries should compile and work on both 32-bit and 64-bit platforms
- Libraries should use at most two files
- **images** [tinyexr](https://github.com/syoyo/tinyexr): EXR image read/write (BSD license) *uses miniz internally* Exceptions will be allowed for good reasons.
- **images** [lodepng](http://lodev.org/lodepng/): PNG encoder/decoder (zlib license)
- **images** [nanoSVG](https://github.com/memononen/nanosvg): 1-file SVG parser; 1-file SVG rasterizer (zlib license)
- **3D** [tinyobjloader](https://github.com/syoyo/tinyobjloader): wavefront OBJ file loader (BSD license)
- **2D** [blendish](https://bitbucket.org/duangle/oui-blendish/src): blender-style widget rendering (MIT license)
- **geometry** [sdf.h](https://github.com/memononen/SDF): compute signed-distance field from antialiased image (MIT license)
- **geometry** [nanoflann](https://github.com/jlblancoc/nanoflann): build KD trees for point clouds (BSD license)
- **geometry** [jc_voronoi](https://github.com/JCash/voronoi): find voronoi regions on float/double data (MIT license)
- _**network** [wby](https://github.com/vurtun/wby): lightweight webserver, fork of webby (BSD license)_
- **audio** [aw_ima.h](https://github.com/afterwise/aw-ima/blob/master/aw-ima.h): IMA-ADPCM audio decoder (MIT license)
- **multithreading** [mts](https://github.com/vurtun/mts): cross-platform multithreaded task scheduler (zlib license)
- **parsing** [SLRE](https://github.com/cesanta/slre): regular expression matcher (GPL v2)
- **parsing** [PicoJSON](https://github.com/kazuho/picojson): JSON parse/serializer for C++ (BSD license)
- _**parsing** [zange](https://github.com/vurtun/zange): JSON parser (MIT license)_
- **tests** [utest](https://github.com/evolutional/utest): unit testing (MIT license)
- **tests** [catch](https://github.com/philsquared/Catch): unit testing (Boost license)
- **tests** [SPUT](http://www.lingua-systems.com/unit-testing/): unit testing (BSD license)
- _**misc** [lualite](https://github.com/janezz55/lualite/): generate lua bindings in C++ (MIT license)_
There are some that have a source file and require a separate header file (which they may ### New libraries and corrections
not even supply). That's twice as many files, and we at nothings/stb cannot condone
this! But you might like them anyway:
- **images** [picopng.cpp](http://lodev.org/lodepng/picopng.cpp): tiny PNG loader (zlib license) See discussion after the list.
- **images** [jpeg-compressor](https://github.com/richgel999/jpeg-compressor): 2-file jpeg compress, 2-file jpeg decompress (public domain)
- **3D** [mikktspace](https://svn.blender.org/svnroot/bf-blender/trunk/blender/intern/mikktspace/): compute tangent space for normal mapping (zlib)
- **2D** [tigr](https://bitbucket.org/rmitton/tigr/src): quick-n-dirty window text/graphics for Windows (public domain)
- **2D** [noc_turtle](https://github.com/guillaumechereau/noc): procedural graphics generator (public domain)
- **geometry** [Tomas Akenine-Moller snippets](http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/): various 3D intersection calculations, not lib-ified (public domain)
- **geometry** [Clipper](http://www.angusj.com/delphi/clipper.php): line & polygon clipping & offsetting (Boost license)
- **network** [yocto](https://github.com/tom-seddon/yhs): non-production-use http server (public domain)
- **network** [happyhttp](http://scumways.com/happyhttp/happyhttp.html): http client requests (zlib license)
- **network** [mongoose](https://github.com/cesanta/mongoose): http server (GPL v2)
- _**crypto** [TweetNaCl](http://tweetnacl.cr.yp.to/software.html): high-quality tiny cryptography library (public domain)_
- **AI** [micropather](http://www.grinninglizard.com/MicroPather/): pathfinding with A* (zlib license)
- **compression** [miniz.c](https://github.com/richgel999/miniz): zlib compression,decompression, zip file, png writing (public domain)
- **compression** [lz4](https://github.com/Cyan4973/lz4): fast but larger LZ compression (BSD license)
- **compression** [fastlz](https://code.google.com/p/fastlz/source/browse/#svn%2Ftrunk): fast but larger LZ compression (MIT license)
- **compression** [pithy](https://github.com/johnezang/pithy): fast but larger LZ compression (BSD license)
- **profiling** [Remotery](https://github.com/Celtoys/Remotery): CPU/GPU profiler Win/Mac/Linux, using web browser for viewer (Apache 2.0 license)
- **profiling** [MicroProfile](https://bitbucket.org/jonasmeyer/microprofile): CPU (and GPU?) profiler, 1-3 header files (unlicense) *uses miniz internally*
- **parsing** [json.h](https://github.com/sheredom/json.h): JSON parser (public domain)
- _**parsing** [jzon.h](https://github.com/Zguy/Jzon): JSON parser, C++ (MIT license)_
- **strings** [dfa](http://bjoern.hoehrmann.de/utf-8/decoder/dfa/): fast utf8 decoder (MIT license)
- **data structures** [klib](http://attractivechaos.github.io/klib/): many 2-file libs: hash, sort, b-tree, etc (MIT license)
- _**data structures** [uthash](https://github.com/troydhanson/uthash): several 1-header, 1-license-file libs: generic hash, list, etc (BSD license)_
- _**data structures** [PackedArray](https://github.com/gpakosz/PackedArray): memory-efficient array of elements with non-pow2 bitcount (WTFPL v2 license)_
- **data structures**; **algorithms** [minilibs](https://github.com/ccxvii/minilibs): two-file regex, binary tree (public domain)
- **files & filenames** [whereami](https://github.com/gpakosz/whereami): get path/filename of executable or module (WTFPL v2 license)
- **misc** [dbgtools](https://github.com/wc-duck/dbgtools): cross-platform debug util libraries (zlib license)
- _**misc** [stmr](https://github.com/wooorm/stmr.c): extract English word stems (MIT license)_
- _**misc** [levenshtein](https://github.com/wooorm/levenshtein.c): compute edit distance between two strings (MIT license)_
- **tests** [pempek_assert.cpp](https://github.com/gpakosz/Assert/tree/master/src): flexible assertions in C++ (WTFPL v2 license)
There is also these XML libraries, but if you're using XML, shame on you: ## Library listing
- **parsing** [tinyxml2](https://github.com/leethomason/tinyxml2): XML (zlib license) **Public domain single-file libraries usable from C and C++ are in bold.** Other
- **parsing** [pugixml](http://pugixml.org/): XML (MIT license) libraries are either non-public domain, or two files, or not usable from both C and C++, or
all three. Libraries of more than two files are mostly forbidden.
There are some libraries that are just _so_ awesome that even though they use more For the API column, "C" means C only, "C++" means C++ only, and "C/C++" means C/C++ usable
than two files we're going to give them special dispensation to appear in their own from either; some files may require *building* as C or C++ but still qualify as "C/C++" as
little list here. If you're a crazy purist, be warned, but otherwise, enjoy! long as the header file uses `extern "C"` to make it work. (In some cases, a header-file-only
library may compile as both C or C++, but produce an implementation that can only be called from
one or the other, because of a lack of use of `extern "C"`; in this case the table still qualifies it
as C/C++, as this is not an obstacle to most users.)
- **user interface** [ImGui](https://github.com/ocornut/imgui): an immediate-mode GUI ("imgui") named "ImGui" (MIT license)
category | library | license | API |files| description
----------------- | --------------------------------------------------------------------- |:--------------------:|:---:|:---:| -----------
AI | [micropather](http://www.grinninglizard.com/MicroPather/) | zlib | C++ | 2 | pathfinding with A*
audio | [aw_ima.h](https://github.com/afterwise/aw-ima/blob/master/aw-ima.h) | MIT |C/C++|**1**| IMA-ADPCM audio decoder
compression |**[miniz.c](https://github.com/richgel999/miniz)** |**public&nbsp;domain**|C/C++|**1**| compression,decompression, zip file, png writing
compression | [lz4](https://github.com/Cyan4973/lz4) | BSD |C/C++| 2 | fast but larger LZ compression
compression | [fastlz](https://code.google.com/p/fastlz/source/browse/#svn%2Ftrunk)| MIT |C/C++| 2 | fast but larger LZ compression
compression | [pithy](https://github.com/johnezang/pithy) | BSD |C/C++| 2 | fast but larger LZ compression
crypto | [TweetNaCl](http://tweetnacl.cr.yp.to/software.html) | **public domain** | C | 2 | high-quality tiny cryptography library
data&nbsp;structures|[klib](http://attractivechaos.github.io/klib/) | MIT |C/C++| 2 | many 2-file libs: hash, sort, b-tree, etc
data structures | [uthash](https://github.com/troydhanson/uthash) | BSD |C/C++| 2 | several 1-header, 1-license-file libs: generic hash, list, etc
data structures | [PackedArray](https://github.com/gpakosz/PackedArray) | **WTFPLv2** | C | 2 | memory-efficient array of elements with non-pow2 bitcount
data structures | [minilibs](https://github.com/ccxvii/minilibs) | **public domain** | C | 2 | two-file binary tress (also regex, etc)
files & filenames |**[DG_misc.h](https://github.com/DanielGibson/Snippets/)** | **public domain** |C/C++|**1**| Daniel Gibson's stb.h-esque cross-platform helpers: path/file, strings
files & filenames | [whereami](https://github.com/gpakosz/whereami) |**WTFPLv2** |C/C++| 2 | get path/filename of executable or module
files & filenames | [noc_file_dialog.h](https://github.com/guillaumechereau/noc) | MIT |C/C++| 1 | file open/save dialogs (Linux/OSX/Windows)
geometry file | [tk_objfile](https://github.com/joeld42/tk_objfile) | MIT |C/C++|**1**| OBJ file loader
geometry file | [tinyply](https://github.com/ddiakopoulos/tinyply) | **public domain** | C++ | 2 | PLY mesh file loader
geometry file | [tinyobjloader](https://github.com/syoyo/tinyobjloader) | BSD | C++ |**1**| wavefront OBJ file loader
geometry math |**[nv_voronoi.h](http://www.icculus.org/~mordred/nvlib/)** | **public domain** |C/C++|**1**| find voronoi regions on lattice w/ integer inputs
geometry math |**[sobol.h](https://github.com/Marc-B-Reynolds/Stand-alone-junk/)** | **public domain** |C/C++|**1**| sobol & stratified sampling sequences
geometry math | [sdf.h](https://github.com/memononen/SDF) | MIT |C/C++|**1**| compute signed-distance field from antialiased image
geometry math | [nanoflann](https://github.com/jlblancoc/nanoflann) | BSD | C++ |**1**| build KD trees for point clouds
geometry math | [jc_voronoi](https://github.com/JCash/voronoi) | MIT |C/C++|**1**| find voronoi regions on float/double data
geometry math | [par_msquares](https://github.com/prideout/par) | MIT |C/C++|**1**| convert (binarized) image to triangles
geometry math | [par_shapes](http://github.prideout.net/shapes/) | MIT |C/C++|**1**| generate various 3d geometric shapes
geometry math | [Tomas Akenine-Moller snippets](http://tinyurl.com/ht79ndj) | **public domain** |C/C++| 2 | various 3D intersection calculations, not lib-ified
geometry math | [Clipper](http://www.angusj.com/delphi/clipper.php) | Boost | C++ | 2 | line & polygon clipping & offsetting
geometry math | [PolyPartition](https://github.com/ivanfratric/polypartition) | MIT | C++ | 2 | polygon triangulation, partitioning
graphics (2d) | [blendish](https://bitbucket.org/duangle/oui-blendish/src) | MIT |C/C++|**1**| blender-style widget rendering
graphics (2d) | [tigr](https://bitbucket.org/rmitton/tigr/src) | **public domain** |C/C++| 2 | quick-n-dirty window text/graphics for Windows
graphics (2d) | [noc_turtle](https://github.com/guillaumechereau/noc) | MIT |C/C++| 2 | procedural graphics generator
graphics (3-D) | [mikktspace](http://tinyurl.com/z6xtucm) | zlib |C/C++| 2 | compute tangent space for normal mapping
graphics (3-D) | [debug-draw](https://github.com/glampert/debug-draw) | **public domain** | C++ |**1**| API-agnostic immediate-mode debug rendering
hardware |**[EasyTab](https://github.com/ApoorvaJ/EasyTab)** | **public domain** |C/C++|**1**| multi-platform tablet input
images | [jo_gif.cpp](http://www.jonolick.com/home/gif-writer) | **public domain** | C++ |**1**| animated GIF writer (CPP file can also be used as H file)
images |**[gif.h](https://github.com/ginsweater/gif-h)** | **public domain** | C |**1**| animated GIF writer (can only include once)
images |**[tiny_jpeg.h](https://github.com/serge-rgb/TinyJPEG/)** | **public domain** |C/C++|**1**| JPEG encoder
images | [miniexr](https://github.com/aras-p/miniexr) | **public domain** | C++ | 2 | OpenEXR writer, needs header file
images | [tinyexr](https://github.com/syoyo/tinyexr) | BSD |C/C++|**1**| EXR image read/write, uses miniz internally
images | [lodepng](http://lodev.org/lodepng/) | zlib |C/C++| 2 | PNG encoder/decoder
images | [nanoSVG](https://github.com/memononen/nanosvg) | zlib |C/C++|**1**| 1-file SVG parser; 1-file SVG rasterizer
images | [picopng.cpp](http://lodev.org/lodepng/picopng.cpp) | zlib | C++ | 2 | tiny PNG loader
images | [jpeg-compressor](https://github.com/richgel999/jpeg-compressor) | **public domain** | C++ | 2 | 2-file jpeg compress, 2-file jpeg decompress
images | [easyexif](https://github.com/mayanklahiri/easyexif) | MIT | C++ | 2 | EXIF metadata extractor for JPEG images
math | [mm_vec.h](https://github.com/vurtun/mmx) | BSD |C/C++|**1**| SIMD vector math
math | [ShaderFastLibs](https://github.com/michaldrobot/ShaderFastLibs) | MIT | C++ |**1**| (also HLSL) approximate transcendental functions optimized for shaders (esp. GCN)
math | [TinyExpr](https://github.com/codeplea/tinyexpr) | zlib | C | 2 | evaluation of math expressions from strings
multithreading | [mm_sched.h](https://github.com/vurtun/mmx) | zlib |C/C++|**1**| cross-platform multithreaded task scheduler
network |**[zed_net](https://github.com/ZedZull/zed_net)** | **public domain** |C/C++|**1**| cross-platform socket wrapper
network | [mm_web.h](https://github.com/vurtun/mmx) | BSD |C/C++|**1**| lightweight webserver, fork of webby
network | [par_easycurl.h](https://github.com/prideout/par) | MIT |C/C++|**1**| curl wrapper
network | [yocto](https://github.com/tom-seddon/yhs) | **public domain** |C/C++| 2 | non-production-use http server
network | [happyhttp](http://scumways.com/happyhttp/happyhttp.html) | zlib | C++ | 2 | http client requests
network | [mongoose](https://github.com/cesanta/mongoose) |_GPLv2_ |C/C++| 2 | http server
network | [LUrlParser](https://github.com/corporateshark/LUrlParser) | MIT | C++ | 2 | lightweight URL & URI parser RFC 1738, RFC 3986
parsing | [SLRE](https://github.com/cesanta/slre) |_GPLv2_ |C/C++|**1**| regular expression matcher
parsing | [PicoJSON](https://github.com/kazuho/picojson) | BSD | C++ |**1**| JSON parse/serializer
parsing | [mm_lexer.h](https://github.com/vurtun/mmx) | zlib |C/C++|**1**| C-esque language lexer
parsing | [json.h](https://github.com/sheredom/json.h) | **public domain** |C/C++| 2 | JSON parser
parsing | [jzon.h](https://github.com/Zguy/Jzon) | MIT | C++ | 2 | JSON parser
parsing | [parson](https://github.com/kgabis/parson) | MIT |C/C++| 2 | JSON parser and serializer
parsing | [minilibs](https://github.com/ccxvii/minilibs) | **public domain** | C | 2 | two-file regex (also binary tree, etc)
profiling | [Remotery](https://github.com/Celtoys/Remotery) | Apache 2.0 |C/C++| 2 | CPU/GPU profiler Win/Mac/Linux, using web browser for viewer
profiling | [MicroProfile](https://bitbucket.org/jonasmeyer/microprofile) | **unlicense** | C++ | 2-4 | CPU (and GPU?) profiler, 1-3 header files, uses miniz internally
scripting | [LIL](http://runtimelegend.com/rep/lil/) | zlib |C/C++| 2 | interpreter for a Tcl-like scripting language
scripting | [lualite](https://github.com/janezz55/lualite/) | MIT | C++ |**1**| generate lua bindings in C++
scripting | [Picol](https://chiselapp.com/user/dbohdan/repository/picol/) | BSD |C/C++|**1**| interpreter for a Tcl-like scripting language
strings |**[DG_misc.h](https://github.com/DanielGibson/Snippets/)** | **public domain** |C/C++|**1**| Daniel Gibson's stb.h-esque cross-platform helpers: path/file, strings
strings |**[utf8](https://github.com/sheredom/utf8.h)** | **public domain** |C/C++|**1**| utf8 string library
strings |**[strpool.h](https://github.com/mattiasgustavsson/libs)** | **public domain** |C/C++|**1**| string interning
strings | [dfa](http://bjoern.hoehrmann.de/utf-8/decoder/dfa/) | MIT |C/C++| 2 | fast utf8 decoder (need a header file)
strings |**[gb_string.h](https://github.com/gingerBill/gb)** | **public domain** |C/C++|**1**| dynamic strings
tests | [utest](https://github.com/evolutional/utest) | MIT |C/C++|**1**| unit testing
tests | [catch](https://github.com/philsquared/Catch) | Boost | C++ |**1**| unit testing
tests | [SPUT](http://www.lingua-systems.com/unit-testing/) | BSD |C/C++|**1**| unit testing
tests | [pempek_assert.cpp](https://github.com/gpakosz/Assert) | **WTFPLv2** | C++ | 2 | flexible assertions
tests | [minctest](https://github.com/codeplea/minctest) | zlib | C |**1**| unit testing
user interface | [dear imgui](https://github.com/ocornut/imgui) | MIT | C++*| 9 | an immediate-mode GUI formerly named "ImGui"; [3rd-party C wrapper](https://github.com/Extrawurst/cimgui)
_misc_ | [MakeID.h](http://www.humus.name/3D/MakeID.h) | **public domain** | C++ |**1**| allocate/deallocate small integer IDs efficiently
_misc_ | [loguru](https://github.com/emilk/loguru) | **public domain** | C++ |**1**| flexible logging
_misc_ | [tinyformat](https://github.com/c42f/tinyformat) | Boost | C++ |**1**| typesafe printf
_misc_ | [dbgtools](https://github.com/wc-duck/dbgtools) | zlib |C/C++| 2 | cross-platform debug util libraries
_misc_ | [stmr](https://github.com/wooorm/stmr.c) | MIT | C | 2 | extract English word stems
_misc_ | [levenshtein](https://github.com/wooorm/levenshtein.c) | MIT | C | 2 | compute edit distance between two strings
There are also these XML libraries, but if you're using XML, shame on you:
- parsing: [tinyxml2](https://github.com/leethomason/tinyxml2): XML
- parsing: [pugixml](http://pugixml.org/): XML (MIT license)
Also you might be interested in other related, but different lists: Also you might be interested in other related, but different lists:
- [clib](https://github.com/clibs/clib/wiki/Packages): list of (mostly) small single C functions (licenses not listed) - [clib](https://github.com/clibs/clib/wiki/Packages): list of (mostly) small single C functions (licenses not listed)
## New libraries and corrections
Submissions of new libraries: I accept submissions (as issues or as pull requests). Please
note that every file that must be included in a user's project counts; a header and a source
file is 2 files, but a header file, source file, and LICENSE (if the license isn't in the
source file) is 3 files, and won't be accepted, because it's not 2 files. But actually
'LICENSE' is a problem for just dropping the library in a source tree anyway, since it's
not scoped to just the library, so library authors are encouraged to include the license in the
source file and not require a separate LICENSE.
Corrections: if information for a library above is wrong, please send a correction as an
issue, pull request, or email. Note that if the list indicates a library works from both
C/C++, but it doesn't, this could be an error in the list or it could be a bug in the
library. If you find a library doesn't work in 32-bit or 64-bit, the library should be
removed from this list, unless it's a bug in the library.
## *List FAQ* ## *List FAQ*
### Can I link directly to this list? ### Can I link directly to this list?

116
stb.h
View File

@ -1,4 +1,4 @@
/* stb.h - v2.25 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h /* stb.h - v2.26 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h
no warranty is offered or implied; use this code at your own risk no warranty is offered or implied; use this code at your own risk
This is a single header file with a bunch of useful utilities This is a single header file with a bunch of useful utilities
@ -25,6 +25,7 @@
Version History Version History
2.26 various warning & buffixes
2.25 various warning & bugfixes 2.25 various warning & bugfixes
2.24 various warning & bugfixes 2.24 various warning & bugfixes
2.23 fix 2.22 2.23 fix 2.22
@ -186,6 +187,9 @@ CREDITS
Mojofreem@github Mojofreem@github
Ryan Whitworth Ryan Whitworth
Vincent Isambart Vincent Isambart
Mike Sartain
Eugene Opalev
Tim Sjostrand
*/ */
#ifndef STB__INCLUDE_STB_H #ifndef STB__INCLUDE_STB_H
@ -206,10 +210,16 @@ CREDITS
#endif #endif
#endif #endif
#ifdef _WIN32 #if defined(_WIN32) && !defined(__MINGW32__)
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE
#endif
#ifndef _CRT_NON_CONFORMING_SWPRINTFS
#define _CRT_NON_CONFORMING_SWPRINTFS #define _CRT_NON_CONFORMING_SWPRINTFS
#endif
#if !defined(_MSC_VER) || _MSC_VER > 1700 #if !defined(_MSC_VER) || _MSC_VER > 1700
#include <intrin.h> // _BitScanReverse #include <intrin.h> // _BitScanReverse
#endif #endif
@ -714,20 +724,41 @@ STB_EXTERN char * stb_sstrdup(char *s);
STB_EXTERN void stbprint(const char *fmt, ...); STB_EXTERN void stbprint(const char *fmt, ...);
STB_EXTERN char *stb_sprintf(const char *fmt, ...); STB_EXTERN char *stb_sprintf(const char *fmt, ...);
STB_EXTERN char *stb_mprintf(const char *fmt, ...); STB_EXTERN char *stb_mprintf(const char *fmt, ...);
STB_EXTERN int stb_snprintf(char *s, size_t n, const char *fmt, ...);
STB_EXTERN int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v);
#ifdef STB_DEFINE #ifdef STB_DEFINE
int stb_vsnprintf(char *s, size_t n, const char *fmt, va_list v)
{
int res;
#ifdef _WIN32
// Could use "_vsnprintf_s(s, n, _TRUNCATE, fmt, v)" ?
res = _vsnprintf(s,n,fmt,v);
#else
res = vsnprintf(s,n,fmt,v);
#endif
if (n) s[n-1] = 0;
// Unix returns length output would require, Windows returns negative when truncated.
return (res >= (int) n || res < 0) ? -1 : res;
}
int stb_snprintf(char *s, size_t n, const char *fmt, ...)
{
int res;
va_list v;
va_start(v,fmt);
res = stb_vsnprintf(s, n, fmt, v);
va_end(v);
return res;
}
char *stb_sprintf(const char *fmt, ...) char *stb_sprintf(const char *fmt, ...)
{ {
static char buffer[1024]; static char buffer[1024];
va_list v; va_list v;
va_start(v,fmt); va_start(v,fmt);
#ifdef _WIN32 stb_vsnprintf(buffer,1024,fmt,v);
_vsnprintf(buffer, 1024, fmt, v);
#else
vsnprintf(buffer, 1024, fmt, v);
#endif
va_end(v); va_end(v);
buffer[1023] = 0;
return buffer; return buffer;
} }
@ -736,13 +767,8 @@ char *stb_mprintf(const char *fmt, ...)
static char buffer[1024]; static char buffer[1024];
va_list v; va_list v;
va_start(v,fmt); va_start(v,fmt);
#ifdef _WIN32 stb_vsnprintf(buffer,1024,fmt,v);
_vsnprintf(buffer, 1024, fmt, v);
#else
vsnprintf(buffer, 1024, fmt, v);
#endif
va_end(v); va_end(v);
buffer[1023] = 0;
return strdup(buffer); return strdup(buffer);
} }
@ -842,9 +868,8 @@ void stbprint(const char *fmt, ...)
va_list v; va_list v;
va_start(v,fmt); va_start(v,fmt);
res = _vsnprintf(buffer, sizeof(buffer), fmt, v); res = stb_vsnprintf(buffer, sizeof(buffer), fmt, v);
va_end(v); va_end(v);
buffer[sizeof(buffer)-1] = 0;
if (res < 0) { if (res < 0) {
tbuf = (char *) malloc(16384); tbuf = (char *) malloc(16384);
@ -1765,6 +1790,7 @@ STB_EXTERN char * stb_strichr(char *s, char t);
STB_EXTERN char * stb_stristr(char *s, char *t); STB_EXTERN char * stb_stristr(char *s, char *t);
STB_EXTERN int stb_prefix_count(char *s, char *t); STB_EXTERN int stb_prefix_count(char *s, char *t);
STB_EXTERN char * stb_plural(int n); // "s" or "" STB_EXTERN char * stb_plural(int n); // "s" or ""
STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n);
STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count);
STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out); STB_EXTERN char **stb_tokens_nested(char *src, char *delimit, int *count, char *nest_in, char *nest_out);
@ -1779,6 +1805,17 @@ STB_EXTERN char **stb_tokens_quoted(char *src, char *delimit, int *count);
#ifdef STB_DEFINE #ifdef STB_DEFINE
size_t stb_strscpy(char *d, const char *s, size_t n)
{
size_t len = strlen(s);
if (len >= n) {
if (n) d[0] = 0;
return 0;
}
strcpy(d,s);
return len + 1;
}
char *stb_plural(int n) char *stb_plural(int n)
{ {
return n == 1 ? "" : "s"; return n == 1 ? "" : "s";
@ -3062,7 +3099,7 @@ typedef struct
#define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n)) #define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n))
// insert an element at i // insert an element at i
#define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n), ((a)[i] = v)) #define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v))
// delete N elements from the middle starting at index 'i' // delete N elements from the middle starting at index 'i'
#define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n)) #define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n))
@ -3248,7 +3285,7 @@ void stb__arr_insertn_(void **pp, int size, int i, int n STB__PARAMS)
} }
z = stb_arr_len2(p); z = stb_arr_len2(p);
stb__arr_addlen_(&p, size, i STB__ARGS); stb__arr_addlen_(&p, size, n STB__ARGS);
memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i)); memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i));
} }
*pp = p; *pp = p;
@ -3258,7 +3295,7 @@ void stb__arr_deleten_(void **pp, int size, int i, int n STB__PARAMS)
{ {
void *p = *pp; void *p = *pp;
if (n) { if (n) {
memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-i)); memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n)));
stb_arrhead2(p)->len -= n; stb_arrhead2(p)->len -= n;
} }
*pp = p; *pp = p;
@ -5863,11 +5900,18 @@ void stb_readdir_free(char **files)
stb_arr_free(f2); stb_arr_free(f2);
} }
static int isdotdirname(char *name)
{
if (name[0] == '.')
return (name[1] == '.') ? !name[2] : !name[1];
return 0;
}
STB_EXTERN int stb_wildmatchi(char *expr, char *candidate); STB_EXTERN int stb_wildmatchi(char *expr, char *candidate);
static char **readdir_raw(char *dir, int return_subdirs, char *mask) static char **readdir_raw(char *dir, int return_subdirs, char *mask)
{ {
char **results = NULL; char **results = NULL;
char buffer[512], with_slash[512]; char buffer[4096], with_slash[4096];
size_t n; size_t n;
#ifdef _MSC_VER #ifdef _MSC_VER
@ -5885,25 +5929,28 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
DIR *z; DIR *z;
#endif #endif
strcpy(buffer,dir); n = stb_strscpy(buffer,dir,sizeof(buffer));
if (!n || n >= sizeof(buffer))
return NULL;
stb_fixpath(buffer); stb_fixpath(buffer);
n = strlen(buffer); n--;
if (n > 0 && (buffer[n-1] != '/')) { if (n > 0 && (buffer[n-1] != '/')) {
buffer[n++] = '/'; buffer[n++] = '/';
} }
buffer[n] = 0; buffer[n] = 0;
strcpy(with_slash, buffer); if (!stb_strscpy(with_slash,buffer,sizeof(with_slash)))
return NULL;
#ifdef _MSC_VER #ifdef _MSC_VER
strcpy(buffer+n, "*.*"); if (!stb_strscpy(buffer+n,"*.*",sizeof(buffer)-n))
return NULL;
ws = stb__from_utf8(buffer); ws = stb__from_utf8(buffer);
z = _wfindfirst((const wchar_t *)ws, &data); z = _wfindfirst((const wchar_t *)ws, &data);
#else #else
z = opendir(dir); z = opendir(dir);
#endif #endif
if (z != none) { if (z != none) {
int nonempty = STB_TRUE; int nonempty = STB_TRUE;
#ifndef _MSC_VER #ifndef _MSC_VER
@ -5924,17 +5971,18 @@ static char **readdir_raw(char *dir, int return_subdirs, char *mask)
is_subdir = !!(data.attrib & _A_SUBDIR); is_subdir = !!(data.attrib & _A_SUBDIR);
#else #else
char *name = data->d_name; char *name = data->d_name;
strcpy(buffer+n,name); if (!stb_strscpy(buffer+n,name,sizeof(buffer)-n))
DIR *y = opendir(buffer); break;
is_subdir = (y != NULL); // Could follow DT_LNK, but would need to check for recursive links.
if (y != NULL) closedir(y); is_subdir = !!(data->d_type & DT_DIR);
#endif #endif
if (is_subdir == return_subdirs) { if (is_subdir == return_subdirs) {
if (!is_subdir || name[0] != '.') { if (!is_subdir || !isdotdirname(name)) {
if (!mask || stb_wildmatchi(mask, name)) { if (!mask || stb_wildmatchi(mask, name)) {
char buffer[512],*p=buffer; char buffer[4096],*p=buffer;
sprintf(buffer, "%s%s", with_slash, name); if ( stb_snprintf(buffer, sizeof(buffer), "%s%s", with_slash, name) < 0 )
break;
if (buffer[0] == '.' && buffer[1] == '/') if (buffer[0] == '.' && buffer[1] == '/')
p = buffer+2; p = buffer+2;
stb_arr_push(results, strdup(p)); stb_arr_push(results, strdup(p));
@ -7786,7 +7834,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value)
void ** stb_ps_getlist(stb_ps *ps, int *count) void ** stb_ps_getlist(stb_ps *ps, int *count)
{ {
int i,n=0; int i,n=0;
void **p; void **p = NULL;
switch (3 & (int) ps) { switch (3 & (int) ps) {
case STB_ps_direct: case STB_ps_direct:
if (ps == NULL) { *count = 0; return NULL; } if (ps == NULL) { *count = 0; return NULL; }

View File

@ -1,4 +1,4 @@
// stb_c_lexer.h - v0.06 - public domain Sean Barrett 2013 // stb_c_lexer.h - v0.07 - public domain Sean Barrett 2013
// lexer for making little C-like languages with recursive-descent parsers // lexer for making little C-like languages with recursive-descent parsers
// //
// This file provides both the interface and the implementation. // This file provides both the interface and the implementation.
@ -10,6 +10,7 @@
// suffixes on integer constants are not handled (you can override this). // suffixes on integer constants are not handled (you can override this).
// //
// History: // History:
// 0.07 fix mishandling of hexadecimal constants parsed by strtol
// 0.06 fix missing next character after ending quote mark (Andreas Fredriksson) // 0.06 fix missing next character after ending quote mark (Andreas Fredriksson)
// 0.05 refixed get_location because github version had lost the fix // 0.05 refixed get_location because github version had lost the fix
// 0.04 fix octal parsing bug // 0.04 fix octal parsing bug
@ -634,7 +635,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
if (p[1] == 'x' || p[1] == 'X') { if (p[1] == 'x' || p[1] == 'X') {
char *q = p+2; char *q = p+2;
#ifdef STB__CLEX_use_stdlib #ifdef STB__CLEX_use_stdlib
lexer->int_number = strtol((char *) p, (char **) q, 16); lexer->int_number = strtol((char *) p, (char **) &q, 16);
#else #else
stb__clex_int n=0; stb__clex_int n=0;
while (q != lexer->eof) { while (q != lexer->eof) {

View File

@ -1,4 +1,4 @@
// stb_easy_font.h - v0.6 - bitmap font for 3D rendering - public domain // stb_easy_font.h - v0.7 - bitmap font for 3D rendering - public domain
// Sean Barrett, Feb 2015 // Sean Barrett, Feb 2015
// //
// Easy-to-deploy, // Easy-to-deploy,
@ -16,8 +16,10 @@
// DOCUMENTATION: // DOCUMENTATION:
// //
// int stb_easy_font_width(char *text) // int stb_easy_font_width(char *text)
// int stb_easy_font_height(char *text)
// //
// Takes a string without newlines and returns the horizontal size. // Takes a string and returns the horizontal size and the
// vertical size (which can vary if 'text' has newlines).
// //
// int stb_easy_font_print(float x, float y, // int stb_easy_font_print(float x, float y,
// char *text, unsigned char color[4], // char *text, unsigned char color[4],
@ -40,7 +42,7 @@
// //
// You can ignore z and color if you get them from elsewhere // You can ignore z and color if you get them from elsewhere
// This format was chosen in the hopes it would make it // This format was chosen in the hopes it would make it
// easier for you to reuse existing buffer-drawing code. // easier for you to reuse existing vertex-buffer-drawing code.
// //
// If you pass in NULL for color, it becomes 255,255,255,255. // If you pass in NULL for color, it becomes 255,255,255,255.
// //
@ -63,11 +65,6 @@
// compact to me; -0.5 is a reasonable compromise as long as // compact to me; -0.5 is a reasonable compromise as long as
// you're scaling the font up. // you're scaling the font up.
// //
// 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.
//
// LICENSE // LICENSE
// //
// This software is in the public domain. Where that dedication is not // This software is in the public domain. Where that dedication is not
@ -76,10 +73,16 @@
// //
// VERSION HISTORY // VERSION HISTORY
// //
// (2016-01-22) 0.7 width() supports multiline text; add height()
// (2015-09-13) 0.6 #include <math.h>; updated license // (2015-09-13) 0.6 #include <math.h>; updated license
// (2015-02-01) 0.5 First release // (2015-02-01) 0.5 First release
#if 0 #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) void print_string(float x, float y, char *text, float r, float g, float b)
{ {
static char buffer[99999]; // ~500 chars static char buffer[99999]; // ~500 chars
@ -222,11 +225,34 @@ static int stb_easy_font_print(float x, float y, char *text, unsigned char color
static int stb_easy_font_width(char *text) static int stb_easy_font_width(char *text)
{ {
float len = 0; float len = 0;
float max_len = 0;
while (*text) { while (*text) {
len += stb_easy_font_charinfo[*text-32].advance & 15; if (*text == '\n') {
len += stb_easy_font_spacing_val; if (len > max_len) max_len = len;
len = 0;
} else {
len += stb_easy_font_charinfo[*text-32].advance & 15;
len += stb_easy_font_spacing_val;
}
++text; ++text;
} }
return (int) ceil(len); if (len > max_len) max_len = len;
return (int) ceil(max_len);
}
static int stb_easy_font_height(char *text)
{
float y = 0;
int nonempty_line=0;
while (*text) {
if (*text == '\n') {
y += 12;
nonempty_line = 0;
} else {
nonempty_line = 1;
}
++text;
}
return (int) ceil(y + (nonempty_line ? 12 : 0));
} }
#endif #endif

View File

@ -1,4 +1,4 @@
/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h /* stb_image - v2.10 - public domain image loader - http://nothings.org/stb_image.h
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@ -146,6 +146,8 @@
Latest revision history: Latest revision history:
2.10 (2016-01-22) avoid warning introduced in 2.09
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) partial animated GIF support 2.07 (2015-09-13) partial animated GIF support
limited 16-bit PSD support limited 16-bit PSD support
@ -175,44 +177,35 @@
============================ Contributors ========================= ============================ Contributors =========================
Image formats Bug fixes & warning fixes Image formats Extensions, features
Sean Barrett (jpeg, png, bmp) Marc LeBlanc Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
Nicolas Schulz (hdr, psd) Christpher Lloyd Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
Jonathan Dummer (tga) Dave Moore Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
Jean-Marc Lienher (gif) Won Chun Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
Tom Seddon (pic) the Horde3D community Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
Thatcher Ulrich (psd) Janez Zemva Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Jonathan Blow Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
urraka@github (animated gif) Laurent Gomila urraka@github (animated gif) Junggon Kim (PNM comments)
Aruelien Pocheville Daniel Gibson (16-bit TGA)
Ryamond Barbiero
David Woo Optimizations & bugfixes
Extensions, features Martin Golini Fabian "ryg" Giesen
Jetro Lauha (stbi_info) Roy Eltham Arseny Kapoulkine
Martin "SpartanJ" Golini (stbi_info) Luke Graham
James "moose2000" Brown (iPhone PNG) Thomas Ruf Bug & warning fixes
Ben "Disch" Wenger (io callbacks) John Bartholomew Marc LeBlanc David Woo Guillaume George Martins Mozeiko
Omar Cornut (1/2/4-bit PNG) Ken Hamada Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson
Nicolas Guillemot (vertical flip) Cort Stratton Dave Moore Roy Eltham Hayaki Saito Phil Jordan
Richard Mitton (16-bit PSD) Blazej Dariusz Roszkowski Won Chun Luke Graham Johan Duparc Nathan Reed
Thibault Reuille the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis
Paul Du Bois Janez Zemva John Bartholomew Michal Cichon svdijk@github
Guillaume George Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson
Jerry Jansson Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github
Hayaki Saito Aruelien Pocheville Thibault Reuille Cass Everitt
Johan Duparc Ryamond Barbiero Paul Du Bois Engin Manap
Ronny Chevalier Blazej Dariusz Roszkowski
Optimizations & bugfixes Michal Cichon Michaelangel007@github
Fabian "ryg" Giesen Tero Hanninen
Arseny Kapoulkine Sergio Gonzalez
Cass Everitt
Engin Manap
If your name should be here but Martins Mozeiko
isn't, let Sean know. Joseph Thomson
Phil Jordan
Nathan Reed
Michaelangel007@github
Nick Verigakis
LICENSE LICENSE
@ -461,12 +454,12 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y,
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
STBIDEF void stbi_hdr_to_ldr_scale(float scale); STBIDEF void stbi_hdr_to_ldr_scale(float scale);
#endif #endif // STBI_NO_HDR
#ifndef STBI_NO_LINEAR #ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
STBIDEF void stbi_ldr_to_hdr_scale(float scale); STBIDEF void stbi_ldr_to_hdr_scale(float scale);
#endif // STBI_NO_HDR #endif // STBI_NO_LINEAR
// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
@ -630,18 +623,22 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
#endif #endif
#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
// ok // ok
#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) #elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
// ok // ok
#else #else
#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." #error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
#endif #endif
#ifndef STBI_MALLOC #ifndef STBI_MALLOC
#define STBI_MALLOC(sz) malloc(sz) #define STBI_MALLOC(sz) malloc(sz)
#define STBI_REALLOC(p,sz) realloc(p,sz) #define STBI_REALLOC(p,newsz) realloc(p,newsz)
#define STBI_FREE(p) free(p) #define STBI_FREE(p) free(p)
#endif
#ifndef STBI_REALLOC_SIZED
#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
#endif #endif
// x86/x64 detection // x86/x64 detection
@ -1186,14 +1183,15 @@ STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void
#endif #endif
} }
static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; #ifndef STBI_NO_LINEAR
static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
#ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
#endif #endif
static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
@ -3616,14 +3614,15 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes
{ {
char *q; char *q;
int cur, limit; int cur, limit, old_limit;
z->zout = zout; z->zout = zout;
if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
cur = (int) (z->zout - z->zout_start); cur = (int) (z->zout - z->zout_start);
limit = (int) (z->zout_end - z->zout_start); limit = old_limit = (int) (z->zout_end - z->zout_start);
while (cur + n > limit) while (cur + n > limit)
limit *= 2; limit *= 2;
q = (char *) STBI_REALLOC(z->zout_start, limit); q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
STBI_NOTUSED(old_limit);
if (q == NULL) return stbi__err("outofmem", "Out of memory"); if (q == NULL) return stbi__err("outofmem", "Out of memory");
z->zout_start = q; z->zout_start = q;
z->zout = q + cur; z->zout = q + cur;
@ -4408,11 +4407,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
if ((int)(ioff + c.length) < (int)ioff) return 0; if ((int)(ioff + c.length) < (int)ioff) return 0;
if (ioff + c.length > idata_limit) { if (ioff + c.length > idata_limit) {
stbi__uint32 idata_limit_old = idata_limit;
stbi_uc *p; stbi_uc *p;
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
while (ioff + c.length > idata_limit) while (ioff + c.length > idata_limit)
idata_limit *= 2; idata_limit *= 2;
p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); STBI_NOTUSED(idata_limit_old);
p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
z->idata = p; z->idata = p;
} }
if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
@ -4598,19 +4599,22 @@ static int stbi__shiftsigned(int v, int shift, int bits)
return result; return result;
} }
static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) typedef struct
{ {
stbi_uc *out; int bpp, offset, hsz;
unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255; unsigned int mr,mg,mb,ma, all_a;
stbi_uc pal[256][4]; } stbi__bmp_data;
int psize=0,i,j,compress=0,width;
int bpp, flip_vertically, pad, target, offset, hsz; static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
{
int hsz;
if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
stbi__get32le(s); // discard filesize stbi__get32le(s); // discard filesize
stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved
stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved
offset = stbi__get32le(s); info->offset = stbi__get32le(s);
hsz = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s);
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
if (hsz == 12) { if (hsz == 12) {
s->img_x = stbi__get16le(s); s->img_x = stbi__get16le(s);
@ -4620,15 +4624,10 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
s->img_y = stbi__get32le(s); s->img_y = stbi__get32le(s);
} }
if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
bpp = stbi__get16le(s); info->bpp = stbi__get16le(s);
if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
flip_vertically = ((int) s->img_y) > 0; if (hsz != 12) {
s->img_y = abs((int) s->img_y); int compress = stbi__get32le(s);
if (hsz == 12) {
if (bpp < 24)
psize = (offset - 14 - 24) / 3;
} else {
compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard sizeof
stbi__get32le(s); // discard hres stbi__get32le(s); // discard hres
@ -4642,26 +4641,26 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
stbi__get32le(s); stbi__get32le(s);
stbi__get32le(s); stbi__get32le(s);
} }
if (bpp == 16 || bpp == 32) { if (info->bpp == 16 || info->bpp == 32) {
mr = mg = mb = 0; info->mr = info->mg = info->mb = 0;
if (compress == 0) { if (compress == 0) {
if (bpp == 32) { if (info->bpp == 32) {
mr = 0xffu << 16; info->mr = 0xffu << 16;
mg = 0xffu << 8; info->mg = 0xffu << 8;
mb = 0xffu << 0; info->mb = 0xffu << 0;
ma = 0xffu << 24; info->ma = 0xffu << 24;
all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
} else { } else {
mr = 31u << 10; info->mr = 31u << 10;
mg = 31u << 5; info->mg = 31u << 5;
mb = 31u << 0; info->mb = 31u << 0;
} }
} else if (compress == 3) { } else if (compress == 3) {
mr = stbi__get32le(s); info->mr = stbi__get32le(s);
mg = stbi__get32le(s); info->mg = stbi__get32le(s);
mb = stbi__get32le(s); info->mb = stbi__get32le(s);
// not documented, but generated by photoshop and handled by mspaint // not documented, but generated by photoshop and handled by mspaint
if (mr == mg && mg == mb) { if (info->mr == info->mg && info->mg == info->mb) {
// ?!?!? // ?!?!?
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
} }
@ -4669,11 +4668,13 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
} }
} else { } else {
STBI_ASSERT(hsz == 108 || hsz == 124); int i;
mr = stbi__get32le(s); if (hsz != 108 && hsz != 124)
mg = stbi__get32le(s); return stbi__errpuc("bad BMP", "bad BMP");
mb = stbi__get32le(s); info->mr = stbi__get32le(s);
ma = stbi__get32le(s); info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s);
info->ma = stbi__get32le(s);
stbi__get32le(s); // discard color space stbi__get32le(s); // discard color space
for (i=0; i < 12; ++i) for (i=0; i < 12; ++i)
stbi__get32le(s); // discard color space parameters stbi__get32le(s); // discard color space parameters
@ -4684,35 +4685,68 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
stbi__get32le(s); // discard reserved stbi__get32le(s); // discard reserved
} }
} }
if (bpp < 16)
psize = (offset - 14 - hsz) >> 2;
} }
return (void *) 1;
}
static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
stbi_uc *out;
unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
stbi_uc pal[256][4];
int psize=0,i,j,width;
int flip_vertically, pad, target;
stbi__bmp_data info;
info.all_a = 255;
if (stbi__bmp_parse_header(s, &info) == NULL)
return NULL; // error code already set
flip_vertically = ((int) s->img_y) > 0;
s->img_y = abs((int) s->img_y);
mr = info.mr;
mg = info.mg;
mb = info.mb;
ma = info.ma;
all_a = info.all_a;
if (info.hsz == 12) {
if (info.bpp < 24)
psize = (info.offset - 14 - 24) / 3;
} else {
if (info.bpp < 16)
psize = (info.offset - 14 - info.hsz) >> 2;
}
s->img_n = ma ? 4 : 3; s->img_n = ma ? 4 : 3;
if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
target = req_comp; target = req_comp;
else else
target = s->img_n; // if they want monochrome, we'll post-convert target = s->img_n; // if they want monochrome, we'll post-convert
out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);
if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (!out) return stbi__errpuc("outofmem", "Out of memory");
if (bpp < 16) { if (info.bpp < 16) {
int z=0; int z=0;
if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
for (i=0; i < psize; ++i) { for (i=0; i < psize; ++i) {
pal[i][2] = stbi__get8(s); pal[i][2] = stbi__get8(s);
pal[i][1] = stbi__get8(s); pal[i][1] = stbi__get8(s);
pal[i][0] = stbi__get8(s); pal[i][0] = stbi__get8(s);
if (hsz != 12) stbi__get8(s); if (info.hsz != 12) stbi__get8(s);
pal[i][3] = 255; pal[i][3] = 255;
} }
stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
if (bpp == 4) width = (s->img_x + 1) >> 1; if (info.bpp == 4) width = (s->img_x + 1) >> 1;
else if (bpp == 8) width = s->img_x; else if (info.bpp == 8) width = s->img_x;
else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
pad = (-width)&3; pad = (-width)&3;
for (j=0; j < (int) s->img_y; ++j) { for (j=0; j < (int) s->img_y; ++j) {
for (i=0; i < (int) s->img_x; i += 2) { for (i=0; i < (int) s->img_x; i += 2) {
int v=stbi__get8(s),v2=0; int v=stbi__get8(s),v2=0;
if (bpp == 4) { if (info.bpp == 4) {
v2 = v & 15; v2 = v & 15;
v >>= 4; v >>= 4;
} }
@ -4721,7 +4755,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
out[z++] = pal[v][2]; out[z++] = pal[v][2];
if (target == 4) out[z++] = 255; if (target == 4) out[z++] = 255;
if (i+1 == (int) s->img_x) break; if (i+1 == (int) s->img_x) break;
v = (bpp == 8) ? stbi__get8(s) : v2; v = (info.bpp == 8) ? stbi__get8(s) : v2;
out[z++] = pal[v][0]; out[z++] = pal[v][0];
out[z++] = pal[v][1]; out[z++] = pal[v][1];
out[z++] = pal[v][2]; out[z++] = pal[v][2];
@ -4733,14 +4767,14 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0; int z = 0;
int easy=0; int easy=0;
stbi__skip(s, offset - 14 - hsz); stbi__skip(s, info.offset - 14 - info.hsz);
if (bpp == 24) width = 3 * s->img_x; if (info.bpp == 24) width = 3 * s->img_x;
else if (bpp == 16) width = 2*s->img_x; else if (info.bpp == 16) width = 2*s->img_x;
else /* bpp = 32 and pad = 0 */ width=0; else /* bpp = 32 and pad = 0 */ width=0;
pad = (-width) & 3; pad = (-width) & 3;
if (bpp == 24) { if (info.bpp == 24) {
easy = 1; easy = 1;
} else if (bpp == 32) { } else if (info.bpp == 32) {
if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
easy = 2; easy = 2;
} }
@ -4765,6 +4799,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
if (target == 4) out[z++] = a; if (target == 4) out[z++] = a;
} }
} else { } else {
int bpp = info.bpp;
for (i=0; i < (int) s->img_x; ++i) { for (i=0; i < (int) s->img_x; ++i) {
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
int a; int a;
@ -4811,20 +4846,55 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
// Targa Truevision - TGA // Targa Truevision - TGA
// by Jonathan Dummer // by Jonathan Dummer
#ifndef STBI_NO_TGA #ifndef STBI_NO_TGA
// returns STBI_rgb or whatever, 0 on error
static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
{
// only RGB or RGBA (incl. 16bit) or grey allowed
if(is_rgb16) *is_rgb16 = 0;
switch(bits_per_pixel) {
case 8: return STBI_grey;
case 16: if(is_grey) return STBI_grey_alpha;
// else: fall-through
case 15: if(is_rgb16) *is_rgb16 = 1;
return STBI_rgb;
case 24: // fall-through
case 32: return bits_per_pixel/8;
default: return 0;
}
}
static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int tga_w, tga_h, tga_comp; int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
int sz; int sz, tga_colormap_type;
stbi__get8(s); // discard Offset stbi__get8(s); // discard Offset
sz = stbi__get8(s); // color type tga_colormap_type = stbi__get8(s); // colormap type
if( sz > 1 ) { if( tga_colormap_type > 1 ) {
stbi__rewind(s); stbi__rewind(s);
return 0; // only RGB or indexed allowed return 0; // only RGB or indexed allowed
} }
sz = stbi__get8(s); // image type tga_image_type = stbi__get8(s); // image type
// only RGB or grey allowed, +/- RLE if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; if (tga_image_type != 1 && tga_image_type != 9) {
stbi__skip(s,9); stbi__rewind(s);
return 0;
}
stbi__skip(s,4); // skip index of first colormap entry and number of entries
sz = stbi__get8(s); // check bits per palette color entry
if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
stbi__rewind(s);
return 0;
}
stbi__skip(s,4); // skip image x and y origin
tga_colormap_bpp = sz;
} else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
stbi__rewind(s);
return 0; // only RGB or grey allowed, +/- RLE
}
stbi__skip(s,9); // skip colormap specification and image x/y origin
tga_colormap_bpp = 0;
}
tga_w = stbi__get16le(s); tga_w = stbi__get16le(s);
if( tga_w < 1 ) { if( tga_w < 1 ) {
stbi__rewind(s); stbi__rewind(s);
@ -4835,44 +4905,80 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
stbi__rewind(s); stbi__rewind(s);
return 0; // test height return 0; // test height
} }
sz = stbi__get8(s); // bits per pixel tga_bits_per_pixel = stbi__get8(s); // bits per pixel
// only RGB or RGBA or grey allowed stbi__get8(s); // ignore alpha bits
if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { if (tga_colormap_bpp != 0) {
stbi__rewind(s); if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
return 0; // when using a colormap, tga_bits_per_pixel is the size of the indexes
// I don't think anything but 8 or 16bit indexes makes sense
stbi__rewind(s);
return 0;
}
tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
} else {
tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
}
if(!tga_comp) {
stbi__rewind(s);
return 0;
} }
tga_comp = sz;
if (x) *x = tga_w; if (x) *x = tga_w;
if (y) *y = tga_h; if (y) *y = tga_h;
if (comp) *comp = tga_comp / 8; if (comp) *comp = tga_comp;
return 1; // seems to have passed everything return 1; // seems to have passed everything
} }
static int stbi__tga_test(stbi__context *s) static int stbi__tga_test(stbi__context *s)
{ {
int res; int res = 0;
int sz; int sz, tga_color_type;
stbi__get8(s); // discard Offset stbi__get8(s); // discard Offset
sz = stbi__get8(s); // color type tga_color_type = stbi__get8(s); // color type
if ( sz > 1 ) return 0; // only RGB or indexed allowed if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed
sz = stbi__get8(s); // image type sz = stbi__get8(s); // image type
if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE if ( tga_color_type == 1 ) { // colormapped (paletted) image
stbi__get16be(s); // discard palette start if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
stbi__get16be(s); // discard palette length stbi__skip(s,4); // skip index of first colormap entry and number of entries
stbi__get8(s); // discard bits per palette color entry sz = stbi__get8(s); // check bits per palette color entry
stbi__get16be(s); // discard x origin if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
stbi__get16be(s); // discard y origin stbi__skip(s,4); // skip image x and y origin
if ( stbi__get16be(s) < 1 ) return 0; // test width } else { // "normal" image w/o colormap
if ( stbi__get16be(s) < 1 ) return 0; // test height if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
stbi__skip(s,9); // skip colormap specification and image x/y origin
}
if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width
if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height
sz = stbi__get8(s); // bits per pixel sz = stbi__get8(s); // bits per pixel
if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
res = 0; if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
else
res = 1; res = 1; // if we got this far, everything's good and we can return 1 instead of 0
errorEnd:
stbi__rewind(s); stbi__rewind(s);
return res; return res;
} }
// read 16bit value and convert to 24bit RGB
void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
{
stbi__uint16 px = stbi__get16le(s);
stbi__uint16 fiveBitMask = 31;
// we have 3 channels with 5bits each
int r = (px >> 10) & fiveBitMask;
int g = (px >> 5) & fiveBitMask;
int b = px & fiveBitMask;
// Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
out[0] = (r * 255)/31;
out[1] = (g * 255)/31;
out[2] = (b * 255)/31;
// some people claim that the most significant bit might be used for alpha
// (possibly if an alpha-bit is set in the "image descriptor byte")
// but that only made 16bit test images completely translucent..
// so let's treat all 15 and 16bit TGAs as RGB with no alpha.
}
static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{ {
// read in the TGA header stuff // read in the TGA header stuff
@ -4888,8 +4994,9 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
int tga_width = stbi__get16le(s); int tga_width = stbi__get16le(s);
int tga_height = stbi__get16le(s); int tga_height = stbi__get16le(s);
int tga_bits_per_pixel = stbi__get8(s); int tga_bits_per_pixel = stbi__get8(s);
int tga_comp = tga_bits_per_pixel / 8; int tga_comp, tga_rgb16=0;
int tga_inverted = stbi__get8(s); int tga_inverted = stbi__get8(s);
// int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
// image data // image data
unsigned char *tga_data; unsigned char *tga_data;
unsigned char *tga_palette = NULL; unsigned char *tga_palette = NULL;
@ -4905,25 +5012,14 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
tga_image_type -= 8; tga_image_type -= 8;
tga_is_RLE = 1; tga_is_RLE = 1;
} }
/* int tga_alpha_bits = tga_inverted & 15; */
tga_inverted = 1 - ((tga_inverted >> 5) & 1); tga_inverted = 1 - ((tga_inverted >> 5) & 1);
// error check
if ( //(tga_indexed) ||
(tga_width < 1) || (tga_height < 1) ||
(tga_image_type < 1) || (tga_image_type > 3) ||
((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) &&
(tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32))
)
{
return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA
}
// If I'm paletted, then I'll use the number of bits from the palette // If I'm paletted, then I'll use the number of bits from the palette
if ( tga_indexed ) if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
{ else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
tga_comp = tga_palette_bits / 8;
} if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
// tga info // tga info
*x = tga_width; *x = tga_width;
@ -4936,7 +5032,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// skip to the data's starting position (offset usually = 0) // skip to the data's starting position (offset usually = 0)
stbi__skip(s, tga_offset ); stbi__skip(s, tga_offset );
if ( !tga_indexed && !tga_is_RLE) { if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
for (i=0; i < tga_height; ++i) { for (i=0; i < tga_height; ++i) {
int row = tga_inverted ? tga_height -i - 1 : i; int row = tga_inverted ? tga_height -i - 1 : i;
stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
@ -4949,15 +5045,22 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// any data to skip? (offset usually = 0) // any data to skip? (offset usually = 0)
stbi__skip(s, tga_palette_start ); stbi__skip(s, tga_palette_start );
// load the palette // load the palette
tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp );
if (!tga_palette) { if (!tga_palette) {
STBI_FREE(tga_data); STBI_FREE(tga_data);
return stbi__errpuc("outofmem", "Out of memory"); return stbi__errpuc("outofmem", "Out of memory");
} }
if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { if (tga_rgb16) {
STBI_FREE(tga_data); stbi_uc *pal_entry = tga_palette;
STBI_FREE(tga_palette); STBI_ASSERT(tga_comp == STBI_rgb);
return stbi__errpuc("bad palette", "Corrupt TGA"); for (i=0; i < tga_palette_len; ++i) {
stbi__tga_read_rgb16(s, pal_entry);
pal_entry += tga_comp;
}
} else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
STBI_FREE(tga_data);
STBI_FREE(tga_palette);
return stbi__errpuc("bad palette", "Corrupt TGA");
} }
} }
// load the data // load the data
@ -4987,23 +5090,22 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// load however much data we did have // load however much data we did have
if ( tga_indexed ) if ( tga_indexed )
{ {
// read in 1 byte, then perform the lookup // read in index, then perform the lookup
int pal_idx = stbi__get8(s); int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
if ( pal_idx >= tga_palette_len ) if ( pal_idx >= tga_palette_len ) {
{ // invalid index
// invalid index
pal_idx = 0; pal_idx = 0;
} }
pal_idx *= tga_bits_per_pixel / 8; pal_idx *= tga_comp;
for (j = 0; j*8 < tga_bits_per_pixel; ++j) for (j = 0; j < tga_comp; ++j) {
{
raw_data[j] = tga_palette[pal_idx+j]; raw_data[j] = tga_palette[pal_idx+j];
} }
} else } else if(tga_rgb16) {
{ STBI_ASSERT(tga_comp == STBI_rgb);
stbi__tga_read_rgb16(s, raw_data);
} else {
// read in the data raw // read in the data raw
for (j = 0; j*8 < tga_bits_per_pixel; ++j) for (j = 0; j < tga_comp; ++j) {
{
raw_data[j] = stbi__get8(s); raw_data[j] = stbi__get8(s);
} }
} }
@ -5042,8 +5144,8 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
} }
} }
// swap RGB // swap RGB - if the source data was RGB16, it already is in the right order
if (tga_comp >= 3) if (tga_comp >= 3 && !tga_rgb16)
{ {
unsigned char* tga_pixel = tga_data; unsigned char* tga_pixel = tga_data;
for (i=0; i < tga_width * tga_height; ++i) for (i=0; i < tga_width * tga_height; ++i)
@ -6017,7 +6119,7 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
char *token; char *token;
int valid = 0; int valid = 0;
if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { if (stbi__hdr_test(s) == 0) {
stbi__rewind( s ); stbi__rewind( s );
return 0; return 0;
} }
@ -6054,29 +6156,17 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
#ifndef STBI_NO_BMP #ifndef STBI_NO_BMP
static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int hsz; void *p;
if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { stbi__bmp_data info;
stbi__rewind( s );
return 0; info.all_a = 255;
} p = stbi__bmp_parse_header(s, &info);
stbi__skip(s,12); stbi__rewind( s );
hsz = stbi__get32le(s); if (p == NULL)
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { return 0;
stbi__rewind( s ); *x = s->img_x;
return 0; *y = s->img_y;
} *comp = info.ma ? 4 : 3;
if (hsz == 12) {
*x = stbi__get16le(s);
*y = stbi__get16le(s);
} else {
*x = stbi__get32le(s);
*y = stbi__get32le(s);
}
if (stbi__get16le(s) != 1) {
stbi__rewind( s );
return 0;
}
*comp = stbi__get16le(s) / 8;
return 1; return 1;
} }
#endif #endif
@ -6222,8 +6312,16 @@ static int stbi__pnm_isspace(char c)
static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) static void stbi__pnm_skip_whitespace(stbi__context *s, char *c)
{ {
while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) for (;;) {
*c = (char) stbi__get8(s); while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
*c = (char) stbi__get8(s);
if (stbi__at_eof(s) || *c != '#')
break;
while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
*c = (char) stbi__get8(s);
}
} }
static int stbi__pnm_isdigit(char c) static int stbi__pnm_isdigit(char c)
@ -6361,10 +6459,17 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
/* /*
revision history: revision history:
2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
2.09 (2016-01-16) allow comments in PNM files
16-bit-per-pixel TGA (not bit-per-component)
info() for TGA could break due to .hdr handling
info() for BMP to shares code instead of sloppy parse
can use STBI_REALLOC_SIZED if allocator doesn't support realloc
code cleanup
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) fix compiler warnings 2.07 (2015-09-13) fix compiler warnings
partial animated GIF support partial animated GIF support
limited 16-bit PSD support limited 16-bpc PSD support
#ifdef unused functions #ifdef unused functions
bug with < 92 byte PIC,PNM,HDR,TGA bug with < 92 byte PIC,PNM,HDR,TGA
2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value

View File

@ -1,4 +1,4 @@
/* stb_image_write - v1.00 - public domain - http://nothings.org/stb/stb_image_write.h /* stb_image_write - v1.01 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk no warranty implied; use at your own risk
@ -34,7 +34,7 @@ USAGE:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
There are also four equivalent functions that use an arbitrary write function. You are There are also four equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these: expected to open/close your file-equivalent before and after calling these:
@ -98,12 +98,16 @@ CREDITS:
github:Chribba github:Chribba
Guillaume Chereau Guillaume Chereau
github:jry2 github:jry2
github:romigrou
Sergio Gonzalez
Jonas Karlsson
Filip Wasil
LICENSE LICENSE
This software is in the public domain. Where that dedication is not This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy, recognized, you are granted a perpetual, irrevocable license to copy,
distribute, and modify this file as you see fit. distribute, and modify this file as you see fit.
*/ */
@ -144,8 +148,12 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w,
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#ifdef _WIN32 #ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE
#endif
#endif #endif
#ifndef STBI_WRITE_NO_STDIO #ifndef STBI_WRITE_NO_STDIO
@ -157,19 +165,25 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w,
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC) #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
// ok // ok
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
// ok // ok
#else #else
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC." #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
#endif #endif
#ifndef STBIW_MALLOC #ifndef STBIW_MALLOC
#define STBIW_MALLOC(sz) malloc(sz) #define STBIW_MALLOC(sz) malloc(sz)
#define STBIW_REALLOC(p,sz) realloc(p,sz) #define STBIW_REALLOC(p,newsz) realloc(p,newsz)
#define STBIW_FREE(p) free(p) #define STBIW_FREE(p) free(p)
#endif #endif
#ifndef STBIW_REALLOC_SIZED
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
#endif
#ifndef STBIW_MEMMOVE #ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif #endif
@ -180,6 +194,8 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w,
#define STBIW_ASSERT(x) assert(x) #define STBIW_ASSERT(x) assert(x)
#endif #endif
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
typedef struct typedef struct
{ {
stbi_write_func *func; stbi_write_func *func;
@ -228,21 +244,21 @@ static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
while (*fmt) { while (*fmt) {
switch (*fmt++) { switch (*fmt++) {
case ' ': break; case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
s->func(s->context,&x,1); s->func(s->context,&x,1);
break; } break; }
case '2': { int x = va_arg(v,int); case '2': { int x = va_arg(v,int);
unsigned char b[2]; unsigned char b[2];
b[0] = (unsigned char) x; b[0] = STBIW_UCHAR(x);
b[1] = (unsigned char) (x>>8); b[1] = STBIW_UCHAR(x>>8);
s->func(s->context,b,2); s->func(s->context,b,2);
break; } break; }
case '4': { stbiw_uint32 x = va_arg(v,int); case '4': { stbiw_uint32 x = va_arg(v,int);
unsigned char b[4]; unsigned char b[4];
b[0]=(unsigned char)x; b[0]=STBIW_UCHAR(x);
b[1]=(unsigned char)(x>>8); b[1]=STBIW_UCHAR(x>>8);
b[2]=(unsigned char)(x>>16); b[2]=STBIW_UCHAR(x>>16);
b[3]=(unsigned char)(x>>24); b[3]=STBIW_UCHAR(x>>24);
s->func(s->context,b,4); s->func(s->context,b,4);
break; } break; }
default: default:
@ -419,13 +435,13 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
} }
if (diff) { if (diff) {
unsigned char header = (unsigned char) (len - 1); unsigned char header = STBIW_UCHAR(len - 1);
s->func(s->context, &header, 1); s->func(s->context, &header, 1);
for (k = 0; k < len; ++k) { for (k = 0; k < len; ++k) {
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
} }
} else { } else {
unsigned char header = (unsigned char) (len - 129); unsigned char header = STBIW_UCHAR(len - 129);
s->func(s->context, &header, 1); s->func(s->context, &header, 1);
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
} }
@ -467,7 +483,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
int exponent; int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
if (maxcomp < 1e-32) { if (maxcomp < 1e-32f) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else { } else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
@ -481,7 +497,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
{ {
unsigned char lengthbyte = (unsigned char) (length+128); unsigned char lengthbyte = STBIW_UCHAR(length+128);
STBIW_ASSERT(length+128 <= 255); STBIW_ASSERT(length+128 <= 255);
s->func(s->context, &lengthbyte, 1); s->func(s->context, &lengthbyte, 1);
s->func(s->context, &databyte, 1); s->func(s->context, &databyte, 1);
@ -489,7 +505,7 @@ void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char dat
void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
{ {
unsigned char lengthbyte = (unsigned char )(length & 0xff); unsigned char lengthbyte = STBIW_UCHAR(length);
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
s->func(s->context, &lengthbyte, 1); s->func(s->context, &lengthbyte, 1);
s->func(s->context, data, length); s->func(s->context, data, length);
@ -647,7 +663,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
{ {
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2); void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
STBIW_ASSERT(p); STBIW_ASSERT(p);
if (p) { if (p) {
if (!*arr) ((int *) p)[1] = 0; if (!*arr) ((int *) p)[1] = 0;
@ -660,7 +676,7 @@ static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{ {
while (*bitcount >= 8) { while (*bitcount >= 8) {
stbiw__sbpush(data, (unsigned char) *bitbuffer); stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
*bitbuffer >>= 8; *bitbuffer >>= 8;
*bitcount -= 8; *bitcount -= 8;
} }
@ -795,7 +811,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
{ {
// compute adler32 on input // compute adler32 on input
unsigned int k=0, s1=1, s2=0; unsigned int s1=1, s2=0;
int blocklen = (int) (data_len % 5552); int blocklen = (int) (data_len % 5552);
j=0; j=0;
while (j < data_len) { while (j < data_len) {
@ -804,10 +820,10 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
j += blocklen; j += blocklen;
blocklen = 5552; blocklen = 5552;
} }
stbiw__sbpush(out, (unsigned char) (s2 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
stbiw__sbpush(out, (unsigned char) s2); stbiw__sbpush(out, STBIW_UCHAR(s2));
stbiw__sbpush(out, (unsigned char) (s1 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
stbiw__sbpush(out, (unsigned char) s1); stbiw__sbpush(out, STBIW_UCHAR(s1));
} }
*out_len = stbiw__sbn(out); *out_len = stbiw__sbn(out);
// make returned pointer freeable // make returned pointer freeable
@ -815,21 +831,52 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
return (unsigned char *) stbiw__sbraw(out); return (unsigned char *) stbiw__sbraw(out);
} }
unsigned int stbiw__crc32(unsigned char *buffer, int len) static unsigned int stbiw__crc32(unsigned char *buffer, int len)
{ {
static unsigned int crc_table[256]; static unsigned int crc_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
unsigned int crc = ~0u; unsigned int crc = ~0u;
int i,j; int i;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i) for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc; return ~crc;
} }
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4) #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
@ -842,9 +889,9 @@ static void stbiw__wpcrc(unsigned char **data, int len)
static unsigned char stbiw__paeth(int a, int b, int c) static unsigned char stbiw__paeth(int a, int b, int c)
{ {
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a; if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
if (pb <= pc) return (unsigned char) b; if (pb <= pc) return STBIW_UCHAR(b);
return (unsigned char) c; return STBIW_UCHAR(c);
} }
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
@ -917,7 +964,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
stbiw__wp32(o, x); stbiw__wp32(o, x);
stbiw__wp32(o, y); stbiw__wp32(o, y);
*o++ = 8; *o++ = 8;
*o++ = (unsigned char) ctype[n]; *o++ = STBIW_UCHAR(ctype[n]);
*o++ = 0; *o++ = 0;
*o++ = 0; *o++ = 0;
*o++ = 0; *o++ = 0;
@ -968,6 +1015,10 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
#endif // STB_IMAGE_WRITE_IMPLEMENTATION #endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history /* Revision history
1.01 (2016-01-16)
STBIW_REALLOC_SIZED: support allocators with no realloc support
avoid race-condition in crc initialization
minor compile issues
1.00 (2015-09-14) 1.00 (2015-09-14)
installable file IO function installable file IO function
0.99 (2015-09-13) 0.99 (2015-09-13)

View File

@ -1,4 +1,4 @@
// stb_tilemap_editor.h - v0.36 - Sean Barrett - http://nothings.org/stb // stb_tilemap_editor.h - v0.37 - Sean Barrett - http://nothings.org/stb
// placed in the public domain - not copyrighted - first released 2014-09 // placed in the public domain - not copyrighted - first released 2014-09
// //
// Embeddable tilemap editor for C/C++ // Embeddable tilemap editor for C/C++
@ -259,7 +259,7 @@
// #define STBTE_MAX_CATEGORIES 100 // #define STBTE_MAX_CATEGORIES 100
// #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB // #define STBTE_UNDO_BUFFER_BYTES (1 << 24) // 16 MB
// #define STBTE_MAX_COPY 90000 // e.g. 300x300 // #define STBTE_MAX_COPY 90000 // e.g. 300x300
// #define STBTE_MAX_PROPERTIESERTIES 10 // max properties per tile // #define STBTE_MAX_PROPERTIES 10 // max properties per tile
// //
// API // API
// //
@ -275,6 +275,7 @@
// either approach allows cut&pasting between levels.) // either approach allows cut&pasting between levels.)
// //
// REVISION HISTORY // REVISION HISTORY
// 0.37 fix warning
// 0.36 minor compiler support // 0.36 minor compiler support
// 0.35 layername button changes // 0.35 layername button changes
// - layername buttons grow with the layer panel // - layername buttons grow with the layer panel
@ -311,6 +312,7 @@
// Josh Huelsman // Josh Huelsman
// Bugfixes: // Bugfixes:
// Ryan Whitworth // Ryan Whitworth
// Eugene Opalev
// //
// LICENSE // LICENSE
// //
@ -328,7 +330,9 @@
#define STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H #define STB_TILEMAP_INCLUDE_STB_TILEMAP_EDITOR_H
#ifdef _WIN32 #ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#endif #endif

View File

@ -1,4 +1,4 @@
// stb_truetype.h - v1.08 - public domain // stb_truetype.h - v1.09 - public domain
// authored from 2009-2015 by Sean Barrett / RAD Game Tools // authored from 2009-2015 by Sean Barrett / RAD Game Tools
// //
// This library processes TrueType files: // This library processes TrueType files:
@ -42,12 +42,15 @@
// Sergey Popov // Sergey Popov
// Giumo X. Clanjor // Giumo X. Clanjor
// Higor Euripedes // Higor Euripedes
// Thomas Fields
// Derek Vinyard
// //
// Misc other: // Misc other:
// Ryan Gordon // Ryan Gordon
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
// variant PackFontRanges to pack and render in separate phases; // variant PackFontRanges to pack and render in separate phases;
@ -1556,7 +1559,7 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
{ {
int x0,y0,x1,y1; int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
// e.g. space character // e.g. space character
if (ix0) *ix0 = 0; if (ix0) *ix0 = 0;
@ -1672,6 +1675,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
{ {
stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
STBTT_assert(z != NULL);
if (!z) return z; if (!z) return z;
// round dx down to avoid overshooting // round dx down to avoid overshooting
@ -1693,6 +1697,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
{ {
stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
STBTT_assert(z != NULL);
//STBTT_assert(e->y0 <= start_point); //STBTT_assert(e->y0 <= start_point);
if (!z) return z; if (!z) return z;
z->fdx = dxdy; z->fdx = dxdy;
@ -1817,21 +1822,23 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
while (e->y0 <= scan_y) { while (e->y0 <= scan_y) {
if (e->y1 > scan_y) { if (e->y1 > scan_y) {
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
// find insertion point if (z != NULL) {
if (active == NULL) // find insertion point
active = z; if (active == NULL)
else if (z->x < active->x) { active = z;
// insert at front else if (z->x < active->x) {
z->next = active; // insert at front
active = z; z->next = active;
} else { active = z;
// find thing to insert AFTER } else {
stbtt__active_edge *p = active; // find thing to insert AFTER
while (p->next && p->next->x < z->x) stbtt__active_edge *p = active;
p = p->next; while (p->next && p->next->x < z->x)
// at this point, p->next->x is NOT < z->x p = p->next;
z->next = p->next; // at this point, p->next->x is NOT < z->x
p->next = z; z->next = p->next;
p->next = z;
}
} }
} }
++e; ++e;
@ -2101,10 +2108,12 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
while (e->y0 <= scan_y_bottom) { while (e->y0 <= scan_y_bottom) {
if (e->y0 != e->y1) { if (e->y0 != e->y1) {
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
STBTT_assert(z->ey >= scan_y_top); if (z != NULL) {
// insert at front STBTT_assert(z->ey >= scan_y_top);
z->next = active; // insert at front
active = z; z->next = active;
active = z;
}
} }
++e; ++e;
} }
@ -2513,6 +2522,7 @@ STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // fo
float scale; float scale;
int x,y,bottom_y, i; int x,y,bottom_y, i;
stbtt_fontinfo f; stbtt_fontinfo f;
f.userdata = NULL;
if (!stbtt_InitFont(&f, data, offset)) if (!stbtt_InitFont(&f, data, offset))
return -1; return -1;
STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
@ -2706,6 +2716,7 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i
unsigned char buffer[STBTT_MAX_OVERSAMPLE]; unsigned char buffer[STBTT_MAX_OVERSAMPLE];
int safe_w = w - kernel_width; int safe_w = w - kernel_width;
int j; int j;
STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
for (j=0; j < h; ++j) { for (j=0; j < h; ++j) {
int i; int i;
unsigned int total; unsigned int total;
@ -2767,6 +2778,7 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i
unsigned char buffer[STBTT_MAX_OVERSAMPLE]; unsigned char buffer[STBTT_MAX_OVERSAMPLE];
int safe_h = h - kernel_width; int safe_h = h - kernel_width;
int j; int j;
STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
for (j=0; j < w; ++j) { for (j=0; j < w; ++j) {
int i; int i;
unsigned int total; unsigned int total;
@ -2975,6 +2987,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd
if (rects == NULL) if (rects == NULL)
return 0; return 0;
info.userdata = spc->user_allocator_context;
stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
@ -3192,6 +3205,7 @@ STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const
// FULL VERSION HISTORY // FULL VERSION HISTORY
// //
// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
// allow PackFontRanges to pack and render in separate phases; // allow PackFontRanges to pack and render in separate phases;

View File

@ -1,8 +1,11 @@
// Ogg Vorbis audio decoder - v1.06 - public domain // Ogg Vorbis audio decoder - v1.07 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Written by Sean Barrett in 2007, last updated in 2014 // Original version written by Sean Barrett in 2007.
// Sponsored by RAD Game Tools. //
// Originally sponsored by RAD Game Tools. Seeking sponsored
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
// Aras Pranckevicius, and Sean Barrett.
// //
// LICENSE // LICENSE
// //
@ -30,11 +33,10 @@
// Laurent Gomila Marc LeBlanc Ronny Chevalier // Laurent Gomila Marc LeBlanc Ronny Chevalier
// Bernhard Wodo Evan Balster "alxprd"@github // Bernhard Wodo Evan Balster "alxprd"@github
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// (If you reported a bug but do not appear in this list, it is because // Phillip Bennefall Rohit
// someone else reported the bug before you. There were too many of you to
// list them all because I was lax about updating for a long time, sorry.)
// //
// Partial history: // Partial history:
// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const
// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) // 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
// some crash fixes when out of memory or with corrupt files // some crash fixes when out of memory or with corrupt files
// fix some inappropriately signed shifts // fix some inappropriately signed shifts
@ -45,8 +47,6 @@
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct) // 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel; // 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
// (API change) report sample rate for decode-full-file funcs // (API change) report sample rate for decode-full-file funcs
// 0.99996 - - bracket #include <malloc.h> for macintosh compilation
// 0.99995 - - avoid alias-optimization issue in float-to-int conversion
// //
// See end of file for full version history. // See end of file for full version history.
@ -155,10 +155,10 @@ extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
// specification does not bound the size of an individual frame. // specification does not bound the size of an individual frame.
extern stb_vorbis *stb_vorbis_open_pushdata( extern stb_vorbis *stb_vorbis_open_pushdata(
unsigned char *datablock, int datablock_length_in_bytes, const unsigned char * datablock, int datablock_length_in_bytes,
int *datablock_memory_consumed_in_bytes, int *datablock_memory_consumed_in_bytes,
int *error, int *error,
stb_vorbis_alloc *alloc_buffer); const stb_vorbis_alloc *alloc_buffer);
// create a vorbis decoder by passing in the initial data block containing // create a vorbis decoder by passing in the initial data block containing
// the ogg&vorbis headers (you don't need to do parse them, just provide // the ogg&vorbis headers (you don't need to do parse them, just provide
// the first N bytes of the file--you're told if it's not enough, see below) // the first N bytes of the file--you're told if it's not enough, see below)
@ -169,7 +169,8 @@ extern stb_vorbis *stb_vorbis_open_pushdata(
// incomplete and you need to pass in a larger block from the start of the file // incomplete and you need to pass in a larger block from the start of the file
extern int stb_vorbis_decode_frame_pushdata( extern int stb_vorbis_decode_frame_pushdata(
stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes, stb_vorbis *f,
const unsigned char *datablock, int datablock_length_in_bytes,
int *channels, // place to write number of float * buffers int *channels, // place to write number of float * buffers
float ***output, // place to write float ** array of float * buffers float ***output, // place to write float ** array of float * buffers
int *samples // place to write number of output samples int *samples // place to write number of output samples
@ -233,18 +234,18 @@ extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *chan
// When you're done with it, just free() the pointer returned in *output. // When you're done with it, just free() the pointer returned in *output.
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
int *error, stb_vorbis_alloc *alloc_buffer); int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note // create an ogg vorbis decoder from an ogg vorbis stream in memory (note
// this must be the entire stream!). on failure, returns NULL and sets *error // this must be the entire stream!). on failure, returns NULL and sets *error
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
extern stb_vorbis * stb_vorbis_open_filename(const char *filename, extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
int *error, stb_vorbis_alloc *alloc_buffer); int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from a filename via fopen(). on failure, // create an ogg vorbis decoder from a filename via fopen(). on failure,
// returns NULL and sets *error (possibly to VORBIS_file_open_failure). // returns NULL and sets *error (possibly to VORBIS_file_open_failure).
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
int *error, stb_vorbis_alloc *alloc_buffer); int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at // create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error. // the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between // note that stb_vorbis must "own" this stream; if you seek it in between
@ -254,7 +255,7 @@ extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
// function, stb_vorbis_open_file_section(), to limit it. // function, stb_vorbis_open_file_section(), to limit it.
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len); int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at // create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell); the stream will be of length 'len' bytes. // the _current_ seek point (ftell); the stream will be of length 'len' bytes.
// on failure, returns NULL and sets *error. note that stb_vorbis must "own" // on failure, returns NULL and sets *error. note that stb_vorbis must "own"
@ -292,15 +293,17 @@ extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***out
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
#endif #endif
// decode the next frame and return the number of samples per channel. the // decode the next frame and return the number of *samples* per channel.
// data is coerced to the number of channels you request according to the // Note that for interleaved data, you pass in the number of shorts (the
// size of your array), but the return value is the number of samples per
// channel, not the total number of samples.
//
// The data is coerced to the number of channels you request according to the
// channel coercion rules (see below). You must pass in the size of your // channel coercion rules (see below). You must pass in the size of your
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer. // buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
// The maximum buffer size needed can be gotten from get_info(); however, // The maximum buffer size needed can be gotten from get_info(); however,
// the Vorbis I specification implies an absolute maximum of 4096 samples // the Vorbis I specification implies an absolute maximum of 4096 samples
// per channel. Note that for interleaved data, you pass in the number of // per channel.
// shorts (the size of your array), but the return value is the number of
// samples per channel, not the total number of samples.
// Channel coercion rules: // Channel coercion rules:
// Let M be the number of channels requested, and N the number of channels present, // Let M be the number of channels requested, and N the number of channels present,
@ -367,7 +370,7 @@ enum STBVorbisError
VORBIS_invalid_first_page, VORBIS_invalid_first_page,
VORBIS_bad_packet_type, VORBIS_bad_packet_type,
VORBIS_cant_find_last_page, VORBIS_cant_find_last_page,
VORBIS_seek_failed, VORBIS_seek_failed
}; };
@ -488,14 +491,8 @@ enum STBVorbisError
// trade off storage for speed. // trade off storage for speed.
//#define STB_VORBIS_DIVIDES_IN_CODEBOOK //#define STB_VORBIS_DIVIDES_IN_CODEBOOK
// STB_VORBIS_CODEBOOK_SHORTS #ifdef STB_VORBIS_CODEBOOK_SHORTS
// The vorbis file format encodes VQ codebook floats as ax+b where a and #error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"
// b are floating point per-codebook constants, and x is a 16-bit int.
// Normally, stb_vorbis decodes them to floats rather than leaving them
// as 16-bit ints and computing ax+b while decoding. This is a speed/space
// tradeoff; you can save space by defining this flag.
#ifndef STB_VORBIS_CODEBOOK_SHORTS
#define STB_VORBIS_CODEBOOK_FLOATS
#endif #endif
// STB_VORBIS_DIVIDE_TABLE // STB_VORBIS_DIVIDE_TABLE
@ -556,11 +553,26 @@ enum STBVorbisError
#if !(defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh)) #if !(defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh))
#include <malloc.h> #include <malloc.h>
#endif #endif
#else #else // STB_VORBIS_NO_CRT
#define NULL 0 #define NULL 0
#endif #define malloc(s) 0
#define free(s) ((void) 0)
#define realloc(s) 0
#endif // STB_VORBIS_NO_CRT
#if !defined(_MSC_VER) && !(defined(__MINGW32__) && defined(__forceinline)) #include <limits.h>
#ifdef __MINGW32__
// eff you mingw:
// "fixed":
// http://sourceforge.net/p/mingw-w64/mailman/message/32882927/
// "no that broke the build, reverted, who cares about C":
// http://sourceforge.net/p/mingw-w64/mailman/message/32890381/
#ifdef __forceinline
#undef __forceinline
#endif
#define __forceinline
#elif !defined(_MSC_VER)
#if __GNUC__ #if __GNUC__
#define __forceinline inline #define __forceinline inline
#else #else
@ -577,6 +589,13 @@ enum STBVorbisError
#endif #endif
#if 0
#include <crtdbg.h>
#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])
#else
#define CHECK(f) ((void) 0)
#endif
#define MAX_BLOCKSIZE_LOG 13 // from specification #define MAX_BLOCKSIZE_LOG 13 // from specification
#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG) #define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG)
@ -593,11 +612,7 @@ typedef signed int int32;
#define FALSE 0 #define FALSE 0
#endif #endif
#ifdef STB_VORBIS_CODEBOOK_FLOATS
typedef float codetype; typedef float codetype;
#else
typedef uint16 codetype;
#endif
// @NOTE // @NOTE
// //
@ -831,13 +846,6 @@ struct stb_vorbis
int channel_buffer_end; int channel_buffer_end;
}; };
extern int my_prof(int slot);
//#define stb_prof my_prof
#ifndef stb_prof
#define stb_prof(x) ((void) 0)
#endif
#if defined(STB_VORBIS_NO_PUSHDATA_API) #if defined(STB_VORBIS_NO_PUSHDATA_API)
#define IS_PUSH_MODE(f) FALSE #define IS_PUSH_MODE(f) FALSE
#elif defined(STB_VORBIS_NO_PULLDATA_API) #elif defined(STB_VORBIS_NO_PULLDATA_API)
@ -904,7 +912,7 @@ static void *setup_malloc(vorb *f, int sz)
static void setup_free(vorb *f, void *p) static void setup_free(vorb *f, void *p)
{ {
if (f->alloc.alloc_buffer) return; // do nothing; setup mem is not a stack if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack
free(p); free(p);
} }
@ -1055,10 +1063,12 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
while (z > 0 && !available[z]) --z; while (z > 0 && !available[z]) --z;
if (z == 0) { return FALSE; } if (z == 0) { return FALSE; }
res = available[z]; res = available[z];
assert(z >= 0 && z < 32);
available[z] = 0; available[z] = 0;
add_entry(c, bit_reverse(res), i, m++, len[i], values); add_entry(c, bit_reverse(res), i, m++, len[i], values);
// propogate availability up the tree // propogate availability up the tree
if (z != len[i]) { if (z != len[i]) {
assert(len[i] >= 0 && len[i] < 32);
for (y=len[i]; y > z; --y) { for (y=len[i]; y > z; --y) {
assert(available[y] == 0); assert(available[y] == 0);
available[y] = res + (1 << (32-y)); available[y] = res + (1 << (32-y));
@ -1576,7 +1586,7 @@ enum
{ {
VORBIS_packet_id = 1, VORBIS_packet_id = 1,
VORBIS_packet_comment = 3, VORBIS_packet_comment = 3,
VORBIS_packet_setup = 5, VORBIS_packet_setup = 5
}; };
static int codebook_decode_scalar_raw(vorb *f, Codebook *c) static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
@ -1584,7 +1594,9 @@ static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
int i; int i;
prep_huffman(f); prep_huffman(f);
assert(c->sorted_codewords || c->codewords); if (c->codewords == NULL && c->sorted_codewords == NULL)
return -1;
// cases to use binary search: sorted_codewords && !c->codewords // cases to use binary search: sorted_codewords && !c->codewords
// sorted_codewords && c->entries > 8 // sorted_codewords && c->entries > 8
if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) { if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) {
@ -1692,15 +1704,9 @@ static int codebook_decode_scalar(vorb *f, Codebook *c)
// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case // CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case
// where we avoid one addition // where we avoid one addition
#ifndef STB_VORBIS_CODEBOOK_FLOATS #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off] * c->delta_value + c->minimum_value) #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off] * c->delta_value) #define CODEBOOK_ELEMENT_BASE(c) (0)
#define CODEBOOK_ELEMENT_BASE(c) (c->minimum_value)
#else
#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
#define CODEBOOK_ELEMENT_BASE(c) (0)
#endif
static int codebook_decode_start(vorb *f, Codebook *c) static int codebook_decode_start(vorb *f, Codebook *c)
{ {
@ -1892,7 +1898,6 @@ static int codebook_decode_deinterleave_repeat_2(vorb *f, Codebook *c, float **o
{ {
z *= c->dimensions; z *= c->dimensions;
stb_prof(11);
if (c->sequence_p) { if (c->sequence_p) {
// haven't optimized this case because I don't have any examples // haven't optimized this case because I don't have any examples
for (i=0; i < effective; ++i) { for (i=0; i < effective; ++i) {
@ -1904,7 +1909,7 @@ static int codebook_decode_deinterleave_repeat_2(vorb *f, Codebook *c, float **o
} }
} else { } else {
i=0; i=0;
if (c_inter == 1) { if (c_inter == 1 && i < effective) {
float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
if (outputs[c_inter]) if (outputs[c_inter])
outputs[c_inter][p_inter] += val; outputs[c_inter][p_inter] += val;
@ -2076,15 +2081,17 @@ static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y
#endif #endif
ady -= abs(base) * adx; ady -= abs(base) * adx;
if (x1 > n) x1 = n; if (x1 > n) x1 = n;
LINE_OP(output[x], inverse_db_table[y]); if (x < x1) {
for (++x; x < x1; ++x) {
err += ady;
if (err >= adx) {
err -= adx;
y += sy;
} else
y += base;
LINE_OP(output[x], inverse_db_table[y]); LINE_OP(output[x], inverse_db_table[y]);
for (++x; x < x1; ++x) {
err += ady;
if (err >= adx) {
err -= adx;
y += sy;
} else
y += base;
LINE_OP(output[x], inverse_db_table[y]);
}
} }
} }
@ -2123,7 +2130,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications)); int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications));
#endif #endif
stb_prof(2); CHECK(f);
for (i=0; i < ch; ++i) for (i=0; i < ch; ++i)
if (!do_not_decode[i]) if (!do_not_decode[i])
memset(residue_buffers[i], 0, sizeof(float) * n); memset(residue_buffers[i], 0, sizeof(float) * n);
@ -2135,11 +2143,9 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
if (j == ch) if (j == ch)
goto done; goto done;
stb_prof(3);
for (pass=0; pass < 8; ++pass) { for (pass=0; pass < 8; ++pass) {
int pcount = 0, class_set = 0; int pcount = 0, class_set = 0;
if (ch == 2) { if (ch == 2) {
stb_prof(13);
while (pcount < part_read) { while (pcount < part_read) {
int z = r->begin + pcount*r->part_size; int z = r->begin + pcount*r->part_size;
int c_inter = (z & 1), p_inter = z>>1; int c_inter = (z & 1), p_inter = z>>1;
@ -2157,7 +2163,6 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
} }
#endif #endif
} }
stb_prof(5);
for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
int z = r->begin + pcount*r->part_size; int z = r->begin + pcount*r->part_size;
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
@ -2168,23 +2173,20 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass]; int b = r->residue_books[c][pass];
if (b >= 0) { if (b >= 0) {
Codebook *book = f->codebooks + b; Codebook *book = f->codebooks + b;
stb_prof(20); // accounts for X time
#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
#else #else
// saves 1% // saves 1%
if (!codebook_decode_deinterleave_repeat_2(f, book, residue_buffers, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
#endif #endif
stb_prof(7);
} else { } else {
z += r->part_size; z += r->part_size;
c_inter = z & 1; c_inter = z & 1;
p_inter = z >> 1; p_inter = z >> 1;
} }
} }
stb_prof(8);
#ifndef STB_VORBIS_DIVIDES_IN_RESIDUE #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
++class_set; ++class_set;
#endif #endif
@ -2217,10 +2219,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass]; int b = r->residue_books[c][pass];
if (b >= 0) { if (b >= 0) {
Codebook *book = f->codebooks + b; Codebook *book = f->codebooks + b;
stb_prof(22);
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
stb_prof(3);
} else { } else {
z += r->part_size; z += r->part_size;
c_inter = 0; c_inter = 0;
@ -2259,10 +2259,8 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
int b = r->residue_books[c][pass]; int b = r->residue_books[c][pass];
if (b >= 0) { if (b >= 0) {
Codebook *book = f->codebooks + b; Codebook *book = f->codebooks + b;
stb_prof(22);
if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
goto done; goto done;
stb_prof(3);
} else { } else {
z += r->part_size; z += r->part_size;
c_inter = z % ch; c_inter = z % ch;
@ -2277,7 +2275,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
} }
goto done; goto done;
} }
stb_prof(9); CHECK(f);
for (pass=0; pass < 8; ++pass) { for (pass=0; pass < 8; ++pass) {
int pcount = 0, class_set=0; int pcount = 0, class_set=0;
@ -2326,7 +2324,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int
} }
} }
done: done:
stb_prof(0); CHECK(f);
temp_alloc_restore(f,temp_alloc_point); temp_alloc_restore(f,temp_alloc_point);
} }
@ -3140,13 +3138,16 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f
int hx = g->Xlist[j]; int hx = g->Xlist[j];
if (lx != hx) if (lx != hx)
draw_line(target, lx,ly, hx,hy, n2); draw_line(target, lx,ly, hx,hy, n2);
CHECK(f);
lx = hx, ly = hy; lx = hx, ly = hy;
} }
} }
if (lx < n2) if (lx < n2) {
// optimization of: draw_line(target, lx,ly, n,ly, n2); // optimization of: draw_line(target, lx,ly, n,ly, n2);
for (j=lx; j < n2; ++j) for (j=lx; j < n2; ++j)
LINE_OP(target[j], inverse_db_table[ly]); LINE_OP(target[j], inverse_db_table[ly]);
CHECK(f);
}
} }
return TRUE; return TRUE;
} }
@ -3217,6 +3218,7 @@ static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, in
*p_right_start = window_center; *p_right_start = window_center;
*p_right_end = n; *p_right_end = n;
} }
return TRUE; return TRUE;
} }
@ -3235,7 +3237,8 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// FLOORS // FLOORS
n2 = n >> 1; n2 = n >> 1;
stb_prof(1); CHECK(f);
for (i=0; i < f->channels; ++i) { for (i=0; i < f->channels; ++i) {
int s = map->chan[i].mux, floor; int s = map->chan[i].mux, floor;
zero_channel[i] = FALSE; zero_channel[i] = FALSE;
@ -3327,7 +3330,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// at this point we've decoded the floor into buffer // at this point we've decoded the floor into buffer
} }
} }
stb_prof(0); CHECK(f);
// at this point we've decoded all floors // at this point we've decoded all floors
if (f->alloc.alloc_buffer) if (f->alloc.alloc_buffer)
@ -3340,6 +3343,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE;
} }
CHECK(f);
// RESIDUE DECODE // RESIDUE DECODE
for (i=0; i < map->submaps; ++i) { for (i=0; i < map->submaps; ++i) {
float *residue_buffers[STB_VORBIS_MAX_CHANNELS]; float *residue_buffers[STB_VORBIS_MAX_CHANNELS];
@ -3364,9 +3368,9 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->alloc.alloc_buffer) if (f->alloc.alloc_buffer)
assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
CHECK(f);
// INVERSE COUPLING // INVERSE COUPLING
stb_prof(14);
for (i = map->coupling_steps-1; i >= 0; --i) { for (i = map->coupling_steps-1; i >= 0; --i) {
int n2 = n >> 1; int n2 = n >> 1;
float *m = f->channel_buffers[map->chan[i].magnitude]; float *m = f->channel_buffers[map->chan[i].magnitude];
@ -3387,10 +3391,10 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
a[j] = a2; a[j] = a2;
} }
} }
CHECK(f);
// finish decoding the floors // finish decoding the floors
#ifndef STB_VORBIS_NO_DEFER_FLOOR #ifndef STB_VORBIS_NO_DEFER_FLOOR
stb_prof(15);
for (i=0; i < f->channels; ++i) { for (i=0; i < f->channels; ++i) {
if (really_zero_channel[i]) { if (really_zero_channel[i]) {
memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
@ -3410,10 +3414,10 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
#endif #endif
// INVERSE MDCT // INVERSE MDCT
stb_prof(16); CHECK(f);
for (i=0; i < f->channels; ++i) for (i=0; i < f->channels; ++i)
inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); inverse_mdct(f->channel_buffers[i], n, f, m->blockflag);
stb_prof(0); CHECK(f);
// this shouldn't be necessary, unless we exited on an error // this shouldn't be necessary, unless we exited on an error
// and want to flush to get to the next packet // and want to flush to get to the next packet
@ -3455,7 +3459,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
uint32 current_end = f->known_loc_for_packet - (n-right_end); uint32 current_end = f->known_loc_for_packet - (n-right_end);
// then let's infer the size of the (probably) short final frame // then let's infer the size of the (probably) short final frame
if (current_end < f->current_loc + right_end) { if (current_end < f->current_loc + (right_end-left_start)) {
if (current_end < f->current_loc) { if (current_end < f->current_loc) {
// negative truncation, that's impossible! // negative truncation, that's impossible!
*len = 0; *len = 0;
@ -3463,6 +3467,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
*len = current_end - f->current_loc; *len = current_end - f->current_loc;
} }
*len += left_start; *len += left_start;
if (*len > right_end) *len = right_end; // this should never happen
f->current_loc += *len; f->current_loc += *len;
return TRUE; return TRUE;
} }
@ -3480,6 +3485,8 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
if (f->alloc.alloc_buffer) if (f->alloc.alloc_buffer)
assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
*len = right_end; // ignore samples after the window goes to 0 *len = right_end; // ignore samples after the window goes to 0
CHECK(f);
return TRUE; return TRUE;
} }
@ -3645,14 +3652,15 @@ static int start_decoder(vorb *f)
get32(f); // bitrate_nominal get32(f); // bitrate_nominal
get32(f); // bitrate_minimum get32(f); // bitrate_minimum
x = get8(f); x = get8(f);
{ int log0,log1; {
log0 = x & 15; int log0,log1;
log1 = x >> 4; log0 = x & 15;
f->blocksize_0 = 1 << log0; log1 = x >> 4;
f->blocksize_1 = 1 << log1; f->blocksize_0 = 1 << log0;
if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); f->blocksize_1 = 1 << log1;
if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup);
if (log0 > log1) return error(f, VORBIS_invalid_setup); if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup);
if (log0 > log1) return error(f, VORBIS_invalid_setup);
} }
// framing_flag // framing_flag
@ -3701,6 +3709,7 @@ static int start_decoder(vorb *f)
int total=0; int total=0;
uint8 *lengths; uint8 *lengths;
Codebook *c = f->codebooks+i; Codebook *c = f->codebooks+i;
CHECK(f);
x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup);
x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup);
x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup);
@ -3712,6 +3721,8 @@ static int start_decoder(vorb *f)
ordered = get_bits(f,1); ordered = get_bits(f,1);
c->sparse = ordered ? 0 : get_bits(f,1); c->sparse = ordered ? 0 : get_bits(f,1);
if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup);
if (c->sparse) if (c->sparse)
lengths = (uint8 *) setup_temp_malloc(f, c->entries); lengths = (uint8 *) setup_temp_malloc(f, c->entries);
else else
@ -3736,6 +3747,8 @@ static int start_decoder(vorb *f)
if (present) { if (present) {
lengths[j] = get_bits(f, 5) + 1; lengths[j] = get_bits(f, 5) + 1;
++total; ++total;
if (lengths[j] == 32)
return error(f, VORBIS_invalid_setup);
} else { } else {
lengths[j] = NO_CODE; lengths[j] = NO_CODE;
} }
@ -3770,6 +3783,7 @@ static int start_decoder(vorb *f)
c->sorted_entries = sorted_count; c->sorted_entries = sorted_count;
values = NULL; values = NULL;
CHECK(f);
if (!c->sparse) { if (!c->sparse) {
c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries); c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries);
if (!c->codewords) return error(f, VORBIS_outofmem); if (!c->codewords) return error(f, VORBIS_outofmem);
@ -3815,6 +3829,7 @@ static int start_decoder(vorb *f)
compute_accelerated_huffman(c); compute_accelerated_huffman(c);
CHECK(f);
c->lookup_type = get_bits(f, 4); c->lookup_type = get_bits(f, 4);
if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup);
if (c->lookup_type > 0) { if (c->lookup_type > 0) {
@ -3828,6 +3843,7 @@ static int start_decoder(vorb *f)
} else { } else {
c->lookup_values = c->entries * c->dimensions; c->lookup_values = c->entries * c->dimensions;
} }
if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup);
mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values);
if (mults == NULL) return error(f, VORBIS_outofmem); if (mults == NULL) return error(f, VORBIS_outofmem);
for (j=0; j < (int) c->lookup_values; ++j) { for (j=0; j < (int) c->lookup_values; ++j) {
@ -3839,6 +3855,7 @@ static int start_decoder(vorb *f)
#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
if (c->lookup_type == 1) { if (c->lookup_type == 1) {
int len, sparse = c->sparse; int len, sparse = c->sparse;
float last=0;
// pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop
if (sparse) { if (sparse) {
if (c->sorted_entries == 0) goto skip; if (c->sorted_entries == 0) goto skip;
@ -3848,21 +3865,22 @@ static int start_decoder(vorb *f)
if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
len = sparse ? c->sorted_entries : c->entries; len = sparse ? c->sorted_entries : c->entries;
for (j=0; j < len; ++j) { for (j=0; j < len; ++j) {
int z = sparse ? c->sorted_values[j] : j, div=1; unsigned int z = sparse ? c->sorted_values[j] : j;
unsigned int div=1;
for (k=0; k < c->dimensions; ++k) { for (k=0; k < c->dimensions; ++k) {
int off = (z / div) % c->lookup_values; int off = (z / div) % c->lookup_values;
c->multiplicands[j*c->dimensions + k] = float val = mults[off];
#ifndef STB_VORBIS_CODEBOOK_FLOATS val = mults[off]*c->delta_value + c->minimum_value + last;
mults[off]; c->multiplicands[j*c->dimensions + k] = val;
#else if (c->sequence_p)
mults[off]*c->delta_value + c->minimum_value; last = val;
// in this case (and this case only) we could pre-expand c->sequence_p, if (k+1 < c->dimensions) {
// and throw away the decode logic for it; have to ALSO do if (div > UINT_MAX / (unsigned int) c->lookup_values) {
// it in the case below, but it can only be done if setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
// STB_VORBIS_CODEBOOK_FLOATS return error(f, VORBIS_invalid_setup);
// !STB_VORBIS_DIVIDES_IN_CODEBOOK }
#endif div *= c->lookup_values;
div *= c->lookup_values; }
} }
} }
setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
@ -3871,28 +3889,25 @@ static int start_decoder(vorb *f)
else else
#endif #endif
{ {
float last=0;
CHECK(f);
c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values);
if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
#ifndef STB_VORBIS_CODEBOOK_FLOATS for (j=0; j < (int) c->lookup_values; ++j) {
memcpy(c->multiplicands, mults, sizeof(c->multiplicands[0]) * c->lookup_values); float val = mults[j] * c->delta_value + c->minimum_value + last;
#else c->multiplicands[j] = val;
for (j=0; j < (int) c->lookup_values; ++j) if (c->sequence_p)
c->multiplicands[j] = mults[j] * c->delta_value + c->minimum_value; last = val;
#endif }
setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
} }
#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
skip:; skip:;
#endif #endif
#ifdef STB_VORBIS_CODEBOOK_FLOATS CHECK(f);
if (c->lookup_type == 2 && c->sequence_p) {
for (j=1; j < (int) c->lookup_values; ++j)
c->multiplicands[j] = c->multiplicands[j-1];
c->sequence_p = 0;
}
#endif
} }
CHECK(f);
} }
// time domain transfers (notused) // time domain transfers (notused)
@ -3988,9 +4003,11 @@ static int start_decoder(vorb *f)
if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup);
r->begin = get_bits(f, 24); r->begin = get_bits(f, 24);
r->end = get_bits(f, 24); r->end = get_bits(f, 24);
if (r->end < r->begin) return error(f, VORBIS_invalid_setup);
r->part_size = get_bits(f,24)+1; r->part_size = get_bits(f,24)+1;
r->classifications = get_bits(f,6)+1; r->classifications = get_bits(f,6)+1;
r->classbook = get_bits(f,8); r->classbook = get_bits(f,8);
if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup);
for (j=0; j < r->classifications; ++j) { for (j=0; j < r->classifications; ++j) {
uint8 high_bits=0; uint8 high_bits=0;
uint8 low_bits=get_bits(f,3); uint8 low_bits=get_bits(f,3);
@ -4171,6 +4188,7 @@ static void vorbis_deinit(stb_vorbis *p)
} }
if (p->codebooks) { if (p->codebooks) {
CHECK(p);
for (i=0; i < p->codebook_count; ++i) { for (i=0; i < p->codebook_count; ++i) {
Codebook *c = p->codebooks + i; Codebook *c = p->codebooks + i;
setup_free(p, c->codeword_lengths); setup_free(p, c->codeword_lengths);
@ -4189,6 +4207,7 @@ static void vorbis_deinit(stb_vorbis *p)
setup_free(p, p->mapping[i].chan); setup_free(p, p->mapping[i].chan);
setup_free(p, p->mapping); setup_free(p, p->mapping);
} }
CHECK(p);
for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) { for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) {
setup_free(p, p->channel_buffers[i]); setup_free(p, p->channel_buffers[i]);
setup_free(p, p->previous_window[i]); setup_free(p, p->previous_window[i]);
@ -4216,7 +4235,7 @@ void stb_vorbis_close(stb_vorbis *p)
setup_free(p,p); setup_free(p,p);
} }
static void vorbis_init(stb_vorbis *p, stb_vorbis_alloc *z) static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
{ {
memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start
if (z) { if (z) {
@ -4374,11 +4393,11 @@ static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len)
// return value: number of bytes we used // return value: number of bytes we used
int stb_vorbis_decode_frame_pushdata( int stb_vorbis_decode_frame_pushdata(
stb_vorbis *f, // the file we're decoding stb_vorbis *f, // the file we're decoding
uint8 *data, int data_len, // the memory available for decoding const uint8 *data, int data_len, // the memory available for decoding
int *channels, // place to write number of float * buffers int *channels, // place to write number of float * buffers
float ***output, // place to write float ** array of float * buffers float ***output, // place to write float ** array of float * buffers
int *samples // place to write number of output samples int *samples // place to write number of output samples
) )
{ {
int i; int i;
@ -4388,11 +4407,11 @@ int stb_vorbis_decode_frame_pushdata(
if (f->page_crc_tests >= 0) { if (f->page_crc_tests >= 0) {
*samples = 0; *samples = 0;
return vorbis_search_for_page_pushdata(f, data, data_len); return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len);
} }
f->stream = data; f->stream = (uint8 *) data;
f->stream_end = data + data_len; f->stream_end = (uint8 *) data + data_len;
f->error = VORBIS__no_error; f->error = VORBIS__no_error;
// check that we have the entire packet in memory // check that we have the entire packet in memory
@ -4444,14 +4463,14 @@ int stb_vorbis_decode_frame_pushdata(
} }
stb_vorbis *stb_vorbis_open_pushdata( stb_vorbis *stb_vorbis_open_pushdata(
unsigned char *data, int data_len, // the memory available for decoding const unsigned char *data, int data_len, // the memory available for decoding
int *data_used, // only defined if result is not NULL int *data_used, // only defined if result is not NULL
int *error, stb_vorbis_alloc *alloc) int *error, const stb_vorbis_alloc *alloc)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
vorbis_init(&p, alloc); vorbis_init(&p, alloc);
p.stream = data; p.stream = (uint8 *) data;
p.stream_end = data + data_len; p.stream_end = (uint8 *) data + data_len;
p.push_mode = TRUE; p.push_mode = TRUE;
if (!start_decoder(&p)) { if (!start_decoder(&p)) {
if (p.eof) if (p.eof)
@ -4971,7 +4990,7 @@ int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
#ifndef STB_VORBIS_NO_STDIO #ifndef STB_VORBIS_NO_STDIO
stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc, unsigned int length) stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
vorbis_init(&p, alloc); vorbis_init(&p, alloc);
@ -4992,7 +5011,7 @@ stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *er
return NULL; return NULL;
} }
stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc)
{ {
unsigned int len, start; unsigned int len, start;
start = ftell(file); start = ftell(file);
@ -5002,7 +5021,7 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, stb
return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len);
} }
stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc)
{ {
FILE *f = fopen(filename, "rb"); FILE *f = fopen(filename, "rb");
if (f) if (f)
@ -5012,7 +5031,7 @@ stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, stb_vorb
} }
#endif // STB_VORBIS_NO_STDIO #endif // STB_VORBIS_NO_STDIO
stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
if (data == NULL) return NULL; if (data == NULL) return NULL;
@ -5392,6 +5411,8 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
#endif // STB_VORBIS_NO_PULLDATA_API #endif // STB_VORBIS_NO_PULLDATA_API
/* Version history /* Version history
1.07 - 2015/01/16 - fixed some warnings, fix mingw, const-correct API
some more crash fixes when out of memory or with corrupt files
1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
some crash fixes when out of memory or with corrupt files some crash fixes when out of memory or with corrupt files
1.05 - 2015/04/19 - don't define __forceinline if it's redundant 1.05 - 2015/04/19 - don't define __forceinline if it's redundant

View File

@ -7,7 +7,7 @@
#define STB_DEFINE #define STB_DEFINE
#include "stb.h" #include "stb.h"
#define PNGSUITE_PRIMARY //#define PNGSUITE_PRIMARY
#if 0 #if 0
void test_ycbcr(void) void test_ycbcr(void)
@ -65,7 +65,7 @@ int main(int argc, char **argv)
int w,h; int w,h;
//test_ycbcr(); //test_ycbcr();
#if 1 #if 0
// test hdr asserts // test hdr asserts
for (h=0; h < 100; h += 2) for (h=0; h < 100; h += 2)
for (w=0; w < 200; ++w) for (w=0; w < 200; ++w)
@ -81,15 +81,17 @@ int main(int argc, char **argv)
for (i=1; i < argc; ++i) { for (i=1; i < argc; ++i) {
int res; int res;
int w2,h2,n2;
unsigned char *data; unsigned char *data;
printf("%s\n", argv[i]); printf("%s\n", argv[i]);
res = stbi_info(argv[1], &w, &h, &n); res = stbi_info(argv[1], &w2, &h2, &n2);
data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n"); data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n");
data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n"); data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n");
data = stbi_load(argv[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n"); data = stbi_load(argv[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n");
data = stbi_load(argv[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n"); data = stbi_load(argv[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n");
data = stbi_load(argv[i], &w, &h, 0, 4); data = stbi_load(argv[i], &w, &h, &n, 4);
assert(data); assert(data);
assert(w == w2 && h == h2 && n == n2);
assert(res); assert(res);
if (data) { if (data) {
char fname[512]; char fname[512];

View File

@ -66,7 +66,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c # ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "MAIN_TEST" /FR /FD /GZ /c
# SUBTRACT CPP /YX # SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"
@ -86,6 +86,10 @@ LINK32=link.exe
# Name "stb - Win32 Debug" # Name "stb - Win32 Debug"
# Begin Source File # Begin Source File
SOURCE=..\docs\other_libs.md
# End Source File
# Begin Source File
SOURCE=.\stb.c SOURCE=.\stb.c
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -130,6 +134,10 @@ SOURCE=..\stb_leakcheck.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb_malloc.h
# End Source File
# Begin Source File
SOURCE=..\stb_perlin.h SOURCE=..\stb_perlin.h
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -8,10 +8,11 @@ extern void stb_vorbis_dumpmem(void);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
size_t memlen; size_t memlen;
unsigned char *mem = stb_fileu("c:/x/theme_03.ogg", &memlen); unsigned char *mem = stb_fileu("c:/x/sketch008.ogg", &memlen);
int chan, samplerate; int chan, samplerate;
short *output; short *output;
int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output); int samples = stb_vorbis_decode_memory(mem, memlen, &chan, &samplerate, &output);
stb_filewrite("c:/x/sketch008.raw", output, samples*4);
return 0; return 0;
} }
#endif #endif