Updated stb headers
This commit is contained in:
parent
4e4b6bef21
commit
e25f1227c0
@ -39,7 +39,8 @@
|
||||
#include "utils.h" // rRES data decompression utility function
|
||||
// NOTE: Includes Android fopen function map
|
||||
|
||||
#include "stb_vorbis.h" // OGG loading functions
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include "stb_vorbis.c" // OGG loading functions
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
|
@ -93,7 +93,7 @@ else
|
||||
endif
|
||||
|
||||
# define all object files required
|
||||
OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o stb_vorbis.o camera.o gestures.o
|
||||
OBJS = core.o rlgl.o raymath.o shapes.o text.o textures.o models.o audio.o utils.o camera.o gestures.o
|
||||
|
||||
# typing 'make' will invoke the first target entry in the file,
|
||||
# in this case, the 'default' target entry is raylib
|
||||
@ -144,10 +144,6 @@ audio.o: audio.c
|
||||
utils.o: utils.c
|
||||
$(CC) -c utils.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
||||
|
||||
# compile stb_vorbis library
|
||||
stb_vorbis.o: stb_vorbis.c
|
||||
$(CC) -c stb_vorbis.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
||||
|
||||
# compile camera module
|
||||
camera.o: camera.c
|
||||
$(CC) -c camera.c $(CFLAGS) $(INCLUDES) -D$(PLATFORM)
|
||||
|
206
src/stb_image.h
206
src/stb_image.h
@ -1,4 +1,4 @@
|
||||
/* stb_image - v2.00b - public domain image loader - http://nothings.org/stb_image.h
|
||||
/* stb_image - v2.05 - public domain image loader - http://nothings.org/stb_image.h
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
@ -143,6 +143,13 @@
|
||||
|
||||
|
||||
Latest revision history:
|
||||
2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
|
||||
2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
|
||||
2.03 (2015-04-12) additional corruption checking
|
||||
stbi_set_flip_vertically_on_load
|
||||
fix NEON support; fix mingw support
|
||||
2.02 (2015-01-19) fix incorrect assert, fix warning
|
||||
2.01 (2015-01-17) fix various warnings
|
||||
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
|
||||
2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD
|
||||
progressive JPEG
|
||||
@ -154,8 +161,6 @@
|
||||
1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted)
|
||||
optimize PNG
|
||||
fix bug in interlaced PNG with user-specified channel count
|
||||
1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG
|
||||
1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc
|
||||
|
||||
See end of file for full revision history.
|
||||
|
||||
@ -178,7 +183,7 @@
|
||||
James "moose2000" Brown (iPhone PNG) Roy Eltham
|
||||
Ben "Disch" Wenger (io callbacks) Luke Graham
|
||||
Omar Cornut (1/2/4-bit PNG) Thomas Ruf
|
||||
John Bartholomew
|
||||
Nicolas Guillemot (vertical flip) John Bartholomew
|
||||
Ken Hamada
|
||||
Optimizations & bugfixes Cort Stratton
|
||||
Fabian "ryg" Giesen Blazej Dariusz Roszkowski
|
||||
@ -191,6 +196,12 @@
|
||||
Ronny Chevalier
|
||||
Michal Cichon
|
||||
Tero Hanninen
|
||||
Sergio Gonzalez
|
||||
Cass Everitt
|
||||
Engin Manap
|
||||
Martins Mozeiko
|
||||
Joseph Thomson
|
||||
Phil Jordan
|
||||
|
||||
License:
|
||||
This software is in the public domain. Where that dedication is not
|
||||
@ -371,6 +382,7 @@ License:
|
||||
// and only if iPhone convert-to-rgb processing is on).
|
||||
//
|
||||
|
||||
|
||||
#define STBI_NO_HDR // RaySan: not required by raylib
|
||||
#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2
|
||||
|
||||
@ -489,6 +501,8 @@ STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultipl
|
||||
// or just pass them through "as-is"
|
||||
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
|
||||
|
||||
// flip the image vertically, so the first pixel in the output array is the bottom left
|
||||
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
|
||||
|
||||
// ZLIB client - used by PNG, available for other purposes
|
||||
|
||||
@ -626,7 +640,38 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
|
||||
#define STBI_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
#if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86))
|
||||
// x86/x64 detection
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
#define STBI__X64_TARGET
|
||||
#elif defined(__i386) || defined(_M_IX86)
|
||||
#define STBI__X86_TARGET
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
|
||||
// NOTE: not clear do we actually need this for the 64-bit path?
|
||||
// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
|
||||
// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
|
||||
// this is just broken and gcc are jerks for not fixing it properly
|
||||
// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
|
||||
#define STBI_NO_SIMD
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
|
||||
// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
|
||||
//
|
||||
// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
|
||||
// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
|
||||
// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
|
||||
// simultaneously enabling "-mstackrealign".
|
||||
//
|
||||
// See https://github.com/nothings/stb/issues/81 for more information.
|
||||
//
|
||||
// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
|
||||
// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
|
||||
#define STBI_NO_SIMD
|
||||
#endif
|
||||
|
||||
#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET)
|
||||
#define STBI_SSE2
|
||||
#include <emmintrin.h>
|
||||
|
||||
@ -879,7 +924,14 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
|
||||
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
|
||||
#endif
|
||||
|
||||
static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
static int stbi__vertically_flip_on_load = 0;
|
||||
|
||||
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
|
||||
{
|
||||
stbi__vertically_flip_on_load = flag_true_if_should_flip;
|
||||
}
|
||||
|
||||
static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
#ifndef STBI_NO_JPEG
|
||||
if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);
|
||||
@ -919,6 +971,53 @@ static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp
|
||||
return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
|
||||
}
|
||||
|
||||
static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
unsigned char *result = stbi__load_main(s, x, y, comp, 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;
|
||||
stbi_uc 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
|
||||
static FILE *stbi__fopen(char const *filename, char const *mode)
|
||||
@ -949,7 +1048,7 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req
|
||||
unsigned char *result;
|
||||
stbi__context s;
|
||||
stbi__start_file(&s,f);
|
||||
result = stbi_load_main(&s,x,y,comp,req_comp);
|
||||
result = stbi__load_flip(&s,x,y,comp,req_comp);
|
||||
if (result) {
|
||||
// need to 'unget' all the characters in the IO buffer
|
||||
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
|
||||
@ -962,25 +1061,29 @@ STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, i
|
||||
{
|
||||
stbi__context s;
|
||||
stbi__start_mem(&s,buffer,len);
|
||||
return stbi_load_main(&s,x,y,comp,req_comp);
|
||||
return stbi__load_flip(&s,x,y,comp,req_comp);
|
||||
}
|
||||
|
||||
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
stbi__context s;
|
||||
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
|
||||
return stbi_load_main(&s,x,y,comp,req_comp);
|
||||
return stbi__load_flip(&s,x,y,comp,req_comp);
|
||||
}
|
||||
|
||||
#ifndef STBI_NO_LINEAR
|
||||
static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
unsigned char *data;
|
||||
#ifndef STBI_NO_HDR
|
||||
if (stbi__hdr_test(s))
|
||||
return stbi__hdr_load(s,x,y,comp,req_comp);
|
||||
if (stbi__hdr_test(s)) {
|
||||
float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp);
|
||||
if (hdr_data)
|
||||
stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
|
||||
return hdr_data;
|
||||
}
|
||||
#endif
|
||||
data = stbi_load_main(s, x, y, comp, req_comp);
|
||||
data = stbi__load_flip(s, x, y, comp, req_comp);
|
||||
if (data)
|
||||
return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
|
||||
return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
|
||||
@ -990,14 +1093,14 @@ STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, in
|
||||
{
|
||||
stbi__context s;
|
||||
stbi__start_mem(&s,buffer,len);
|
||||
return stbi_loadf_main(&s,x,y,comp,req_comp);
|
||||
return stbi__loadf_main(&s,x,y,comp,req_comp);
|
||||
}
|
||||
|
||||
STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
stbi__context s;
|
||||
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
|
||||
return stbi_loadf_main(&s,x,y,comp,req_comp);
|
||||
return stbi__loadf_main(&s,x,y,comp,req_comp);
|
||||
}
|
||||
|
||||
#ifndef STBI_NO_STDIO
|
||||
@ -1015,7 +1118,7 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_
|
||||
{
|
||||
stbi__context s;
|
||||
stbi__start_file(&s,f);
|
||||
return stbi_loadf_main(&s,x,y,comp,req_comp);
|
||||
return stbi__loadf_main(&s,x,y,comp,req_comp);
|
||||
}
|
||||
#endif // !STBI_NO_STDIO
|
||||
|
||||
@ -1138,6 +1241,10 @@ stbi_inline static int stbi__at_eof(stbi__context *s)
|
||||
|
||||
static void stbi__skip(stbi__context *s, int n)
|
||||
{
|
||||
if (n < 0) {
|
||||
s->img_buffer = s->img_buffer_end;
|
||||
return;
|
||||
}
|
||||
if (s->io.read) {
|
||||
int blen = (int) (s->img_buffer_end - s->img_buffer);
|
||||
if (blen < n) {
|
||||
@ -1546,6 +1653,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
|
||||
|
||||
sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
|
||||
k = stbi_lrot(j->code_buffer, n);
|
||||
STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
|
||||
j->code_buffer = k & ~stbi__bmask[n];
|
||||
k &= stbi__bmask[n];
|
||||
j->code_bits -= n;
|
||||
@ -1730,15 +1838,12 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
||||
short *p = &data[stbi__jpeg_dezigzag[k]];
|
||||
if (*p != 0)
|
||||
if (stbi__jpeg_get_bit(j))
|
||||
{
|
||||
if ((*p & bit)==0)
|
||||
{
|
||||
if ((*p & bit)==0) {
|
||||
if (*p > 0)
|
||||
*p += bit;
|
||||
else
|
||||
*p -= bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
k = j->spec_start;
|
||||
@ -1754,8 +1859,11 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
||||
if (r)
|
||||
j->eob_run += stbi__jpeg_get_bits(j, r);
|
||||
r = 64; // force end of block
|
||||
} else
|
||||
r = 16; // r=15 is the code for 16 0s
|
||||
} else {
|
||||
// r=15 s=0 should write 16 0s, so we just do
|
||||
// a run of 15 0s and then write s (which is 0),
|
||||
// so we don't have to do anything special here
|
||||
}
|
||||
} else {
|
||||
if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
|
||||
// sign bit
|
||||
@ -1767,27 +1875,21 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
||||
|
||||
// advance by r
|
||||
while (k <= j->spec_end) {
|
||||
short *p = &data[stbi__jpeg_dezigzag[k]];
|
||||
short *p = &data[stbi__jpeg_dezigzag[k++]];
|
||||
if (*p != 0) {
|
||||
if (stbi__jpeg_get_bit(j))
|
||||
{
|
||||
if ((*p & bit)==0)
|
||||
{
|
||||
if ((*p & bit)==0) {
|
||||
if (*p > 0)
|
||||
*p += bit;
|
||||
else
|
||||
*p -= bit;
|
||||
}
|
||||
}
|
||||
++k;
|
||||
} else {
|
||||
if (r == 0) {
|
||||
if (s)
|
||||
data[stbi__jpeg_dezigzag[k++]] = s;
|
||||
*p = (short) s;
|
||||
break;
|
||||
}
|
||||
--r;
|
||||
++k;
|
||||
}
|
||||
}
|
||||
} while (k <= j->spec_end);
|
||||
@ -2207,7 +2309,7 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
|
||||
// pass 1
|
||||
dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
|
||||
dct_trn16(row2, row3);
|
||||
dct_trn16(row4, row5);
|
||||
dct_trn16(row4, row5);
|
||||
dct_trn16(row6, row7);
|
||||
|
||||
// pass 2
|
||||
@ -2434,7 +2536,6 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
|
||||
for (x=0; x < z->img_comp[n].h; ++x) {
|
||||
int x2 = (i*z->img_comp[n].h + x);
|
||||
int y2 = (j*z->img_comp[n].v + y);
|
||||
//int ha = z->img_comp[n].ha; // RaySan: Unused, commented to avoid warning
|
||||
short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
|
||||
if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
|
||||
return 0;
|
||||
@ -2701,6 +2802,10 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
|
||||
static int stbi__decode_jpeg_image(stbi__jpeg *j)
|
||||
{
|
||||
int m;
|
||||
for (m = 0; m < 4; m++) {
|
||||
j->img_comp[m].raw_data = NULL;
|
||||
j->img_comp[m].raw_coeff = NULL;
|
||||
}
|
||||
j->restart_interval = 0;
|
||||
if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
|
||||
m = stbi__get_marker(j);
|
||||
@ -3013,7 +3118,7 @@ static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc cons
|
||||
__m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
|
||||
__m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
|
||||
__m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f));
|
||||
__m128i y_bias = _mm_set1_epi8((char) 128);
|
||||
__m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
|
||||
__m128i xw = _mm_set1_epi16(255); // alpha channel
|
||||
|
||||
for (; i+7 < count; i += 8) {
|
||||
@ -3380,7 +3485,8 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
|
||||
++sizes[sizelist[i]];
|
||||
sizes[0] = 0;
|
||||
for (i=1; i < 16; ++i)
|
||||
STBI_ASSERT(sizes[i] <= (1 << i));
|
||||
if (sizes[i] > (1 << i))
|
||||
return stbi__err("bad sizes", "Corrupt PNG");
|
||||
code = 0;
|
||||
for (i=1; i < 16; ++i) {
|
||||
next_code[i] = code;
|
||||
@ -3388,7 +3494,7 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
|
||||
z->firstsymbol[i] = (stbi__uint16) k;
|
||||
code = (code + sizes[i]);
|
||||
if (sizes[i])
|
||||
if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt JPEG");
|
||||
if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
|
||||
z->maxcode[i] = code << (16-i); // preshift for inner loop
|
||||
code <<= 1;
|
||||
k += sizes[i];
|
||||
@ -3557,9 +3663,9 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
||||
p = (stbi_uc *) (zout - dist);
|
||||
if (dist == 1) { // run of one byte; common in images.
|
||||
stbi_uc v = *p;
|
||||
do *zout++ = v; while (--len);
|
||||
if (len) { do *zout++ = v; while (--len); }
|
||||
} else {
|
||||
do *zout++ = *p++; while (--len);
|
||||
if (len) { do *zout++ = *p++; while (--len); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3587,7 +3693,7 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a)
|
||||
n = 0;
|
||||
while (n < hlit + hdist) {
|
||||
int c = stbi__zhuffman_decode(a, &z_codelength);
|
||||
STBI_ASSERT(c >= 0 && c < 19);
|
||||
if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
|
||||
if (c < 16)
|
||||
lencodes[n++] = (stbi_uc) c;
|
||||
else if (c == 16) {
|
||||
@ -4019,7 +4125,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
||||
cur[i*2+0] = cur[i];
|
||||
}
|
||||
} else {
|
||||
assert(img_n == 3);
|
||||
STBI_ASSERT(img_n == 3);
|
||||
for (i=x-1; i >= 0; --i) {
|
||||
cur[i*4+3] = 255;
|
||||
cur[i*4+2] = cur[i*3+2];
|
||||
@ -4284,6 +4390,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
||||
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
||||
if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
|
||||
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
|
||||
if ((int)(ioff + c.length) < (int)ioff) return 0;
|
||||
if (ioff + c.length > idata_limit) {
|
||||
stbi_uc *p;
|
||||
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
|
||||
@ -4643,7 +4750,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
|
||||
}
|
||||
} else {
|
||||
for (i=0; i < (int) s->img_x; ++i) {
|
||||
stbi__uint32 v = (stbi__uint32) (bpp == 16 ? stbi__get16le(s) : stbi__get32le(s));
|
||||
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
|
||||
int a;
|
||||
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
|
||||
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
|
||||
@ -4800,7 +4907,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
|
||||
*y = tga_height;
|
||||
if (comp) *comp = tga_comp;
|
||||
|
||||
tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp );
|
||||
tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp );
|
||||
if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
|
||||
|
||||
// skip to the data's starting position (offset usually = 0)
|
||||
@ -5461,6 +5568,7 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
|
||||
stbi__gif_lzw *p;
|
||||
|
||||
lzw_cs = stbi__get8(s);
|
||||
if (lzw_cs > 12) return NULL;
|
||||
clear = 1 << lzw_cs;
|
||||
first = 1;
|
||||
codesize = lzw_cs + 1;
|
||||
@ -6130,7 +6238,7 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
|
||||
#ifndef STBI_NO_PSD
|
||||
if (stbi__psd_info(s, x, y, comp)) return 1;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef STBI_NO_PIC
|
||||
if (stbi__pic_info(s, x, y, comp)) return 1;
|
||||
#endif
|
||||
@ -6192,6 +6300,13 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
||||
|
||||
/*
|
||||
revision history:
|
||||
2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
|
||||
2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
|
||||
2.03 (2015-04-12) extra corruption checking (mmozeiko)
|
||||
stbi_set_flip_vertically_on_load (nguillemot)
|
||||
fix NEON support; fix mingw support
|
||||
2.02 (2015-01-19) fix incorrect assert, fix warning
|
||||
2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
|
||||
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
|
||||
2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
|
||||
progressive JPEG (stb)
|
||||
@ -6276,7 +6391,7 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
||||
1.21 fix use of 'stbi_uc' in header (reported by jon blow)
|
||||
1.20 added support for Softimage PIC, by Tom Seddon
|
||||
1.19 bug in interlaced PNG corruption check (found by ryg)
|
||||
1.18 2008-08-02
|
||||
1.18 (2008-08-02)
|
||||
fix a threading bug (local mutable static)
|
||||
1.17 support interlaced PNG
|
||||
1.16 major bugfix - stbi__convert_format converted one too many pixels
|
||||
@ -6321,5 +6436,6 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
||||
0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
|
||||
0.51 obey req_comp requests, 1-component jpegs return as 1-component,
|
||||
on 'test' only check type, not whether we support this variant
|
||||
0.50 first released version
|
||||
0.50 (2006-11-19)
|
||||
first released version
|
||||
*/
|
||||
|
@ -1,16 +1,15 @@
|
||||
/* stb_image_write - v0.95 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
/* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h
|
||||
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
|
||||
Before including,
|
||||
Before #including,
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
in the file that you want to have the implementation.
|
||||
|
||||
Will probably not work correctly with strict-aliasing optimizations.
|
||||
in the file that you want to have the implementation.
|
||||
|
||||
Will probably not work correctly with strict-aliasing optimizations.
|
||||
|
||||
ABOUT:
|
||||
|
||||
@ -22,16 +21,24 @@ ABOUT:
|
||||
for source code compactness and simplicitly, not optimal image file size
|
||||
or run-time performance.
|
||||
|
||||
BUILDING:
|
||||
|
||||
You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
|
||||
You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
|
||||
malloc,realloc,free.
|
||||
You can define STBIW_MEMMOVE() to replace memmove()
|
||||
|
||||
USAGE:
|
||||
|
||||
There are three functions, one for each image file format:
|
||||
There are four functions, one for each image file format:
|
||||
|
||||
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
|
||||
|
||||
Each function returns 0 on failure and non-0 on success.
|
||||
|
||||
|
||||
The functions create an image file defined by the parameters. The image
|
||||
is a rectangle of pixels stored from left-to-right, top-to-bottom.
|
||||
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
|
||||
@ -44,13 +51,30 @@ USAGE:
|
||||
PNG creates output files with the same number of components as the input.
|
||||
The BMP format expands Y to RGB in the file format and does not
|
||||
output alpha.
|
||||
|
||||
|
||||
PNG supports writing rectangles of data even when the bytes storing rows of
|
||||
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
|
||||
by supplying the stride between the beginning of adjacent rows. The other
|
||||
formats do not. (Thus you cannot write a native-format BMP through the BMP
|
||||
writer, both because it is in BGR order and because it may have padding
|
||||
at the end of the line.)
|
||||
|
||||
HDR expects linear float data. Since the format is always 32-bit rgb(e)
|
||||
data, alpha (if provided) is discarded, and for monochrome data it is
|
||||
replicated across all three channels.
|
||||
|
||||
CREDITS:
|
||||
|
||||
PNG/BMP/TGA
|
||||
Sean Barrett
|
||||
HDR
|
||||
Baldur Karlsson
|
||||
TGA monochrome:
|
||||
Jean-Sebastien Guay
|
||||
misc enhancements:
|
||||
Tim Kelsey
|
||||
bugfixes:
|
||||
github:Chribba
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_STB_IMAGE_WRITE_H
|
||||
@ -60,9 +84,10 @@ USAGE:
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
|
||||
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
|
||||
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
|
||||
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@ -76,7 +101,30 @@ extern int stbi_write_tga(char const *filename, int w, int h, int comp, const vo
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC)
|
||||
// ok
|
||||
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC)
|
||||
// ok
|
||||
#else
|
||||
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC."
|
||||
#endif
|
||||
|
||||
#ifndef STBIW_MALLOC
|
||||
#define STBIW_MALLOC(sz) malloc(sz)
|
||||
#define STBIW_REALLOC(p,sz) realloc(p,sz)
|
||||
#define STBIW_FREE(p) free(p)
|
||||
#endif
|
||||
#ifndef STBIW_MEMMOVE
|
||||
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef STBIW_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBIW_ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
typedef unsigned int stbiw_uint32;
|
||||
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
|
||||
@ -95,7 +143,7 @@ static void writefv(FILE *f, const char *fmt, va_list v)
|
||||
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
|
||||
fwrite(b,4,1,f); break; }
|
||||
default:
|
||||
assert(0);
|
||||
STBIW_ASSERT(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -108,7 +156,7 @@ static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
|
||||
fwrite(arr, 3, 1, f);
|
||||
}
|
||||
|
||||
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
|
||||
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
|
||||
{
|
||||
unsigned char bg[3] = { 255, 0, 255}, px[3];
|
||||
stbiw_uint32 zero = 0;
|
||||
@ -117,7 +165,7 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
|
||||
if (y <= 0)
|
||||
return;
|
||||
|
||||
if (vdir < 0)
|
||||
if (vdir < 0)
|
||||
j_end = -1, j = y-1;
|
||||
else
|
||||
j_end = y, j = 0;
|
||||
@ -128,8 +176,12 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
|
||||
if (write_alpha < 0)
|
||||
fwrite(&d[comp-1], 1, 1, f);
|
||||
switch (comp) {
|
||||
case 1:
|
||||
case 2: fwrite(d, 1, 1, f);
|
||||
case 1: fwrite(d, 1, 1, f);
|
||||
break;
|
||||
case 2: if (expand_mono)
|
||||
write3(f, d[0],d[0],d[0]); // monochrome bmp
|
||||
else
|
||||
fwrite(d, 1, 1, f); // monochrome TGA
|
||||
break;
|
||||
case 4:
|
||||
if (!write_alpha) {
|
||||
@ -151,7 +203,7 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
|
||||
}
|
||||
}
|
||||
|
||||
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
|
||||
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
|
||||
{
|
||||
FILE *f;
|
||||
if (y < 0 || x < 0) return 0;
|
||||
@ -161,7 +213,7 @@ static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, in
|
||||
va_start(v, fmt);
|
||||
writefv(f, fmt, v);
|
||||
va_end(v);
|
||||
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
|
||||
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
|
||||
fclose(f);
|
||||
}
|
||||
return f != NULL;
|
||||
@ -170,7 +222,7 @@ static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, in
|
||||
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
|
||||
{
|
||||
int pad = (-x*3) & 3;
|
||||
return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
|
||||
return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
|
||||
"11 4 22 4" "4 44 22 444444",
|
||||
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
|
||||
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
|
||||
@ -181,10 +233,159 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat
|
||||
int has_alpha = (comp == 2 || comp == 4);
|
||||
int colorbytes = has_alpha ? comp-1 : comp;
|
||||
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
|
||||
return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
|
||||
return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
|
||||
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
|
||||
}
|
||||
|
||||
// *************************************************************************************************
|
||||
// Radiance RGBE HDR writer
|
||||
// by Baldur Karlsson
|
||||
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
|
||||
{
|
||||
int exponent;
|
||||
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
|
||||
|
||||
if (maxcomp < 1e-32) {
|
||||
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
|
||||
} else {
|
||||
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
|
||||
|
||||
rgbe[0] = (unsigned char)(linear[0] * normalize);
|
||||
rgbe[1] = (unsigned char)(linear[1] * normalize);
|
||||
rgbe[2] = (unsigned char)(linear[2] * normalize);
|
||||
rgbe[3] = (unsigned char)(exponent + 128);
|
||||
}
|
||||
}
|
||||
|
||||
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
|
||||
{
|
||||
unsigned char lengthbyte = (unsigned char) (length+128);
|
||||
STBIW_ASSERT(length+128 <= 255);
|
||||
fwrite(&lengthbyte, 1, 1, f);
|
||||
fwrite(&databyte, 1, 1, f);
|
||||
}
|
||||
|
||||
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
|
||||
{
|
||||
unsigned char lengthbyte = (unsigned char )(length & 0xff);
|
||||
STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
|
||||
fwrite(&lengthbyte, 1, 1, f);
|
||||
fwrite(data, length, 1, f);
|
||||
}
|
||||
|
||||
void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
|
||||
{
|
||||
unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
|
||||
unsigned char rgbe[4];
|
||||
float linear[3];
|
||||
int x;
|
||||
|
||||
scanlineheader[2] = (width&0xff00)>>8;
|
||||
scanlineheader[3] = (width&0x00ff);
|
||||
|
||||
/* skip RLE for images too small or large */
|
||||
if (width < 8 || width >= 32768) {
|
||||
for (x=0; x < width; x++) {
|
||||
switch (comp) {
|
||||
case 4: /* fallthrough */
|
||||
case 3: linear[2] = scanline[x*comp + 2];
|
||||
linear[1] = scanline[x*comp + 1];
|
||||
linear[0] = scanline[x*comp + 0];
|
||||
break;
|
||||
case 2: /* fallthrough */
|
||||
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
|
||||
break;
|
||||
}
|
||||
stbiw__linear_to_rgbe(rgbe, linear);
|
||||
fwrite(rgbe, 4, 1, f);
|
||||
}
|
||||
} else {
|
||||
int c,r;
|
||||
/* encode into scratch buffer */
|
||||
for (x=0; x < width; x++) {
|
||||
switch(comp) {
|
||||
case 4: /* fallthrough */
|
||||
case 3: linear[2] = scanline[x*comp + 2];
|
||||
linear[1] = scanline[x*comp + 1];
|
||||
linear[0] = scanline[x*comp + 0];
|
||||
break;
|
||||
case 2: /* fallthrough */
|
||||
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
|
||||
break;
|
||||
}
|
||||
stbiw__linear_to_rgbe(rgbe, linear);
|
||||
scratch[x + width*0] = rgbe[0];
|
||||
scratch[x + width*1] = rgbe[1];
|
||||
scratch[x + width*2] = rgbe[2];
|
||||
scratch[x + width*3] = rgbe[3];
|
||||
}
|
||||
|
||||
fwrite(scanlineheader, 4, 1, f);
|
||||
|
||||
/* RLE each component separately */
|
||||
for (c=0; c < 4; c++) {
|
||||
unsigned char *comp = &scratch[width*c];
|
||||
|
||||
x = 0;
|
||||
while (x < width) {
|
||||
// find first run
|
||||
r = x;
|
||||
while (r+2 < width) {
|
||||
if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
|
||||
break;
|
||||
++r;
|
||||
}
|
||||
if (r+2 >= width)
|
||||
r = width;
|
||||
// dump up to first run
|
||||
while (x < r) {
|
||||
int len = r-x;
|
||||
if (len > 128) len = 128;
|
||||
stbiw__write_dump_data(f, len, &comp[x]);
|
||||
x += len;
|
||||
}
|
||||
// if there's a run, output it
|
||||
if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
|
||||
// find next byte after run
|
||||
while (r < width && comp[r] == comp[x])
|
||||
++r;
|
||||
// output run up to r
|
||||
while (x < r) {
|
||||
int len = r-x;
|
||||
if (len > 127) len = 127;
|
||||
stbiw__write_run_data(f, len, comp[x]);
|
||||
x += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
|
||||
{
|
||||
int i;
|
||||
FILE *f;
|
||||
if (y <= 0 || x <= 0 || data == NULL) return 0;
|
||||
f = fopen(filename, "wb");
|
||||
if (f) {
|
||||
/* Each component is stored separately. Allocate scratch space for full output scanline. */
|
||||
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
|
||||
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
|
||||
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
|
||||
for(i=0; i < y; i++)
|
||||
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
|
||||
STBIW_FREE(scratch);
|
||||
fclose(f);
|
||||
}
|
||||
return f != NULL;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// PNG
|
||||
|
||||
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
|
||||
#define stbiw__sbraw(a) ((int *) (a) - 2)
|
||||
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
|
||||
@ -196,13 +397,13 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat
|
||||
|
||||
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
|
||||
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
|
||||
#define stbiw__sbfree(a) ((a) ? free(stbiw__sbraw(a)),0 : 0)
|
||||
#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
|
||||
|
||||
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
|
||||
{
|
||||
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
|
||||
void *p = realloc(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
||||
assert(p);
|
||||
void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
|
||||
STBIW_ASSERT(p);
|
||||
if (p) {
|
||||
if (!*arr) ((int *) p)[1] = 0;
|
||||
*arr = (void *) ((int *) p + 2);
|
||||
@ -287,7 +488,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
||||
|
||||
i=0;
|
||||
while (i < data_len-3) {
|
||||
// hash next 3 bytes of data to be compressed
|
||||
// hash next 3 bytes of data to be compressed
|
||||
int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
|
||||
unsigned char *bestloc = 0;
|
||||
unsigned char **hlist = hash_table[h];
|
||||
@ -300,7 +501,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
||||
}
|
||||
// when hash table entry is too long, delete half the entries
|
||||
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
|
||||
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
||||
STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
||||
stbiw__sbn(hash_table[h]) = quality;
|
||||
}
|
||||
stbiw__sbpush(hash_table[h],data+i);
|
||||
@ -323,7 +524,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
||||
|
||||
if (bestloc) {
|
||||
int d = (int) (data+i - bestloc); // distance back
|
||||
assert(d <= 32767 && best <= 258);
|
||||
STBIW_ASSERT(d <= 32767 && best <= 258);
|
||||
for (j=0; best > lengthc[j+1]-1; ++j);
|
||||
stbiw__zlib_huff(j+257);
|
||||
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
|
||||
@ -364,7 +565,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
|
||||
}
|
||||
*out_len = stbiw__sbn(out);
|
||||
// make returned pointer freeable
|
||||
memmove(stbiw__sbraw(out), out, *out_len);
|
||||
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
|
||||
return (unsigned char *) stbiw__sbraw(out);
|
||||
}
|
||||
|
||||
@ -411,8 +612,8 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
||||
if (stride_bytes == 0)
|
||||
stride_bytes = x * n;
|
||||
|
||||
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
|
||||
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
|
||||
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
|
||||
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
|
||||
for (j=0; j < y; ++j) {
|
||||
static int mapping[] = { 0,1,2,3,4 };
|
||||
static int firstmap[] = { 0,1,0,5,6 };
|
||||
@ -451,20 +652,20 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
||||
}
|
||||
// when we get here, best contains the filter type, and line_buffer contains the data
|
||||
filt[j*(x*n+1)] = (unsigned char) best;
|
||||
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
|
||||
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
|
||||
}
|
||||
free(line_buffer);
|
||||
STBIW_FREE(line_buffer);
|
||||
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
|
||||
free(filt);
|
||||
STBIW_FREE(filt);
|
||||
if (!zlib) return 0;
|
||||
|
||||
// each tag requires 12 bytes of overhead
|
||||
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
|
||||
out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
|
||||
if (!out) return 0;
|
||||
*out_len = 8 + 12+13 + 12+zlen + 12;
|
||||
|
||||
o=out;
|
||||
memcpy(o,sig,8); o+= 8;
|
||||
STBIW_MEMMOVE(o,sig,8); o+= 8;
|
||||
stbiw__wp32(o, 13); // header length
|
||||
stbiw__wptag(o, "IHDR");
|
||||
stbiw__wp32(o, x);
|
||||
@ -478,14 +679,16 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in
|
||||
|
||||
stbiw__wp32(o, zlen);
|
||||
stbiw__wptag(o, "IDAT");
|
||||
memcpy(o, zlib, zlen); o += zlen; free(zlib);
|
||||
STBIW_MEMMOVE(o, zlib, zlen);
|
||||
o += zlen;
|
||||
STBIW_FREE(zlib);
|
||||
stbiw__wpcrc(&o, zlen);
|
||||
|
||||
stbiw__wp32(o,0);
|
||||
stbiw__wptag(o, "IEND");
|
||||
stbiw__wpcrc(&o,0);
|
||||
|
||||
assert(o == out + *out_len);
|
||||
STBIW_ASSERT(o == out + *out_len);
|
||||
|
||||
return out;
|
||||
}
|
||||
@ -497,16 +700,22 @@ int stbi_write_png(char const *filename, int x, int y, int comp, const void *dat
|
||||
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
|
||||
if (!png) return 0;
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) { free(png); return 0; }
|
||||
if (!f) { STBIW_FREE(png); return 0; }
|
||||
fwrite(png, 1, len, f);
|
||||
fclose(f);
|
||||
free(png);
|
||||
STBIW_FREE(png);
|
||||
return 1;
|
||||
}
|
||||
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
/* Revision history
|
||||
|
||||
0.98 (2015-04-08)
|
||||
added STBIW_MALLOC, STBIW_ASSERT etc
|
||||
0.97 (2015-01-18)
|
||||
fixed HDR asserts, rewrote HDR rle logic
|
||||
0.96 (2015-01-17)
|
||||
add HDR output
|
||||
fix monochrome BMP
|
||||
0.95 (2014-08-17)
|
||||
add monochrome TGA output
|
||||
0.94 (2014-05-31)
|
||||
|
391
src/stb_vorbis.c
391
src/stb_vorbis.c
@ -1,5 +1,389 @@
|
||||
// Ogg Vorbis audio decoder - v1.05 - public domain
|
||||
// http://nothings.org/stb_vorbis/
|
||||
//
|
||||
// Written by Sean Barrett in 2007, last updated in 2014
|
||||
// Sponsored by RAD Game Tools.
|
||||
//
|
||||
// Placed in the public domain April 2007 by the author: no copyright
|
||||
// is claimed, and you may use it for any purpose you like.
|
||||
//
|
||||
// No warranty for any purpose is expressed or implied by the author (nor
|
||||
// by RAD Game Tools). Report bugs and send enhancements to the author.
|
||||
//
|
||||
// Limitations:
|
||||
//
|
||||
// - seeking not supported except manually via PUSHDATA api
|
||||
// - floor 0 not supported (used in old ogg vorbis files pre-2004)
|
||||
// - lossless sample-truncation at beginning ignored
|
||||
// - cannot concatenate multiple vorbis streams
|
||||
// - sample positions are 32-bit, limiting seekable 192Khz
|
||||
// files to around 6 hours (Ogg supports 64-bit)
|
||||
//
|
||||
// Bugfix/warning contributors:
|
||||
// Terje Mathisen Niklas Frykholm Andy Hill
|
||||
// Casey Muratori John Bolton Gargaj
|
||||
// Laurent Gomila Marc LeBlanc Ronny Chevalier
|
||||
// Bernhard Wodo Evan Balster "alxprd"@github
|
||||
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
|
||||
// (If you reported a bug but do not appear in this list, it is because
|
||||
// someone else reported the bug before you. There were too many of you to
|
||||
// list them all because I was lax about updating for a long time, sorry.)
|
||||
//
|
||||
// Partial history:
|
||||
// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant
|
||||
// 1.04 - 2014/08/27 - fix missing const-correct case in API
|
||||
// 1.03 - 2014/08/07 - warning fixes
|
||||
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
|
||||
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
|
||||
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
|
||||
// (API change) report sample rate for decode-full-file funcs
|
||||
// 0.99996 - - bracket #include <malloc.h> for macintosh compilation
|
||||
// 0.99995 - - avoid alias-optimization issue in float-to-int conversion
|
||||
//
|
||||
// See end of file for full version history.
|
||||
|
||||
#include "stb_vorbis.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// HEADER BEGINS HERE
|
||||
//
|
||||
|
||||
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
|
||||
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
|
||||
#define STB_VORBIS_NO_STDIO 1
|
||||
#endif
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
// NOTE: Added to work with raylib on Android
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
#include "utils.h" // Android fopen function map
|
||||
#endif
|
||||
|
||||
// RaySan: Added for Linux
|
||||
#ifdef __linux
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////// THREAD SAFETY
|
||||
|
||||
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
|
||||
// them from multiple threads at the same time. However, you can have multiple
|
||||
// stb_vorbis* handles and decode from them independently in multiple thrads.
|
||||
|
||||
|
||||
/////////// MEMORY ALLOCATION
|
||||
|
||||
// normally stb_vorbis uses malloc() to allocate memory at startup,
|
||||
// and alloca() to allocate temporary memory during a frame on the
|
||||
// stack. (Memory consumption will depend on the amount of setup
|
||||
// data in the file and how you set the compile flags for speed
|
||||
// vs. size. In my test files the maximal-size usage is ~150KB.)
|
||||
//
|
||||
// You can modify the wrapper functions in the source (setup_malloc,
|
||||
// setup_temp_malloc, temp_malloc) to change this behavior, or you
|
||||
// can use a simpler allocation model: you pass in a buffer from
|
||||
// which stb_vorbis will allocate _all_ its memory (including the
|
||||
// temp memory). "open" may fail with a VORBIS_outofmem if you
|
||||
// do not pass in enough data; there is no way to determine how
|
||||
// much you do need except to succeed (at which point you can
|
||||
// query get_info to find the exact amount required. yes I know
|
||||
// this is lame).
|
||||
//
|
||||
// If you pass in a non-NULL buffer of the type below, allocation
|
||||
// will occur from it as described above. Otherwise just pass NULL
|
||||
// to use malloc()/alloca()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *alloc_buffer;
|
||||
int alloc_buffer_length_in_bytes;
|
||||
} stb_vorbis_alloc;
|
||||
|
||||
|
||||
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
|
||||
|
||||
typedef struct stb_vorbis stb_vorbis;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int sample_rate;
|
||||
int channels;
|
||||
|
||||
unsigned int setup_memory_required;
|
||||
unsigned int setup_temp_memory_required;
|
||||
unsigned int temp_memory_required;
|
||||
|
||||
int max_frame_size;
|
||||
} stb_vorbis_info;
|
||||
|
||||
// get general information about the file
|
||||
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
|
||||
|
||||
// get the last error detected (clears it, too)
|
||||
extern int stb_vorbis_get_error(stb_vorbis *f);
|
||||
|
||||
// close an ogg vorbis file and free all memory in use
|
||||
extern void stb_vorbis_close(stb_vorbis *f);
|
||||
|
||||
// this function returns the offset (in samples) from the beginning of the
|
||||
// file that will be returned by the next decode, if it is known, or -1
|
||||
// otherwise. after a flush_pushdata() call, this may take a while before
|
||||
// it becomes valid again.
|
||||
// NOT WORKING YET after a seek with PULLDATA API
|
||||
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
|
||||
|
||||
// returns the current seek point within the file, or offset from the beginning
|
||||
// of the memory buffer. In pushdata mode it returns 0.
|
||||
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
|
||||
|
||||
/////////// PUSHDATA API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PUSHDATA_API
|
||||
|
||||
// this API allows you to get blocks of data from any source and hand
|
||||
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
|
||||
// you how much it used, and you have to give it the rest next time;
|
||||
// and stb_vorbis may not have enough data to work with and you will
|
||||
// need to give it the same data again PLUS more. Note that the Vorbis
|
||||
// specification does not bound the size of an individual frame.
|
||||
|
||||
extern stb_vorbis *stb_vorbis_open_pushdata(
|
||||
unsigned char *datablock, int datablock_length_in_bytes,
|
||||
int *datablock_memory_consumed_in_bytes,
|
||||
int *error,
|
||||
stb_vorbis_alloc *alloc_buffer);
|
||||
// create a vorbis decoder by passing in the initial data block containing
|
||||
// the ogg&vorbis headers (you don't need to do parse them, just provide
|
||||
// the first N bytes of the file--you're told if it's not enough, see below)
|
||||
// on success, returns an stb_vorbis *, does not set error, returns the amount of
|
||||
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
|
||||
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
|
||||
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
|
||||
// incomplete and you need to pass in a larger block from the start of the file
|
||||
|
||||
extern int stb_vorbis_decode_frame_pushdata(
|
||||
stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes,
|
||||
int *channels, // place to write number of float * buffers
|
||||
float ***output, // place to write float ** array of float * buffers
|
||||
int *samples // place to write number of output samples
|
||||
);
|
||||
// decode a frame of audio sample data if possible from the passed-in data block
|
||||
//
|
||||
// return value: number of bytes we used from datablock
|
||||
//
|
||||
// possible cases:
|
||||
// 0 bytes used, 0 samples output (need more data)
|
||||
// N bytes used, 0 samples output (resynching the stream, keep going)
|
||||
// N bytes used, M samples output (one frame of data)
|
||||
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
|
||||
// frame, because Vorbis always "discards" the first frame.
|
||||
//
|
||||
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
|
||||
// instead only datablock_length_in_bytes-3 or less. This is because it wants
|
||||
// to avoid missing parts of a page header if they cross a datablock boundary,
|
||||
// without writing state-machiney code to record a partial detection.
|
||||
//
|
||||
// The number of channels returned are stored in *channels (which can be
|
||||
// NULL--it is always the same as the number of channels reported by
|
||||
// get_info). *output will contain an array of float* buffers, one per
|
||||
// channel. In other words, (*output)[0][0] contains the first sample from
|
||||
// the first channel, and (*output)[1][0] contains the first sample from
|
||||
// the second channel.
|
||||
|
||||
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
|
||||
// inform stb_vorbis that your next datablock will not be contiguous with
|
||||
// previous ones (e.g. you've seeked in the data); future attempts to decode
|
||||
// frames will cause stb_vorbis to resynchronize (as noted above), and
|
||||
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
|
||||
// will begin decoding the _next_ frame.
|
||||
//
|
||||
// if you want to seek using pushdata, you need to seek in your file, then
|
||||
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
|
||||
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
|
||||
// if you don't like the result, seek your file again and repeat.
|
||||
#endif
|
||||
|
||||
|
||||
////////// PULLING INPUT API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PULLDATA_API
|
||||
// This API assumes stb_vorbis is allowed to pull data from a source--
|
||||
// either a block of memory containing the _entire_ vorbis stream, or a
|
||||
// FILE * that you or it create, or possibly some other reading mechanism
|
||||
// if you go modify the source to replace the FILE * case with some kind
|
||||
// of callback to your code. (But if you don't support seeking, you may
|
||||
// just want to go ahead and use pushdata.)
|
||||
|
||||
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
|
||||
#endif
|
||||
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
|
||||
#endif
|
||||
// decode an entire file and output the data interleaved into a malloc()ed
|
||||
// buffer stored in *output. The return value is the number of samples
|
||||
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
|
||||
// When you're done with it, just free() the pointer returned in *output.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
|
||||
// this must be the entire stream!). on failure, returns NULL and sets *error
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from a filename via fopen(). on failure,
|
||||
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
|
||||
// note that stb_vorbis must "own" this stream; if you seek it in between
|
||||
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
|
||||
// perform stb_vorbis_seek_*() operations on this file, it will assume it
|
||||
// owns the _entire_ rest of the file after the start point. Use the next
|
||||
// function, stb_vorbis_open_file_section(), to limit it.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
|
||||
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
|
||||
// this stream; if you seek it in between calls to stb_vorbis, it will become
|
||||
// confused.
|
||||
#endif
|
||||
|
||||
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
|
||||
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
|
||||
// NOT WORKING YET
|
||||
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
|
||||
// after calling seek_frame(), the next call to get_frame_*() will include
|
||||
// the specified sample. after calling stb_vorbis_seek(), the next call to
|
||||
// stb_vorbis_get_samples_* will start with the specified sample. If you
|
||||
// do not need to seek to EXACTLY the target sample when using get_samples_*,
|
||||
// you can also use seek_frame().
|
||||
|
||||
extern void stb_vorbis_seek_start(stb_vorbis *f);
|
||||
// this function is equivalent to stb_vorbis_seek(f,0), but it
|
||||
// actually works
|
||||
|
||||
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
|
||||
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
|
||||
// these functions return the total length of the vorbis stream
|
||||
|
||||
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
|
||||
// decode the next frame and return the number of samples. the number of
|
||||
// channels returned are stored in *channels (which can be NULL--it is always
|
||||
// the same as the number of channels reported by get_info). *output will
|
||||
// contain an array of float* buffers, one per channel. These outputs will
|
||||
// be overwritten on the next call to stb_vorbis_get_frame_*.
|
||||
//
|
||||
// You generally should not intermix calls to stb_vorbis_get_frame_*()
|
||||
// and stb_vorbis_get_samples_*(), since the latter calls the former.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
|
||||
#endif
|
||||
// decode the next frame and return the number of samples per channel. the
|
||||
// data is coerced to the number of channels you request according to the
|
||||
// channel coercion rules (see below). You must pass in the size of your
|
||||
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
|
||||
// The maximum buffer size needed can be gotten from get_info(); however,
|
||||
// the Vorbis I specification implies an absolute maximum of 4096 samples
|
||||
// per channel. Note that for interleaved data, you pass in the number of
|
||||
// shorts (the size of your array), but the return value is the number of
|
||||
// samples per channel, not the total number of samples.
|
||||
|
||||
// Channel coercion rules:
|
||||
// Let M be the number of channels requested, and N the number of channels present,
|
||||
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
|
||||
// and stereo R be the sum of all R and center channels (channel assignment from the
|
||||
// vorbis spec).
|
||||
// M N output
|
||||
// 1 k sum(Ck) for all k
|
||||
// 2 * stereo L, stereo R
|
||||
// k l k > l, the first l channels, then 0s
|
||||
// k l k <= l, the first k channels
|
||||
// Note that this is not _good_ surround etc. mixing at all! It's just so
|
||||
// you get something useful.
|
||||
|
||||
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
|
||||
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
|
||||
// Returns the number of samples stored per channel; it may be less than requested
|
||||
// at the end of the file. If there are no more samples in the file, returns 0.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
|
||||
#endif
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. Applies the coercion rules above
|
||||
// to produce 'channels' channels. Returns the number of samples stored per channel;
|
||||
// it may be less than requested at the end of the file. If there are no more
|
||||
// samples in the file, returns 0.
|
||||
|
||||
#endif
|
||||
|
||||
//////// ERROR CODES
|
||||
|
||||
enum STBVorbisError
|
||||
{
|
||||
VORBIS__no_error,
|
||||
|
||||
VORBIS_need_more_data=1, // not a real error
|
||||
|
||||
VORBIS_invalid_api_mixing, // can't mix API modes
|
||||
VORBIS_outofmem, // not enough memory
|
||||
VORBIS_feature_not_supported, // uses floor 0
|
||||
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
|
||||
VORBIS_file_open_failure, // fopen() failed
|
||||
VORBIS_seek_without_length, // can't seek in unknown-length file
|
||||
|
||||
VORBIS_unexpected_eof=10, // file is truncated?
|
||||
VORBIS_seek_invalid, // seek past EOF
|
||||
|
||||
// decoding errors (corrupt/invalid stream) -- you probably
|
||||
// don't care about the exact details of these
|
||||
|
||||
// vorbis errors:
|
||||
VORBIS_invalid_setup=20,
|
||||
VORBIS_invalid_stream,
|
||||
|
||||
// ogg errors:
|
||||
VORBIS_missing_capture_pattern=30,
|
||||
VORBIS_invalid_stream_structure_version,
|
||||
VORBIS_continued_packet_flag_invalid,
|
||||
VORBIS_incorrect_stream_serial_number,
|
||||
VORBIS_invalid_first_page,
|
||||
VORBIS_bad_packet_type,
|
||||
VORBIS_cant_find_last_page,
|
||||
VORBIS_seek_failed,
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
//
|
||||
// HEADER ENDS HERE
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef STB_VORBIS_HEADER_ONLY
|
||||
|
||||
@ -180,7 +564,7 @@
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#if !defined(_MSC_VER) && !(defined(__MINGW32__) && defined(__forceinline))
|
||||
#if __GNUC__
|
||||
#define __forceinline inline
|
||||
#else
|
||||
@ -3562,7 +3946,7 @@ static int start_decoder(vorb *f)
|
||||
g->sorted_order[j] = (uint8) p[j].y;
|
||||
// precompute the neighbors
|
||||
for (j=2; j < g->values; ++j) {
|
||||
int low = 0,hi = 0;
|
||||
int low,hi;
|
||||
neighbors(g->Xlist, j, &low,&hi);
|
||||
g->neighbors[j][0] = low;
|
||||
g->neighbors[j][1] = hi;
|
||||
@ -5024,6 +5408,7 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in
|
||||
#endif // STB_VORBIS_NO_PULLDATA_API
|
||||
|
||||
/* Version history
|
||||
1.05 - 2015/04/19 - don't define __forceinline if it's redundant
|
||||
1.04 - 2014/08/27 - fix missing const-correct case in API
|
||||
1.03 - 2014/08/07 - Warning fixes
|
||||
1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows
|
||||
|
384
src/stb_vorbis.h
384
src/stb_vorbis.h
@ -1,384 +0,0 @@
|
||||
// Ogg Vorbis audio decoder - v1.04 - public domain
|
||||
// http://nothings.org/stb_vorbis/
|
||||
//
|
||||
// Written by Sean Barrett in 2007, last updated in 2014
|
||||
// Sponsored by RAD Game Tools.
|
||||
//
|
||||
// Placed in the public domain April 2007 by the author: no copyright
|
||||
// is claimed, and you may use it for any purpose you like.
|
||||
//
|
||||
// No warranty for any purpose is expressed or implied by the author (nor
|
||||
// by RAD Game Tools). Report bugs and send enhancements to the author.
|
||||
//
|
||||
// Limitations:
|
||||
//
|
||||
// - seeking not supported except manually via PUSHDATA api
|
||||
// - floor 0 not supported (used in old ogg vorbis files pre-2004)
|
||||
// - lossless sample-truncation at beginning ignored
|
||||
// - cannot concatenate multiple vorbis streams
|
||||
// - sample positions are 32-bit, limiting seekable 192Khz
|
||||
// files to around 6 hours (Ogg supports 64-bit)
|
||||
//
|
||||
// Bugfix/warning contributors:
|
||||
// Terje Mathisen Niklas Frykholm Andy Hill
|
||||
// Casey Muratori John Bolton Gargaj
|
||||
// Laurent Gomila Marc LeBlanc Ronny Chevalier
|
||||
// Bernhard Wodo Evan Balster "alxprd"@github
|
||||
// Tom Beaumont Ingo Leitgeb
|
||||
// (If you reported a bug but do not appear in this list, it is because
|
||||
// someone else reported the bug before you. There were too many of you to
|
||||
// list them all because I was lax about updating for a long time, sorry.)
|
||||
//
|
||||
// Partial history:
|
||||
// 1.04 - 2014/08/27 - fix missing const-correct case in API
|
||||
// 1.03 - 2014/08/07 - warning fixes
|
||||
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
|
||||
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
|
||||
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
|
||||
// (API change) report sample rate for decode-full-file funcs
|
||||
// 0.99996 - - bracket #include <malloc.h> for macintosh compilation
|
||||
// 0.99995 - - avoid alias-optimization issue in float-to-int conversion
|
||||
//
|
||||
// See end of file for full version history.
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// HEADER BEGINS HERE
|
||||
//
|
||||
|
||||
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
|
||||
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
|
||||
#define STB_VORBIS_NO_STDIO 1
|
||||
#endif
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
// NOTE: Added to work with raylib on Android
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
#include "utils.h" // Android fopen function map
|
||||
#endif
|
||||
|
||||
#ifdef __linux
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////// THREAD SAFETY
|
||||
|
||||
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
|
||||
// them from multiple threads at the same time. However, you can have multiple
|
||||
// stb_vorbis* handles and decode from them independently in multiple thrads.
|
||||
|
||||
|
||||
/////////// MEMORY ALLOCATION
|
||||
|
||||
// normally stb_vorbis uses malloc() to allocate memory at startup,
|
||||
// and alloca() to allocate temporary memory during a frame on the
|
||||
// stack. (Memory consumption will depend on the amount of setup
|
||||
// data in the file and how you set the compile flags for speed
|
||||
// vs. size. In my test files the maximal-size usage is ~150KB.)
|
||||
//
|
||||
// You can modify the wrapper functions in the source (setup_malloc,
|
||||
// setup_temp_malloc, temp_malloc) to change this behavior, or you
|
||||
// can use a simpler allocation model: you pass in a buffer from
|
||||
// which stb_vorbis will allocate _all_ its memory (including the
|
||||
// temp memory). "open" may fail with a VORBIS_outofmem if you
|
||||
// do not pass in enough data; there is no way to determine how
|
||||
// much you do need except to succeed (at which point you can
|
||||
// query get_info to find the exact amount required. yes I know
|
||||
// this is lame).
|
||||
//
|
||||
// If you pass in a non-NULL buffer of the type below, allocation
|
||||
// will occur from it as described above. Otherwise just pass NULL
|
||||
// to use malloc()/alloca()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *alloc_buffer;
|
||||
int alloc_buffer_length_in_bytes;
|
||||
} stb_vorbis_alloc;
|
||||
|
||||
|
||||
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
|
||||
|
||||
typedef struct stb_vorbis stb_vorbis;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int sample_rate;
|
||||
int channels;
|
||||
|
||||
unsigned int setup_memory_required;
|
||||
unsigned int setup_temp_memory_required;
|
||||
unsigned int temp_memory_required;
|
||||
|
||||
int max_frame_size;
|
||||
} stb_vorbis_info;
|
||||
|
||||
// get general information about the file
|
||||
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
|
||||
|
||||
// get the last error detected (clears it, too)
|
||||
extern int stb_vorbis_get_error(stb_vorbis *f);
|
||||
|
||||
// close an ogg vorbis file and free all memory in use
|
||||
extern void stb_vorbis_close(stb_vorbis *f);
|
||||
|
||||
// this function returns the offset (in samples) from the beginning of the
|
||||
// file that will be returned by the next decode, if it is known, or -1
|
||||
// otherwise. after a flush_pushdata() call, this may take a while before
|
||||
// it becomes valid again.
|
||||
// NOT WORKING YET after a seek with PULLDATA API
|
||||
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
|
||||
|
||||
// returns the current seek point within the file, or offset from the beginning
|
||||
// of the memory buffer. In pushdata mode it returns 0.
|
||||
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
|
||||
|
||||
/////////// PUSHDATA API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PUSHDATA_API
|
||||
|
||||
// this API allows you to get blocks of data from any source and hand
|
||||
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
|
||||
// you how much it used, and you have to give it the rest next time;
|
||||
// and stb_vorbis may not have enough data to work with and you will
|
||||
// need to give it the same data again PLUS more. Note that the Vorbis
|
||||
// specification does not bound the size of an individual frame.
|
||||
|
||||
extern stb_vorbis *stb_vorbis_open_pushdata(
|
||||
unsigned char *datablock, int datablock_length_in_bytes,
|
||||
int *datablock_memory_consumed_in_bytes,
|
||||
int *error,
|
||||
stb_vorbis_alloc *alloc_buffer);
|
||||
// create a vorbis decoder by passing in the initial data block containing
|
||||
// the ogg&vorbis headers (you don't need to do parse them, just provide
|
||||
// the first N bytes of the file--you're told if it's not enough, see below)
|
||||
// on success, returns an stb_vorbis *, does not set error, returns the amount of
|
||||
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
|
||||
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
|
||||
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
|
||||
// incomplete and you need to pass in a larger block from the start of the file
|
||||
|
||||
extern int stb_vorbis_decode_frame_pushdata(
|
||||
stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes,
|
||||
int *channels, // place to write number of float * buffers
|
||||
float ***output, // place to write float ** array of float * buffers
|
||||
int *samples // place to write number of output samples
|
||||
);
|
||||
// decode a frame of audio sample data if possible from the passed-in data block
|
||||
//
|
||||
// return value: number of bytes we used from datablock
|
||||
//
|
||||
// possible cases:
|
||||
// 0 bytes used, 0 samples output (need more data)
|
||||
// N bytes used, 0 samples output (resynching the stream, keep going)
|
||||
// N bytes used, M samples output (one frame of data)
|
||||
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
|
||||
// frame, because Vorbis always "discards" the first frame.
|
||||
//
|
||||
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
|
||||
// instead only datablock_length_in_bytes-3 or less. This is because it wants
|
||||
// to avoid missing parts of a page header if they cross a datablock boundary,
|
||||
// without writing state-machiney code to record a partial detection.
|
||||
//
|
||||
// The number of channels returned are stored in *channels (which can be
|
||||
// NULL--it is always the same as the number of channels reported by
|
||||
// get_info). *output will contain an array of float* buffers, one per
|
||||
// channel. In other words, (*output)[0][0] contains the first sample from
|
||||
// the first channel, and (*output)[1][0] contains the first sample from
|
||||
// the second channel.
|
||||
|
||||
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
|
||||
// inform stb_vorbis that your next datablock will not be contiguous with
|
||||
// previous ones (e.g. you've seeked in the data); future attempts to decode
|
||||
// frames will cause stb_vorbis to resynchronize (as noted above), and
|
||||
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
|
||||
// will begin decoding the _next_ frame.
|
||||
//
|
||||
// if you want to seek using pushdata, you need to seek in your file, then
|
||||
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
|
||||
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
|
||||
// if you don't like the result, seek your file again and repeat.
|
||||
#endif
|
||||
|
||||
|
||||
////////// PULLING INPUT API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PULLDATA_API
|
||||
// This API assumes stb_vorbis is allowed to pull data from a source--
|
||||
// either a block of memory containing the _entire_ vorbis stream, or a
|
||||
// FILE * that you or it create, or possibly some other reading mechanism
|
||||
// if you go modify the source to replace the FILE * case with some kind
|
||||
// of callback to your code. (But if you don't support seeking, you may
|
||||
// just want to go ahead and use pushdata.)
|
||||
|
||||
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
|
||||
#endif
|
||||
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
|
||||
#endif
|
||||
// decode an entire file and output the data interleaved into a malloc()ed
|
||||
// buffer stored in *output. The return value is the number of samples
|
||||
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
|
||||
// When you're done with it, just free() the pointer returned in *output.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
|
||||
// this must be the entire stream!). on failure, returns NULL and sets *error
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from a filename via fopen(). on failure,
|
||||
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
|
||||
// note that stb_vorbis must "own" this stream; if you seek it in between
|
||||
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
|
||||
// perform stb_vorbis_seek_*() operations on this file, it will assume it
|
||||
// owns the _entire_ rest of the file after the start point. Use the next
|
||||
// function, stb_vorbis_open_file_section(), to limit it.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
|
||||
int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
|
||||
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
|
||||
// this stream; if you seek it in between calls to stb_vorbis, it will become
|
||||
// confused.
|
||||
#endif
|
||||
|
||||
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
|
||||
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
|
||||
// NOT WORKING YET
|
||||
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
|
||||
// after calling seek_frame(), the next call to get_frame_*() will include
|
||||
// the specified sample. after calling stb_vorbis_seek(), the next call to
|
||||
// stb_vorbis_get_samples_* will start with the specified sample. If you
|
||||
// do not need to seek to EXACTLY the target sample when using get_samples_*,
|
||||
// you can also use seek_frame().
|
||||
|
||||
extern void stb_vorbis_seek_start(stb_vorbis *f);
|
||||
// this function is equivalent to stb_vorbis_seek(f,0), but it
|
||||
// actually works
|
||||
|
||||
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
|
||||
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
|
||||
// these functions return the total length of the vorbis stream
|
||||
|
||||
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
|
||||
// decode the next frame and return the number of samples. the number of
|
||||
// channels returned are stored in *channels (which can be NULL--it is always
|
||||
// the same as the number of channels reported by get_info). *output will
|
||||
// contain an array of float* buffers, one per channel. These outputs will
|
||||
// be overwritten on the next call to stb_vorbis_get_frame_*.
|
||||
//
|
||||
// You generally should not intermix calls to stb_vorbis_get_frame_*()
|
||||
// and stb_vorbis_get_samples_*(), since the latter calls the former.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
|
||||
#endif
|
||||
// decode the next frame and return the number of samples per channel. the
|
||||
// data is coerced to the number of channels you request according to the
|
||||
// channel coercion rules (see below). You must pass in the size of your
|
||||
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
|
||||
// The maximum buffer size needed can be gotten from get_info(); however,
|
||||
// the Vorbis I specification implies an absolute maximum of 4096 samples
|
||||
// per channel. Note that for interleaved data, you pass in the number of
|
||||
// shorts (the size of your array), but the return value is the number of
|
||||
// samples per channel, not the total number of samples.
|
||||
|
||||
// Channel coercion rules:
|
||||
// Let M be the number of channels requested, and N the number of channels present,
|
||||
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
|
||||
// and stereo R be the sum of all R and center channels (channel assignment from the
|
||||
// vorbis spec).
|
||||
// M N output
|
||||
// 1 k sum(Ck) for all k
|
||||
// 2 * stereo L, stereo R
|
||||
// k l k > l, the first l channels, then 0s
|
||||
// k l k <= l, the first k channels
|
||||
// Note that this is not _good_ surround etc. mixing at all! It's just so
|
||||
// you get something useful.
|
||||
|
||||
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
|
||||
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
|
||||
// Returns the number of samples stored per channel; it may be less than requested
|
||||
// at the end of the file. If there are no more samples in the file, returns 0.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
|
||||
#endif
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. Applies the coercion rules above
|
||||
// to produce 'channels' channels. Returns the number of samples stored per channel;
|
||||
// it may be less than requested at the end of the file. If there are no more
|
||||
// samples in the file, returns 0.
|
||||
|
||||
#endif
|
||||
|
||||
//////// ERROR CODES
|
||||
|
||||
enum STBVorbisError
|
||||
{
|
||||
VORBIS__no_error,
|
||||
|
||||
VORBIS_need_more_data=1, // not a real error
|
||||
|
||||
VORBIS_invalid_api_mixing, // can't mix API modes
|
||||
VORBIS_outofmem, // not enough memory
|
||||
VORBIS_feature_not_supported, // uses floor 0
|
||||
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
|
||||
VORBIS_file_open_failure, // fopen() failed
|
||||
VORBIS_seek_without_length, // can't seek in unknown-length file
|
||||
|
||||
VORBIS_unexpected_eof=10, // file is truncated?
|
||||
VORBIS_seek_invalid, // seek past EOF
|
||||
|
||||
// decoding errors (corrupt/invalid stream) -- you probably
|
||||
// don't care about the exact details of these
|
||||
|
||||
// vorbis errors:
|
||||
VORBIS_invalid_setup=20,
|
||||
VORBIS_invalid_stream,
|
||||
|
||||
// ogg errors:
|
||||
VORBIS_missing_capture_pattern=30,
|
||||
VORBIS_invalid_stream_structure_version,
|
||||
VORBIS_continued_packet_flag_invalid,
|
||||
VORBIS_incorrect_stream_serial_number,
|
||||
VORBIS_invalid_first_page,
|
||||
VORBIS_bad_packet_type,
|
||||
VORBIS_cant_find_last_page,
|
||||
VORBIS_seek_failed,
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
//
|
||||
// HEADER ENDS HERE
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
Loading…
Reference in New Issue
Block a user