From c9a9130e28537bf773e90de21a166bad479d0818 Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Wed, 15 May 2024 19:29:28 +0200 Subject: [PATCH] u08-1 --- lib/stb_image.h | 7985 +++++++++++++++++++++++++++++++++++++ obj/cube.mtl | 10 + obj/plane.obj | 15 + texture/checkerboard.png | Bin 0 -> 5310 bytes texture/crate.png | Bin 0 -> 99456 bytes texture/pb-bw.png | Bin 0 -> 2459 bytes texture/pb.png | Bin 0 -> 27323 bytes u08-1/Makefile | 34 + u08-1/fragmentShader.glsl | 51 + u08-1/main.c | 407 ++ u08-1/matrixMath.c | 295 ++ u08-1/matrixMath.h | 104 + u08-1/test.c | 130 + u08-1/transformation.c | 79 + u08-1/transformation.h | 11 + u08-1/vertexShader.glsl | 23 + u08-1/wavefrontobj.c | 190 + u08-1/wavefrontobj.h | 29 + 18 files changed, 9363 insertions(+) create mode 100644 lib/stb_image.h create mode 100644 obj/cube.mtl create mode 100644 obj/plane.obj create mode 100644 texture/checkerboard.png create mode 100644 texture/crate.png create mode 100644 texture/pb-bw.png create mode 100644 texture/pb.png create mode 100644 u08-1/Makefile create mode 100644 u08-1/fragmentShader.glsl create mode 100644 u08-1/main.c create mode 100644 u08-1/matrixMath.c create mode 100644 u08-1/matrixMath.h create mode 100644 u08-1/test.c create mode 100644 u08-1/transformation.c create mode 100644 u08-1/transformation.h create mode 100644 u08-1/vertexShader.glsl create mode 100644 u08-1/wavefrontobj.c create mode 100644 u08-1/wavefrontobj.h diff --git a/lib/stb_image.h b/lib/stb_image.h new file mode 100644 index 0000000..7300952 --- /dev/null +++ b/lib/stb_image.h @@ -0,0 +1,7985 @@ +/* stb_image - v2.29 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 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 + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data); +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// 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_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +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; } +#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_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { + h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + j->marker = stbi__skip_jpeg_junk_at_end(j); + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); + } else { + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); + } + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + int hit_zeof_once; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); + } + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + 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"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } + return 1; + } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (len > a->zout_end - zout) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + a->hit_zeof_once = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub +}; + +static int stbi__paeth(int a, int b, int c) +{ + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + + for (j=0; j < y; ++j) { + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; + int filter = *raw++; + + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; + } + + raw += nk; + + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; + + // expand bits to bytes first + if (depth == 4) { + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; + } + } else if (depth == 2) { + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; + } + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; + } + } + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); + if (img_n == 1) { + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; + } + } else { + STBI_ASSERT(img_n == 3); + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; + } + } + } + } + } + + STBI_FREE(filter_buf); + if (!all_ok) return 0; + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + } + // even with SCAN_header, have to scan to see if we have a tRNS + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + 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; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +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"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + 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; + STBI_NOTUSED(ri); + + 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); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + 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 - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#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; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 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); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // 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; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + 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) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + 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 + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)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] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((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 void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + 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); + + 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 + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + 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 + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } + + if (req_comp && req_comp != s->img_n) { + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + 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) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 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.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ \ No newline at end of file diff --git a/obj/cube.mtl b/obj/cube.mtl new file mode 100644 index 0000000..f231bdf --- /dev/null +++ b/obj/cube.mtl @@ -0,0 +1,10 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl None +Ns 500 +Ka 0.8 0.8 0.8 +Kd 0.8 0.8 0.8 +Ks 0.8 0.8 0.8 +d 1 +illum 2 diff --git a/obj/plane.obj b/obj/plane.obj new file mode 100644 index 0000000..f8e6525 --- /dev/null +++ b/obj/plane.obj @@ -0,0 +1,15 @@ +# Blender v3.0.1 OBJ File: '' +# www.blender.org +o Plane +v -1.000000 0.000000 1.000000 +v 1.000000 0.000000 1.000000 +v -1.000000 0.000000 -1.000000 +v 1.000000 0.000000 -1.000000 +vt 0.000000 0.000000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vn 0.0000 1.0000 0.0000 +usemtl None +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 diff --git a/texture/checkerboard.png b/texture/checkerboard.png new file mode 100644 index 0000000000000000000000000000000000000000..c63c9cdf682bfc8bde1ca6b0b39242ab8fe555f4 GIT binary patch literal 5310 zcmeHKc~leU79X@Mf=WcF6}7~m7Ohz(3nbG7L7*g0(7X^uTG38sCOD9dWF!Gx(5KX$ zMa2iA$nsRQE)`T1P!SYd+M-yg3RO!Lc~qn>#k%185>WBH{=+%;KXXpb%-rR7@BQ8T z-DFnDr-u%4_H>3IXoyT2tbiapaBBxS4FH!0+7uXq29in2*^~k`(+x(wn$!?z^NsKlW_aC)x;yWw)T#;Z)O; z`#0LUtE&A&MvRY}G%->9ZOthUkH^;|8gm!UdDxOKIZ;|(a?WSqxdV&pOVf~RZH$)U zf(i4Mm)`TrYX92pNao`$G=0bckEqJ~Q;8AI6^phxQvczSY*DG{&a~wAR`(Gb?rkmEv&Ez--vd`&D%Jm&s-1MV z?Bs(3L#Ihc?%%$xQJH>uY|^N7^Nr`rF7KjM-aQZYgv1Js--Mc8t5_e{+ zJuP7^xBjMd>85DS%DmAYuyVZAJ!4#ya`k0*MOdcd+*#I%oS^kl#&e=L*3sDdT?Mj| z-3x>|EDN(O_n0|bdkq7kHSxp%f~w1vdZc*vnuW?vaZqmnZ9K4?H&6z&HAjX zK7Pid%cjP;Nn`l5e|QfaN&cE&xE2`}%ex>Xc4Y7Tp4%>4*OdBrY~_q~Lt`s453c{S zC^cW?<%Tz|`iMtsk5<4aKhx13pRJ`k= zN4Gmq)EzjMj87_0#!JEVxaCpyg|>@3x#gjG=jVu%ihsYt*EKPC$7?U%uWo4eei)gy zIQ3++clCbp)5L(XdFR9%J9aMZiuE+7txcrXgq=PiI8yig_q##a)rDz zVOI`O^a~7ci1zr`ey8oj1H(|MYKQ;kun9Ls$2)Gdv`24@Nz8j@dgLS8VCSD<$!bdt zsR$HTl5M$NtE#{8nOM_WQ|J(#{v@OQ;CX$n%TO0FPg4}}um)9qTYttls-z&_ZH8N@ z`^>_HV_OcMN?cR&#lC}gB!9XDiL^v^JKu3wEh8&^xzos*8|A4heD-=yoS-Q6df4eI z>>hU%H*Pvv_ic)^Qo7#jx$9zc+?`L(G#AMSJ5~JjM=gieWbY}s-tB+*-kCu+mpJSz z%{rlQRQt>JA1bXIR$o43&YUCsMAxz=yQg{7+4Rw8XGGMsF74ty-7&e|>_Y87S}Ev? ze+m^9@2MGLFgUGs_epMUX^y^E`67A8)f=wHO5;wC2V)z-a`Ys@5}X|#hG2Rv3&r&+ zf@RSfz>z#o`Ext|DScorH0}`~-te;u1!rAe<9!2qNZ_(j+4hku+V2CB<8x<#wenGlPFVZ%khy;aO+&}}AEoP;quTuu+t8wom}#b-$ z%kX!mi;cJ%Q3QY93jv-ajQJF0K-g@v*~~KYSbAd&8y1N~Yz~*r<1F;SI%0VQEDfS&#;Kdm7={58DJ)XM_kgKa?#Y?#GiYqjjY z9wsUz0f6)-^p_qcCHO62D+rT*fe|A@5(pjT-4_DKUi%vs7&W$XaEuN1y%w07Kvejx zkfE}0`D+g=1u>-7VDkcGzhz00>NjM)m77&#E2nQF!2LDuTh^~?w;2Pg@Ngtpk1epK zCkvJ^tnm?CkC8ZHyY<6Vz9y-|yTc9L2&hF}|XF*b#j za3oMJlQ6g}&KrqbgHmeXAYp`&x&@Xu3MHu}A}G|#ChW`QaD{$;ejJgA2MgghMzaW` z2~46D6XvkEe4EDF76cRnh()b)3IJ?!Pzw@dBv49kROkEK^vn4DbiFgW zoZr0g5IXQL$P8X*&aVz$1zv?5RMSF(p zM@kkR;&|KM!BObEsi7nqf(FoK!GTK4wR=A<9g-3-cp!YL`?Igd228a}UUqnYL+eM4 z2}#}KI$jn$Oz|2H4S?)Ypa6&t(I6-2gLnS;7pTX_YmbbO?r1eHnbO~o?<7?*qur&n zd2ve3ix>SX`yKIPn0HObP7nLxe)r=3lKxJbWvQ{xE*jZ&B=1WN7#~O$GCg?T)UTHP E4@y>L)c^nh literal 0 HcmV?d00001 diff --git a/texture/crate.png b/texture/crate.png new file mode 100644 index 0000000000000000000000000000000000000000..0f0e74eae06100edd2e81127a16ed93460dab3ed GIT binary patch literal 99456 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 literal 0 HcmV?d00001 diff --git a/texture/pb.png b/texture/pb.png new file mode 100644 index 0000000000000000000000000000000000000000..410d767242c1b47ceeedbad134c339b4ff77aad7 GIT binary patch literal 27323 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 $@ + +main.o: $(SHADERS) matrixMath.h transformation.h wavefrontobj.h + +test.o: matrixMath.h transformation.h wavefrontobj.h + +%.o: %.c + gcc -c $< + +run: cg1.out + ./cg1.out + +test: test.out + ./test.out + +clean: + rm $(SHADERS) main.o test.o $(OBJ) cg1.out test.out \ No newline at end of file diff --git a/u08-1/fragmentShader.glsl b/u08-1/fragmentShader.glsl new file mode 100644 index 0000000..a831556 --- /dev/null +++ b/u08-1/fragmentShader.glsl @@ -0,0 +1,51 @@ +#version 330 core + +in vec3 normal; +in vec3 fragmentPosition; +in vec2 textureCoordinate; + + +uniform vec4 ambientColor; +uniform vec4 diffusionColor; +uniform vec4 specularColor; + +uniform float shininess; + +uniform vec4 ambientLight; +uniform vec3 lightPosition; +uniform vec4 lightColor; + +uniform sampler2D myTexture; + + +float emissionStrength = 0.0; + + +void main() { + vec4 color = texture(myTexture, textureCoordinate); + + vec3 norm = normalize(normal); + vec3 lightDir = normalize(lightPosition - fragmentPosition); + vec3 eyeDir = -normalize(fragmentPosition); + + float diff = max(dot(norm, lightDir), 0.0); + + vec3 halfway = (lightDir + eyeDir) / length(lightDir + eyeDir); + float specular = pow(max(dot(halfway, norm), 0.0), shininess); + + + gl_FragColor = + // EMISSION + diffusionColor * emissionStrength + + + // // AMBIENT + ambientLight * ambientColor + + + // DIFFUSION + diff * lightColor * diffusionColor + + + // SPECULAR + specular * lightColor * specularColor; + + gl_FragColor = color; +} \ No newline at end of file diff --git a/u08-1/main.c b/u08-1/main.c new file mode 100644 index 0000000..581fb7a --- /dev/null +++ b/u08-1/main.c @@ -0,0 +1,407 @@ +#include + +#include +#include + +#include "vertexShader.c" +#include "fragmentShader.c" + +#include "matrixMath.h" +#include "transformation.h" +#include "wavefrontobj.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "../lib/stb_image.h" + +#include +#include +#include +#include + +GLuint program; +GLuint vao; +GLuint texture; + + +int numFaces = 0; + +bool exitRequested = false; + +GLFWwindow* window; + +GLfloat aspectRatio = 1.0f; + +double timeBetweenUpdates = 0.2f; + +double timeSinceUpdate = 0.0f; +int framesSinceUpdate = 0; + +GLfloat step = 0.0f; +const GLfloat pi = 3.14159f; + +vec3 cameraPosition = {0.0f, 3.0f, 5.5f}; + +char* defaultModel = "../obj/cube.obj"; +char** model = &defaultModel; + +char* defaultTexture = "../texture/crate.png"; +char** textureFile = &defaultTexture; + +// input handler for camera movement +void handleInputs(double deltaTime) { + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { + cameraPosition.z += deltaTime * 10; + } + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + cameraPosition.z -= deltaTime * 10; + } + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { + cameraPosition.y += deltaTime * 10; + } + if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) { + cameraPosition.y -= deltaTime * 10; + } +} + +// input handler to quit with ESC +void keyboardHandler(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (action == GLFW_PRESS) { + if (key == GLFW_KEY_ESCAPE) { + exitRequested = true; + } + } +} + + +void init(void) { + // create and compile vertex shader + const GLchar *vertexTextConst = vertexShader_glsl; + + GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexTextConst, &vertexShader_glsl_len); + glCompileShader(vertexShader); + + + GLint status; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); + + if (!status) { + printf("Error compiling vertex shader: "); + GLchar infoLog[1024]; + glGetShaderInfoLog(vertexShader, 1024, NULL, infoLog); + printf("%s",infoLog); + } + + vertexTextConst = NULL; + + + + // create and compile fragment shader + + const GLchar *fragmentTextConst = fragmentShader_glsl; + + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentTextConst, &fragmentShader_glsl_len); + glCompileShader(fragmentShader); + + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status); + + if (!status) { + printf("Error compiling fragment shader: "); + GLchar infoLog[1024]; + glGetShaderInfoLog(fragmentShader, 1024, NULL, infoLog); + printf("%s",infoLog); + } + + // create and link shader program + program = glCreateProgram(); + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &status); + + if (!status) { + printf("Error linking program: "); + GLchar infoLog[1024]; + glGetProgramInfoLog(program, 1024, NULL, infoLog); + printf("%s",infoLog); + } + glValidateProgram(program); + + + glGetProgramiv(program, GL_VALIDATE_STATUS, &status); + + if (!status) { + printf("Error validating program: "); + GLchar infoLog[1024]; + glGetProgramInfoLog(program, 1024, NULL, infoLog); + printf("%s",infoLog); + } + + + // --------------- READ MODEL FILE + ParsedObjFile teapot = readObjFile(*model); + numFaces = teapot.length; + + // write teapot faces to buffer + GLuint triangleVertexBufferObject; + glGenBuffers(1, &triangleVertexBufferObject); + glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, teapot.length * sizeof(face), teapot.faces, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + + // -------------- READ TEXTURE FILE + int width, height, nrChannels; + unsigned char* image = stbi_load(*textureFile, &width, &height, &nrChannels, 0); + + // default: 3 channels, RGB + GLenum format = GL_RGB; + + // alpha channel is present + if (nrChannels == 4) { + + // set format to RGBA + format = GL_RGBA; + } + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format, GL_UNSIGNED_BYTE, image); + // load texture using previously determined format ----- ^^^^^^ + + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + stbi_image_free(image); + + + // create vertex array object + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBufferObject); + + // vertex positions + glVertexAttribPointer( + 0, + 3, + GL_FLOAT, + GL_FALSE, + sizeof(vertex), + 0 + ); + glEnableVertexAttribArray(0); + + // vertex normals + glVertexAttribPointer( + 1, + 3, + GL_FLOAT, + GL_FALSE, + sizeof(vertex), + (void*) offsetof(vertex, normal) + ); + glEnableVertexAttribArray(1); + + // vertex texture coordinates + glVertexAttribPointer( + 2, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(vertex), + (void*) offsetof(vertex, texture) + ); + glEnableVertexAttribArray(2); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + + // ENABLE BACKFACE CULLING + glFrontFace(GL_CCW); + glEnable(GL_CULL_FACE); + + // ENABLE DEPTH BUFFER + glEnable(GL_DEPTH_TEST); + + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); +} + +void updateStats() { + printf("\rFPS: %.1f", framesSinceUpdate / timeSinceUpdate); + printf(" - Camera Position: [%f, %f, %f]", cameraPosition.x, cameraPosition.y, cameraPosition.z); + fflush(stdout); +} + +void draw(void) { + + // FPS Counter + framesSinceUpdate++; + double deltaTime = glfwGetTime(); + timeSinceUpdate += deltaTime; + glfwSetTime(0.0f); + + if (timeSinceUpdate >= timeBetweenUpdates) { + updateStats(); + timeSinceUpdate = 0.0f; + framesSinceUpdate = 0; + } + + // camera movement + handleInputs(deltaTime); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUseProgram(program); + glBindVertexArray(vao); + + // step for rotations + // counts up to 1.0 and then resets back to 0.0 forever + step += deltaTime / 5; + if (step > 1.0f) step -= 1.0f; + if (step < 0.0f) step += 1.0f; + + // step multiplied by pi * 2 for use in rotation and trig functions + GLfloat stepi = step * pi * 2; + + + // ------------- MODEL TRANSFORMATION --------------------- + // SCALE -> ROTATE -> TRANSLATE + + mat4 modelTransformation; + identity(&modelTransformation); + + rotateY(&modelTransformation, &modelTransformation, stepi); + + + // ------------- VIEWING TRANSFORMATION ------------------- + vec3 origin = {0.0f, 0.0f, 0.0f}; + vec3 up = {0.0f, 1.0f, 0.0f}; + + mat4 viewingTransformation; + lookAt(&viewingTransformation, &cameraPosition, &origin, &up); + + + + // -------------- PROJECTION TRANSFORMATION ---------------- + mat4 projectionTransformation; + GLfloat near = 0.1f; + GLfloat far = 20.0f; + perspectiveProjection(&projectionTransformation, near, far); + + + + // -------------- NORMALISATION TRANSFORMATION ------------- + mat4 normalisationTransformation; + GLfloat fovy = pi / 2; + normalisedDeviceCoordinatesFov(&normalisationTransformation, fovy, aspectRatio, near, far); + + + mat4 modelView; + identity(&modelView); + multiply(&modelView, &modelTransformation, &modelView); + multiply(&modelView, &viewingTransformation, &modelView); + + mat4 projection; + identity(&projection); + multiply(&projection, &projectionTransformation, &projection); + multiply(&projection, &normalisationTransformation, &projection); + + // calculate matrix for normals + mat3 normalModelView; + mat3From4(&normalModelView, &modelView); + mat3Inverse(&normalModelView, &normalModelView); + mat3Transpose(&normalModelView, &normalModelView); + + // send transformation matrix to shader + glUniformMatrix4fv(glGetUniformLocation(program, "modelView"), 1, GL_FALSE, (GLfloat*)&modelView); + glUniformMatrix3fv(glGetUniformLocation(program, "normalModelView"), 1, GL_FALSE, (GLfloat*)&normalModelView); + glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, (GLfloat*)&projection); + + + vec4 lightPosition = {cos(stepi * 2) * 3.0f, 3.0f, sin(stepi * 2) * 3.0f, 1.0f}; + multiplyAny((GLfloat *)&lightPosition, (GLfloat *)&modelView, (GLfloat *)&lightPosition, 4, 4, 1); + + glUniform3f(glGetUniformLocation(program, "lightPosition"), lightPosition.x, lightPosition.y, lightPosition.z); + + + // SET TEXTURE + GLuint textureLocation = glGetUniformLocation(program, "myTexture"); + glUniform1i(textureLocation, 13); + glActiveTexture(GL_TEXTURE13); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + + // SET MATERIAL DATA + glUniform4f(glGetUniformLocation(program, "ambientColor"), 0.25f, 0.22f, 0.06f, 1.0f); + glUniform4f(glGetUniformLocation(program, "diffusionColor"), 0.35f, 0.31f, 0.09f, 1.0f); + glUniform4f(glGetUniformLocation(program, "specularColor"), 0.80f, 0.72f, 0.21f, 1.0f); + glUniform1f(glGetUniformLocation(program, "shininess"), 83.2f * 4.0f); + + // SET LIGHT DATA + glUniform4f(glGetUniformLocation(program, "lightColor"), 1.0f, 1.0f, 1.0f, 1.0f); + glUniform4f(glGetUniformLocation(program, "ambientLight"), 0.2f, 0.2f, 0.2f, 1.0f); + + + // draw!!1 + glDrawArrays(GL_TRIANGLES, 0, numFaces * 3); +} + +// change viewport size and adjust aspect ratio when changing window size +void framebuffer_size_callback(GLFWwindow *window, int width, int height) { + glViewport(0, 0, width, height); + aspectRatio = (float)width / height; +} + +int main(int argc, char **argv) { + + if (argc == 2) { + model = &argv[1]; + } + // initialise window + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + window = glfwCreateWindow(700, 700, "Computergrafik 1", NULL, NULL); + + if (!window) { + printf("Failed to create window\n"); + glfwTerminate(); + return -1; + } + + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwMakeContextCurrent(window); + + // disable framerate cap + glfwSwapInterval(0); + + // register keyboard event handler + glfwSetKeyCallback(window, keyboardHandler); + + // initialise glew + glewInit(); + + printf("OpenGL version supported by this platform (%s):\n", glGetString(GL_VERSION)); + + init(); + + // exit when window should close or exit is requested (ESC) + while (!glfwWindowShouldClose(window) && !exitRequested) { + draw(); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwTerminate(); + + return 0; +} \ No newline at end of file diff --git a/u08-1/matrixMath.c b/u08-1/matrixMath.c new file mode 100644 index 0000000..95d59c5 --- /dev/null +++ b/u08-1/matrixMath.c @@ -0,0 +1,295 @@ +#include +#include +#include +#include +#include + +#include "matrixMath.h" + +// MATRICES IN COLUMN MAJOR + +void vec3Zero(vec3* out) { + for (int i = 0; i < 3; i++) { + ((GLfloat*)out)[i] = 0; + } +} + +void vec3Add(vec3* out, vec3* a, vec3* b) { + for (int i = 0; i < 3; i++) { + ((GLfloat*)out)[i] = ((GLfloat*)a)[i] + ((GLfloat*)b)[i]; + } +} + +void vec3Multiply(vec3* out, vec3* a, GLfloat x) { + for (int i = 0; i < 3; i++) { + ((GLfloat*)out)[i] = ((GLfloat*)a)[i] * x; + } +} + +void vec3Subtract(vec3* out, vec3* a, vec3* b) { + vec3 minusB; + vec3Multiply(&minusB, b, -1); + vec3Add(out, a, &minusB); +} + +void vec3Cross(vec3* out, vec3* a, vec3* b) { + vec3 result; + result.x = a->y * b->z - a->z * b->y; + result.y = a->z * b->x - a->x * b->z; + result.z = a->x * b->y - a->y * b->x; + memcpy(out, &result, sizeof(vec3)); +} + +GLfloat vec3Length(vec3* a) { + return (GLfloat)sqrt(a->x * a->x + a->y * a->y + a->z * a->z); +} + +GLfloat vec3Dot(vec3* a, vec3* b) { + return a->x * b->x + a->y * b->y + a->z * b->z; +} + +void vec3Normalise(vec3* out, vec3* a) { + vec3Multiply(out, a, 1 / vec3Length(a)); +} +// CREATE 4x4 IDENTITY MATRIX +void identity(mat4* out) { + for (int i = 0; i < 16; i++) { + ((GLfloat*)out)[i] = (i % 4 == i / 4); + } +} + +// CREATE 4x4 TRANSLATION MATRIX +void translation(mat4* out, vec3* v) { + identity(out); + out->m03 = v->x; + out->m13 = v->y; + out->m23 = v->z; +} + +// CREATE 4x4 SCALING MATRIX +void scaling(mat4* out, vec3* v) { + identity(out); + out->m00 = v->x; + out->m11 = v->y; + out->m22 = v->z; +} + +// CREATE 4x4 ROTATION MATRIX AROUND Z AXIS +/* cos a -sin a 0 0 + * sin a cos a 0 0 + * 0 0 1 0 + * 0 0 0 1 +*/ +void rotationZ(mat4* out, GLfloat angle) { + identity(out); + out->m00 = cos(angle); + out->m10 = sin(angle); + out->m01 = -sin(angle); + out->m11 = cos(angle); +} + +// CREATE 4x4 ROTATION MATRIX AROUND Y AXIS +/* cos a 0 sin a 0 + * 0 1 0 0 + * -sin a 0 cos a 0 + * 0 0 0 1 +*/ +void rotationY(mat4* out, GLfloat angle) { + identity(out); + out->m00 = cos(angle); + out->m20 = -sin(angle); + out->m02 = sin(angle); + out->m22 = cos(angle); +} + +// CREATE 4x4 ROTATION MATRIX AROUND Y AXIS +void rotationX(mat4* out, GLfloat angle) { + identity(out); + out->m11 = cos(angle); + out->m21 = sin(angle); + out->m12 = -sin(angle); + out->m22 = cos(angle); +} + +// MULTIPLY ANY TO MATRICES +void multiplyAny(GLfloat* out, GLfloat* A, GLfloat* B, int wA, int hA, int wB) { + int sizeOut = hA * wB; + GLfloat* result = (GLfloat*) malloc(sizeOut * sizeof(GLfloat)); + for (int i = 0; i < sizeOut; i++) { + result[i] = 0; + for (int j = 0; j < wA; j++) { + result[i] += A[j * hA + i % hA] * B[j + i / hA * wB]; + } + } + memcpy(out, result, sizeOut * sizeof(GLfloat)); + free(result); + result = NULL; +} + +// MULTIPLY TWO 4x4 MATRICES +void multiply(mat4* out, mat4* A, mat4* B) { + multiplyAny((GLfloat*)out, (GLfloat*)A, (GLfloat*)B, 4, 4, 4); +} + +// MULTIPLY in WITH TRANSLATION MATRIX OF v +void translate(mat4* out, mat4* in, vec3* v) { + mat4 translationMatrix; + translation(&translationMatrix, v); + multiply(out, &translationMatrix, in); +} + +// MULTIPLY in WITH SCALING MATRIX OF v +void scale(mat4* out, mat4* in, vec3* v) { + mat4 scalingMatrix; + scaling(&scalingMatrix, v); + multiply(out, &scalingMatrix, in); +} + +// MULTIPLY in WITH ROTATION MATRIX OF a AROUND Z AXIS +void rotateZ(mat4* out, mat4* in, GLfloat angle) { + mat4 rotationMatrix; + rotationZ(&rotationMatrix, angle); + multiply(out, &rotationMatrix, in); +} +// MULTIPLY in WITH ROTATION MATRIX OF a AROUND Y AXIS +void rotateY(mat4* out, mat4* in, GLfloat angle) { + mat4 rotationMatrix; + rotationY(&rotationMatrix, angle); + multiply(out, &rotationMatrix, in); +} +// MULTIPLY in WITH ROTATION MATRIX OF a AROUND X AXIS +void rotateX(mat4* out, mat4* in, GLfloat angle) { + mat4 rotationMatrix; + rotationX(&rotationMatrix, angle); + multiply(out, &rotationMatrix, in); +} + +void transposeAny(GLfloat* out, GLfloat* in, int w, int h) { + int size = w * h; + GLfloat* result = (GLfloat*) malloc(size * sizeof(GLfloat)); + + for (int i = 0; i < size; i++) { + result[i] = in[(i % w) * h + i / w]; + } + + memcpy(out, result, size * sizeof(GLfloat)); + free(result); + result = NULL; +} + + +void transpose(mat4* out, mat4* in) { + transposeAny((GLfloat*)out, (GLfloat*)in, 4, 4); +} + +void printAny(GLfloat* M, int w, int h) { + GLfloat* transposed = (GLfloat*) malloc(w * h * sizeof(GLfloat)); + transposeAny(transposed, M, w, h); + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + printf("%.4f ", transposed[i * w + j]); + } + printf("\n"); + } + free(transposed); + transposed = NULL; +} + +void vec3Print(vec3* a) { + printAny((GLfloat*)a, 1, 3); +} + +void mat4Print(mat4* m) { + printAny((GLfloat*)m, 4, 4); +} + +void mat3Print(mat3* m) { + printAny((GLfloat*)m, 3, 3); +} + +void mat3From4(mat3* out, mat4* in) { + memcpy(&out->m00, &in->m00, sizeof(vec3)); + memcpy(&out->m01, &in->m01, sizeof(vec3)); + memcpy(&out->m02, &in->m02, sizeof(vec3)); +} + +void mat3Transpose(mat3* out, mat3* in) { + transposeAny((GLfloat*)out, (GLfloat*)in, 3, 3); +} + +/** + * a - m00 b - m01 c - m02 + * d - m10 e - m11 f - m12 + * g - m20 h - m21 i - m22 + */ +void mat3Minor(mat3* out, mat3* in) { + mat3 result; + + result.m00 = in->m11 * in->m22 - in->m21 * in->m12; + result.m01 = in->m10 * in->m22 - in->m20 * in->m12; + result.m02 = in->m10 * in->m21 - in->m20 * in->m11; + + result.m10 = in->m01 * in->m22 - in->m21 * in->m02; + result.m11 = in->m00 * in->m22 - in->m20 * in->m02; + result.m12 = in->m00 * in->m21 - in->m20 * in->m01; + + result.m20 = in->m01 * in->m12 - in->m11 * in->m02; + result.m21 = in->m00 * in->m12 - in->m10 * in->m02; + result.m22 = in->m00 * in->m11 - in->m10 * in->m01; + + memcpy(out, &result, sizeof(mat3)); +} + +void mat3Cofactor(mat3* out, mat3* in) { + mat3 result; + mat3Minor(out, in); + + out->m01 *= -1; + out->m10 *= -1; + out->m21 *= -1; + out->m12 *= -1; +} + +void mat3Adjoint(mat3* out, mat3* in) { + mat3Cofactor(out, in); + mat3Transpose(out, out); +} + +void mat3MultiplyScalar(mat3* out, mat3* in, GLfloat x) { + for (int i = 0; i < 9; i++) { + ((GLfloat*)out)[i] = ((GLfloat*)in)[i] * x; + } +} + +GLfloat mat3Determinant(mat3* M) { + return + M->m00 * M->m11 * M->m22 + + M->m01 * M->m12 * M->m20 + + M->m02 * M->m10 * M->m21 + + - M->m20 * M->m11 * M->m02 + - M->m21 * M->m12 * M->m00 + - M->m22 * M->m10 * M->m01 + ; +} + +void mat3Inverse(mat3* out, mat3* in) { + mat3 result; + mat3Adjoint(&result, in); + mat3MultiplyScalar(&result, &result, 1 / mat3Determinant(in)); + + memcpy(out, &result, sizeof(mat3)); +} + +GLfloat sumDiffAny(GLfloat* A, GLfloat* B, int w, int h) { + GLfloat result = 0; + for (int i = 0; i < w * h; i++) { + result += fabs(A[i] - B[i]); + } + return result; +} + +GLfloat mat3SumDiff(mat3* A, mat3* B) { + return sumDiffAny((GLfloat*)A, (GLfloat*)B, 3, 3); +} \ No newline at end of file diff --git a/u08-1/matrixMath.h b/u08-1/matrixMath.h new file mode 100644 index 0000000..78d32ab --- /dev/null +++ b/u08-1/matrixMath.h @@ -0,0 +1,104 @@ +#ifndef MATRIX_MATH +#define MATRIX_MATH + +#include + +typedef struct { + GLfloat x; + GLfloat y; + GLfloat z; +} vec3; + +typedef struct { + GLfloat x; + GLfloat y; + GLfloat z; + GLfloat w; +} vec4; + +typedef struct { + GLfloat x; + GLfloat y; +} vec2; + +typedef struct { + GLfloat m00; + GLfloat m10; + GLfloat m20; + GLfloat m30; + + GLfloat m01; + GLfloat m11; + GLfloat m21; + GLfloat m31; + + GLfloat m02; + GLfloat m12; + GLfloat m22; + GLfloat m32; + + GLfloat m03; + GLfloat m13; + GLfloat m23; + GLfloat m33; +} mat4; + +typedef struct { + GLfloat m00; + GLfloat m10; + GLfloat m20; + + GLfloat m01; + GLfloat m11; + GLfloat m21; + + GLfloat m02; + GLfloat m12; + GLfloat m22; +} mat3; + +extern void vec3Zero(vec3* out); +extern void vec3Add(vec3* out, vec3* a, vec3* b); +extern void vec3Multiply(vec3* out, vec3* a, GLfloat x); +extern void vec3Subtract(vec3* out, vec3* a, vec3* b); +extern void vec3Cross(vec3* out, vec3* a, vec3* b); +extern void vec3Normalise(vec3* out, vec3* a); +extern GLfloat vec3Length(vec3* a); +extern GLfloat vec3Dot(vec3* a, vec3* b); + +extern void identity(mat4* out); +extern void translation(mat4* out, vec3* v); +extern void scaling(mat4* out, vec3* v); +extern void rotationZ(mat4* out, GLfloat angle); +extern void rotationY(mat4* out, GLfloat angle); +extern void rotationX(mat4* out, GLfloat angle); + +extern void multiplyAny(GLfloat* out, GLfloat* A, GLfloat* B, int wA, int hA, int wB); +extern void multiply(mat4* out, mat4* A, mat4* B); + +extern void translate(mat4* out, mat4* in, vec3* v); +extern void scale(mat4* out, mat4* in, vec3* v); +extern void rotateZ(mat4* out, mat4* in, GLfloat angle); +extern void rotateY(mat4* out, mat4* in, GLfloat angle); +extern void rotateX(mat4* out, mat4* in, GLfloat angle); + +extern void transposeAny(GLfloat* out, GLfloat* in, int w, int h); +extern void transpose(mat4* out, mat4* in); + +extern void printAny(GLfloat* M, int w, int h); +extern void vec3Print(vec3* a); +extern void mat4Print(mat4* m); +extern void mat3Print(mat3* m); + +extern void mat3From4(mat3* out, mat4* in); +extern void mat3MultiplyScalar(mat3* out, mat3* in, GLfloat x); +extern GLfloat mat3Determinant(mat3* m); +extern void mat3Transpose(mat3* out, mat3* in); +extern void mat3Minor(mat3* out, mat3* in); +extern void mat3Cofactor(mat3* out, mat3* in); +extern void mat3Adjoint(mat3* out, mat3* in); +extern void mat3Inverse(mat3* out, mat3* in); + +extern GLfloat sumDiffAny(GLfloat* A, GLfloat* B, int w, int h); +extern GLfloat mat3SumDiff(mat3* A, mat3* B); +#endif \ No newline at end of file diff --git a/u08-1/test.c b/u08-1/test.c new file mode 100644 index 0000000..b317647 --- /dev/null +++ b/u08-1/test.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include + +#include "matrixMath.h" + + +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KNRM "\x1B[0m" + +#define EPSILON 0.001f + +int exitCode = 0; + +void printTest(char* name, bool result) { + if (result) { + printf("%s PASSED%s - %s\n", KGRN, KNRM, name); + } else { + printf("%s!!! FAILED%s - %s\n", KRED, KNRM, name); + exitCode = 1; + } +} + +void testSumDiff() { + mat3 A = {1, 0, 0, -1, 0, -1, 1, -1, 9}; + mat3 B = {0, 1, -1, 0, 0, 1, 1, -1, 8}; + GLfloat target = 7; + + GLfloat value = mat3SumDiff(&A, &B); + + bool result = fabs(value - target) < EPSILON; + + if (!result) { + printf("\nA:\n"); + mat3Print(&A); + printf("\nB:\n"); + mat3Print(&B); + printf("target: %f\n", target); + printf("value: %f\n", value); + } + + printTest("mat3SumDiff", result); +} + +void testMat3Minor() { + mat3 M = {2, 0, 1, -1, 5, -1, 3, 2, -2}; + mat3 target = {-8, 5, -17, -2, -7, 4, -5, -1, 10}; + + mat3Minor(&M, &M); + + printTest("mat3Minor", mat3SumDiff(&M, &target) < EPSILON); +} + +void testMat3Cofactor() { + mat3 M = {2, 0, 1, -1, 5, -1, 3, 2, -2}; + mat3 target = {-8, -5, -17, 2, -7, -4, -5, 1, 10}; + + mat3Cofactor(&M, &M); + + printTest("mat3Cofactor", mat3SumDiff(&M, &target) < EPSILON); +} + +void testMat3Adjoint() { + mat3 M = {1, 2, -1, 2, 1, 2, -1, 2, 1}; + mat3 target = {-3, -4, 5, -4, 0, -4, 5, -4, -3}; + + + mat3Adjoint(&M, &M); + + printTest("mat3Adjoint", mat3SumDiff(&M, &target) < EPSILON); +} + +void testMat3MultiplyScalar() { + mat3 M = {1, 2, 3, 4, 0, -1.5f, -2.5f, -3.5f, -4.5f}; + GLfloat x = 0.9f; + mat3 target = {0.9f, 1.8f, 2.7f, 3.6f, 0, -1.35f, -2.25f, -3.15f, -4.05f}; + + mat3MultiplyScalar(&M, &M, x); + + printTest("mat3MultiplyScalar", mat3SumDiff(&M, &target) < EPSILON); +} + +void testMat3Determinant() { + mat3 M = {1, -3, 2, 3, -1, 3, 2, -3, 1}; + GLfloat target = -15; + + printTest("mat3Determinant", fabs(mat3Determinant(&M) - target) < EPSILON); +} + +void testMat3Inverse() { + mat3 M = {1, 2, -1, 2, 1, 2, -1, 2, 1}; + mat3 target = {0.1875f, 0.25f, -0.3125f, 0.25f, 0, 0.25f, -0.3125f, 0.25f, 0.1875f}; + + mat3Inverse(&M, &M); + + bool result = mat3SumDiff(&M, &target) < EPSILON; + + if (!result) { + printf("\nM:\n"); + mat3Print(&M); + printf("\ntarget:\n"); + mat3Print(&target); + } + + printTest("mat3Inverse", result); +} + +void testMat3Transpose() { + mat3 M = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + mat3 target = {1, 4, 7, 2, 5, 8, 3, 6, 9}; + + mat3Transpose(&M, &M); + + printTest("mat3Transpose", mat3SumDiff(&M, &target) < EPSILON); +} + +int main(void) { + testSumDiff(); + testMat3Minor(); + testMat3Cofactor(); + testMat3Adjoint(); + testMat3MultiplyScalar(); + testMat3Determinant(); + testMat3Inverse(); + testMat3Transpose(); + + return exitCode; +} \ No newline at end of file diff --git a/u08-1/transformation.c b/u08-1/transformation.c new file mode 100644 index 0000000..b914ab6 --- /dev/null +++ b/u08-1/transformation.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include + +#include "matrixMath.h" +#include "transformation.h" + +void lookAt(mat4* out, vec3* eye, vec3* look, vec3* up) { + + + vec3 n; + vec3Subtract(&n, eye, look); + + vec3 u; + vec3Cross(&u, up, &n); + + vec3 v; + vec3Cross(&v, &n, &u); + + + vec3Normalise(&n, &n); + vec3Normalise(&u, &u); + vec3Normalise(&v, &v); + + + mat4 Mr; + identity(&Mr); + + memcpy(&Mr.m00, &u, sizeof(vec3)); + memcpy(&Mr.m01, &v, sizeof(vec3)); + memcpy(&Mr.m02, &n, sizeof(vec3)); + transpose(&Mr, &Mr); + + + vec3 t; + vec3Multiply(&u, &u, -1); + vec3Multiply(&v, &v, -1); + vec3Multiply(&n, &n, -1); + + + + t.x = vec3Dot(&u, eye); + t.y = vec3Dot(&v, eye); + t.z = vec3Dot(&n, eye); + + + memcpy(&Mr.m03, &t, sizeof(vec3)); + + memcpy(out, &Mr, sizeof(mat4)); +} + +void perspectiveProjection(mat4* out, GLfloat near, GLfloat far) { + identity(out); + + out->m22 = 1 + (far / near); + out->m32 = - 1.0f / near; + out->m23 = far; + out->m33 = 0; +} + +void normalisedDeviceCoordinates(mat4* out, GLfloat r, GLfloat l, GLfloat t, GLfloat b, GLfloat n, GLfloat f) { + identity(out); + + out->m00 = 2 / (r - l); + out->m11 = 2 / (t - b); + out->m22 = -2 / (f - n); + + out->m03 = - (r + l) / (r - l); + out->m13 = - (t + b) / (t - b); + out->m23 = - (f + n) / (f - n); +} + +void normalisedDeviceCoordinatesFov(mat4* out, GLfloat fovy, GLfloat aspectRatio, GLfloat n, GLfloat f) { + GLfloat t = tan(fovy / 2) * n; + GLfloat r = t * aspectRatio; + normalisedDeviceCoordinates(out, r, -r, t, -t, n, f); +} \ No newline at end of file diff --git a/u08-1/transformation.h b/u08-1/transformation.h new file mode 100644 index 0000000..9bbc03d --- /dev/null +++ b/u08-1/transformation.h @@ -0,0 +1,11 @@ +#ifndef TRANSFORMATION_H +#define TRANSFORMATION_H + +#include + +extern void lookAt(mat4* out, vec3* eye, vec3* look, vec3* up); +extern void perspectiveProjection(mat4* out, GLfloat near, GLfloat far); +extern void normalisedDeviceCoordinates(mat4* out, GLfloat r, GLfloat l, GLfloat t, GLfloat b, GLfloat n, GLfloat f); +extern void normalisedDeviceCoordinatesFov(mat4* out, GLfloat fovy, GLfloat aspectRatio, GLfloat n, GLfloat f); + +#endif \ No newline at end of file diff --git a/u08-1/vertexShader.glsl b/u08-1/vertexShader.glsl new file mode 100644 index 0000000..50173b6 --- /dev/null +++ b/u08-1/vertexShader.glsl @@ -0,0 +1,23 @@ +#version 330 core +layout (location = 0) in vec3 aPosition; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec2 aTextureCoordinate; + +uniform mat4 modelView; +uniform mat3 normalModelView; +uniform mat4 projection; + + +out vec3 normal; +out vec3 fragmentPosition; +out vec2 textureCoordinate; +void main() { + normal = normalModelView * aNormal; + textureCoordinate = aTextureCoordinate; + + vec4 modelViewPos = modelView * vec4(aPosition, 1.0); + + gl_Position = projection * modelViewPos; + + fragmentPosition = vec3(modelViewPos); +} \ No newline at end of file diff --git a/u08-1/wavefrontobj.c b/u08-1/wavefrontobj.c new file mode 100644 index 0000000..439d822 --- /dev/null +++ b/u08-1/wavefrontobj.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include + +#include "wavefrontobj.h" + +#define OBJ_LINE_BUFFER_SIZE 256 + +/** + * + * ADJUSTMENT NEEDED FOR + * - Face Definitions other than vertex/texture/normal + * - Vertex positions including w + * - Any faces using vertices yet to be defined + * (File is read top to bottom. A face using a vertex + * defined underneath it in the file will not work) + * + */ + +ParsedObjFile readObjFile(char* path) { + ParsedObjFile parsedFile; + + FILE* fp = fopen(path, "r"); + + if (fp == NULL) { + fprintf(stderr, "File could not be opened: %s", path); + parsedFile.faces = NULL; + parsedFile.length = 0; + } + + uint numVertices = 0; + uint numVertexNormals = 0; + uint numFaces = 0; + uint numTextureCoords = 0; + + char buf[OBJ_LINE_BUFFER_SIZE]; + + while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) { + if (buf[0] == 'v') { + if (buf[1] == ' ') { + numVertices++; + } else if (buf[1] == 't') { + numTextureCoords++; + } else if (buf[1] == 'n') { + numVertexNormals++; + } + } + if (buf[0] == 'f') { + int numSpaces = 0; + for (int i = 0; i < strlen(buf); i++) { + if (buf[i] == ' ') { + numSpaces++; + } + } + numFaces += numSpaces - 2; + } + } + + // printf("Vertices: %d\nFaces: %d\nNormals:%d\nTextures:%d\n", numVertices, numFaces, numVertexNormals, numTextureCoords); + + vec3* vertices = (vec3*) malloc(sizeof(vec3) * numVertices); + vec3* normals = (vec3*) malloc(sizeof(vec3) * numVertexNormals); + + vec2* textures = (vec2*) malloc(sizeof(vec2) * numTextureCoords); + + face* faces = (face*) malloc(sizeof(face) * numFaces); + + parsedFile.faces = faces; + parsedFile.length = numFaces; + + rewind(fp); + + uint curVertex = 0; + uint curNormal = 0; + uint curFace = 0; + uint curTexture = 0; + + while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) { + if (buf[0] == 'v') { + if (buf[1] == ' ') { + + sscanf(buf, + "v %f %f %f", + &vertices[curVertex].x, + &vertices[curVertex].y, + &vertices[curVertex].z + ); + curVertex++; + + } else if (buf[1] == 't') { + + int readValues = sscanf(buf, + "vt %f %f", + &textures[curTexture].x, + &textures[curTexture].y + ); + + if (readValues != 2) { + textures[curTexture].y = 0; + } + + curTexture++; + + + } else if (buf[1] == 'n') { + + sscanf(buf, + "vn %f %f %f", + &normals[curNormal].x, + &normals[curNormal].y, + &normals[curNormal].z + ); + curNormal++; + + } + } + + if (buf[0] == 'f') { + int v1, v2, v3; + int vt1, vt2, vt3; + int vn1, vn2, vn3; + + sscanf(buf, + "f %d/%d/%d %d/%d/%d %d/%d/%d", + &v1, &vt1, &vn1, + &v2, &vt2, &vn2, + &v3, &vt3, &vn3 + ); + + memcpy(&faces[curFace].v1.position, &vertices[v1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.position, &vertices[v2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.position, &vertices[v3 - 1], sizeof(vec3)); + + memcpy(&faces[curFace].v1.normal, &normals[vn1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.normal, &normals[vn2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.normal, &normals[vn3 - 1], sizeof(vec3)); + + memcpy(&faces[curFace].v1.texture, &textures[vt1 - 1], sizeof(vec2)); + memcpy(&faces[curFace].v2.texture, &textures[vt2 - 1], sizeof(vec2)); + memcpy(&faces[curFace].v3.texture, &textures[vt3 - 1], sizeof(vec2)); + + curFace++; + + int numSpaces = 0; + for (int i = 0; i < strlen(buf); i++) { + if (buf[i] == ' ') { + numSpaces++; + } + } + + if (numSpaces == 4) { + sscanf(buf, + "f %d/%d/%d %*d/%*d/%*d %d/%d/%d %d/%d/%d", + &v1, &vt1, &vn1, + &v2, &vt2, &vn2, + &v3, &vt3, &vn3 + ); + + memcpy(&faces[curFace].v1.position, &vertices[v1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.position, &vertices[v2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.position, &vertices[v3 - 1], sizeof(vec3)); + + memcpy(&faces[curFace].v1.normal, &normals[vn1 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v2.normal, &normals[vn2 - 1], sizeof(vec3)); + memcpy(&faces[curFace].v3.normal, &normals[vn3 - 1], sizeof(vec3)); + + memcpy(&faces[curFace].v1.texture, &textures[vt1 - 1], sizeof(vec2)); + memcpy(&faces[curFace].v2.texture, &textures[vt2 - 1], sizeof(vec2)); + memcpy(&faces[curFace].v3.texture, &textures[vt3 - 1], sizeof(vec2)); + + curFace++; + } + + + // TODO: textures + } + + } + + free(vertices); + free(normals); + fclose(fp); + + return parsedFile; +} + +void clearParsedFile(ParsedObjFile file) { + free(file.faces); +} \ No newline at end of file diff --git a/u08-1/wavefrontobj.h b/u08-1/wavefrontobj.h new file mode 100644 index 0000000..7726a39 --- /dev/null +++ b/u08-1/wavefrontobj.h @@ -0,0 +1,29 @@ +#ifndef WAVEFRONTOBJ_H +#define WAVEFRONTOBJ_H + +#include +#include "matrixMath.h" + +typedef struct { + vec3 position; + vec3 normal; + vec2 texture; +} vertex; + +typedef struct { + vertex v1; + vertex v2; + vertex v3; +} face; + +typedef struct { + face* faces; + GLuint length; +} ParsedObjFile; + + +extern ParsedObjFile readObjFile(char* path); +extern void clearParsedFile(ParsedObjFile file); + + +#endif \ No newline at end of file