Update C sources, add new functions
This commit is contained in:
parent
661c7a9f55
commit
0f4ce7d6d9
30 changed files with 8465 additions and 2315 deletions
2050
raylib/external/par_shapes.h
vendored
Normal file
2050
raylib/external/par_shapes.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
913
raylib/external/rgif.h
vendored
Normal file
913
raylib/external/rgif.h
vendored
Normal file
|
@ -0,0 +1,913 @@
|
|||
/**********************************************************************************************
|
||||
*
|
||||
* rgif.h original implementation by Charlie Tangora [ctangora -at- gmail -dot- com]
|
||||
* adapted to C99, reformatted and renamed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This file offers a simple, very limited way to create animated GIFs directly in code.
|
||||
*
|
||||
* Those looking for particular cleverness are likely to be disappointed; it's pretty
|
||||
* much a straight-ahead implementation of the GIF format with optional Floyd-Steinberg
|
||||
* dithering. (It does at least use delta encoding - only the changed portions of each
|
||||
* frame are saved.)
|
||||
*
|
||||
* So resulting files are often quite large. The hope is that it will be handy nonetheless
|
||||
* as a quick and easily-integrated way for programs to spit out animations.
|
||||
*
|
||||
* Only RGBA8 is currently supported as an input format. (The alpha is ignored.)
|
||||
*
|
||||
* CONFIGURATION:
|
||||
*
|
||||
* #define RGIF_IMPLEMENTATION
|
||||
* Generates the implementation of the library into the included file.
|
||||
* If not defined, the library is in header only mode and can be included in other headers
|
||||
* or source files without problems. But only ONE file should hold the implementation.
|
||||
*
|
||||
* USAGE:
|
||||
* 1) Create a GifWriter struct. Pass it to GifBegin() to initialize and write the header.
|
||||
* 2) Pass subsequent frames to GifWriteFrame().
|
||||
* 3) Finally, call GifEnd() to close the file handle and free memory.
|
||||
*
|
||||
*
|
||||
* LICENSE: 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.
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#ifndef GIF_H
|
||||
#define GIF_H
|
||||
|
||||
#include <stdio.h> // Required for: FILE
|
||||
|
||||
//#define RGIF_STATIC
|
||||
#ifdef RGIF_STATIC
|
||||
#define RGIFDEF static // Functions just visible to module including this file
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
#define RGIFDEF extern "C" // Functions visible from other files (no name mangling of functions in C++)
|
||||
#else
|
||||
#define RGIFDEF extern // Functions visible from other files
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// NOTE: By default use bitDepth = 8, dither = false
|
||||
RGIFDEF bool GifBegin(const char *filename, unsigned int width, unsigned int height, unsigned int delay, unsigned int bitDepth, bool dither);
|
||||
RGIFDEF bool GifWriteFrame(const unsigned char *image, unsigned int width, unsigned int height, unsigned int delay, int bitDepth, bool dither);
|
||||
RGIFDEF bool GifEnd();
|
||||
|
||||
#endif // GIF_H
|
||||
|
||||
|
||||
/***********************************************************************************
|
||||
*
|
||||
* GIF IMPLEMENTATION
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#if defined(RGIF_IMPLEMENTATION)
|
||||
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fclose()
|
||||
#include <string.h> // Required for: memcpy()
|
||||
|
||||
// Define these macros to hook into a custom memory allocator.
|
||||
// GIF_TEMP_MALLOC and GIF_TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs
|
||||
// and any temp memory allocated by a function will be freed before it exits.
|
||||
#if !defined(GIF_TEMP_MALLOC)
|
||||
#include <stdlib.h>
|
||||
|
||||
#define GIF_TEMP_MALLOC malloc
|
||||
#define GIF_TEMP_FREE free
|
||||
#endif
|
||||
|
||||
// Check if custom malloc/free functions defined, if not, using standard ones
|
||||
// GIF_MALLOC and GIF_FREE are used only by GifBegin and GifEnd respectively,
|
||||
// to allocate a buffer the size of the image, which is used to find changed pixels for delta-encoding.
|
||||
#if !defined(GIF_MALLOC)
|
||||
#include <stdlib.h> // Required for: malloc(), free()
|
||||
|
||||
#define GIF_MALLOC(size) malloc(size)
|
||||
#define GIF_FREE(ptr) free(ptr)
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#define GIFMIN(a, b) (((a)<(b))?(a):(b))
|
||||
#define GIFMAX(a, b) (((a)>(b))?(a):(b))
|
||||
#define GIFABS(x) ((x)<0?-(x):(x))
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Gif palette structure
|
||||
typedef struct GifPalette {
|
||||
int bitDepth;
|
||||
|
||||
unsigned char r[256];
|
||||
unsigned char g[256];
|
||||
unsigned char b[256];
|
||||
|
||||
// k-d tree over RGB space, organized in heap fashion
|
||||
// i.e. left child of node i is node i*2, right child is node i*2 + 1
|
||||
// nodes 256-511 are implicitly the leaves, containing a color
|
||||
unsigned char treeSplitElt[255];
|
||||
unsigned char treeSplit[255];
|
||||
} GifPalette;
|
||||
|
||||
|
||||
// Simple structure to write out the LZW-compressed
|
||||
// portion of the imageone bit at a time
|
||||
typedef struct GifBitStatus {
|
||||
unsigned char bitIndex; // how many bits in the partial byte written so far
|
||||
unsigned char byte; // current partial byte
|
||||
|
||||
unsigned int chunkIndex;
|
||||
unsigned char chunk[256]; // bytes are written in here until we have 256 of them, then written to the file
|
||||
} GifBitStatus;
|
||||
|
||||
// The LZW dictionary is a 256-ary tree constructed
|
||||
// as the file is encoded, this is one node
|
||||
typedef struct GifLzwNode {
|
||||
uint16_t m_next[256];
|
||||
} GifLzwNode;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
const int gifTransparentIndex = 0; // Transparent color index
|
||||
|
||||
static FILE *gifFile;
|
||||
unsigned char *gifFrame;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module specific Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
static void GifGetClosestPaletteColor(GifPalette *pPal, int r, int g, int b, int *bestInd, int *bestDiff, int treeRoot);
|
||||
static void GifSwapPixels(unsigned char *image, int pixA, int pixB);
|
||||
static int GifPartition(unsigned char *image, const int left, const int right, const int elt, int pivotIndex);
|
||||
static void GifPartitionByMedian(unsigned char *image, int left, int right, int com, int neededCenter);
|
||||
static void GifSplitPalette(unsigned char *image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette *pal);
|
||||
static int GifPickChangedPixels(const unsigned char *lastFrame, unsigned char *frame, int numPixels);
|
||||
static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned int width, unsigned int height, int bitDepth, bool buildForDither, GifPalette *pPal);
|
||||
static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal);
|
||||
static void GifThresholdImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal);
|
||||
static void GifWriteBit(GifBitStatus *stat, unsigned int bit);
|
||||
static void GifWriteChunk(FILE *f, GifBitStatus *stat);
|
||||
static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigned int length);
|
||||
static void GifWritePalette(const GifPalette *pPal, FILE *f);
|
||||
static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int delay, GifPalette *pPal);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Creates a gif file
|
||||
// NOTE: Initializes internal file pointer (only one gif recording at a time)
|
||||
// The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value.
|
||||
RGIFDEF bool GifBegin(const char *filename, unsigned int width, unsigned int height, unsigned int delay, unsigned int bitDepth, bool dither)
|
||||
{
|
||||
#if _MSC_VER >= 1400
|
||||
gifFile = 0;
|
||||
fopen_s(&gifFile, filename, "wb");
|
||||
#else
|
||||
gifFile = fopen(filename, "wb");
|
||||
#endif
|
||||
|
||||
if (!gifFile) return false;
|
||||
|
||||
// Allocate space for one gif frame
|
||||
gifFrame = (unsigned char *)GIF_MALLOC(width*height*4);
|
||||
|
||||
// GIF Header
|
||||
fputs("GIF89a",gifFile);
|
||||
|
||||
// Reference: http://www.onicos.com/staff/iz/formats/gif.html
|
||||
|
||||
// GIF Screen Descriptor
|
||||
fputc(width & 0xff, gifFile);
|
||||
fputc((width >> 8) & 0xff, gifFile); // Screen width (2 byte)
|
||||
fputc(height & 0xff, gifFile);
|
||||
fputc((height >> 8) & 0xff, gifFile); // Screen height (2 byte)
|
||||
|
||||
fputc(0xf0, gifFile); // Color table flags: unsorted global color table of 2 entries (1 byte, bit-flags)
|
||||
fputc(0, gifFile); // Background color index
|
||||
fputc(0, gifFile); // Pixel Aspect Ratio (square, we need to specify this because it's 1989)
|
||||
|
||||
// GIF Global Color table (just a dummy palette)
|
||||
// Color 0: black
|
||||
fputc(0, gifFile);
|
||||
fputc(0, gifFile);
|
||||
fputc(0, gifFile);
|
||||
// Color 1: also black
|
||||
fputc(0, gifFile);
|
||||
fputc(0, gifFile);
|
||||
fputc(0, gifFile);
|
||||
|
||||
if (delay != 0)
|
||||
{
|
||||
// Application Extension Block (19 bytes long)
|
||||
fputc(0x21, gifFile); // GIF Extension code
|
||||
fputc(0xff, gifFile); // Application Extension Label
|
||||
fputc(11, gifFile); // Length of Application Block (11 byte)
|
||||
fputs("NETSCAPE2.0", gifFile); // Application Identifier (Netscape 2.0 block)
|
||||
|
||||
fputc(0x03, gifFile); // Length of Data Sub-Block (3 bytes)
|
||||
fputc(0x01, gifFile); // 0x01
|
||||
fputc(0x00, gifFile); // This specifies the number of times,
|
||||
fputc(0x00, gifFile); // the loop should be executed (infinitely)
|
||||
|
||||
fputc(0x00, gifFile); // Data Sub-Block Terminator.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes out a new frame to a GIF in progress.
|
||||
// NOTE: gifFile should have been initialized with GifBegin()
|
||||
// AFAIK, it is legal to use different bit depths for different frames of an image -
|
||||
// this may be handy to save bits in animations that don't change much.
|
||||
RGIFDEF bool GifWriteFrame(const unsigned char *image, unsigned int width, unsigned int height, unsigned int delay, int bitDepth, bool dither)
|
||||
{
|
||||
if (!gifFile) return false;
|
||||
|
||||
const unsigned char *oldImage = gifFrame;
|
||||
|
||||
GifPalette pal;
|
||||
GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal);
|
||||
|
||||
if (dither) GifDitherImage(oldImage, image, gifFrame, width, height, &pal);
|
||||
else GifThresholdImage(oldImage, image, gifFrame, width, height, &pal);
|
||||
|
||||
GifWriteLzwImage(gifFile, gifFrame, 0, 0, width, height, delay, &pal);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Writes the EOF code, closes the file handle, and frees temp memory used by a GIF.
|
||||
// Many if not most viewers will still display a GIF properly if the EOF code is missing,
|
||||
// but it's still a good idea to write it out.
|
||||
RGIFDEF bool GifEnd()
|
||||
{
|
||||
if (!gifFile) return false;
|
||||
|
||||
fputc(0x3b, gifFile); // Trailer (end of file)
|
||||
fclose(gifFile);
|
||||
|
||||
GIF_FREE(gifFrame);
|
||||
|
||||
gifFile = NULL;
|
||||
gifFrame = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module specific Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// walks the k-d tree to pick the palette entry for a desired color.
|
||||
// Takes as in/out parameters the current best color and its error -
|
||||
// only changes them if it finds a better color in its subtree.
|
||||
// this is the major hotspot in the code at the moment.
|
||||
static void GifGetClosestPaletteColor(GifPalette *pPal, int r, int g, int b, int *bestInd, int *bestDiff, int treeRoot)
|
||||
{
|
||||
// base case, reached the bottom of the tree
|
||||
if (treeRoot > (1<<pPal->bitDepth)-1)
|
||||
{
|
||||
int ind = treeRoot-(1<<pPal->bitDepth);
|
||||
if (ind == gifTransparentIndex) return;
|
||||
|
||||
// check whether this color is better than the current winner
|
||||
int r_err = r - ((int32_t)pPal->r[ind]);
|
||||
int g_err = g - ((int32_t)pPal->g[ind]);
|
||||
int b_err = b - ((int32_t)pPal->b[ind]);
|
||||
int diff = GIFABS(r_err)+GIFABS(g_err)+GIFABS(b_err);
|
||||
|
||||
if (diff < *bestDiff)
|
||||
{
|
||||
*bestInd = ind;
|
||||
*bestDiff = diff;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// take the appropriate color (r, g, or b) for this node of the k-d tree
|
||||
int comps[3]; comps[0] = r; comps[1] = g; comps[2] = b;
|
||||
int splitComp = comps[pPal->treeSplitElt[treeRoot]];
|
||||
|
||||
int splitPos = pPal->treeSplit[treeRoot];
|
||||
if (splitPos > splitComp)
|
||||
{
|
||||
// check the left subtree
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
|
||||
if (*bestDiff > (splitPos - splitComp))
|
||||
{
|
||||
// cannot prove there's not a better value in the right subtree, check that too
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2 + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2 + 1);
|
||||
|
||||
if (*bestDiff > splitComp - splitPos)
|
||||
{
|
||||
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GifSwapPixels(unsigned char *image, int pixA, int pixB)
|
||||
{
|
||||
unsigned char rA = image[pixA*4];
|
||||
unsigned char gA = image[pixA*4 + 1];
|
||||
unsigned char bA = image[pixA*4+2];
|
||||
unsigned char aA = image[pixA*4+3];
|
||||
|
||||
unsigned char rB = image[pixB*4];
|
||||
unsigned char gB = image[pixB*4 + 1];
|
||||
unsigned char bB = image[pixB*4+2];
|
||||
unsigned char aB = image[pixA*4+3];
|
||||
|
||||
image[pixA*4] = rB;
|
||||
image[pixA*4 + 1] = gB;
|
||||
image[pixA*4+2] = bB;
|
||||
image[pixA*4+3] = aB;
|
||||
|
||||
image[pixB*4] = rA;
|
||||
image[pixB*4 + 1] = gA;
|
||||
image[pixB*4+2] = bA;
|
||||
image[pixB*4+3] = aA;
|
||||
}
|
||||
|
||||
// just the partition operation from quicksort
|
||||
static int GifPartition(unsigned char *image, const int left, const int right, const int elt, int pivotIndex)
|
||||
{
|
||||
const int pivotValue = image[(pivotIndex)*4+elt];
|
||||
GifSwapPixels(image, pivotIndex, right-1);
|
||||
int storeIndex = left;
|
||||
bool split = 0;
|
||||
for (int ii=left; ii<right-1; ++ii)
|
||||
{
|
||||
int arrayVal = image[ii*4+elt];
|
||||
if (arrayVal < pivotValue)
|
||||
{
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
}
|
||||
else if (arrayVal == pivotValue)
|
||||
{
|
||||
if (split)
|
||||
{
|
||||
GifSwapPixels(image, ii, storeIndex);
|
||||
++storeIndex;
|
||||
}
|
||||
split = !split;
|
||||
}
|
||||
}
|
||||
GifSwapPixels(image, storeIndex, right-1);
|
||||
return storeIndex;
|
||||
}
|
||||
|
||||
// Perform an incomplete sort, finding all elements above and below the desired median
|
||||
static void GifPartitionByMedian(unsigned char *image, int left, int right, int com, int neededCenter)
|
||||
{
|
||||
if (left < right-1)
|
||||
{
|
||||
int pivotIndex = left + (right-left)/2;
|
||||
|
||||
pivotIndex = GifPartition(image, left, right, com, pivotIndex);
|
||||
|
||||
// Only "sort" the section of the array that contains the median
|
||||
if (pivotIndex > neededCenter)
|
||||
GifPartitionByMedian(image, left, pivotIndex, com, neededCenter);
|
||||
|
||||
if (pivotIndex < neededCenter)
|
||||
GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter);
|
||||
}
|
||||
}
|
||||
|
||||
// Builds a palette by creating a balanced k-d tree of all pixels in the image
|
||||
static void GifSplitPalette(unsigned char *image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist,
|
||||
int treeNode, bool buildForDither, GifPalette *pal)
|
||||
{
|
||||
if (lastElt <= firstElt || numPixels == 0)
|
||||
return;
|
||||
|
||||
// base case, bottom of the tree
|
||||
if (lastElt == firstElt + 1)
|
||||
{
|
||||
if (buildForDither)
|
||||
{
|
||||
// Dithering needs at least one color as dark as anything
|
||||
// in the image and at least one brightest color -
|
||||
// otherwise it builds up error and produces strange artifacts
|
||||
if (firstElt == 1)
|
||||
{
|
||||
// special case: the darkest color in the image
|
||||
unsigned int r=255, g=255, b=255;
|
||||
for (int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r = GIFMIN(r, image[ii*4+0]);
|
||||
g = GIFMIN(g, image[ii*4 + 1]);
|
||||
b = GIFMIN(b, image[ii*4+2]);
|
||||
}
|
||||
|
||||
pal->r[firstElt] = r;
|
||||
pal->g[firstElt] = g;
|
||||
pal->b[firstElt] = b;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstElt == (1 << pal->bitDepth)-1)
|
||||
{
|
||||
// special case: the lightest color in the image
|
||||
unsigned int r=0, g=0, b=0;
|
||||
for (int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r = GIFMAX(r, image[ii*4+0]);
|
||||
g = GIFMAX(g, image[ii*4 + 1]);
|
||||
b = GIFMAX(b, image[ii*4+2]);
|
||||
}
|
||||
|
||||
pal->r[firstElt] = r;
|
||||
pal->g[firstElt] = g;
|
||||
pal->b[firstElt] = b;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, take the average of all colors in this subcube
|
||||
uint64_t r=0, g=0, b=0;
|
||||
for (int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
r += image[ii*4+0];
|
||||
g += image[ii*4 + 1];
|
||||
b += image[ii*4+2];
|
||||
}
|
||||
|
||||
r += numPixels / 2; // round to nearest
|
||||
g += numPixels / 2;
|
||||
b += numPixels / 2;
|
||||
|
||||
r /= numPixels;
|
||||
g /= numPixels;
|
||||
b /= numPixels;
|
||||
|
||||
pal->r[firstElt] = (unsigned char)r;
|
||||
pal->g[firstElt] = (unsigned char)g;
|
||||
pal->b[firstElt] = (unsigned char)b;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the axis with the largest range
|
||||
int minR = 255, maxR = 0;
|
||||
int minG = 255, maxG = 0;
|
||||
int minB = 255, maxB = 0;
|
||||
for (int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
int r = image[ii*4+0];
|
||||
int g = image[ii*4 + 1];
|
||||
int b = image[ii*4+2];
|
||||
|
||||
if (r > maxR) maxR = r;
|
||||
if (r < minR) minR = r;
|
||||
|
||||
if (g > maxG) maxG = g;
|
||||
if (g < minG) minG = g;
|
||||
|
||||
if (b > maxB) maxB = b;
|
||||
if (b < minB) minB = b;
|
||||
}
|
||||
|
||||
int rRange = maxR - minR;
|
||||
int gRange = maxG - minG;
|
||||
int bRange = maxB - minB;
|
||||
|
||||
// and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it)
|
||||
int splitCom = 1;
|
||||
if (bRange > gRange) splitCom = 2;
|
||||
if (rRange > bRange && rRange > gRange) splitCom = 0;
|
||||
|
||||
int subPixelsA = numPixels *(splitElt - firstElt) / (lastElt - firstElt);
|
||||
int subPixelsB = numPixels-subPixelsA;
|
||||
|
||||
GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA);
|
||||
|
||||
pal->treeSplitElt[treeNode] = splitCom;
|
||||
pal->treeSplit[treeNode] = image[subPixelsA*4+splitCom];
|
||||
|
||||
GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, buildForDither, pal);
|
||||
GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2 + 1, buildForDither, pal);
|
||||
}
|
||||
|
||||
// Finds all pixels that have changed from the previous image and
|
||||
// moves them to the fromt of th buffer.
|
||||
// This allows us to build a palette optimized for the colors of the
|
||||
// changed pixels only.
|
||||
static int GifPickChangedPixels(const unsigned char *lastFrame, unsigned char *frame, int numPixels)
|
||||
{
|
||||
int numChanged = 0;
|
||||
unsigned char *writeIter = frame;
|
||||
|
||||
for (int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
if (lastFrame[0] != frame[0] ||
|
||||
lastFrame[1] != frame[1] ||
|
||||
lastFrame[2] != frame[2])
|
||||
{
|
||||
writeIter[0] = frame[0];
|
||||
writeIter[1] = frame[1];
|
||||
writeIter[2] = frame[2];
|
||||
++numChanged;
|
||||
writeIter += 4;
|
||||
}
|
||||
lastFrame += 4;
|
||||
frame += 4;
|
||||
}
|
||||
|
||||
return numChanged;
|
||||
}
|
||||
|
||||
// Creates a palette by placing all the image pixels in a k-d tree and then averaging the blocks at the bottom.
|
||||
// This is known as the "modified median split" technique
|
||||
static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned int width, unsigned int height, int bitDepth, bool buildForDither, GifPalette *pPal)
|
||||
{
|
||||
pPal->bitDepth = bitDepth;
|
||||
|
||||
// SplitPalette is destructive (it sorts the pixels by color) so
|
||||
// we must create a copy of the image for it to destroy
|
||||
int imageSize = width*height*4*sizeof(unsigned char);
|
||||
unsigned char *destroyableImage = (unsigned char*)GIF_TEMP_MALLOC(imageSize);
|
||||
memcpy(destroyableImage, nextFrame, imageSize);
|
||||
|
||||
int numPixels = width*height;
|
||||
if (lastFrame)
|
||||
numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels);
|
||||
|
||||
const int lastElt = 1 << bitDepth;
|
||||
const int splitElt = lastElt/2;
|
||||
const int splitDist = splitElt/2;
|
||||
|
||||
GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal);
|
||||
|
||||
GIF_TEMP_FREE(destroyableImage);
|
||||
|
||||
// add the bottom node for the transparency index
|
||||
pPal->treeSplit[1 << (bitDepth-1)] = 0;
|
||||
pPal->treeSplitElt[1 << (bitDepth-1)] = 0;
|
||||
|
||||
pPal->r[0] = pPal->g[0] = pPal->b[0] = 0;
|
||||
}
|
||||
|
||||
// Implements Floyd-Steinberg dithering, writes palette value to alpha
|
||||
static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal)
|
||||
{
|
||||
int numPixels = width*height;
|
||||
|
||||
// quantPixels initially holds color*256 for all pixels
|
||||
// The extra 8 bits of precision allow for sub-single-color error values
|
||||
// to be propagated
|
||||
int32_t *quantPixels = (int32_t*)GIF_TEMP_MALLOC(sizeof(int32_t)*numPixels*4);
|
||||
|
||||
for (int ii=0; ii<numPixels*4; ++ii)
|
||||
{
|
||||
unsigned char pix = nextFrame[ii];
|
||||
int32_t pix16 = (int32_t)pix*256;
|
||||
quantPixels[ii] = pix16;
|
||||
}
|
||||
|
||||
for (unsigned int yy=0; yy<height; ++yy)
|
||||
{
|
||||
for (unsigned int xx=0; xx<width; ++xx)
|
||||
{
|
||||
int32_t *nextPix = quantPixels + 4*(yy*width+xx);
|
||||
const unsigned char *lastPix = lastFrame? lastFrame + 4*(yy*width+xx) : NULL;
|
||||
|
||||
// Compute the colors we want (rounding to nearest)
|
||||
int32_t rr = (nextPix[0] + 127) / 256;
|
||||
int32_t gg = (nextPix[1] + 127) / 256;
|
||||
int32_t bb = (nextPix[2] + 127) / 256;
|
||||
|
||||
// if it happens that we want the color from last frame, then just write out
|
||||
// a transparent pixel
|
||||
if (lastFrame &&
|
||||
lastPix[0] == rr &&
|
||||
lastPix[1] == gg &&
|
||||
lastPix[2] == bb)
|
||||
{
|
||||
nextPix[0] = rr;
|
||||
nextPix[1] = gg;
|
||||
nextPix[2] = bb;
|
||||
nextPix[3] = gifTransparentIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = gifTransparentIndex;
|
||||
|
||||
// Search the palete
|
||||
GifGetClosestPaletteColor(pPal, rr, gg, bb, &bestInd, &bestDiff, 1);
|
||||
|
||||
// Write the result to the temp buffer
|
||||
int32_t r_err = nextPix[0] - (int32_t)(pPal->r[bestInd])*256;
|
||||
int32_t g_err = nextPix[1] - (int32_t)(pPal->g[bestInd])*256;
|
||||
int32_t b_err = nextPix[2] - (int32_t)(pPal->b[bestInd])*256;
|
||||
|
||||
nextPix[0] = pPal->r[bestInd];
|
||||
nextPix[1] = pPal->g[bestInd];
|
||||
nextPix[2] = pPal->b[bestInd];
|
||||
nextPix[3] = bestInd;
|
||||
|
||||
// Propagate the error to the four adjacent locations
|
||||
// that we haven't touched yet
|
||||
int quantloc_7 = (yy*width+xx + 1);
|
||||
int quantloc_3 = (yy*width+width+xx-1);
|
||||
int quantloc_5 = (yy*width+width+xx);
|
||||
int quantloc_1 = (yy*width+width+xx + 1);
|
||||
|
||||
if (quantloc_7 < numPixels)
|
||||
{
|
||||
int32_t *pix7 = quantPixels+4*quantloc_7;
|
||||
pix7[0] += GIFMAX(-pix7[0], r_err*7 / 16);
|
||||
pix7[1] += GIFMAX(-pix7[1], g_err*7 / 16);
|
||||
pix7[2] += GIFMAX(-pix7[2], b_err*7 / 16);
|
||||
}
|
||||
|
||||
if (quantloc_3 < numPixels)
|
||||
{
|
||||
int32_t *pix3 = quantPixels+4*quantloc_3;
|
||||
pix3[0] += GIFMAX(-pix3[0], r_err*3 / 16);
|
||||
pix3[1] += GIFMAX(-pix3[1], g_err*3 / 16);
|
||||
pix3[2] += GIFMAX(-pix3[2], b_err*3 / 16);
|
||||
}
|
||||
|
||||
if (quantloc_5 < numPixels)
|
||||
{
|
||||
int32_t *pix5 = quantPixels+4*quantloc_5;
|
||||
pix5[0] += GIFMAX(-pix5[0], r_err*5 / 16);
|
||||
pix5[1] += GIFMAX(-pix5[1], g_err*5 / 16);
|
||||
pix5[2] += GIFMAX(-pix5[2], b_err*5 / 16);
|
||||
}
|
||||
|
||||
if (quantloc_1 < numPixels)
|
||||
{
|
||||
int32_t *pix1 = quantPixels+4*quantloc_1;
|
||||
pix1[0] += GIFMAX(-pix1[0], r_err / 16);
|
||||
pix1[1] += GIFMAX(-pix1[1], g_err / 16);
|
||||
pix1[2] += GIFMAX(-pix1[2], b_err / 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the palettized result to the output buffer
|
||||
for (int ii=0; ii<numPixels*4; ++ii)
|
||||
{
|
||||
outFrame[ii] = quantPixels[ii];
|
||||
}
|
||||
|
||||
GIF_TEMP_FREE(quantPixels);
|
||||
}
|
||||
|
||||
// Picks palette colors for the image using simple thresholding, no dithering
|
||||
static void GifThresholdImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal)
|
||||
{
|
||||
unsigned int numPixels = width*height;
|
||||
for (unsigned int ii=0; ii<numPixels; ++ii)
|
||||
{
|
||||
// if a previous color is available, and it matches the current color,
|
||||
// set the pixel to transparent
|
||||
if (lastFrame &&
|
||||
lastFrame[0] == nextFrame[0] &&
|
||||
lastFrame[1] == nextFrame[1] &&
|
||||
lastFrame[2] == nextFrame[2])
|
||||
{
|
||||
outFrame[0] = lastFrame[0];
|
||||
outFrame[1] = lastFrame[1];
|
||||
outFrame[2] = lastFrame[2];
|
||||
outFrame[3] = gifTransparentIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// palettize the pixel
|
||||
int32_t bestDiff = 1000000;
|
||||
int32_t bestInd = 1;
|
||||
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], &bestInd, &bestDiff, 1);
|
||||
|
||||
// Write the resulting color to the output buffer
|
||||
outFrame[0] = pPal->r[bestInd];
|
||||
outFrame[1] = pPal->g[bestInd];
|
||||
outFrame[2] = pPal->b[bestInd];
|
||||
outFrame[3] = bestInd;
|
||||
}
|
||||
|
||||
if (lastFrame) lastFrame += 4;
|
||||
outFrame += 4;
|
||||
nextFrame += 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// insert a single bit
|
||||
static void GifWriteBit(GifBitStatus *stat, unsigned int bit)
|
||||
{
|
||||
bit = bit & 1;
|
||||
bit = bit << stat->bitIndex;
|
||||
stat->byte |= bit;
|
||||
|
||||
++stat->bitIndex;
|
||||
if (stat->bitIndex > 7)
|
||||
{
|
||||
// move the newly-finished byte to the chunk buffer
|
||||
stat->chunk[stat->chunkIndex++] = stat->byte;
|
||||
// and start a new byte
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// write all bytes so far to the file
|
||||
static void GifWriteChunk(FILE *f, GifBitStatus *stat)
|
||||
{
|
||||
fputc(stat->chunkIndex, f);
|
||||
fwrite(stat->chunk, 1, stat->chunkIndex, f);
|
||||
|
||||
stat->bitIndex = 0;
|
||||
stat->byte = 0;
|
||||
stat->chunkIndex = 0;
|
||||
}
|
||||
|
||||
static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigned int length)
|
||||
{
|
||||
for (unsigned int ii=0; ii<length; ++ii)
|
||||
{
|
||||
GifWriteBit(stat, code);
|
||||
code = code >> 1;
|
||||
|
||||
if (stat->chunkIndex == 255)
|
||||
{
|
||||
GifWriteChunk(f, stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write a 256-color (8-bit) image palette to the file
|
||||
static void GifWritePalette(const GifPalette *pPal, FILE *f)
|
||||
{
|
||||
fputc(0, f); // first color: transparency
|
||||
fputc(0, f);
|
||||
fputc(0, f);
|
||||
|
||||
for (int ii=1; ii<(1 << pPal->bitDepth); ++ii)
|
||||
{
|
||||
unsigned int r = pPal->r[ii];
|
||||
unsigned int g = pPal->g[ii];
|
||||
unsigned int b = pPal->b[ii];
|
||||
|
||||
fputc(r, f);
|
||||
fputc(g, f);
|
||||
fputc(b, f);
|
||||
}
|
||||
}
|
||||
|
||||
// write the image header, LZW-compress and write out the image
|
||||
static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int delay, GifPalette *pPal)
|
||||
{
|
||||
// graphics control extension
|
||||
fputc(0x21, f);
|
||||
fputc(0xf9, f);
|
||||
fputc(0x04, f);
|
||||
fputc(0x05, f); // leave prev frame in place, this frame has transparency
|
||||
fputc(delay & 0xff, f);
|
||||
fputc((delay >> 8) & 0xff, f);
|
||||
fputc(gifTransparentIndex, f); // transparent color index
|
||||
fputc(0, f);
|
||||
|
||||
fputc(0x2c, f); // image descriptor block
|
||||
|
||||
fputc(left & 0xff, f); // corner of image in canvas space
|
||||
fputc((left >> 8) & 0xff, f);
|
||||
fputc(top & 0xff, f);
|
||||
fputc((top >> 8) & 0xff, f);
|
||||
|
||||
fputc(width & 0xff, f); // width and height of image
|
||||
fputc((width >> 8) & 0xff, f);
|
||||
fputc(height & 0xff, f);
|
||||
fputc((height >> 8) & 0xff, f);
|
||||
|
||||
//fputc(0, f); // no local color table, no transparency
|
||||
//fputc(0x80, f); // no local color table, but transparency
|
||||
|
||||
fputc(0x80 + pPal->bitDepth-1, f); // local color table present, 2 ^ bitDepth entries
|
||||
GifWritePalette(pPal, f);
|
||||
|
||||
const int minCodeSize = pPal->bitDepth;
|
||||
const unsigned int clearCode = 1 << pPal->bitDepth;
|
||||
|
||||
fputc(minCodeSize, f); // min code size 8 bits
|
||||
|
||||
GifLzwNode *codetree = (GifLzwNode *)GIF_TEMP_MALLOC(sizeof(GifLzwNode)*4096);
|
||||
|
||||
memset(codetree, 0, sizeof(GifLzwNode)*4096);
|
||||
int32_t curCode = -1;
|
||||
unsigned int codeSize = minCodeSize + 1;
|
||||
unsigned int maxCode = clearCode + 1;
|
||||
|
||||
GifBitStatus stat;
|
||||
stat.byte = 0;
|
||||
stat.bitIndex = 0;
|
||||
stat.chunkIndex = 0;
|
||||
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // start with a fresh LZW dictionary
|
||||
|
||||
for (unsigned int yy=0; yy<height; ++yy)
|
||||
{
|
||||
for (unsigned int xx=0; xx<width; ++xx)
|
||||
{
|
||||
unsigned char nextValue = image[(yy*width+xx)*4+3];
|
||||
|
||||
// "loser mode" - no compression, every single code is followed immediately by a clear
|
||||
//WriteCode(f, stat, nextValue, codeSize);
|
||||
//WriteCode(f, stat, 256, codeSize);
|
||||
|
||||
if (curCode < 0)
|
||||
{
|
||||
// first value in a new run
|
||||
curCode = nextValue;
|
||||
}
|
||||
else if (codetree[curCode].m_next[nextValue])
|
||||
{
|
||||
// current run already in the dictionary
|
||||
curCode = codetree[curCode].m_next[nextValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
// finish the current run, write a code
|
||||
GifWriteCode(f, &stat, curCode, codeSize);
|
||||
|
||||
// insert the new run into the dictionary
|
||||
codetree[curCode].m_next[nextValue] = ++maxCode;
|
||||
|
||||
if (maxCode >= (1ul << codeSize))
|
||||
{
|
||||
// dictionary entry count has broken a size barrier,
|
||||
// we need more bits for codes
|
||||
codeSize++;
|
||||
}
|
||||
if (maxCode == 4095)
|
||||
{
|
||||
// the dictionary is full, clear it out and begin anew
|
||||
GifWriteCode(f, &stat, clearCode, codeSize); // clear tree
|
||||
|
||||
memset(codetree, 0, sizeof(GifLzwNode)*4096);
|
||||
curCode = -1;
|
||||
codeSize = minCodeSize + 1;
|
||||
maxCode = clearCode + 1;
|
||||
}
|
||||
|
||||
curCode = nextValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compression footer
|
||||
GifWriteCode(f, &stat, curCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode, codeSize);
|
||||
GifWriteCode(f, &stat, clearCode + 1, minCodeSize + 1);
|
||||
|
||||
// write out the last partial chunk
|
||||
while (stat.bitIndex) GifWriteBit(&stat, 0);
|
||||
if (stat.chunkIndex) GifWriteChunk(f, &stat);
|
||||
|
||||
fputc(0, f); // image block terminator
|
||||
|
||||
GIF_TEMP_FREE(codetree);
|
||||
}
|
||||
|
||||
#endif // RGIF_IMPLEMENTATION
|
184
raylib/external/stb_image.h
vendored
184
raylib/external/stb_image.h
vendored
|
@ -1,4 +1,4 @@
|
|||
/* stb_image - v2.15 - public domain image loader - http://nothings.org/stb_image.h
|
||||
/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
|
@ -48,6 +48,7 @@ LICENSE
|
|||
|
||||
RECENT REVISION HISTORY:
|
||||
|
||||
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
|
||||
|
@ -58,10 +59,6 @@ RECENT REVISION HISTORY:
|
|||
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
|
||||
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
|
||||
2.07 (2015-09-13) partial animated GIF support
|
||||
limited 16-bit PSD support
|
||||
minor bugs, code cleanup, and compiler warnings
|
||||
|
||||
See end of file for full revision history.
|
||||
|
||||
|
@ -83,6 +80,7 @@ RECENT REVISION HISTORY:
|
|||
Optimizations & bugfixes
|
||||
Fabian "ryg" Giesen
|
||||
Arseny Kapoulkine
|
||||
John-Mark Allen
|
||||
|
||||
Bug & warning fixes
|
||||
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
|
||||
|
@ -98,7 +96,7 @@ RECENT REVISION HISTORY:
|
|||
Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210
|
||||
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw
|
||||
Blazej Dariusz Roszkowski Gregory Mullen github:phprus
|
||||
|
||||
Christian Floisand Kevin Schmidt github:poppolopoppo
|
||||
*/
|
||||
|
||||
#ifndef STBI_INCLUDE_STB_IMAGE_H
|
||||
|
@ -134,11 +132,12 @@ RECENT REVISION HISTORY:
|
|||
// 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 'req_comp' if req_comp is non-zero, or *comp otherwise.
|
||||
// If req_comp is non-zero, *comp has the number of components that _would_
|
||||
// have been output otherwise. E.g. if you set req_comp to 4, you will always
|
||||
// get RGBA output, but you can check *comp to see if it's trivially opaque
|
||||
// because e.g. there were only 3 channels in the source image.
|
||||
// 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:
|
||||
|
@ -150,10 +149,10 @@ RECENT REVISION HISTORY:
|
|||
// 4 red, green, blue, alpha
|
||||
//
|
||||
// If image loading fails for any reason, the return value will be NULL,
|
||||
// and *x, *y, *comp 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
|
||||
// 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.
|
||||
|
@ -310,7 +309,7 @@ RECENT REVISION HISTORY:
|
|||
|
||||
enum
|
||||
{
|
||||
STBI_default = 0, // only used for req_comp
|
||||
STBI_default = 0, // only used for desired_channels
|
||||
|
||||
STBI_grey = 1,
|
||||
STBI_grey_alpha = 2,
|
||||
|
@ -352,12 +351,12 @@ typedef struct
|
|||
// 8-bits-per-channel interface
|
||||
//
|
||||
|
||||
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_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_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
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
|
||||
|
||||
|
@ -366,22 +365,24 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_i
|
|||
// 16-bits-per-channel interface
|
||||
//
|
||||
|
||||
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_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
|
||||
// @TODO the other variants
|
||||
|
||||
////////////////////////////////////
|
||||
//
|
||||
// float-per-channel interface
|
||||
//
|
||||
#ifndef STBI_NO_LINEAR
|
||||
STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
|
||||
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
|
||||
|
@ -639,7 +640,7 @@ static int stbi__cpuid3(void)
|
|||
|
||||
#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
|
||||
|
||||
static int stbi__sse2_available()
|
||||
static int stbi__sse2_available(void)
|
||||
{
|
||||
int info3 = stbi__cpuid3();
|
||||
return ((info3 >> 26) & 1) != 0;
|
||||
|
@ -647,7 +648,7 @@ static int stbi__sse2_available()
|
|||
#else // assume GCC-style if not VC++
|
||||
#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
|
||||
|
||||
static int stbi__sse2_available()
|
||||
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
|
||||
|
@ -1029,6 +1030,30 @@ static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int chan
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
stbi__result_info ri;
|
||||
|
@ -1046,21 +1071,8 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x,
|
|||
// @TODO: move stbi__convert_format to here
|
||||
|
||||
if (stbi__vertically_flip_on_load) {
|
||||
int w = *x, h = *y;
|
||||
int channels = req_comp ? req_comp : *comp;
|
||||
int row,col,z;
|
||||
stbi_uc *image = (stbi_uc *) result;
|
||||
|
||||
// @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
|
||||
for (row = 0; row < (h>>1); row++) {
|
||||
for (col = 0; col < w; col++) {
|
||||
for (z = 0; z < channels; z++) {
|
||||
stbi_uc temp = image[(row * w + col) * channels + z];
|
||||
image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
|
||||
image[((h - row - 1) * w + col) * channels + z] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
|
||||
}
|
||||
|
||||
return (unsigned char *) result;
|
||||
|
@ -1084,21 +1096,8 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
|
|||
// @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 w = *x, h = *y;
|
||||
int channels = req_comp ? req_comp : *comp;
|
||||
int row,col,z;
|
||||
stbi__uint16 *image = (stbi__uint16 *) result;
|
||||
|
||||
// @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
|
||||
for (row = 0; row < (h>>1); row++) {
|
||||
for (col = 0; col < w; col++) {
|
||||
for (z = 0; z < channels; z++) {
|
||||
stbi__uint16 temp = image[(row * w + col) * channels + z];
|
||||
image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
|
||||
image[((h - row - 1) * w + col) * channels + z] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
|
||||
}
|
||||
|
||||
return (stbi__uint16 *) result;
|
||||
|
@ -1108,21 +1107,8 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
|
|||
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 w = *x, h = *y;
|
||||
int depth = req_comp ? req_comp : *comp;
|
||||
int row,col,z;
|
||||
float temp;
|
||||
|
||||
// @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
|
||||
for (row = 0; row < (h>>1); row++) {
|
||||
for (col = 0; col < w; col++) {
|
||||
for (z = 0; z < depth; z++) {
|
||||
temp = result[(row * w + col) * depth + z];
|
||||
result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
|
||||
result[((h - row - 1) * w + col) * depth + z] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
int channels = req_comp ? req_comp : *comp;
|
||||
stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1191,6 +1177,20 @@ STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, i
|
|||
|
||||
#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;
|
||||
|
@ -2806,7 +2806,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
|
|||
if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
|
||||
|
||||
for (i=0; i < 64; ++i)
|
||||
z->dequant[t][stbi__jpeg_dezigzag[i]] = sixteen ? stbi__get16be(z->s) : stbi__get8(z->s);
|
||||
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;
|
||||
|
@ -3611,20 +3611,20 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
|
|||
} 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 k = coutput[3][i];
|
||||
out[0] = stbi__blinn_8x8(coutput[0][i], k);
|
||||
out[1] = stbi__blinn_8x8(coutput[1][i], k);
|
||||
out[2] = stbi__blinn_8x8(coutput[2][i], k);
|
||||
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 k = coutput[3][i];
|
||||
out[0] = stbi__blinn_8x8(255 - out[0], k);
|
||||
out[1] = stbi__blinn_8x8(255 - out[1], k);
|
||||
out[2] = stbi__blinn_8x8(255 - out[2], k);
|
||||
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
|
||||
|
@ -3649,10 +3649,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
|
|||
}
|
||||
} else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
|
||||
for (i=0; i < z->s->img_x; ++i) {
|
||||
stbi_uc k = coutput[3][i];
|
||||
stbi_uc r = stbi__blinn_8x8(coutput[0][i], k);
|
||||
stbi_uc g = stbi__blinn_8x8(coutput[1][i], k);
|
||||
stbi_uc b = stbi__blinn_8x8(coutput[2][i], k);
|
||||
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;
|
||||
|
@ -4297,11 +4297,10 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
|||
|
||||
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
||||
img_len = (img_width_bytes + 1) * y;
|
||||
if (s->img_x == x && s->img_y == y) {
|
||||
if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
||||
} else { // interlaced:
|
||||
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
||||
}
|
||||
// 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");
|
||||
|
||||
for (j=0; j < y; ++j) {
|
||||
stbi_uc *cur = a->out + stride*j;
|
||||
|
@ -4654,9 +4653,10 @@ static void stbi__de_iphone(stbi__png *z)
|
|||
stbi_uc a = p[3];
|
||||
stbi_uc t = p[0];
|
||||
if (a) {
|
||||
p[0] = p[2] * 255 / a;
|
||||
p[1] = p[1] * 255 / a;
|
||||
p[2] = t * 255 / 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;
|
||||
|
@ -4819,6 +4819,9 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
|||
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;
|
||||
return 1;
|
||||
|
@ -6966,6 +6969,13 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
|||
|
||||
/*
|
||||
revision history:
|
||||
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;
|
||||
|
|
13
raylib/external/stb_image_resize.h
vendored
13
raylib/external/stb_image_resize.h
vendored
|
@ -1,4 +1,4 @@
|
|||
/* stb_image_resize - v0.94 - public domain image resizing
|
||||
/* stb_image_resize - v0.95 - public domain image resizing
|
||||
by Jorge L Rodriguez (@VinoBS) - 2014
|
||||
http://github.com/nothings/stb
|
||||
|
||||
|
@ -156,8 +156,10 @@
|
|||
Jorge L Rodriguez: Implementation
|
||||
Sean Barrett: API design, optimizations
|
||||
Aras Pranckevicius: bugfix
|
||||
|
||||
Nathan Reed: warning fixes
|
||||
|
||||
REVISIONS
|
||||
0.95 (2017-07-23) fixed warnings
|
||||
0.94 (2017-03-18) fixed warnings
|
||||
0.93 (2017-03-03) fixed bug with certain combinations of heights
|
||||
0.92 (2017-01-02) fix integer overflow on large (>2GB) images
|
||||
|
@ -393,8 +395,9 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
|
|||
|
||||
#ifndef STBIR_MALLOC
|
||||
#include <stdlib.h>
|
||||
#define STBIR_MALLOC(size,c) malloc(size)
|
||||
#define STBIR_FREE(ptr,c) free(ptr)
|
||||
// use comma operator to evaluate c, to avoid "unused parameter" warnings
|
||||
#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
|
||||
#define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
@ -983,7 +986,7 @@ static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
|
|||
|
||||
return (m);
|
||||
}
|
||||
return n; // NOTREACHED
|
||||
// NOTREACHED
|
||||
|
||||
default:
|
||||
STBIR_ASSERT(!"Unimplemented edge type");
|
||||
|
|
378
raylib/external/stb_image_write.h
vendored
378
raylib/external/stb_image_write.h
vendored
|
@ -1,5 +1,5 @@
|
|||
/* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
|
||||
/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Before #including,
|
||||
|
@ -35,6 +35,7 @@ USAGE:
|
|||
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data);
|
||||
|
||||
There are also four equivalent functions that use an arbitrary write function. You are
|
||||
expected to open/close your file-equivalent before and after calling these:
|
||||
|
@ -43,6 +44,7 @@ USAGE:
|
|||
int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||
int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
|
||||
|
||||
where the callback is:
|
||||
void stbi_write_func(void *context, void *data, int size);
|
||||
|
@ -79,6 +81,10 @@ USAGE:
|
|||
|
||||
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
|
||||
data, set the global variable 'stbi_write_tga_with_rle' to 0.
|
||||
|
||||
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
|
||||
Higher quality looks better but results in a bigger image.
|
||||
JPEG baseline (no JPEG progressive).
|
||||
|
||||
CREDITS:
|
||||
|
||||
|
@ -94,6 +100,9 @@ CREDITS:
|
|||
Alan Hickman
|
||||
initial file IO callback implementation
|
||||
Emmanuel Julien
|
||||
JPEG
|
||||
Jon Olick (original jo_jpeg.cpp code)
|
||||
Daniel Gibson
|
||||
bugfixes:
|
||||
github:Chribba
|
||||
Guillaume Chereau
|
||||
|
@ -131,6 +140,7 @@ STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const
|
|||
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
|
||||
#endif
|
||||
|
||||
typedef void stbi_write_func(void *context, void *data, int size);
|
||||
|
@ -139,6 +149,7 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w,
|
|||
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
|
||||
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
|
||||
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -277,6 +288,11 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
|
|||
va_end(v);
|
||||
}
|
||||
|
||||
static void stbiw__putc(stbi__write_context *s, unsigned char c)
|
||||
{
|
||||
s->func(s->context, &c, 1);
|
||||
}
|
||||
|
||||
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
|
||||
{
|
||||
unsigned char arr[3];
|
||||
|
@ -450,7 +466,7 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
|
|||
return 1;
|
||||
}
|
||||
|
||||
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
|
||||
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
stbi__start_write_callbacks(&s, func, context);
|
||||
|
@ -458,7 +474,7 @@ int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, i
|
|||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
|
||||
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
if (stbi__start_write_file(&s,filename)) {
|
||||
|
@ -620,7 +636,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
|
|||
}
|
||||
}
|
||||
|
||||
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
|
||||
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
stbi__start_write_callbacks(&s, func, context);
|
||||
|
@ -628,7 +644,7 @@ int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, i
|
|||
}
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||
{
|
||||
stbi__write_context s;
|
||||
if (stbi__start_write_file(&s,filename)) {
|
||||
|
@ -1013,9 +1029,359 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ***************************************************************************
|
||||
*
|
||||
* JPEG writer
|
||||
*
|
||||
* This is based on Jon Olick's jo_jpeg.cpp:
|
||||
* public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
|
||||
*/
|
||||
|
||||
static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,
|
||||
24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };
|
||||
|
||||
static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
|
||||
int bitBuf = *bitBufP, bitCnt = *bitCntP;
|
||||
bitCnt += bs[1];
|
||||
bitBuf |= bs[0] << (24 - bitCnt);
|
||||
while(bitCnt >= 8) {
|
||||
unsigned char c = (bitBuf >> 16) & 255;
|
||||
stbiw__putc(s, c);
|
||||
if(c == 255) {
|
||||
stbiw__putc(s, 0);
|
||||
}
|
||||
bitBuf <<= 8;
|
||||
bitCnt -= 8;
|
||||
}
|
||||
*bitBufP = bitBuf;
|
||||
*bitCntP = bitCnt;
|
||||
}
|
||||
|
||||
static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
|
||||
float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
|
||||
float z1, z2, z3, z4, z5, z11, z13;
|
||||
|
||||
float tmp0 = d0 + d7;
|
||||
float tmp7 = d0 - d7;
|
||||
float tmp1 = d1 + d6;
|
||||
float tmp6 = d1 - d6;
|
||||
float tmp2 = d2 + d5;
|
||||
float tmp5 = d2 - d5;
|
||||
float tmp3 = d3 + d4;
|
||||
float tmp4 = d3 - d4;
|
||||
|
||||
// Even part
|
||||
float tmp10 = tmp0 + tmp3; // phase 2
|
||||
float tmp13 = tmp0 - tmp3;
|
||||
float tmp11 = tmp1 + tmp2;
|
||||
float tmp12 = tmp1 - tmp2;
|
||||
|
||||
d0 = tmp10 + tmp11; // phase 3
|
||||
d4 = tmp10 - tmp11;
|
||||
|
||||
z1 = (tmp12 + tmp13) * 0.707106781f; // c4
|
||||
d2 = tmp13 + z1; // phase 5
|
||||
d6 = tmp13 - z1;
|
||||
|
||||
// Odd part
|
||||
tmp10 = tmp4 + tmp5; // phase 2
|
||||
tmp11 = tmp5 + tmp6;
|
||||
tmp12 = tmp6 + tmp7;
|
||||
|
||||
// The rotator is modified from fig 4-8 to avoid extra negations.
|
||||
z5 = (tmp10 - tmp12) * 0.382683433f; // c6
|
||||
z2 = tmp10 * 0.541196100f + z5; // c2-c6
|
||||
z4 = tmp12 * 1.306562965f + z5; // c2+c6
|
||||
z3 = tmp11 * 0.707106781f; // c4
|
||||
|
||||
z11 = tmp7 + z3; // phase 5
|
||||
z13 = tmp7 - z3;
|
||||
|
||||
*d5p = z13 + z2; // phase 6
|
||||
*d3p = z13 - z2;
|
||||
*d1p = z11 + z4;
|
||||
*d7p = z11 - z4;
|
||||
|
||||
*d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6;
|
||||
}
|
||||
|
||||
static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
|
||||
int tmp1 = val < 0 ? -val : val;
|
||||
val = val < 0 ? val-1 : val;
|
||||
bits[1] = 1;
|
||||
while(tmp1 >>= 1) {
|
||||
++bits[1];
|
||||
}
|
||||
bits[0] = val & ((1<<bits[1])-1);
|
||||
}
|
||||
|
||||
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
|
||||
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
|
||||
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
|
||||
int dataOff, i, diff, end0pos;
|
||||
int DU[64];
|
||||
|
||||
// DCT rows
|
||||
for(dataOff=0; dataOff<64; dataOff+=8) {
|
||||
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
|
||||
}
|
||||
// DCT columns
|
||||
for(dataOff=0; dataOff<8; ++dataOff) {
|
||||
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);
|
||||
}
|
||||
// Quantize/descale/zigzag the coefficients
|
||||
for(i=0; i<64; ++i) {
|
||||
float v = CDU[i]*fdtbl[i];
|
||||
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
|
||||
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
|
||||
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
|
||||
}
|
||||
|
||||
// Encode DC
|
||||
diff = DU[0] - DC;
|
||||
if (diff == 0) {
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
|
||||
} else {
|
||||
unsigned short bits[2];
|
||||
stbiw__jpg_calcBits(diff, bits);
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
|
||||
}
|
||||
// Encode ACs
|
||||
end0pos = 63;
|
||||
for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {
|
||||
}
|
||||
// end0pos = first element in reverse order !=0
|
||||
if(end0pos == 0) {
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
|
||||
return DU[0];
|
||||
}
|
||||
for(i = 1; i <= end0pos; ++i) {
|
||||
int startpos = i;
|
||||
int nrzeroes;
|
||||
unsigned short bits[2];
|
||||
for (; DU[i]==0 && i<=end0pos; ++i) {
|
||||
}
|
||||
nrzeroes = i-startpos;
|
||||
if ( nrzeroes >= 16 ) {
|
||||
int lng = nrzeroes>>4;
|
||||
int nrmarker;
|
||||
for (nrmarker=1; nrmarker <= lng; ++nrmarker)
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
|
||||
nrzeroes &= 15;
|
||||
}
|
||||
stbiw__jpg_calcBits(DU[i], bits);
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
|
||||
}
|
||||
if(end0pos != 63) {
|
||||
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
|
||||
}
|
||||
return DU[0];
|
||||
}
|
||||
|
||||
static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {
|
||||
// Constants that don't pollute global namespace
|
||||
static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
|
||||
static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
|
||||
static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};
|
||||
static const unsigned char std_ac_luminance_values[] = {
|
||||
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
|
||||
0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
|
||||
0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
|
||||
0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
|
||||
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
|
||||
0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
|
||||
0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
|
||||
};
|
||||
static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};
|
||||
static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
|
||||
static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};
|
||||
static const unsigned char std_ac_chrominance_values[] = {
|
||||
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
|
||||
0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
|
||||
0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
|
||||
0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
|
||||
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
|
||||
0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
|
||||
0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
|
||||
};
|
||||
// Huffman tables
|
||||
static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};
|
||||
static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};
|
||||
static const unsigned short YAC_HT[256][2] = {
|
||||
{10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
|
||||
};
|
||||
static const unsigned short UVAC_HT[256][2] = {
|
||||
{0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},
|
||||
{1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
|
||||
};
|
||||
static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,
|
||||
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
|
||||
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
|
||||
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
|
||||
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
|
||||
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
|
||||
|
||||
int row, col, i, k;
|
||||
float fdtbl_Y[64], fdtbl_UV[64];
|
||||
unsigned char YTable[64], UVTable[64];
|
||||
|
||||
if(!data || !width || !height || comp > 4 || comp < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
quality = quality ? quality : 90;
|
||||
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
|
||||
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
|
||||
|
||||
for(i = 0; i < 64; ++i) {
|
||||
int uvti, yti = (YQT[i]*quality+50)/100;
|
||||
YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);
|
||||
uvti = (UVQT[i]*quality+50)/100;
|
||||
UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
|
||||
}
|
||||
|
||||
for(row = 0, k = 0; row < 8; ++row) {
|
||||
for(col = 0; col < 8; ++col, ++k) {
|
||||
fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
|
||||
fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
|
||||
}
|
||||
}
|
||||
|
||||
// Write Headers
|
||||
{
|
||||
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
|
||||
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
|
||||
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
|
||||
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
|
||||
s->func(s->context, (void*)head0, sizeof(head0));
|
||||
s->func(s->context, (void*)YTable, sizeof(YTable));
|
||||
stbiw__putc(s, 1);
|
||||
s->func(s->context, UVTable, sizeof(UVTable));
|
||||
s->func(s->context, (void*)head1, sizeof(head1));
|
||||
s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);
|
||||
s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));
|
||||
stbiw__putc(s, 0x10); // HTYACinfo
|
||||
s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);
|
||||
s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));
|
||||
stbiw__putc(s, 1); // HTUDCinfo
|
||||
s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);
|
||||
s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
|
||||
stbiw__putc(s, 0x11); // HTUACinfo
|
||||
s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);
|
||||
s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
|
||||
s->func(s->context, (void*)head2, sizeof(head2));
|
||||
}
|
||||
|
||||
// Encode 8x8 macroblocks
|
||||
{
|
||||
static const unsigned short fillBits[] = {0x7F, 7};
|
||||
const unsigned char *imageData = (const unsigned char *)data;
|
||||
int DCY=0, DCU=0, DCV=0;
|
||||
int bitBuf=0, bitCnt=0;
|
||||
// comp == 2 is grey+alpha (alpha is ignored)
|
||||
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
|
||||
int x, y, pos;
|
||||
for(y = 0; y < height; y += 8) {
|
||||
for(x = 0; x < width; x += 8) {
|
||||
float YDU[64], UDU[64], VDU[64];
|
||||
for(row = y, pos = 0; row < y+8; ++row) {
|
||||
for(col = x; col < x+8; ++col, ++pos) {
|
||||
int p = row*width*comp + col*comp;
|
||||
float r, g, b;
|
||||
if(row >= height) {
|
||||
p -= width*comp*(row+1 - height);
|
||||
}
|
||||
if(col >= width) {
|
||||
p -= comp*(col+1 - width);
|
||||
}
|
||||
|
||||
r = imageData[p+0];
|
||||
g = imageData[p+ofsG];
|
||||
b = imageData[p+ofsB];
|
||||
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;
|
||||
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;
|
||||
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;
|
||||
}
|
||||
}
|
||||
|
||||
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
|
||||
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
|
||||
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
|
||||
}
|
||||
}
|
||||
|
||||
// Do the bit alignment of the EOI marker
|
||||
stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
|
||||
}
|
||||
|
||||
// EOI
|
||||
stbiw__putc(s, 0xFF);
|
||||
stbiw__putc(s, 0xD9);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
|
||||
{
|
||||
stbi__write_context s;
|
||||
stbi__start_write_callbacks(&s, func, context);
|
||||
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
|
||||
}
|
||||
|
||||
|
||||
#ifndef STBI_WRITE_NO_STDIO
|
||||
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
|
||||
{
|
||||
stbi__write_context s;
|
||||
if (stbi__start_write_file(&s,filename)) {
|
||||
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
|
||||
stbi__end_write_file(&s);
|
||||
return r;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
/* Revision history
|
||||
1.07 (2017-07-24)
|
||||
doc fix
|
||||
1.06 (2017-07-23)
|
||||
writing JPEG (using Jon Olick's code)
|
||||
1.05 ???
|
||||
1.04 (2017-03-03)
|
||||
monochrome BMP expansion
|
||||
1.03 ???
|
||||
|
|
316
raylib/external/stb_perlin.h
vendored
Normal file
316
raylib/external/stb_perlin.h
vendored
Normal file
|
@ -0,0 +1,316 @@
|
|||
// stb_perlin.h - v0.3 - perlin noise
|
||||
// public domain single-file C implementation by Sean Barrett
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file.
|
||||
//
|
||||
//
|
||||
// to create the implementation,
|
||||
// #define STB_PERLIN_IMPLEMENTATION
|
||||
// in *one* C/CPP file that includes this file.
|
||||
//
|
||||
//
|
||||
// Documentation:
|
||||
//
|
||||
// float stb_perlin_noise3( float x,
|
||||
// float y,
|
||||
// float z,
|
||||
// int x_wrap=0,
|
||||
// int y_wrap=0,
|
||||
// int z_wrap=0)
|
||||
//
|
||||
// This function computes a random value at the coordinate (x,y,z).
|
||||
// Adjacent random values are continuous but the noise fluctuates
|
||||
// its randomness with period 1, i.e. takes on wholly unrelated values
|
||||
// at integer points. Specifically, this implements Ken Perlin's
|
||||
// revised noise function from 2002.
|
||||
//
|
||||
// The "wrap" parameters can be used to create wraparound noise that
|
||||
// wraps at powers of two. The numbers MUST be powers of two. Specify
|
||||
// 0 to mean "don't care". (The noise always wraps every 256 due
|
||||
// details of the implementation, even if you ask for larger or no
|
||||
// wrapping.)
|
||||
//
|
||||
// Fractal Noise:
|
||||
//
|
||||
// Three common fractal noise functions are included, which produce
|
||||
// a wide variety of nice effects depending on the parameters
|
||||
// provided. Note that each function will call stb_perlin_noise3
|
||||
// 'octaves' times, so this parameter will affect runtime.
|
||||
//
|
||||
// float stb_perlin_ridge_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, float offset, int octaves,
|
||||
// int x_wrap, int y_wrap, int z_wrap);
|
||||
//
|
||||
// float stb_perlin_fbm_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain, int octaves,
|
||||
// int x_wrap, int y_wrap, int z_wrap);
|
||||
//
|
||||
// float stb_perlin_turbulence_noise3(float x, float y, float z,
|
||||
// float lacunarity, float gain,int octaves,
|
||||
// int x_wrap, int y_wrap, int z_wrap);
|
||||
//
|
||||
// Typical values to start playing with:
|
||||
// octaves = 6 -- number of "octaves" of noise3() to sum
|
||||
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
|
||||
// gain = 0.5 -- relative weighting applied to each successive octave
|
||||
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
|
||||
//
|
||||
//
|
||||
// Contributors:
|
||||
// Jack Mott - additional noise functions
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
|
||||
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
// not same permutation table as Perlin's reference to avoid copyright issues;
|
||||
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
|
||||
// @OPTIMIZE: should this be unsigned char instead of int for cache?
|
||||
static unsigned char stb__perlin_randtab[512] =
|
||||
{
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
|
||||
// and a second copy so we don't need an extra mask or static initializer
|
||||
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
|
||||
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
|
||||
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
|
||||
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
|
||||
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
|
||||
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
|
||||
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
|
||||
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
|
||||
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
|
||||
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
|
||||
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
|
||||
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
|
||||
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
|
||||
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
|
||||
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
|
||||
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
|
||||
};
|
||||
|
||||
static float stb__perlin_lerp(float a, float b, float t)
|
||||
{
|
||||
return a + (b-a) * t;
|
||||
}
|
||||
|
||||
static int stb__perlin_fastfloor(float a)
|
||||
{
|
||||
int ai = (int) a;
|
||||
return (a < ai) ? ai-1 : ai;
|
||||
}
|
||||
|
||||
// different grad function from Perlin's, but easy to modify to match reference
|
||||
static float stb__perlin_grad(int hash, float x, float y, float z)
|
||||
{
|
||||
static float basis[12][4] =
|
||||
{
|
||||
{ 1, 1, 0 },
|
||||
{ -1, 1, 0 },
|
||||
{ 1,-1, 0 },
|
||||
{ -1,-1, 0 },
|
||||
{ 1, 0, 1 },
|
||||
{ -1, 0, 1 },
|
||||
{ 1, 0,-1 },
|
||||
{ -1, 0,-1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0,-1, 1 },
|
||||
{ 0, 1,-1 },
|
||||
{ 0,-1,-1 },
|
||||
};
|
||||
|
||||
// perlin's gradient has 12 cases so some get used 1/16th of the time
|
||||
// and some 2/16ths. We reduce bias by changing those fractions
|
||||
// to 5/64ths and 6/64ths, and the same 4 cases get the extra weight.
|
||||
static unsigned char indices[64] =
|
||||
{
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,9,1,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,
|
||||
};
|
||||
|
||||
// if you use reference permutation table, change 63 below to 15 to match reference
|
||||
// (this is why the ordering of the table above is funky)
|
||||
float *grad = basis[indices[hash & 63]];
|
||||
return grad[0]*x + grad[1]*y + grad[2]*z;
|
||||
}
|
||||
|
||||
float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
float u,v,w;
|
||||
float n000,n001,n010,n011,n100,n101,n110,n111;
|
||||
float n00,n01,n10,n11;
|
||||
float n0,n1;
|
||||
|
||||
unsigned int x_mask = (x_wrap-1) & 255;
|
||||
unsigned int y_mask = (y_wrap-1) & 255;
|
||||
unsigned int z_mask = (z_wrap-1) & 255;
|
||||
int px = stb__perlin_fastfloor(x);
|
||||
int py = stb__perlin_fastfloor(y);
|
||||
int pz = stb__perlin_fastfloor(z);
|
||||
int x0 = px & x_mask, x1 = (px+1) & x_mask;
|
||||
int y0 = py & y_mask, y1 = (py+1) & y_mask;
|
||||
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
|
||||
int r0,r1, r00,r01,r10,r11;
|
||||
|
||||
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
|
||||
|
||||
x -= px; u = stb__perlin_ease(x);
|
||||
y -= py; v = stb__perlin_ease(y);
|
||||
z -= pz; w = stb__perlin_ease(z);
|
||||
|
||||
r0 = stb__perlin_randtab[x0];
|
||||
r1 = stb__perlin_randtab[x1];
|
||||
|
||||
r00 = stb__perlin_randtab[r0+y0];
|
||||
r01 = stb__perlin_randtab[r0+y1];
|
||||
r10 = stb__perlin_randtab[r1+y0];
|
||||
r11 = stb__perlin_randtab[r1+y1];
|
||||
|
||||
n000 = stb__perlin_grad(stb__perlin_randtab[r00+z0], x , y , z );
|
||||
n001 = stb__perlin_grad(stb__perlin_randtab[r00+z1], x , y , z-1 );
|
||||
n010 = stb__perlin_grad(stb__perlin_randtab[r01+z0], x , y-1, z );
|
||||
n011 = stb__perlin_grad(stb__perlin_randtab[r01+z1], x , y-1, z-1 );
|
||||
n100 = stb__perlin_grad(stb__perlin_randtab[r10+z0], x-1, y , z );
|
||||
n101 = stb__perlin_grad(stb__perlin_randtab[r10+z1], x-1, y , z-1 );
|
||||
n110 = stb__perlin_grad(stb__perlin_randtab[r11+z0], x-1, y-1, z );
|
||||
n111 = stb__perlin_grad(stb__perlin_randtab[r11+z1], x-1, y-1, z-1 );
|
||||
|
||||
n00 = stb__perlin_lerp(n000,n001,w);
|
||||
n01 = stb__perlin_lerp(n010,n011,w);
|
||||
n10 = stb__perlin_lerp(n100,n101,w);
|
||||
n11 = stb__perlin_lerp(n110,n111,w);
|
||||
|
||||
n0 = stb__perlin_lerp(n00,n01,v);
|
||||
n1 = stb__perlin_lerp(n10,n11,v);
|
||||
|
||||
return stb__perlin_lerp(n0,n1,u);
|
||||
}
|
||||
|
||||
float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float prev = 1.0f;
|
||||
float amplitude = 0.5f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = (float)(stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap));
|
||||
r = r<0 ? -r : r; // fabs()
|
||||
r = offset - r;
|
||||
r = r*r;
|
||||
sum += r*amplitude*prev;
|
||||
prev = r;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
sum += stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
|
||||
{
|
||||
int i;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (i = 0; i < octaves; i++) {
|
||||
float r = stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
|
||||
r = r<0 ? -r : r; // fabs()
|
||||
sum += r;
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
#endif // STB_PERLIN_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
11
raylib/external/stb_rect_pack.h
vendored
11
raylib/external/stb_rect_pack.h
vendored
|
@ -524,17 +524,6 @@ static int rect_height_compare(const void *a, const void *b)
|
|||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int rect_width_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->w > q->w)
|
||||
return -1;
|
||||
if (p->w < q->w)
|
||||
return 1;
|
||||
return (p->h > q->h) ? -1 : (p->h < q->h);
|
||||
}
|
||||
|
||||
static int rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
|
|
529
raylib/external/stb_truetype.h
vendored
529
raylib/external/stb_truetype.h
vendored
|
@ -1,4 +1,4 @@
|
|||
// stb_truetype.h - v1.15 - public domain
|
||||
// stb_truetype.h - v1.17 - public domain
|
||||
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
|
||||
//
|
||||
// This library processes TrueType files:
|
||||
|
@ -6,6 +6,7 @@
|
|||
// extract glyph metrics
|
||||
// extract glyph shapes
|
||||
// render glyphs to one-channel bitmaps with antialiasing (box filter)
|
||||
// render glyphs to one-channel SDF bitmaps (signed-distance field/function)
|
||||
//
|
||||
// Todo:
|
||||
// non-MS cmaps
|
||||
|
@ -26,9 +27,10 @@
|
|||
// Ryan Gordon
|
||||
// Simon Glass
|
||||
// github:IntellectualKitty
|
||||
// Imanol Celaya
|
||||
//
|
||||
// Bug/warning reports/fixes:
|
||||
// "Zer" on mollyrocket (with fix)
|
||||
// "Zer" on mollyrocket
|
||||
// Cass Everitt
|
||||
// stoiko (Haemimont Games)
|
||||
// Brian Hook
|
||||
|
@ -51,9 +53,12 @@
|
|||
// Thomas Fields
|
||||
// Derek Vinyard
|
||||
// Cort Stratton
|
||||
// github:oyvindjam
|
||||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 1.17 (2017-07-23) make more arguments const; doc fix
|
||||
// 1.16 (2017-07-12) SDF support
|
||||
// 1.15 (2017-03-03) make more arguments const
|
||||
// 1.14 (2017-01-16) num-fonts-in-TTC function
|
||||
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
|
||||
|
@ -92,7 +97,7 @@
|
|||
// Improved 3D API (more shippable):
|
||||
// #include "stb_rect_pack.h" -- optional, but you really want it
|
||||
// stbtt_PackBegin()
|
||||
// stbtt_PackSetOversample() -- for improved quality on small fonts
|
||||
// stbtt_PackSetOversampling() -- for improved quality on small fonts
|
||||
// stbtt_PackFontRanges() -- pack and renders
|
||||
// stbtt_PackEnd()
|
||||
// stbtt_GetPackedQuad()
|
||||
|
@ -110,6 +115,7 @@
|
|||
// Character advance/positioning
|
||||
// stbtt_GetCodepointHMetrics()
|
||||
// stbtt_GetFontVMetrics()
|
||||
// stbtt_GetFontVMetricsOS2()
|
||||
// stbtt_GetCodepointKernAdvance()
|
||||
//
|
||||
// Starting with version 1.06, the rasterizer was replaced with a new,
|
||||
|
@ -407,6 +413,18 @@ int main(int arg, char **argv)
|
|||
#ifndef STBTT_sqrt
|
||||
#include <math.h>
|
||||
#define STBTT_sqrt(x) sqrt(x)
|
||||
#define STBTT_pow(x,y) pow(x,y)
|
||||
#endif
|
||||
|
||||
#ifndef STBTT_cos
|
||||
#include <math.h>
|
||||
#define STBTT_cos(x) cos(x)
|
||||
#define STBTT_acos(x) acos(x)
|
||||
#endif
|
||||
|
||||
#ifndef STBTT_fabs
|
||||
#include <math.h>
|
||||
#define STBTT_fabs(x) fabs(x)
|
||||
#endif
|
||||
|
||||
#ifndef STBTT_fabs
|
||||
|
@ -432,7 +450,7 @@ int main(int arg, char **argv)
|
|||
#endif
|
||||
|
||||
#ifndef STBTT_memcpy
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#define STBTT_memcpy memcpy
|
||||
#define STBTT_memset memset
|
||||
#endif
|
||||
|
@ -548,7 +566,7 @@ STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
|
|||
|
||||
#define STBTT_POINT_SIZE(x) (-(x))
|
||||
|
||||
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
|
||||
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
|
||||
int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
|
||||
// Creates character bitmaps from the font_index'th font found in fontdata (use
|
||||
// font_index=0 if you don't know what that is). It creates num_chars_in_range
|
||||
|
@ -573,7 +591,7 @@ typedef struct
|
|||
unsigned char h_oversample, v_oversample; // don't set these, they're used internally
|
||||
} stbtt_pack_range;
|
||||
|
||||
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
|
||||
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
|
||||
// Creates character bitmaps from multiple ranges of characters stored in
|
||||
// ranges. This will usually create a better-packed bitmap than multiple
|
||||
// calls to stbtt_PackFontRange. Note that you can call this multiple
|
||||
|
@ -715,6 +733,12 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in
|
|||
// these are expressed in unscaled coordinates, so you must multiply by
|
||||
// the scale factor for a given size
|
||||
|
||||
STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
|
||||
// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
|
||||
// table (specific to MS/Windows TTF files).
|
||||
//
|
||||
// Returns 1 on success (table present), 0 on failure.
|
||||
|
||||
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
|
||||
// the bounding box around all possible characters
|
||||
|
||||
|
@ -809,6 +833,10 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns
|
|||
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
|
||||
// shift for the character
|
||||
|
||||
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
|
||||
// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
|
||||
// is performed (see stbtt_PackSetOversampling)
|
||||
|
||||
STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
// get the bbox of the bitmap centered around the glyph origin; so the
|
||||
// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
|
||||
|
@ -826,6 +854,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float
|
|||
STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
|
||||
STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
|
||||
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
|
||||
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
|
||||
STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
|
||||
|
||||
|
@ -848,6 +877,64 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap
|
|||
int invert, // if non-zero, vertically flip shape
|
||||
void *userdata); // context for to STBTT_MALLOC
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Signed Distance Function (or Field) rendering
|
||||
|
||||
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
|
||||
// frees the SDF bitmap allocated below
|
||||
|
||||
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
|
||||
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
|
||||
// These functions compute a discretized SDF field for a single character, suitable for storing
|
||||
// in a single-channel texture, sampling with bilinear filtering, and testing against
|
||||
// larger than some threshhold to produce scalable fonts.
|
||||
// info -- the font
|
||||
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
|
||||
// glyph/codepoint -- the character to generate the SDF for
|
||||
// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0),
|
||||
// which allows effects like bit outlines
|
||||
// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
|
||||
// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
|
||||
// if positive, > onedge_value is inside; if negative, < onedge_value is inside
|
||||
// width,height -- output height & width of the SDF bitmap (including padding)
|
||||
// xoff,yoff -- output origin of the character
|
||||
// return value -- a 2D array of bytes 0..255, width*height in size
|
||||
//
|
||||
// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
|
||||
// optimal use of the limited 0..255 for your application, trading off precision
|
||||
// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
|
||||
//
|
||||
// Example:
|
||||
// scale = stbtt_ScaleForPixelHeight(22)
|
||||
// padding = 5
|
||||
// onedge_value = 180
|
||||
// pixel_dist_scale = 180/5.0 = 36.0
|
||||
//
|
||||
// This will create an SDF bitmap in which the character is about 22 pixels
|
||||
// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
|
||||
// shape, sample the SDF at each pixel and fill the pixel if the SDF value
|
||||
// is greater than or equal to 180/255. (You'll actually want to antialias,
|
||||
// which is beyond the scope of this example.) Additionally, you can compute
|
||||
// offset outlines (e.g. to stroke the character border inside & outside,
|
||||
// or only outside). For example, to fill outside the character up to 3 SDF
|
||||
// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
|
||||
// choice of variables maps a range from 5 pixels outside the shape to
|
||||
// 2 pixels inside the shape to 0..255; this is intended primarily for apply
|
||||
// outside effects only (the interior range is needed to allow proper
|
||||
// antialiasing of the font at *smaller* sizes)
|
||||
//
|
||||
// The function computes the SDF analytically at each SDF pixel, not by e.g.
|
||||
// building a higher-res bitmap and approximating it. In theory the quality
|
||||
// should be as high as possible for an SDF of this size & representation, but
|
||||
// unclear if this is true in practice (perhaps building a higher-res bitmap
|
||||
// and computing from that can allow drop-out prevention).
|
||||
//
|
||||
// The algorithm has not been optimized at all, so expect it to be slow
|
||||
// if computing lots of characters or very large sizes.
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Finding the right font...
|
||||
|
@ -2201,6 +2288,17 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in
|
|||
if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
|
||||
}
|
||||
|
||||
STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)
|
||||
{
|
||||
int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");
|
||||
if (!tab)
|
||||
return 0;
|
||||
if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68);
|
||||
if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
|
||||
if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
|
||||
return 1;
|
||||
}
|
||||
|
||||
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
|
||||
{
|
||||
*x0 = ttSHORT(info->data + info->head + 36);
|
||||
|
@ -2693,19 +2791,18 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
|||
// from the other y segment, and it might ignored as an empty segment. to avoid
|
||||
// that, we need to explicitly produce segments based on x positions.
|
||||
|
||||
// rename variables to clear pairs
|
||||
// rename variables to clearly-defined pairs
|
||||
float y0 = y_top;
|
||||
float x1 = (float) (x);
|
||||
float x2 = (float) (x+1);
|
||||
float x3 = xb;
|
||||
float y3 = y_bottom;
|
||||
float y1,y2;
|
||||
|
||||
// x = e->x + e->dx * (y-y_top)
|
||||
// (y-y_top) = (x - e->x) / e->dx
|
||||
// y = (x - e->x) / e->dx + y_top
|
||||
y1 = (x - x0) / dx + y_top;
|
||||
y2 = (x+1 - x0) / dx + y_top;
|
||||
float y1 = (x - x0) / dx + y_top;
|
||||
float y2 = (x+1 - x0) / dx + y_top;
|
||||
|
||||
if (x0 < x1 && x3 > x2) { // three segments descending down-right
|
||||
stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
|
||||
|
@ -3600,6 +3697,29 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
|||
return k;
|
||||
}
|
||||
|
||||
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
|
||||
{
|
||||
stbtt_MakeGlyphBitmapSubpixel(info,
|
||||
output,
|
||||
out_w - (prefilter_x - 1),
|
||||
out_h - (prefilter_y - 1),
|
||||
out_stride,
|
||||
scale_x,
|
||||
scale_y,
|
||||
shift_x,
|
||||
shift_y,
|
||||
glyph);
|
||||
|
||||
if (prefilter_x > 1)
|
||||
stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
|
||||
|
||||
if (prefilter_y > 1)
|
||||
stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
|
||||
|
||||
*sub_x = stbtt__oversample_shift(prefilter_x);
|
||||
*sub_y = stbtt__oversample_shift(prefilter_y);
|
||||
}
|
||||
|
||||
// rects array must be big enough to accommodate all characters in the given ranges
|
||||
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||
{
|
||||
|
@ -3688,7 +3808,7 @@ STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect
|
|||
stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
|
||||
}
|
||||
|
||||
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
|
||||
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
|
||||
{
|
||||
stbtt_fontinfo info;
|
||||
int i,j,n, return_value = 1;
|
||||
|
@ -3724,7 +3844,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd
|
|||
return return_value;
|
||||
}
|
||||
|
||||
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
|
||||
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
|
||||
int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
|
||||
{
|
||||
stbtt_pack_range range;
|
||||
|
@ -3763,6 +3883,387 @@ STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int
|
|||
*xpos += b->xadvance;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// sdf computation
|
||||
//
|
||||
|
||||
#define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
|
||||
{
|
||||
float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
|
||||
float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
|
||||
float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
|
||||
float roperp = orig[1]*ray[0] - orig[0]*ray[1];
|
||||
|
||||
float a = q0perp - 2*q1perp + q2perp;
|
||||
float b = q1perp - q0perp;
|
||||
float c = q0perp - roperp;
|
||||
|
||||
float s0 = 0., s1 = 0.;
|
||||
int num_s = 0;
|
||||
|
||||
if (a != 0.0) {
|
||||
float discr = b*b - a*c;
|
||||
if (discr > 0.0) {
|
||||
float rcpna = -1 / a;
|
||||
float d = (float) sqrt(discr);
|
||||
s0 = (b+d) * rcpna;
|
||||
s1 = (b-d) * rcpna;
|
||||
if (s0 >= 0.0 && s0 <= 1.0)
|
||||
num_s = 1;
|
||||
if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
|
||||
if (num_s == 0) s0 = s1;
|
||||
++num_s;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 2*b*s + c = 0
|
||||
// s = -c / (2*b)
|
||||
s0 = c / (-2 * b);
|
||||
if (s0 >= 0.0 && s0 <= 1.0)
|
||||
num_s = 1;
|
||||
}
|
||||
|
||||
if (num_s == 0)
|
||||
return 0;
|
||||
else {
|
||||
float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
|
||||
float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
|
||||
|
||||
float q0d = q0[0]*rayn_x + q0[1]*rayn_y;
|
||||
float q1d = q1[0]*rayn_x + q1[1]*rayn_y;
|
||||
float q2d = q2[0]*rayn_x + q2[1]*rayn_y;
|
||||
float rod = orig[0]*rayn_x + orig[1]*rayn_y;
|
||||
|
||||
float q10d = q1d - q0d;
|
||||
float q20d = q2d - q0d;
|
||||
float q0rd = q0d - rod;
|
||||
|
||||
hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
|
||||
hits[0][1] = a*s0+b;
|
||||
|
||||
if (num_s > 1) {
|
||||
hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
|
||||
hits[1][1] = a*s1+b;
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int equal(float *a, float *b)
|
||||
{
|
||||
return (a[0] == b[0] && a[1] == b[1]);
|
||||
}
|
||||
|
||||
static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
|
||||
{
|
||||
int i;
|
||||
float orig[2], ray[2] = { 1, 0 };
|
||||
float y_frac;
|
||||
int winding = 0;
|
||||
|
||||
orig[0] = x;
|
||||
orig[1] = y;
|
||||
|
||||
// make sure y never passes through a vertex of the shape
|
||||
y_frac = (float) fmod(y, 1.0f);
|
||||
if (y_frac < 0.01f)
|
||||
y += 0.01f;
|
||||
else if (y_frac > 0.99f)
|
||||
y -= 0.01f;
|
||||
orig[1] = y;
|
||||
|
||||
// test a ray from (-infinity,y) to (x,y)
|
||||
for (i=0; i < nverts; ++i) {
|
||||
if (verts[i].type == STBTT_vline) {
|
||||
int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
|
||||
int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y;
|
||||
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
|
||||
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
|
||||
if (x_inter < x)
|
||||
winding += (y0 < y1) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
if (verts[i].type == STBTT_vcurve) {
|
||||
int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
|
||||
int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy;
|
||||
int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ;
|
||||
int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
|
||||
int by = STBTT_max(y0,STBTT_max(y1,y2));
|
||||
if (y > ay && y < by && x > ax) {
|
||||
float q0[2],q1[2],q2[2];
|
||||
float hits[2][2];
|
||||
q0[0] = (float)x0;
|
||||
q0[1] = (float)y0;
|
||||
q1[0] = (float)x1;
|
||||
q1[1] = (float)y1;
|
||||
q2[0] = (float)x2;
|
||||
q2[1] = (float)y2;
|
||||
if (equal(q0,q1) || equal(q1,q2)) {
|
||||
x0 = (int)verts[i-1].x;
|
||||
y0 = (int)verts[i-1].y;
|
||||
x1 = (int)verts[i ].x;
|
||||
y1 = (int)verts[i ].y;
|
||||
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
|
||||
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
|
||||
if (x_inter < x)
|
||||
winding += (y0 < y1) ? 1 : -1;
|
||||
}
|
||||
} else {
|
||||
int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
|
||||
if (num_hits >= 1)
|
||||
if (hits[0][0] < 0)
|
||||
winding += (hits[0][1] < 0 ? -1 : 1);
|
||||
if (num_hits >= 2)
|
||||
if (hits[1][0] < 0)
|
||||
winding += (hits[1][1] < 0 ? -1 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return winding;
|
||||
}
|
||||
|
||||
static float stbtt__cuberoot( float x )
|
||||
{
|
||||
if (x<0)
|
||||
return -(float) STBTT_pow(-x,1.0f/3.0f);
|
||||
else
|
||||
return (float) STBTT_pow( x,1.0f/3.0f);
|
||||
}
|
||||
|
||||
// x^3 + c*x^2 + b*x + a = 0
|
||||
static int stbtt__solve_cubic(float a, float b, float c, float* r)
|
||||
{
|
||||
float s = -a / 3;
|
||||
float p = b - a*a / 3;
|
||||
float q = a * (2*a*a - 9*b) / 27 + c;
|
||||
float p3 = p*p*p;
|
||||
float d = q*q + 4*p3 / 27;
|
||||
if (d >= 0) {
|
||||
float z = (float) STBTT_sqrt(d);
|
||||
float u = (-q + z) / 2;
|
||||
float v = (-q - z) / 2;
|
||||
u = stbtt__cuberoot(u);
|
||||
v = stbtt__cuberoot(v);
|
||||
r[0] = s + u + v;
|
||||
return 1;
|
||||
} else {
|
||||
float u = (float) STBTT_sqrt(-p/3);
|
||||
float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
|
||||
float m = (float) STBTT_cos(v);
|
||||
float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
|
||||
r[0] = s + u * 2 * m;
|
||||
r[1] = s - u * (m + n);
|
||||
r[2] = s - u * (m - n);
|
||||
|
||||
//STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
|
||||
//STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
|
||||
//STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
|
||||
{
|
||||
float scale_x = scale, scale_y = scale;
|
||||
int ix0,iy0,ix1,iy1;
|
||||
int w,h;
|
||||
unsigned char *data;
|
||||
|
||||
// if one scale is 0, use same scale for both
|
||||
if (scale_x == 0) scale_x = scale_y;
|
||||
if (scale_y == 0) {
|
||||
if (scale_x == 0) return NULL; // if both scales are 0, return NULL
|
||||
scale_y = scale_x;
|
||||
}
|
||||
|
||||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
||||
|
||||
// if empty, return NULL
|
||||
if (ix0 == ix1 || iy0 == iy1)
|
||||
return NULL;
|
||||
|
||||
ix0 -= padding;
|
||||
iy0 -= padding;
|
||||
ix1 += padding;
|
||||
iy1 += padding;
|
||||
|
||||
w = (ix1 - ix0);
|
||||
h = (iy1 - iy0);
|
||||
|
||||
if (width ) *width = w;
|
||||
if (height) *height = h;
|
||||
if (xoff ) *xoff = ix0;
|
||||
if (yoff ) *yoff = iy0;
|
||||
|
||||
// invert for y-downwards bitmaps
|
||||
scale_y = -scale_y;
|
||||
|
||||
{
|
||||
int x,y,i,j;
|
||||
float *precompute;
|
||||
stbtt_vertex *verts;
|
||||
int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
|
||||
data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
|
||||
precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
|
||||
|
||||
for (i=0,j=num_verts-1; i < num_verts; j=i++) {
|
||||
if (verts[i].type == STBTT_vline) {
|
||||
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
|
||||
float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
|
||||
float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
|
||||
precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
|
||||
} else if (verts[i].type == STBTT_vcurve) {
|
||||
float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
|
||||
float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
|
||||
float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
|
||||
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
||||
float len2 = bx*bx + by*by;
|
||||
if (len2 != 0.0f)
|
||||
precompute[i] = 1.0f / (bx*bx + by*by);
|
||||
else
|
||||
precompute[i] = 0.0f;
|
||||
} else
|
||||
precompute[i] = 0.0f;
|
||||
}
|
||||
|
||||
for (y=iy0; y < iy1; ++y) {
|
||||
for (x=ix0; x < ix1; ++x) {
|
||||
float val;
|
||||
float min_dist = 999999.0f;
|
||||
float sx = (float) x + 0.5f;
|
||||
float sy = (float) y + 0.5f;
|
||||
float x_gspace = (sx / scale_x);
|
||||
float y_gspace = (sy / scale_y);
|
||||
|
||||
int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
|
||||
|
||||
for (i=0; i < num_verts; ++i) {
|
||||
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
|
||||
|
||||
// check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
|
||||
float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||
if (dist2 < min_dist*min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
|
||||
if (verts[i].type == STBTT_vline) {
|
||||
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
|
||||
|
||||
// coarse culling against bbox
|
||||
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
|
||||
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
|
||||
float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
|
||||
STBTT_assert(i != 0);
|
||||
if (dist < min_dist) {
|
||||
// check position along line
|
||||
// x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
|
||||
// minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
|
||||
float dx = x1-x0, dy = y1-y0;
|
||||
float px = x0-sx, py = y0-sy;
|
||||
// minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy
|
||||
// derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
|
||||
float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
|
||||
if (t >= 0.0f && t <= 1.0f)
|
||||
min_dist = dist;
|
||||
}
|
||||
} else if (verts[i].type == STBTT_vcurve) {
|
||||
float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
|
||||
float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y;
|
||||
float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
|
||||
float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
|
||||
float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
|
||||
float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
|
||||
// coarse culling against bbox to avoid computing cubic unnecessarily
|
||||
if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
|
||||
int num=0;
|
||||
float ax = x1-x0, ay = y1-y0;
|
||||
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
||||
float mx = x0 - sx, my = y0 - sy;
|
||||
float res[3],px,py,t,it;
|
||||
float a_inv = precompute[i];
|
||||
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
|
||||
float a = 3*(ax*bx + ay*by);
|
||||
float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
|
||||
float c = mx*ax+my*ay;
|
||||
if (a == 0.0) { // if a is 0, it's linear
|
||||
if (b != 0.0) {
|
||||
res[num++] = -c/b;
|
||||
}
|
||||
} else {
|
||||
float discriminant = b*b - 4*a*c;
|
||||
if (discriminant < 0)
|
||||
num = 0;
|
||||
else {
|
||||
float root = (float) STBTT_sqrt(discriminant);
|
||||
res[0] = (-b - root)/(2*a);
|
||||
res[1] = (-b + root)/(2*a);
|
||||
num = 2; // don't bother distinguishing 1-solution case, as code below will still work
|
||||
}
|
||||
}
|
||||
} else {
|
||||
float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
|
||||
float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
|
||||
float d = (mx*ax+my*ay) * a_inv;
|
||||
num = stbtt__solve_cubic(b, c, d, res);
|
||||
}
|
||||
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
|
||||
t = res[0], it = 1.0f - t;
|
||||
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
||||
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
|
||||
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
|
||||
if (dist2 < min_dist * min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
}
|
||||
if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
|
||||
t = res[1], it = 1.0f - t;
|
||||
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
||||
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
|
||||
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
|
||||
if (dist2 < min_dist * min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
}
|
||||
if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
|
||||
t = res[2], it = 1.0f - t;
|
||||
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
||||
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
|
||||
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
|
||||
if (dist2 < min_dist * min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (winding == 0)
|
||||
min_dist = -min_dist; // if outside the shape, value is negative
|
||||
val = onedge_value + pixel_dist_scale * min_dist;
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
else if (val > 255)
|
||||
val = 255;
|
||||
data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
|
||||
}
|
||||
}
|
||||
STBTT_free(precompute, info->userdata);
|
||||
STBTT_free(verts, info->userdata);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
|
||||
{
|
||||
return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
|
||||
}
|
||||
|
||||
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
|
||||
{
|
||||
STBTT_free(bitmap, userdata);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -3970,6 +4471,10 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
|
|||
|
||||
// FULL VERSION HISTORY
|
||||
//
|
||||
// 1.16 (2017-07-12) SDF support
|
||||
// 1.15 (2017-03-03) make more arguments const
|
||||
// 1.14 (2017-01-16) num-fonts-in-TTC function
|
||||
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
|
||||
// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
|
||||
// 1.11 (2016-04-02) fix unused-variable warning
|
||||
// 1.10 (2016-04-02) allow user-defined fabs() replacement
|
||||
|
|
1
raylib/external/stb_vorbis.c
vendored
1
raylib/external/stb_vorbis.c
vendored
|
@ -193,6 +193,7 @@
|
|||
#undef __forceinline
|
||||
#endif
|
||||
#define __forceinline
|
||||
#define alloca __builtin_alloca
|
||||
#elif !defined(_MSC_VER)
|
||||
#if __GNUC__
|
||||
#define __forceinline inline
|
||||
|
|
5
raylib/external/stb_vorbis.h
vendored
5
raylib/external/stb_vorbis.h
vendored
|
@ -1,4 +1,4 @@
|
|||
// Ogg Vorbis audio decoder - v1.10 - public domain
|
||||
// Ogg Vorbis audio decoder - v1.11 - public domain
|
||||
// http://nothings.org/stb_vorbis/
|
||||
//
|
||||
// Original version written by Sean Barrett in 2007.
|
||||
|
@ -29,9 +29,10 @@
|
|||
// Bernhard Wodo Evan Balster alxprd@github
|
||||
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
|
||||
// Phillip Bennefall Rohit Thiago Goulart
|
||||
// manxorist@github saga musix
|
||||
// manxorist@github saga musix github:infatum
|
||||
//
|
||||
// Partial history:
|
||||
// 1.11 - 2017/07/23 - fix MinGW compilation
|
||||
// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory
|
||||
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version
|
||||
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue