From 721c788fdb56dc98ccbc7cc4b6434d1ca2d8cef3 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sat, 11 Mar 2017 18:42:47 +0100 Subject: [PATCH 01/95] stb_image_write: JPEG writer based on jo_jpeg.cpp jo_jpeg.cpp is a Public Domain JPEG writer written by Jon Olick in 2012 http://www.jonolick.com/code.html My changes to jo_jpeg: * port to plain C89 (+ // comments, as supported by MSVC6) * support for 2 comp input (Greyscale+Alpha, Alpha is ignored) * use stbi__write_context abstraction instead of stdio for writing * adjust names to stbiw-style --- stb_image_write.h | 360 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) diff --git a/stb_image_write.h b/stb_image_write.h index df62339..caebb5b 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -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_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) 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]; @@ -1013,6 +1029,350 @@ 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<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]] = yti < 1 ? 1 : yti > 255 ? 255 : yti; + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = 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,height>>8,height&0xFF,width>>8,width&0xFF,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 From e5144a3996188a58668bec528e7d7f09a091ef7a Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sat, 11 Mar 2017 18:58:02 +0100 Subject: [PATCH 02/95] stb_image_write.h: Consistently use STBIWDEF for stbi_write_* Some functions were missing that in the definition, others weren't, all had it in the declarations. Added mention of JPG and HDR formats at the top of the file --- stb_image_write.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index caebb5b..1d84a39 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -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 + 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, @@ -466,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); @@ -474,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)) { @@ -636,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); @@ -644,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)) { From c7110588a4d24c4bb5155c184fbb77dd90b3116e Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 19 Mar 2017 17:51:43 -0700 Subject: [PATCH 03/95] update README with info about SSE2 on GCC --- README.md | 16 ++++++++++++++++ tools/README.footer.md | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/README.md b/README.md index 4d9d323..7d6d82c 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,22 @@ dual-license for you to choose from. No, because it's public domain you can freely relicense it to whatever license your new library wants to be. +#### What's the deal with SSE support in GCC-based compilers? + +stb_image will either use SSE2 (if you compile with -msse2) or +will not use any SIMD at all, rather than trying to detect the +processor at runtime and handle it correctly. As I understand it, +the approved path in GCC for runtime-detection require +you to use multiple source files, one for each CPU configuration. +Because stb_image is a header-file library that compiles in only +one source file, there's no approved way to build both an +SSE-enabled and a non-SSE-enabled variation. + +While we've tried to work around it, we've had multiple issues over +the years due to specific versions of gcc breaking what we're doing, +so we've given up on it. See https://github.com/nothings/stb/issues/280 +and https://github.com/nothings/stb/issues/410 for examples. + #### Some of these libraries seem redundant to existing open source libraries. Are they better somehow? Generally they're only better in that they're easier to integrate, diff --git a/tools/README.footer.md b/tools/README.footer.md index b492e0a..f6f4bf5 100644 --- a/tools/README.footer.md +++ b/tools/README.footer.md @@ -21,6 +21,22 @@ dual-license for you to choose from. No, because it's public domain you can freely relicense it to whatever license your new library wants to be. +#### What's the deal with SSE support in GCC-based compilers? + +stb_image will either use SSE2 (if you compile with -msse2) or +will not use any SIMD at all, rather than trying to detect the +processor at runtime and handle it correctly. As I understand it, +the approved path in GCC for runtime-detection require +you to use multiple source files, one for each CPU configuration. +Because stb_image is a header-file library that compiles in only +one source file, there's no approved way to build both an +SSE-enabled and a non-SSE-enabled variation. + +While we've tried to work around it, we've had multiple issues over +the years due to specific versions of gcc breaking what we're doing, +so we've given up on it. See https://github.com/nothings/stb/issues/280 +and https://github.com/nothings/stb/issues/410 for examples. + #### Some of these libraries seem redundant to existing open source libraries. Are they better somehow? Generally they're only better in that they're easier to integrate, From f3d8e52ddc2e0790689821be4fc8dd08b78b9f14 Mon Sep 17 00:00:00 2001 From: Cort Date: Tue, 28 Mar 2017 21:36:54 -0700 Subject: [PATCH 04/95] stb_truetype: fontdata can be const in stbtt_PackFontRange[s]() --- stb_truetype.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index fc5b978..84440e2 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -548,7 +548,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 +573,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 @@ -3688,7 +3688,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 +3724,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; From dda7d72841f6ce976c2b83948b0f1c7341088302 Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Tue, 18 Apr 2017 15:57:24 +0200 Subject: [PATCH 05/95] Add STB_DXT_STATIC option. --- stb_dxt.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/stb_dxt.h b/stb_dxt.h index 5399799..c352b76 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -35,8 +35,14 @@ extern "C" { #endif -void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode); -void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel); +#ifdef STB_DXT_STATIC +#define STBDDEF static +#else +#define STBDDEF extern +#endif + +STBDDEF void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode); +STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel); #ifdef __cplusplus } From 1dfdf5558df6123b445851722d3560ae7c52081b Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Tue, 18 Apr 2017 16:01:44 +0200 Subject: [PATCH 06/95] Fix STBI_NO_STDIO. --- stb_image.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/stb_image.h b/stb_image.h index ae2ada6..0c2b2c0 100644 --- a/stb_image.h +++ b/stb_image.h @@ -352,12 +352,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 @@ -365,9 +365,8 @@ 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); #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 @@ -377,11 +376,11 @@ STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_i // 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 From 97ae5fb3db20acaf76fa9e6e31234848678292c1 Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Tue, 18 Apr 2017 17:36:48 +0200 Subject: [PATCH 07/95] Edit contributor list. --- stb_image.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 0c2b2c0..ec6157e 100644 --- a/stb_image.h +++ b/stb_image.h @@ -98,7 +98,8 @@ 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 - + Kevin Schmidt + */ #ifndef STBI_INCLUDE_STB_IMAGE_H From 96e1f0474c4dec5a8a17a20a0fa1efc3040ed436 Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Tue, 18 Apr 2017 17:42:41 +0200 Subject: [PATCH 08/95] Edit contributor list. --- stb_dxt.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stb_dxt.h b/stb_dxt.h index c352b76..e68c7a8 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -19,6 +19,9 @@ // v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom // v1.00 - (stb) first release // +// contributors: +// Kevin Schmidt +// // LICENSE // // See end of file for license information. From 9b3358fec13d0847886672e4ccd6e6aa6408a229 Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Tue, 18 Apr 2017 18:28:02 +0200 Subject: [PATCH 09/95] Add feature to replace abs/fabs and memset with your own. --- stb_dxt.h | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/stb_dxt.h b/stb_dxt.h index 5399799..95320d0 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -61,8 +61,23 @@ void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two // #define STB_DXT_USE_ROUNDING_BIAS #include + +#if !defined(STBD_ABS) || !defined(STBI_FABS) #include -#include // memset +#endif + +#ifndef STBD_ABS +#define STBD_ABS(i) abs(i) +#endif + +#ifndef STBD_FABS +#define STBD_FABS(x) fabs(x) +#endif + +#ifndef STBD_MEMSET +#include +#define STBD_MEMSET(x) memset(x) +#endif static unsigned char stb__Expand5[32]; static unsigned char stb__Expand6[64]; @@ -127,13 +142,13 @@ static void stb__PrepareOptTable(unsigned char *Table,const unsigned char *expan for (mx=0;mx> 4)]; ep1[0] = bp[ 0] - dp[ 0]; @@ -349,9 +364,9 @@ static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax1 vfb = b; } - magn = fabs(vfr); - if (fabs(vfg) > magn) magn = fabs(vfg); - if (fabs(vfb) > magn) magn = fabs(vfb); + magn = STBD_FABS(vfr); + if (STBD_FABS(vfg) > magn) magn = STBD_FABS(vfg); + if (STBD_FABS(vfb) > magn) magn = STBD_FABS(vfb); if(magn < 4.0f) { // too small, default to luminance v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000. From 50e6be0de6a2211f7ec6d6d82eacb34e583fd1c0 Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Tue, 18 Apr 2017 18:31:15 +0200 Subject: [PATCH 10/95] Edit contributor list. --- stb_dxt.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stb_dxt.h b/stb_dxt.h index 95320d0..3ff25bc 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -19,6 +19,9 @@ // v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom // v1.00 - (stb) first release // +// contributors: +// Kevin Schmidt +// // LICENSE // // See end of file for license information. From 13942348e08e1b68fa439a5fabf8baf108466bb0 Mon Sep 17 00:00:00 2001 From: Tim Wright Date: Tue, 18 Apr 2017 19:54:57 -0600 Subject: [PATCH 11/95] Fixing void * compile error for C++ --- stretchy_buffer.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stretchy_buffer.h b/stretchy_buffer.h index bb711f6..bc11083 100644 --- a/stretchy_buffer.h +++ b/stretchy_buffer.h @@ -162,6 +162,10 @@ // the main trick is in realizing in the first place that it's // possible to do this in a generic, type-safe way in C. // +// Contributors: +// +// Timothy Wright (github:ZenToad) +// // LICENSE // // See end of file for license information. @@ -189,7 +193,7 @@ #define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a)) #define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0) -#define stb__sbgrow(a,n) ((a) = stb__sbgrowf((a), (n), sizeof(*(a)))) +#define stb__sbgrow(a,n) (*((void **)&(a)) = stb__sbgrowf((a), (n), sizeof(*(a)))) #include From 4963448726f8cc4d1ad3d83fe3be862199f4f1e1 Mon Sep 17 00:00:00 2001 From: Infatum Date: Thu, 20 Apr 2017 15:49:36 +0300 Subject: [PATCH 12/95] fix: Build on MinGW32 --- stb.h | 2 ++ stb_vorbis.c | 1 + 2 files changed, 3 insertions(+) diff --git a/stb.h b/stb.h index edd2e1b..70c0899 100644 --- a/stb.h +++ b/stb.h @@ -193,6 +193,8 @@ CREDITS Tim Sjostrand */ +#include + #ifndef STB__INCLUDE_STB_H #define STB__INCLUDE_STB_H diff --git a/stb_vorbis.c b/stb_vorbis.c index 1181e6d..233522a 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -576,6 +576,7 @@ enum STBVorbisError #undef __forceinline #endif #define __forceinline +#define alloca __builtin_alloca #elif !defined(_MSC_VER) #if __GNUC__ #define __forceinline inline From d8796f05bfea3f286ea5b95bba4a0a275d639e63 Mon Sep 17 00:00:00 2001 From: Jean-Sebastien Bevilacqua Date: Tue, 25 Apr 2017 21:02:48 +0200 Subject: [PATCH 13/95] Robustify stbi__sse2_available in stb_image.h Function `stbi__sse2_available` takes no argument, we should be explicit by passing `void` as argument. It will remove warnings from 'some' compilers. --- stb_image.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stb_image.h b/stb_image.h index ae2ada6..c2ed20b 100644 --- a/stb_image.h +++ b/stb_image.h @@ -639,7 +639,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 +647,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 From 8a55e1e5a54794b42f0398e37d9057eaed738831 Mon Sep 17 00:00:00 2001 From: ppiastucki Date: Wed, 26 Apr 2017 22:32:37 +0200 Subject: [PATCH 14/95] Add support for BC4 --- stb_dxt.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stb_dxt.h b/stb_dxt.h index 5399799..ee0decb 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -36,6 +36,7 @@ extern "C" { #endif void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode); +void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src_r_one_byte_per_pixel); void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel); #ifdef __cplusplus @@ -636,6 +637,11 @@ void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int a stb__CompressColorBlock(dest,(unsigned char*) src,mode); } +void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src) +{ + stb__CompressAlphaBlock(dest,(unsigned char*) src, 1); +} + void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src) { stb__CompressAlphaBlock(dest,(unsigned char*) src,2); From 9bcda8bb1c19191ef10dec0cf1bb09908c97e769 Mon Sep 17 00:00:00 2001 From: PopPoLoPoPpo Date: Fri, 5 May 2017 00:39:08 +0200 Subject: [PATCH 15/95] Add stbi_load_16() variants to load from memory or callbacks --- stb_image.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index ae2ada6..3644a0f 100644 --- a/stb_image.h +++ b/stb_image.h @@ -370,7 +370,8 @@ STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *channel #ifndef STBI_NO_STDIO 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 +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); //////////////////////////////////// // @@ -1191,6 +1192,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; From 7091cb6ed65f6bfbdacf3ffcc23dc61bed59831f Mon Sep 17 00:00:00 2001 From: Nathan Reed Date: Thu, 11 May 2017 22:48:46 -0700 Subject: [PATCH 16/95] Fix integer conversion warning --- stb_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index ae2ada6..6e4568e 100644 --- a/stb_image.h +++ b/stb_image.h @@ -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; From 76a1a1c408c29ff39d0d98af1f7e55b099b10052 Mon Sep 17 00:00:00 2001 From: Nathan Reed Date: Thu, 11 May 2017 22:49:19 -0700 Subject: [PATCH 17/95] Fix variable-shadowing warnings --- stb_image.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/stb_image.h b/stb_image.h index 6e4568e..75a9c22 100644 --- a/stb_image.h +++ b/stb_image.h @@ -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; From fb524e67685d6f17063e5c16942df688d9f7a987 Mon Sep 17 00:00:00 2001 From: Nathan Reed Date: Thu, 11 May 2017 22:51:19 -0700 Subject: [PATCH 18/95] Fix warning about context parameter being unused when STBIR_MALLOC and STBIR_FREE have their default definitions. --- stb_image_resize.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stb_image_resize.h b/stb_image_resize.h index b507e04..488e67d 100644 --- a/stb_image_resize.h +++ b/stb_image_resize.h @@ -393,8 +393,9 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int #ifndef STBIR_MALLOC #include -#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 From de080e6d0bfa41475e6afa71f2e32359403304f9 Mon Sep 17 00:00:00 2001 From: Nathan Reed Date: Thu, 11 May 2017 22:53:03 -0700 Subject: [PATCH 19/95] Fix warning about unreachable code --- stb_image_resize.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image_resize.h b/stb_image_resize.h index 488e67d..1c97ce9 100644 --- a/stb_image_resize.h +++ b/stb_image_resize.h @@ -984,7 +984,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"); From cbca86de6560d7953a7cd3860e6f221ae3fd2a1b Mon Sep 17 00:00:00 2001 From: Nathan Reed Date: Thu, 11 May 2017 22:59:43 -0700 Subject: [PATCH 20/95] Add myself to contributors list --- stb_image_resize.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stb_image_resize.h b/stb_image_resize.h index 1c97ce9..0168a29 100644 --- a/stb_image_resize.h +++ b/stb_image_resize.h @@ -156,7 +156,8 @@ Jorge L Rodriguez: Implementation Sean Barrett: API design, optimizations Aras Pranckevicius: bugfix - + Nathan Reed: warning fixes + REVISIONS 0.94 (2017-03-18) fixed warnings 0.93 (2017-03-03) fixed bug with certain combinations of heights From f0baa0c287feeaa01c332fa786ac30285a0b65e7 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 4 Jul 2017 16:55:50 +0200 Subject: [PATCH 21/95] stb_image_write.h: Fix compilation in C++11 mode clang says: error: non-constant-expression cannot be narrowed from type 'int' to 'unsigned char' in initializer list [-Wc++11-narrowing] so I explicitly cast affected stuff to unsigned char. --- stb_image_write.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stb_image_write.h b/stb_image_write.h index 1d84a39..4dc45d4 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -1283,7 +1283,8 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in { 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,height>>8,height&0xFF,width>>8,width&0xFF,3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,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); From e6bbecd3a9c73be061aeb51d6e4fe19317bc4d89 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 4 Jul 2017 18:07:33 +0200 Subject: [PATCH 22/95] stb_image_write.h: Set PNG compress lvl via stbi_write_png_level This allows the user to change the deflate/zlib compress level used for PNG compression by changing a global variable. --- stb_image_write.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/stb_image_write.h b/stb_image_write.h index df62339..44c8943 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -73,6 +73,9 @@ USAGE: writer, both because it is in BGR order and because it may have padding at the end of the line.) + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_level' (it defaults to 8). + 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. @@ -124,6 +127,7 @@ extern "C" { #else #define STBIWDEF extern extern int stbi_write_tga_with_rle; +extern int stbi_write_png_level; #endif #ifndef STBI_WRITE_NO_STDIO @@ -894,6 +898,12 @@ static unsigned char stbiw__paeth(int a, int b, int c) return STBIW_UCHAR(c); } +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_level = 8; +#else +int stbi_write_png_level = 8; +#endif + // @OPTIMIZE: provide an option that always forces left-predict or paeth predict unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { @@ -949,7 +959,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); } STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_level); STBIW_FREE(filt); if (!zlib) return 0; From be21113512b4c1ab8a9fce23d5ad9ca4184bc25e Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 4 Jul 2017 19:34:31 +0200 Subject: [PATCH 23/95] stb_image_write.h: Allow setting custom zlib compress function for PNG The builtin stbi_zlib_compress does not compress as well as zlib or miniz (which is not too surprising as it's <200 LOC), thus PNGs created by stb_image_write are about 20-50% bigger than PNGs compressed with libpng. This change lets the user supply a custom deflate/zlib-style compress function, which improves compression a lot. This was requested in #113. Example for zlib: #include unsigned char* compress_for_stbiw(unsigned char *data, int data_len, int *out_len, int quality) { uLongf bufSize = compressBound(data_len); // note that buf will be free'd by stb_image_write.h // with STBIW_FREE() (plain free() by default) unsigned char* buf = malloc(bufSize); if(buf == NULL) return NULL; if(compress2(buf, &bufSize, data, data_len, quality) != Z_OK) { free(buf); return NULL; } *out_len = bufSize; return buf; } #define STBIW_ZLIB_COMPRESS compress_for_stbiw #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" // ... --- stb_image_write.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 44c8943..a084364 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -16,16 +16,22 @@ ABOUT: adapted to write to memory or a general streaming interface; let me know. The PNG output is not optimal; it is 20-50% larger than the file - written by a decent optimizing implementation. This library is designed - for source code compactness and simplicity, not optimal image file size - or run-time performance. + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + 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() + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), USAGE: @@ -650,6 +656,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da // PNG writer // +#ifndef STBIW_ZLIB_COMPRESS // 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] @@ -730,8 +737,14 @@ static unsigned int stbiw__zhash(unsigned char *data) #define stbiw__ZHASH 16384 +#endif // STBIW_ZLIB_COMPRESS + unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; @@ -833,6 +846,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l // make returned pointer freeable STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS } static unsigned int stbiw__crc32(unsigned char *buffer, int len) From 5defc65c233b640dad83f5cebf481d91ebcf2f8a Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Wed, 12 Jul 2017 06:34:52 -0700 Subject: [PATCH 24/95] Initial SDF support --- stb_truetype.h | 446 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 435 insertions(+), 11 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 5784549..c265753 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -398,6 +398,18 @@ int main(int arg, char **argv) #ifndef STBTT_sqrt #include #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_cos + #include + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) #endif // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h @@ -418,7 +430,7 @@ int main(int arg, char **argv) #endif #ifndef STBTT_memcpy - #include + #include #define STBTT_memcpy memcpy #define STBTT_memset memset #endif @@ -623,7 +635,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); // The following structure is defined publically so you can declare one on // the stack or as a global or etc, but you should treat it as opaque. -typedef struct stbtt_fontinfo +struct stbtt_fontinfo { void * userdata; unsigned char * data; // pointer to .ttf file @@ -634,7 +646,7 @@ typedef struct stbtt_fontinfo int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf int index_map; // a cmap mapping for our chosen character encoding int indexToLocFormat; // format needed to map from glyph index to glyph -} stbtt_fontinfo; +}; STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); // Given an offset into the file that defines a font, this function builds @@ -774,6 +786,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 @@ -791,6 +807,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); @@ -804,6 +821,14 @@ typedef struct STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata); +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function rendering + +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); + + ////////////////////////////////////////////////////////////////////////////// // // Finding the right font... @@ -1974,7 +1999,7 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, } y_crossing += dy * (x2 - (x1+1)); - STBTT_assert(fabs(area) <= 1.01f); + STBTT_assert(STBTT_fabs(area) <= 1.01f); scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (y1-y_crossing); @@ -2001,12 +2026,12 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, // that, we need to explicitly produce segments based on x positions. // rename variables to clear pairs - float y0 = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - float y1,y2; + float x1,x2,x3,y3,y2; + y0 = y_top; + x1 = (float) (x); + x2 = (float) (x+1); + x3 = xb; + y3 = y_bottom; // x = e->x + e->dx * (y-y_top) // (y-y_top) = (x - e->x) / e->dx @@ -2106,7 +2131,7 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int m; sum += scanline2[i]; k = scanline[i] + sum; - k = (float) fabs(k)*255 + 0.5f; + k = (float) STBTT_fabs(k)*255 + 0.5f; m = (int) k; if (m > 255) m = 255; result->pixels[j*result->stride + i] = (unsigned char) m; @@ -2850,6 +2875,29 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fon 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, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { @@ -3012,6 +3060,382 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, i *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); +} ////////////////////////////////////////////////////////////////////////////// // From 9a2e92e81803d11163f769da78f0c6062e73eda7 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Wed, 12 Jul 2017 07:10:13 -0700 Subject: [PATCH 25/95] SDF documentation --- stb_truetype.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/stb_truetype.h b/stb_truetype.h index 25f8b7f..73653e5 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -867,10 +867,56 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap ////////////////////////////////////////////////////////////////////////////// // -// Signed Distance Function rendering +// 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 +// a 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) +// 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(12) +// padding = 5 +// onedge_value = 60 +// pixel_dist_scale = (255-60) / 5.0 = 39.0 +// +// This will create an SDF bitmap in which the character is about 12 pixels +// high but the whole bitmap is about 22 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is less than or equal to 60/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 +// pixels, you would compare against (60+39.0*3)/255 = 177/255. The above +// choice of variables maps a range from 1.5 pixels inside the shape to +// 5 pixels outside the shape; this is intended primarily for apply outside +// effects only (the interior range is to allow accurate antialiasing etc) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. So the quality should +// be as high as possible for an SDF of this size & representation. The algorithm +// has not been optimized at all, so expect it to be slow if computing lots of +// characters or very large sizes. + + ////////////////////////////////////////////////////////////////////////////// @@ -4187,6 +4233,11 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa 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); +} + ////////////////////////////////////////////////////////////////////////////// // // font name matching -- recommended not to use this From 38479bc58c9097802f45459553200accda76dffd Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Wed, 12 Jul 2017 07:25:20 -0700 Subject: [PATCH 26/95] stb_truetype version number --- stb_truetype.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 73653e5..3f83676 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,4 +1,4 @@ -// stb_truetype.h - v1.15 - public domain +// stb_truetype.h - v1.16 - 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 @@ -28,7 +29,7 @@ // github:IntellectualKitty // // Bug/warning reports/fixes: -// "Zer" on mollyrocket (with fix) +// "Zer" on mollyrocket // Cass Everitt // stoiko (Haemimont Games) // Brian Hook @@ -54,6 +55,7 @@ // // 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 @@ -4444,6 +4446,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 From 423298e07169bced18a82c2d0e6a6341a19db65c Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Wed, 12 Jul 2017 09:27:04 -0700 Subject: [PATCH 27/95] fix SDF documentation and add example code --- stb_truetype.h | 38 ++++---- tests/sdf/sdf_test.c | 152 ++++++++++++++++++++++++++++++++ tests/sdf/sdf_test_arial_16.png | Bin 0 -> 121269 bytes tests/sdf/sdf_test_times_16.png | Bin 0 -> 108371 bytes tests/sdf/sdf_test_times_50.png | Bin 0 -> 104962 bytes 5 files changed, 173 insertions(+), 17 deletions(-) create mode 100644 tests/sdf/sdf_test.c create mode 100644 tests/sdf/sdf_test_arial_16.png create mode 100644 tests/sdf/sdf_test_times_16.png create mode 100644 tests/sdf/sdf_test_times_50.png diff --git a/stb_truetype.h b/stb_truetype.h index 3f83676..a0150e4 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -878,7 +878,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc 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 -// a threshhold to produce scalable fonts. +// 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 @@ -886,6 +886,7 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // 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 @@ -895,29 +896,32 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // and special effects. SDF values outside the range 0..255 are clamped to 0..255. // // Example: -// scale = stbtt_ScaleForPixelHeight(12) +// scale = stbtt_ScaleForPixelHeight(22) // padding = 5 -// onedge_value = 60 -// pixel_dist_scale = (255-60) / 5.0 = 39.0 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 // -// This will create an SDF bitmap in which the character is about 12 pixels -// high but the whole bitmap is about 22 pixels high. To produce a filled +// 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 less than or equal to 60/255. (You'll actually want to antialias, +// 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 -// pixels, you would compare against (60+39.0*3)/255 = 177/255. The above -// choice of variables maps a range from 1.5 pixels inside the shape to -// 5 pixels outside the shape; this is intended primarily for apply outside -// effects only (the interior range is to allow accurate antialiasing etc) +// 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. So the quality should -// be as high as possible for an SDF of this size & representation. The algorithm -// has not been optimized at all, so expect it to be slow if computing lots of -// characters or very large sizes. - +// 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. diff --git a/tests/sdf/sdf_test.c b/tests/sdf/sdf_test.c new file mode 100644 index 0000000..d5b0ca0 --- /dev/null +++ b/tests/sdf/sdf_test.c @@ -0,0 +1,152 @@ +#define STB_DEFINE +#include "stb.h" + +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" + +// used both to compute SDF and in 'shader' +float sdf_size = 32.0; // the larger this is, the better large font sizes look +float pixel_dist_scale = 64.0; // trades off precision w/ ability to handle *smaller* sizes +int onedge_value = 128; +int padding = 3; // not used in shader + +typedef struct +{ + float advance; + signed char xoff; + signed char yoff; + unsigned char w,h; + unsigned char *data; +} fontchar; + +fontchar fdata[128]; + +#define BITMAP_W 1200 +#define BITMAP_H 800 +unsigned char bitmap[BITMAP_H][BITMAP_W][3]; + +char *sample = "This is goofy text, size %d!"; +char *small_sample = "This is goofy text, size %d! Really needs in-shader supersampling to look good."; + +void blend_pixel(int x, int y, int color, float alpha) +{ + int i; + for (i=0; i < 3; ++i) + bitmap[y][x][i] = (unsigned char) (stb_lerp(alpha, bitmap[y][x][i], color)+0.5); // round +} + +void draw_char(float px, float py, char c, float relative_scale) +{ + int x,y; + fontchar *fc = &fdata[c]; + float fx0 = px + fc->xoff*relative_scale; + float fy0 = py + fc->yoff*relative_scale; + float fx1 = fx0 + fc->w*relative_scale; + float fy1 = fy0 + fc->h*relative_scale; + int ix0 = (int) floor(fx0); + int iy0 = (int) floor(fy0); + int ix1 = (int) ceil(fx1); + int iy1 = (int) ceil(fy1); + // clamp to viewport + if (ix0 < 0) ix0 = 0; + if (iy0 < 0) iy0 = 0; + if (ix1 > BITMAP_W) ix1 = BITMAP_W; + if (iy1 > BITMAP_H) iy1 = BITMAP_H; + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float sdf_dist, pix_dist; + float bmx = stb_linear_remap(x, fx0, fx1, 0, fc->w); + float bmy = stb_linear_remap(y, fy0, fy1, 0, fc->h); + int v00,v01,v10,v11; + float v0,v1,v; + int sx0 = (int) bmx; + int sx1 = sx0+1; + int sy0 = (int) bmy; + int sy1 = sy0+1; + // compute lerp weights + bmx = bmx - sx0; + bmy = bmy - sy0; + // clamp to edge + sx0 = stb_clamp(sx0, 0, fc->w-1); + sx1 = stb_clamp(sx1, 0, fc->w-1); + sy0 = stb_clamp(sy0, 0, fc->h-1); + sy1 = stb_clamp(sy1, 0, fc->h-1); + // bilinear texture sample + v00 = fc->data[sy0*fc->w+sx0]; + v01 = fc->data[sy0*fc->w+sx1]; + v10 = fc->data[sy1*fc->w+sx0]; + v11 = fc->data[sy1*fc->w+sx1]; + v0 = stb_lerp(bmx,v00,v01); + v1 = stb_lerp(bmx,v10,v11); + v = stb_lerp(bmy,v0 ,v1 ); + #if 0 + // non-anti-aliased + if (v > onedge_value) + blend_pixel(x,y,0,1.0); + #else + // Following math can be greatly simplified + + // convert distance in SDF value to distance in SDF bitmap + sdf_dist = stb_linear_remap(v, onedge_value, onedge_value+pixel_dist_scale, 0, 1); + // convert distance in SDF bitmap to distance in output bitmap + pix_dist = sdf_dist * relative_scale; + // anti-alias by mapping 1/2 pixel around contour from 0..1 alpha + v = stb_linear_remap(pix_dist, -0.5f, 0.5f, 0, 1); + if (v > 1) v = 1; + if (v > 0) + blend_pixel(x,y,0,v); + #endif + } + } +} + + +void print_text(float x, float y, char *text, float scale) +{ + int i; + for (i=0; text[i]; ++i) { + if (fdata[text[i]].data) + draw_char(x,y,text[i],scale); + x += fdata[text[i]].advance * scale; + } +} + +int main(int argc, char **argv) +{ + int ch; + float scale, ypos; + stbtt_fontinfo font; + void *data = stb_file("c:/windows/fonts/times.ttf", NULL); + stbtt_InitFont(&font, data, 0); + + scale = stbtt_ScaleForPixelHeight(&font, sdf_size); + + for (ch=32; ch < 127; ++ch) { + fontchar fc; + int xoff,yoff,w,h, advance; + fc.data = stbtt_GetCodepointSDF(&font, scale, ch, padding, onedge_value, pixel_dist_scale, &w, &h, &xoff, &yoff); + fc.xoff = xoff; + fc.yoff = yoff; + fc.w = w; + fc.h = h; + stbtt_GetCodepointHMetrics(&font, ch, &advance, NULL); + fc.advance = advance * scale; + fdata[ch] = fc; + } + + ypos = 60; + memset(bitmap, 255, sizeof(bitmap)); + print_text(400, ypos+30, stb_sprintf("sdf bitmap height %d", (int) sdf_size), 30/sdf_size); + ypos += 80; + for (scale = 8.0; scale < 120.0; scale *= 1.33f) { + print_text(80, ypos+scale, stb_sprintf(scale == 8.0 ? small_sample : sample, (int) scale), scale / sdf_size); + ypos += scale*1.05f + 20; + } + + stbi_write_png("sdf_test.png", BITMAP_W, BITMAP_H, 3, bitmap, 0); + return 0; +} diff --git a/tests/sdf/sdf_test_arial_16.png b/tests/sdf/sdf_test_arial_16.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2bc1e487517ebd6b7544c29076ff0305b9e139 GIT binary patch literal 121269 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 literal 0 HcmV?d00001 diff --git a/tests/sdf/sdf_test_times_16.png b/tests/sdf/sdf_test_times_16.png new file mode 100644 index 0000000000000000000000000000000000000000..c76e7b96c472f224702555dafdf7cd042fca7ff5 GIT binary patch literal 108371 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 literal 0 HcmV?d00001 diff --git a/tests/sdf/sdf_test_times_50.png b/tests/sdf/sdf_test_times_50.png new file mode 100644 index 0000000000000000000000000000000000000000..bf4974f009fefb6ab03639c7cf7f18390312a055 GIT binary patch literal 104962 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 literal 0 HcmV?d00001 From cccbc3f5a93f465c96e245f01f51fda8a90ae310 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Fri, 21 Jul 2017 20:17:34 -0700 Subject: [PATCH 28/95] stb_sprintf: Clean up the mess with clang-format --- stb_sprintf.h | 2180 +++++++++++++++++++++++++++++++------------------ 1 file changed, 1397 insertions(+), 783 deletions(-) diff --git a/stb_sprintf.h b/stb_sprintf.h index 0ed30a0..469dd5d 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -20,7 +20,7 @@ /* Single file sprintf replacement. -Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. +Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. Hereby placed in public domain. This is a full sprintf replacement that supports everything that @@ -29,19 +29,19 @@ hex floats, field parameters (%*.*d stuff), length reads backs, etc. Why would you need this if sprintf already exists? Well, first off, it's *much* faster (see below). It's also much smaller than the CRT -versions code-space-wise. We've also added some simple improvements +versions code-space-wise. We've also added some simple improvements that are super handy (commas in thousands, callbacks at buffer full, -for example). Finally, the format strings for MSVC and GCC differ -for 64-bit integers (among other small things), so this lets you use +for example). Finally, the format strings for MSVC and GCC differ +for 64-bit integers (among other small things), so this lets you use the same format strings in cross platform code. It uses the standard single file trick of being both the header file -and the source itself. If you just include it normally, you just get +and the source itself. If you just include it normally, you just get the header file function definitions. To get the code, you include it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. It only uses va_args macros from the C runtime to do it's work. It -does cast doubles to S64s and shifts and divides U64s, which does +does cast doubles to S64s and shifts and divides U64s, which does drag in CRT code on most platforms. It compiles to roughly 8K with float support, and 4K without. @@ -78,9 +78,9 @@ doubles with error correction (double-doubles, for ~105 bits of precision). This conversion is round-trip perfect - that is, an atof of the values output here will give you the bit-exact double back. -One difference is that our insignificant digits will be different than -with MSVC or GCC (but they don't match each other either). We also -don't attempt to find the minimum length matching float (pre-MSVC15 +One difference is that our insignificant digits will be different than +with MSVC or GCC (but they don't match each other either). We also +don't attempt to find the minimum length matching float (pre-MSVC15 doesn't either). If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT @@ -95,18 +95,18 @@ for size_t and ptr_diff_t (%jd %zd) as well. EXTRAS: ======= Like some GCCs, for integers and floats, you can use a ' (single quote) -specifier and commas will be inserted on the thousands: "%'d" on 12345 +specifier and commas will be inserted on the thousands: "%'d" on 12345 would print 12,345. -For integers and floats, you can use a "$" specifier and the number +For integers and floats, you can use a "$" specifier and the number will be converted to float and then divided to get kilo, mega, giga or -tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is -"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn 2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three $:s: "%$$$d" -> "2.42 M". To remove the space between the number and the suffix, add "_" specifier: "%_$d" -> "2.53M". -In addition to octal and hexadecimal conversions, you can print +In addition to octal and hexadecimal conversions, you can print integers in binary: "%b" for 256 would print 100. PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): @@ -131,9 +131,9 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): */ #if defined(__has_feature) - #if __has_feature(address_sanitizer) - #define STBI__ASAN __attribute__((no_sanitize("address"))) - #endif +#if __has_feature(address_sanitizer) +#define STBI__ASAN __attribute__((no_sanitize("address"))) +#endif #endif #ifndef STBI__ASAN #define STBI__ASAN @@ -152,30 +152,30 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): #endif #endif -#include // for va_list() +#include // for va_list() #ifndef STB_SPRINTF_MIN #define STB_SPRINTF_MIN 512 // how many characters per callback #endif -typedef char * STBSP_SPRINTFCB( char * buf, void * user, int len ); +typedef char *STBSP_SPRINTFCB(char *buf, void *user, int len); #ifndef STB_SPRINTF_DECORATE -#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names +#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names #endif -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintf )( char * buf, char const * fmt, va_list va ); -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ); -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( sprintf ) ( char * buf, char const * fmt, ... ); -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( snprintf )( char * buf, int count, char const * fmt, ... ); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...); -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ); -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE( set_separators )( char comma, char period ); +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); #endif // STB_SPRINTF_H_INCLUDE #ifdef STB_SPRINTF_IMPLEMENTATION -#include // for va_arg() +#include // for va_arg() #define stbsp__uint32 unsigned int #define stbsp__int32 signed int @@ -189,7 +189,7 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE( set_separators )( char comma, char p #endif #define stbsp__uint16 unsigned short -#ifndef stbsp__uintptr +#ifndef stbsp__uintptr #if defined(__ppc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) #define stbsp__uintptr stbsp__uint64 #else @@ -197,13 +197,13 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE( set_separators )( char comma, char p #endif #endif -#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) -#if defined(_MSC_VER) && (_MSC_VER<1900) +#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) +#if defined(_MSC_VER) && (_MSC_VER < 1900) #define STB_SPRINTF_MSVC_MODE #endif #endif -#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses +#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses #define STBSP__UNALIGNED(code) #else #define STBSP__UNALIGNED(code) code @@ -211,19 +211,21 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE( set_separators )( char comma, char p #ifndef STB_SPRINTF_NOFLOAT // internal float utility functions -static stbsp__int32 stbsp__real_to_str( char const * * start, stbsp__uint32 * len, char *out, stbsp__int32 * decimal_pos, double value, stbsp__uint32 frac_digits ); -static stbsp__int32 stbsp__real_to_parts( stbsp__int64 * bits, stbsp__int32 * expo, double value ); +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); #define STBSP__SPECIAL 0x7000 #endif -static char stbsp__period='.'; -static char stbsp__comma=','; -static char stbsp__digitpair[201]="00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"; +static char stbsp__period = '.'; +static char stbsp__comma = ','; +static char stbsp__digitpair[201] = + "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576" + "7778798081828384858687888990919293949596979899"; -STBSP__PUBLICDEF void STB_SPRINTF_DECORATE( set_separators )( char pcomma, char pperiod ) +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) { - stbsp__period=pperiod; - stbsp__comma=pcomma; + stbsp__period = pperiod; + stbsp__comma = pcomma; } #define STBSP__LEFTJUST 1 @@ -242,582 +244,1057 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE( set_separators )( char pcomma, char static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) { - sign[0] = 0; - if (fl&STBSP__NEGATIVE) { - sign[0]=1; - sign[1]='-'; - } else if (fl&STBSP__LEADINGSPACE) { - sign[0]=1; - sign[1]=' '; - } else if (fl&STBSP__LEADINGPLUS) { - sign[0]=1; - sign[1]='+'; - } + sign[0] = 0; + if (fl & STBSP__NEGATIVE) { + sign[0] = 1; + sign[1] = '-'; + } else if (fl & STBSP__LEADINGSPACE) { + sign[0] = 1; + sign[1] = ' '; + } else if (fl & STBSP__LEADINGPLUS) { + sign[0] = 1; + sign[1] = '+'; + } } - -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) { - static char hex[]="0123456789abcdefxp"; - static char hexu[]="0123456789ABCDEFXP"; - char * bf; - char const * f; - int tlen = 0; + static char hex[] = "0123456789abcdefxp"; + static char hexu[] = "0123456789ABCDEFXP"; + char *bf; + char const *f; + int tlen = 0; - bf = buf; - f = fmt; - for(;;) - { - stbsp__int32 fw,pr,tz; stbsp__uint32 fl; + bf = buf; + f = fmt; + for (;;) { + stbsp__int32 fw, pr, tz; + stbsp__uint32 fl; - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) { int len = (int)(bf-buf); if ((len+(bytes))>=STB_SPRINTF_MIN) { tlen+=len; if (0==(bf=buf=callback(buf,user,len))) goto done; } } - #define stbsp__chk_cb_buf(bytes) { if ( callback ) { stbsp__chk_cb_bufL(bytes); } } - #define stbsp__flush_cb() { stbsp__chk_cb_bufL(STB_SPRINTF_MIN-1); } //flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl,v) cl = v; if ( callback ) { int lg = STB_SPRINTF_MIN-(int)(bf-buf); if (cl>lg) cl=lg; } +// macros for the callback buffer stuff +#define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } +#define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } +#define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer +#define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } - // fast copy everything up to the next % (or end of string) - for(;;) - { - while (((stbsp__uintptr)f)&3) - { - schk1: if (f[0]=='%') goto scandd; - schk2: if (f[0]==0) goto endfmt; - stbsp__chk_cb_buf(1); *bf++=f[0]; ++f; - } - for(;;) - { - // Check if the next 4 bytes contain %(0x25) or end of string. - // Using the 'hasless' trick: - // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord - stbsp__uint32 v,c; - v=*(stbsp__uint32*)f; c=(~v)&0x80808080; - if (((v^0x25252525)-0x01010101)&c) goto schk1; - if ((v-0x01010101)&c) goto schk2; - if (callback) if ((STB_SPRINTF_MIN-(int)(bf-buf))<4) goto schk1; - *(stbsp__uint32*)bf=v; bf+=4; f+=4; + // fast copy everything up to the next % (or end of string) + for (;;) { + while (((stbsp__uintptr)f) & 3) { + schk1: + if (f[0] == '%') + goto scandd; + schk2: + if (f[0] == 0) + goto endfmt; + stbsp__chk_cb_buf(1); + *bf++ = f[0]; + ++f; + } + for (;;) { + // Check if the next 4 bytes contain %(0x25) or end of string. + // Using the 'hasless' trick: + // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + stbsp__uint32 v, c; + v = *(stbsp__uint32 *)f; + c = (~v) & 0x80808080; + if (((v ^ 0x25252525) - 0x01010101) & c) + goto schk1; + if ((v - 0x01010101) & c) + goto schk2; + if (callback) + if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) + goto schk1; + *(stbsp__uint32 *)bf = v; + bf += 4; + f += 4; + } } - } scandd: + scandd: - ++f; + ++f; - // ok, we have a percent, read the modifiers first - fw = 0; pr = -1; fl = 0; tz = 0; - - // flags - for(;;) - { - switch(f[0]) - { - // if we have left justify - case '-': fl|=STBSP__LEFTJUST; ++f; continue; - // if we have leading plus - case '+': fl|=STBSP__LEADINGPLUS; ++f; continue; - // if we have leading space - case ' ': fl|=STBSP__LEADINGSPACE; ++f; continue; - // if we have leading 0x - case '#': fl|=STBSP__LEADING_0X; ++f; continue; - // if we have thousand commas - case '\'': fl|=STBSP__TRIPLET_COMMA; ++f; continue; - // if we have kilo marker (none->kilo->kibi->jedec) - case '$': - if (fl&STBSP__METRIC_SUFFIX) - { - if (fl&STBSP__METRIC_1024) - { - fl|=STBSP__METRIC_JEDEC; - } - else - { - fl|=STBSP__METRIC_1024; - } + // ok, we have a percent, read the modifiers first + fw = 0; + pr = -1; + fl = 0; + tz = 0; + + // flags + for (;;) { + switch (f[0]) { + // if we have left justify + case '-': + fl |= STBSP__LEFTJUST; + ++f; + continue; + // if we have leading plus + case '+': + fl |= STBSP__LEADINGPLUS; + ++f; + continue; + // if we have leading space + case ' ': + fl |= STBSP__LEADINGSPACE; + ++f; + continue; + // if we have leading 0x + case '#': + fl |= STBSP__LEADING_0X; + ++f; + continue; + // if we have thousand commas + case '\'': + fl |= STBSP__TRIPLET_COMMA; + ++f; + continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { + fl |= STBSP__METRIC_JEDEC; + } else { + fl |= STBSP__METRIC_1024; + } + } else { + fl |= STBSP__METRIC_SUFFIX; } - else - { - fl|=STBSP__METRIC_SUFFIX; - } - ++f; continue; - // if we don't want space between metric suffix and number - case '_': fl|=STBSP__METRIC_NOSPACE; ++f; continue; - // if we have leading zero - case '0': fl|=STBSP__LEADINGZERO; ++f; goto flags_done; - default: goto flags_done; + ++f; + continue; + // if we don't want space between metric suffix and number + case '_': + fl |= STBSP__METRIC_NOSPACE; + ++f; + continue; + // if we have leading zero + case '0': + fl |= STBSP__LEADINGZERO; + ++f; + goto flags_done; + default: goto flags_done; + } } - } - flags_done: - - // get the field width - if ( f[0] == '*' ) {fw = va_arg(va,stbsp__uint32); ++f;} else { while (( f[0] >= '0' ) && ( f[0] <= '9' )) { fw = fw * 10 + f[0] - '0'; f++; } } - // get the precision - if ( f[0]=='.' ) { ++f; if ( f[0] == '*' ) {pr = va_arg(va,stbsp__uint32); ++f;} else { pr = 0; while (( f[0] >= '0' ) && ( f[0] <= '9' )) { pr = pr * 10 + f[0] - '0'; f++; } } } - - // handle integer size overrides - switch(f[0]) - { + flags_done: + + // get the field width + if (f[0] == '*') { + fw = va_arg(va, stbsp__uint32); + ++f; + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { + fw = fw * 10 + f[0] - '0'; + f++; + } + } + // get the precision + if (f[0] == '.') { + ++f; + if (f[0] == '*') { + pr = va_arg(va, stbsp__uint32); + ++f; + } else { + pr = 0; + while ((f[0] >= '0') && (f[0] <= '9')) { + pr = pr * 10 + f[0] - '0'; + f++; + } + } + } + + // handle integer size overrides + switch (f[0]) { // are we halfwidth? - case 'h': fl|=STBSP__HALFWIDTH; ++f; break; + case 'h': + fl |= STBSP__HALFWIDTH; + ++f; + break; // are we 64-bit (unix style) - case 'l': ++f; if ( f[0]=='l') { fl|=STBSP__INTMAX; ++f; } break; + case 'l': + ++f; + if (f[0] == 'l') { + fl |= STBSP__INTMAX; + ++f; + } + break; // are we 64-bit on intmax? (c99) - case 'j': fl|=STBSP__INTMAX; ++f; break; + case 'j': + fl |= STBSP__INTMAX; + ++f; + break; // are we 64-bit on size_t or ptrdiff_t? (c99) - case 'z': case 't': fl|=((sizeof(char*)==8)?STBSP__INTMAX:0); ++f; break; + case 'z': + case 't': + fl |= ((sizeof(char *) == 8) ? STBSP__INTMAX : 0); + ++f; + break; // are we 64-bit (msft style) - case 'I': if ( ( f[1]=='6') && ( f[2]=='4') ) { fl|=STBSP__INTMAX; f+=3; } - else if ( ( f[1]=='3') && ( f[2]=='2') ) { f+=3; } - else { fl|=((sizeof(void*)==8)?STBSP__INTMAX:0); ++f; } break; + case 'I': + if ((f[1] == '6') && (f[2] == '4')) { + fl |= STBSP__INTMAX; + f += 3; + } else if ((f[1] == '3') && (f[2] == '2')) { + f += 3; + } else { + fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); + ++f; + } + break; default: break; - } + } - // handle each replacement - switch( f[0] ) - { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 - char num[STBSP__NUMSZ]; - char lead[8]; - char tail[8]; - char *s; - char const *h; - stbsp__uint32 l,n,cs; - stbsp__uint64 n64; - #ifndef STB_SPRINTF_NOFLOAT - double fv; - #endif - stbsp__int32 dp; char const * sn; + // handle each replacement + switch (f[0]) { +#define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + char num[STBSP__NUMSZ]; + char lead[8]; + char tail[8]; + char *s; + char const *h; + stbsp__uint32 l, n, cs; + stbsp__uint64 n64; +#ifndef STB_SPRINTF_NOFLOAT + double fv; +#endif + stbsp__int32 dp; + char const *sn; case 's': - // get the string - s = va_arg(va,char*); if (s==0) s = (char*)"null"; - // get the length - sn = s; - for(;;) - { - if ((((stbsp__uintptr)sn)&3)==0) break; + // get the string + s = va_arg(va, char *); + if (s == 0) + s = (char *)"null"; + // get the length + sn = s; + for (;;) { + if ((((stbsp__uintptr)sn) & 3) == 0) + break; lchk: - if (sn[0]==0) goto ld; - ++sn; - } - n = 0xffffffff; - if (pr>=0) { n=(stbsp__uint32)(sn-s); if (n>=(stbsp__uint32)pr) goto ld; n=((stbsp__uint32)(pr-n))>>2; } - while(n) - { - stbsp__uint32 v=*(stbsp__uint32*)sn; - if ((v-0x01010101)&(~v)&0x80808080UL) goto lchk; - sn+=4; - --n; - } - goto lchk; - ld: + if (sn[0] == 0) + goto ld; + ++sn; + } + n = 0xffffffff; + if (pr >= 0) { + n = (stbsp__uint32)(sn - s); + if (n >= (stbsp__uint32)pr) + goto ld; + n = ((stbsp__uint32)(pr - n)) >> 2; + } + while (n) { + stbsp__uint32 v = *(stbsp__uint32 *)sn; + if ((v - 0x01010101) & (~v) & 0x80808080UL) + goto lchk; + sn += 4; + --n; + } + goto lchk; + ld: - l = (stbsp__uint32) ( sn - s ); - // clamp to precision - if ( l > (stbsp__uint32)pr ) l = pr; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - // copy the string in - goto scopy; + l = (stbsp__uint32)(sn - s); + // clamp to precision + if (l > (stbsp__uint32)pr) + l = pr; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + // copy the string in + goto scopy; case 'c': // char - // get the character - s = num + STBSP__NUMSZ -1; *s = (char)va_arg(va,int); - l = 1; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - goto scopy; + // get the character + s = num + STBSP__NUMSZ - 1; + *s = (char)va_arg(va, int); + l = 1; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; case 'n': // weird write-bytes specifier - { int * d = va_arg(va,int*); - *d = tlen + (int)( bf - buf ); } - break; + { + int *d = va_arg(va, int *); + *d = tlen + (int)(bf - buf); + } break; #ifdef STB_SPRINTF_NOFLOAT - case 'A': // float - case 'a': // hex float - case 'G': // float - case 'g': // float - case 'E': // float - case 'e': // float - case 'f': // float - va_arg(va,double); // eat it - s = (char*)"No float"; - l = 8; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - goto scopy; + case 'A': // float + case 'a': // hex float + case 'G': // float + case 'g': // float + case 'E': // float + case 'e': // float + case 'f': // float + va_arg(va, double); // eat it + s = (char *)"No float"; + l = 8; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; #else case 'A': // float - h=hexu; - goto hexfloat; + h = hexu; + goto hexfloat; case 'a': // hex float - h=hex; - hexfloat: - fv = va_arg(va,double); - if (pr==-1) pr=6; // default is 6 - // read the double into a string - if ( stbsp__real_to_parts( (stbsp__int64*)&n64, &dp, fv ) ) - fl |= STBSP__NEGATIVE; - - s = num+64; + h = hex; + hexfloat: + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) + fl |= STBSP__NEGATIVE; - stbsp__lead_sign(fl, lead); + s = num + 64; - if (dp==-1023) dp=(n64)?-1022:0; else n64|=(((stbsp__uint64)1)<<52); - n64<<=(64-56); - if (pr<15) n64+=((((stbsp__uint64)8)<<56)>>(pr*4)); - // add leading chars - - #ifdef STB_SPRINTF_MSVC_MODE - *s++='0';*s++='x'; - #else - lead[1+lead[0]]='0'; lead[2+lead[0]]='x'; lead[0]+=2; - #endif - *s++=h[(n64>>60)&15]; n64<<=4; - if ( pr ) *s++=stbsp__period; - sn = s; + stbsp__lead_sign(fl, lead); - // print the bits - n = pr; if (n>13) n = 13; if (pr>(stbsp__int32)n) tz=pr-n; pr = 0; - while(n--) { *s++=h[(n64>>60)&15]; n64<<=4; } + if (dp == -1023) + dp = (n64) ? -1022 : 0; + else + n64 |= (((stbsp__uint64)1) << 52); + n64 <<= (64 - 56); + if (pr < 15) + n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); +// add leading chars - // print the expo - tail[1]=h[17]; - if (dp<0) { tail[2]='-'; dp=-dp;} else tail[2]='+'; - n = (dp>=1000)?6:((dp>=100)?5:((dp>=10)?4:3)); - tail[0]=(char)n; - for(;;) { tail[n]='0'+dp%10; if (n<=3) break; --n; dp/=10; } +#ifdef STB_SPRINTF_MSVC_MODE + *s++ = '0'; + *s++ = 'x'; +#else + lead[1 + lead[0]] = '0'; + lead[2 + lead[0]] = 'x'; + lead[0] += 2; +#endif + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + if (pr) + *s++ = stbsp__period; + sn = s; - dp = (int)(s-sn); - l = (int)(s-(num+64)); - s = num+64; - cs = 1 + (3<<24); - goto scopy; + // print the bits + n = pr; + if (n > 13) + n = 13; + if (pr > (stbsp__int32)n) + tz = pr - n; + pr = 0; + while (n--) { + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + } + + // print the expo + tail[1] = h[17]; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; + n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + + dp = (int)(s - sn); + l = (int)(s - (num + 64)); + s = num + 64; + cs = 1 + (3 << 24); + goto scopy; case 'G': // float - h=hexu; - goto dosmallfloat; + h = hexu; + goto dosmallfloat; case 'g': // float - h=hex; - dosmallfloat: - fv = va_arg(va,double); - if (pr==-1) pr=6; else if (pr==0) pr = 1; // default is 6 - // read the double into a string - if ( stbsp__real_to_str( &sn, &l, num, &dp, fv, (pr-1)|0x80000000 ) ) - fl |= STBSP__NEGATIVE; + h = hex; + dosmallfloat: + fv = va_arg(va, double); + if (pr == -1) + pr = 6; + else if (pr == 0) + pr = 1; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) + fl |= STBSP__NEGATIVE; - // clamp the precision and delete extra zeros after clamp - n = pr; - if ( l > (stbsp__uint32)pr ) l = pr; while ((l>1)&&(pr)&&(sn[l-1]=='0')) { --pr; --l; } + // clamp the precision and delete extra zeros after clamp + n = pr; + if (l > (stbsp__uint32)pr) + l = pr; + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + --pr; + --l; + } - // should we use %e - if ((dp<=-4)||(dp>(stbsp__int32)n)) - { - if ( pr > (stbsp__int32)l ) pr = l-1; else if ( pr ) --pr; // when using %e, there is one digit before the decimal - goto doexpfromg; - } - // this is the insane action to get the pr to match %g sematics for %f - if(dp>0) { pr=(dp<(stbsp__int32)l)?l-dp:0; } else { pr = -dp+((pr>(stbsp__int32)l)?l:pr); } - goto dofloatfromg; + // should we use %e + if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if (pr > (stbsp__int32)l) + pr = l - 1; + else if (pr) + --pr; // when using %e, there is one digit before the decimal + goto doexpfromg; + } + // this is the insane action to get the pr to match %g sematics for %f + if (dp > 0) { + pr = (dp < (stbsp__int32)l) ? l - dp : 0; + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? l : pr); + } + goto dofloatfromg; case 'E': // float - h=hexu; - goto doexp; + h = hexu; + goto doexp; case 'e': // float - h=hex; - doexp: - fv = va_arg(va,double); - if (pr==-1) pr=6; // default is 6 - // read the double into a string - if ( stbsp__real_to_str( &sn, &l, num, &dp, fv, pr|0x80000000 ) ) - fl |= STBSP__NEGATIVE; - doexpfromg: - tail[0]=0; - stbsp__lead_sign(fl, lead); - if ( dp == STBSP__SPECIAL ) { s=(char*)sn; cs=0; pr=0; goto scopy; } - s=num+64; - // handle leading chars - *s++=sn[0]; + h = hex; + doexp: + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) + fl |= STBSP__NEGATIVE; + doexpfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + // handle leading chars + *s++ = sn[0]; - if (pr) *s++=stbsp__period; + if (pr) + *s++ = stbsp__period; - // handle after decimal - if ((l-1)>(stbsp__uint32)pr) l=pr+1; - for(n=1;n=100)?5:4; - #endif - tail[0]=(char)n; - for(;;) { tail[n]='0'+dp%10; if (n<=3) break; --n; dp/=10; } - cs = 1 + (3<<24); // how many tens - goto flt_lead; + // handle after decimal + if ((l - 1) > (stbsp__uint32)pr) + l = pr + 1; + for (n = 1; n < l; n++) + *s++ = sn[n]; + // trailing zeros + tz = pr - (l - 1); + pr = 0; + // dump expo + tail[1] = h[0xe]; + dp -= 1; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; +#ifdef STB_SPRINTF_MSVC_MODE + n = 5; +#else + n = (dp >= 100) ? 5 : 4; +#endif + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + cs = 1 + (3 << 24); // how many tens + goto flt_lead; case 'f': // float - fv = va_arg(va,double); - doafloat: - // do kilos - if (fl&STBSP__METRIC_SUFFIX) - { + fv = va_arg(va, double); + doafloat: + // do kilos + if (fl & STBSP__METRIC_SUFFIX) { double divisor; - divisor=1000.0f; - if (fl&STBSP__METRIC_1024) divisor = 1024.0; - while(fl<0x4000000) { if ((fv-divisor)) break; fv/=divisor; fl+=0x1000000; } - } - if (pr==-1) pr=6; // default is 6 - // read the double into a string - if ( stbsp__real_to_str( &sn, &l, num, &dp, fv, pr ) ) - fl |= STBSP__NEGATIVE; - dofloatfromg: - tail[0]=0; - stbsp__lead_sign(fl, lead); - if ( dp == STBSP__SPECIAL ) { s=(char*)sn; cs=0; pr=0; goto scopy; } - s=num+64; - - // handle the three decimal varieties - if (dp<=0) - { - stbsp__int32 i; - // handle 0.000*000xxxx - *s++='0'; if (pr) *s++=stbsp__period; - n=-dp; if((stbsp__int32)n>pr) n=pr; i=n; while(i) { if ((((stbsp__uintptr)s)&3)==0) break; *s++='0'; --i; } while(i>=4) { *(stbsp__uint32*)s=0x30303030; s+=4; i-=4; } while(i) { *s++='0'; --i; } - if ((stbsp__int32)(l+n)>pr) l=pr-n; i=l; while(i) { *s++=*sn++; --i; } - tz = pr-(n+l); - cs = 1 + (3<<24); // how many tens did we write (for commas below) - } - else - { - cs = (fl&STBSP__TRIPLET_COMMA)?((600-(stbsp__uint32)dp)%3):0; - if ((stbsp__uint32)dp>=l) - { - // handle xxxx000*000.0 - n=0; for(;;) { if ((fl&STBSP__TRIPLET_COMMA) && (++cs==4)) { cs = 0; *s++=stbsp__comma; } else { *s++=sn[n]; ++n; if (n>=l) break; } } - if (n<(stbsp__uint32)dp) - { - n = dp - n; - if ((fl&STBSP__TRIPLET_COMMA)==0) { while(n) { if ((((stbsp__uintptr)s)&3)==0) break; *s++='0'; --n; } while(n>=4) { *(stbsp__uint32*)s=0x30303030; s+=4; n-=4; } } - while(n) { if ((fl&STBSP__TRIPLET_COMMA) && (++cs==4)) { cs = 0; *s++=stbsp__comma; } else { *s++='0'; --n; } } + divisor = 1000.0f; + if (fl & STBSP__METRIC_1024) + divisor = 1024.0; + while (fl < 0x4000000) { + if ((fv < divisor) && (fv > -divisor)) + break; + fv /= divisor; + fl += 0x1000000; } - cs = (int)(s-(num+64)) + (3<<24); // cs is how many tens - if (pr) { *s++=stbsp__period; tz=pr;} - } - else - { - // handle xxxxx.xxxx000*000 - n=0; for(;;) { if ((fl&STBSP__TRIPLET_COMMA) && (++cs==4)) { cs = 0; *s++=stbsp__comma; } else { *s++=sn[n]; ++n; if (n>=(stbsp__uint32)dp) break; } } - cs = (int)(s-(num+64)) + (3<<24); // cs is how many tens - if (pr) *s++=stbsp__period; - if ((l-dp)>(stbsp__uint32)pr) l=pr+dp; - while(n>24) - { // SI kilo is 'k', JEDEC and SI kibits are 'K'. - if (fl&STBSP__METRIC_1024) - tail[idx+1]="_KMGT"[fl>>24]; - else - tail[idx+1]="_kMGT"[fl>>24]; - idx++; - // If printing kibits and not in jedec, add the 'i'. - if (fl&STBSP__METRIC_1024&&!(fl&STBSP__METRIC_JEDEC)) - { - tail[idx+1]='i'; - idx++; - } - tail[0]=idx; - } - } - }; + } + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) + fl |= STBSP__NEGATIVE; + dofloatfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; - flt_lead: - // get the length that we copied - l = (stbsp__uint32) ( s-(num+64) ); - s=num+64; - goto scopy; + // handle the three decimal varieties + if (dp <= 0) { + stbsp__int32 i; + // handle 0.000*000xxxx + *s++ = '0'; + if (pr) + *s++ = stbsp__period; + n = -dp; + if ((stbsp__int32)n > pr) + n = pr; + i = n; + while (i) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + i -= 4; + } + while (i) { + *s++ = '0'; + --i; + } + if ((stbsp__int32)(l + n) > pr) + l = pr - n; + i = l; + while (i) { + *s++ = *sn++; + --i; + } + tz = pr - (n + l); + cs = 1 + (3 << 24); // how many tens did we write (for commas below) + } else { + cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; + if ((stbsp__uint32)dp >= l) { + // handle xxxx000*000.0 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= l) + break; + } + } + if (n < (stbsp__uint32)dp) { + n = dp - n; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --n; + } + while (n >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + n -= 4; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = '0'; + --n; + } + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) { + *s++ = stbsp__period; + tz = pr; + } + } else { + // handle xxxxx.xxxx000*000 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= (stbsp__uint32)dp) + break; + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) + *s++ = stbsp__period; + if ((l - dp) > (stbsp__uint32)pr) + l = pr + dp; + while (n < l) { + *s++ = sn[n]; + ++n; + } + tz = pr - (l - dp); + } + } + pr = 0; + + // handle k,m,g,t + if (fl & STBSP__METRIC_SUFFIX) { + char idx; + idx = 1; + if (fl & STBSP__METRIC_NOSPACE) + idx = 0; + tail[0] = idx; + tail[1] = ' '; + { + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl & STBSP__METRIC_1024) + tail[idx + 1] = "_KMGT"[fl >> 24]; + else + tail[idx + 1] = "_kMGT"[fl >> 24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + tail[idx + 1] = 'i'; + idx++; + } + tail[0] = idx; + } + } + }; + + flt_lead: + // get the length that we copied + l = (stbsp__uint32)(s - (num + 64)); + s = num + 64; + goto scopy; #endif case 'B': // upper binary - h = hexu; - goto binary; + h = hexu; + goto binary; case 'b': // lower binary - h = hex; - binary: - lead[0]=0; - if (fl&STBSP__LEADING_0X) { lead[0]=2;lead[1]='0';lead[2]=h[0xb]; } - l=(8<<4)|(1<<8); - goto radixnum; + h = hex; + binary: + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[0xb]; + } + l = (8 << 4) | (1 << 8); + goto radixnum; case 'o': // octal - h = hexu; - lead[0]=0; - if (fl&STBSP__LEADING_0X) { lead[0]=1;lead[1]='0'; } - l=(3<<4)|(3<<8); - goto radixnum; + h = hexu; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 1; + lead[1] = '0'; + } + l = (3 << 4) | (3 << 8); + goto radixnum; case 'p': // pointer - fl |= (sizeof(void*)==8)?STBSP__INTMAX:0; - pr = sizeof(void*)*2; - fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // drop through to X - + fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; + pr = sizeof(void *) * 2; + fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros + // drop through to X + case 'X': // upper binary - h = hexu; - goto dohexb; + h = hexu; + goto dohexb; case 'x': // lower binary - h = hex; dohexb: - l=(4<<4)|(4<<8); - lead[0]=0; - if (fl&STBSP__LEADING_0X) { lead[0]=2;lead[1]='0';lead[2]=h[16]; } - radixnum: - // get the number - if ( fl&STBSP__INTMAX ) - n64 = va_arg(va,stbsp__uint64); - else - n64 = va_arg(va,stbsp__uint32); + h = hex; + dohexb: + l = (4 << 4) | (4 << 8); + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[16]; + } + radixnum: + // get the number + if (fl & STBSP__INTMAX) + n64 = va_arg(va, stbsp__uint64); + else + n64 = va_arg(va, stbsp__uint32); - s = num + STBSP__NUMSZ; dp = 0; - // clear tail, and clear leading if value is zero - tail[0]=0; if (n64==0) { lead[0]=0; if (pr==0) { l=0; cs = ( ((l>>4)&15)) << 24; goto scopy; } } - // convert to string - for(;;) { *--s = h[n64&((1<<(l>>8))-1)]; n64>>=(l>>8); if ( ! ( (n64) || ((stbsp__int32) ( (num+STBSP__NUMSZ) - s ) < pr ) ) ) break; if ( fl&STBSP__TRIPLET_COMMA) { ++l; if ((l&15)==((l>>4)&15)) { l&=~15; *--s=stbsp__comma; } } }; - // get the tens and the comma pos - cs = (stbsp__uint32) ( (num+STBSP__NUMSZ) - s ) + ( ( ((l>>4)&15)) << 24 ); - // get the length that we copied - l = (stbsp__uint32) ( (num+STBSP__NUMSZ) - s ); - // copy it - goto scopy; + s = num + STBSP__NUMSZ; + dp = 0; + // clear tail, and clear leading if value is zero + tail[0] = 0; + if (n64 == 0) { + lead[0] = 0; + if (pr == 0) { + l = 0; + cs = (((l >> 4) & 15)) << 24; + goto scopy; + } + } + // convert to string + for (;;) { + *--s = h[n64 & ((1 << (l >> 8)) - 1)]; + n64 >>= (l >> 8); + if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) + break; + if (fl & STBSP__TRIPLET_COMMA) { + ++l; + if ((l & 15) == ((l >> 4) & 15)) { + l &= ~15; + *--s = stbsp__comma; + } + } + }; + // get the tens and the comma pos + cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + // copy it + goto scopy; case 'u': // unsigned case 'i': case 'd': // integer - // get the integer and abs it - if ( fl&STBSP__INTMAX ) - { - stbsp__int64 i64 = va_arg(va,stbsp__int64); n64 = (stbsp__uint64)i64; if ((f[0]!='u') && (i64<0)) { n64=(stbsp__uint64)-i64; fl|=STBSP__NEGATIVE; } - } - else - { - stbsp__int32 i = va_arg(va,stbsp__int32); n64 = (stbsp__uint32)i; if ((f[0]!='u') && (i<0)) { n64=(stbsp__uint32)-i; fl|=STBSP__NEGATIVE; } - } + // get the integer and abs it + if (fl & STBSP__INTMAX) { + stbsp__int64 i64 = va_arg(va, stbsp__int64); + n64 = (stbsp__uint64)i64; + if ((f[0] != 'u') && (i64 < 0)) { + n64 = (stbsp__uint64)-i64; + fl |= STBSP__NEGATIVE; + } + } else { + stbsp__int32 i = va_arg(va, stbsp__int32); + n64 = (stbsp__uint32)i; + if ((f[0] != 'u') && (i < 0)) { + n64 = (stbsp__uint32)-i; + fl |= STBSP__NEGATIVE; + } + } - #ifndef STB_SPRINTF_NOFLOAT - if (fl&STBSP__METRIC_SUFFIX) { if (n64<1024) pr=0; else if (pr==-1) pr=1; fv=(double)(stbsp__int64)n64; goto doafloat; } - #endif +#ifndef STB_SPRINTF_NOFLOAT + if (fl & STBSP__METRIC_SUFFIX) { + if (n64 < 1024) + pr = 0; + else if (pr == -1) + pr = 1; + fv = (double)(stbsp__int64)n64; + goto doafloat; + } +#endif - // convert to string - s = num+STBSP__NUMSZ; l=0; - - for(;;) - { - // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) - char * o=s-8; - if (n64>=100000000) { n = (stbsp__uint32)( n64 % 100000000); n64 /= 100000000; } else {n = (stbsp__uint32)n64; n64 = 0; } - if((fl&STBSP__TRIPLET_COMMA)==0) { while(n) { s-=2; *(stbsp__uint16*)s=*(stbsp__uint16*)&stbsp__digitpair[(n%100)*2]; n/=100; } } - while (n) { if ( ( fl&STBSP__TRIPLET_COMMA) && (l++==3) ) { l=0; *--s=stbsp__comma; --o; } else { *--s=(char)(n%10)+'0'; n/=10; } } - if (n64==0) { if ((s[0]=='0') && (s!=(num+STBSP__NUMSZ))) ++s; break; } - while (s!=o) if ( ( fl&STBSP__TRIPLET_COMMA) && (l++==3) ) { l=0; *--s=stbsp__comma; --o; } else { *--s='0'; } - } + // convert to string + s = num + STBSP__NUMSZ; + l = 0; - tail[0]=0; - stbsp__lead_sign(fl, lead); + for (;;) { + // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) + char *o = s - 8; + if (n64 >= 100000000) { + n = (stbsp__uint32)(n64 % 100000000); + n64 /= 100000000; + } else { + n = (stbsp__uint32)n64; + n64 = 0; + } + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + s -= 2; + *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; + n /= 100; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = (char)(n % 10) + '0'; + n /= 10; + } + } + if (n64 == 0) { + if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) + ++s; + break; + } + while (s != o) + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = '0'; + } + } - // get the length that we copied - l = (stbsp__uint32) ( (num+STBSP__NUMSZ) - s ); if ( l == 0 ) { *--s='0'; l = 1; } - cs = l + (3<<24); - if (pr<0) pr = 0; + tail[0] = 0; + stbsp__lead_sign(fl, lead); - scopy: - // get fw=leading/trailing space, pr=leading zeros - if (pr<(stbsp__int32)l) pr = l; - n = pr + lead[0] + tail[0] + tz; - if (fw<(stbsp__int32)n) fw = n; - fw -= n; - pr -= l; + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + if (l == 0) { + *--s = '0'; + l = 1; + } + cs = l + (3 << 24); + if (pr < 0) + pr = 0; - // handle right justify and leading zeros - if ( (fl&STBSP__LEFTJUST)==0 ) - { - if (fl&STBSP__LEADINGZERO) // if leading zeros, everything is in pr - { - pr = (fw>pr)?fw:pr; - fw = 0; - } - else - { - fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas - } - } + scopy: + // get fw=leading/trailing space, pr=leading zeros + if (pr < (stbsp__int32)l) + pr = l; + n = pr + lead[0] + tail[0] + tz; + if (fw < (stbsp__int32)n) + fw = n; + fw -= n; + pr -= l; - // copy the spaces and/or zeros - if (fw+pr) - { - stbsp__int32 i; stbsp__uint32 c; + // handle right justify and leading zeros + if ((fl & STBSP__LEFTJUST) == 0) { + if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr + { + pr = (fw > pr) ? fw : pr; + fw = 0; + } else { + fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas + } + } - // copy leading spaces (or when doing %8.4d stuff) - if ( (fl&STBSP__LEFTJUST)==0 ) while(fw>0) { stbsp__cb_buf_clamp(i,fw); fw -= i; while(i) { if ((((stbsp__uintptr)bf)&3)==0) break; *bf++=' '; --i; } while(i>=4) { *(stbsp__uint32*)bf=0x20202020; bf+=4; i-=4; } while (i) {*bf++=' '; --i;} stbsp__chk_cb_buf(1); } - - // copy leader - sn=lead+1; while(lead[0]) { stbsp__cb_buf_clamp(i,lead[0]); lead[0] -= (char)i; while (i) {*bf++=*sn++; --i;} stbsp__chk_cb_buf(1); } - - // copy leading zeros - c = cs >> 24; cs &= 0xffffff; - cs = (fl&STBSP__TRIPLET_COMMA)?((stbsp__uint32)(c-((pr+cs)%(c+1)))):0; - while(pr>0) { stbsp__cb_buf_clamp(i,pr); pr -= i; if((fl&STBSP__TRIPLET_COMMA)==0) { while(i) { if ((((stbsp__uintptr)bf)&3)==0) break; *bf++='0'; --i; } while(i>=4) { *(stbsp__uint32*)bf=0x30303030; bf+=4; i-=4; } } while (i) { if((fl&STBSP__TRIPLET_COMMA) && (cs++==c)) { cs = 0; *bf++=stbsp__comma; } else *bf++='0'; --i; } stbsp__chk_cb_buf(1); } - } + // copy the spaces and/or zeros + if (fw + pr) { + stbsp__int32 i; + stbsp__uint32 c; - // copy leader if there is still one - sn=lead+1; while(lead[0]) { stbsp__int32 i; stbsp__cb_buf_clamp(i,lead[0]); lead[0] -= (char)i; while (i) {*bf++=*sn++; --i;} stbsp__chk_cb_buf(1); } + // copy leading spaces (or when doing %8.4d stuff) + if ((fl & STBSP__LEFTJUST) == 0) + while (fw > 0) { + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = ' '; + --i; + } + stbsp__chk_cb_buf(1); + } - // copy the string - n = l; while (n) { stbsp__int32 i; stbsp__cb_buf_clamp(i,n); n-=i; STBSP__UNALIGNED( while(i>=4) { *(stbsp__uint32*)bf=*(stbsp__uint32*)s; bf+=4; s+=4; i-=4; } ) while (i) {*bf++=*s++; --i;} stbsp__chk_cb_buf(1); } + // copy leader + sn = lead + 1; + while (lead[0]) { + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } - // copy trailing zeros - while(tz) { stbsp__int32 i; stbsp__cb_buf_clamp(i,tz); tz -= i; while(i) { if ((((stbsp__uintptr)bf)&3)==0) break; *bf++='0'; --i; } while(i>=4) { *(stbsp__uint32*)bf=0x30303030; bf+=4; i-=4; } while (i) {*bf++='0'; --i;} stbsp__chk_cb_buf(1); } + // copy leading zeros + c = cs >> 24; + cs &= 0xffffff; + cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; + while (pr > 0) { + stbsp__cb_buf_clamp(i, pr); + pr -= i; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + } + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + cs = 0; + *bf++ = stbsp__comma; + } else + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + } - // copy tail if there is one - sn=tail+1; while(tail[0]) { stbsp__int32 i; stbsp__cb_buf_clamp(i,tail[0]); tail[0] -= (char)i; while (i) {*bf++=*sn++; --i;} stbsp__chk_cb_buf(1); } + // copy leader if there is still one + sn = lead + 1; + while (lead[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } - // handle the left justify - if (fl&STBSP__LEFTJUST) if (fw>0) { while (fw) { stbsp__int32 i; stbsp__cb_buf_clamp(i,fw); fw-=i; while(i) { if ((((stbsp__uintptr)bf)&3)==0) break; *bf++=' '; --i; } while(i>=4) { *(stbsp__uint32*)bf=0x20202020; bf+=4; i-=4; } while (i--) *bf++=' '; stbsp__chk_cb_buf(1); } } - break; + // copy the string + n = l; + while (n) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, n); + n -= i; + STBSP__UNALIGNED(while (i >= 4) { + *(stbsp__uint32 *)bf = *(stbsp__uint32 *)s; + bf += 4; + s += 4; + i -= 4; + }) + while (i) { + *bf++ = *s++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy trailing zeros + while (tz) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tz); + tz -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy tail if there is one + sn = tail + 1; + while (tail[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tail[0]); + tail[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // handle the left justify + if (fl & STBSP__LEFTJUST) + if (fw > 0) { + while (fw) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i--) + *bf++ = ' '; + stbsp__chk_cb_buf(1); + } + } + break; default: // unknown, just copy code - s = num + STBSP__NUMSZ -1; *s = f[0]; - l = 1; - fw=pr=fl=0; - lead[0]=0; tail[0]=0; pr = 0; dp = 0; cs = 0; - goto scopy; - } - ++f; - } - endfmt: + s = num + STBSP__NUMSZ - 1; + *s = f[0]; + l = 1; + fw = pr = fl = 0; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + } + ++f; + } +endfmt: - if (!callback) - *bf = 0; - else - stbsp__flush_cb(); - - done: - return tlen + (int)(bf-buf); + if (!callback) + *bf = 0; + else + stbsp__flush_cb(); + +done: + return tlen + (int)(bf - buf); } // cleanup @@ -839,82 +1316,85 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintfcb )( STBSP_SPRINTFCB * callb // ============================================================================ // wrapper functions -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( sprintf )( char * buf, char const * fmt, ... ) +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) { - int result; - va_list va; - va_start( va, fmt ); - result = STB_SPRINTF_DECORATE( vsprintfcb )( 0, 0, buf, fmt, va ); - va_end(va); - return result; + int result; + va_list va; + va_start(va, fmt); + result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); + va_end(va); + return result; } -typedef struct stbsp__context -{ - char * buf; - int count; - char tmp[ STB_SPRINTF_MIN ]; +typedef struct stbsp__context { + char *buf; + int count; + char tmp[STB_SPRINTF_MIN]; } stbsp__context; -static char * stbsp__clamp_callback( char * buf, void * user, int len ) +static char *stbsp__clamp_callback(char *buf, void *user, int len) { - stbsp__context * c = (stbsp__context*)user; + stbsp__context *c = (stbsp__context *)user; - if ( len > c->count ) len = c->count; + if (len > c->count) + len = c->count; - if (len) - { - if ( buf != c->buf ) - { - char * s, * d, * se; - d = c->buf; s = buf; se = buf+len; - do{ *d++ = *s++; } while (sbuf += len; - c->count -= len; - } - - if ( c->count <= 0 ) return 0; - return ( c->count >= STB_SPRINTF_MIN ) ? c->buf : c->tmp; // go direct into buffer if you can + if (len) { + if (buf != c->buf) { + char *s, *d, *se; + d = c->buf; + s = buf; + se = buf + len; + do { + *d++ = *s++; + } while (s < se); + } + c->buf += len; + c->count -= len; + } + + if (c->count <= 0) + return 0; + return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can } -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va) { - stbsp__context c; - int l; + stbsp__context c; + int l; - if ( count == 0 ) - return 0; + if (count == 0) + return 0; - c.buf = buf; - c.count = count; + c.buf = buf; + c.count = count; - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); - - // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count - l = count - 1; - buf[l] = 0; + STB_SPRINTF_DECORATE(vsprintfcb)(stbsp__clamp_callback, &c, stbsp__clamp_callback(0, &c, 0), fmt, va); - return l; + // zero-terminate + l = (int)(c.buf - buf); + if (l >= count) // should never be greater, only equal (or less) than count + l = count - 1; + buf[l] = 0; + + return l; } -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( snprintf )( char * buf, int count, char const * fmt, ... ) +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) { - int result; - va_list va; - va_start( va, fmt ); + int result; + va_list va; + va_start(va, fmt); - result = STB_SPRINTF_DECORATE( vsnprintf )( buf, count, fmt, va ); - va_end(va); + result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); + va_end(va); - return result; + return result; } -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintf )( char * buf, char const * fmt, va_list va ) +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) { - return STB_SPRINTF_DECORATE( vsprintfcb )( 0, 0, buf, fmt, va ); + return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); } // ======================================================================= @@ -923,280 +1403,414 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsprintf )( char * buf, char const * #ifndef STB_SPRINTF_NOFLOAT // copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) -#define STBSP__COPYFP(dest,src) { int cn; for(cn=0;cn<8;cn++) ((char*)&dest)[cn]=((char*)&src)[cn]; } - +#define STBSP__COPYFP(dest, src) \ + { \ + int cn; \ + for (cn = 0; cn < 8; cn++) \ + ((char *)&dest)[cn] = ((char *)&src)[cn]; \ + } + // get float info -static stbsp__int32 stbsp__real_to_parts( stbsp__int64 * bits, stbsp__int32 * expo, double value ) +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) { - double d; - stbsp__int64 b = 0; + double d; + stbsp__int64 b = 0; - // load value and round at the frac_digits - d = value; + // load value and round at the frac_digits + d = value; - STBSP__COPYFP( b, d ); + STBSP__COPYFP(b, d); - *bits = b & ((((stbsp__uint64)1)<<52)-1); - *expo = (stbsp__int32) (((b >> 52) & 2047)-1023); - - return (stbsp__int32)(b >> 63); + *bits = b & ((((stbsp__uint64)1) << 52) - 1); + *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); + + return (stbsp__int32)(b >> 63); } -static double const stbsp__bot[23]={1e+000,1e+001,1e+002,1e+003,1e+004,1e+005,1e+006,1e+007,1e+008,1e+009,1e+010,1e+011,1e+012,1e+013,1e+014,1e+015,1e+016,1e+017,1e+018,1e+019,1e+020,1e+021,1e+022}; -static double const stbsp__negbot[22]={1e-001,1e-002,1e-003,1e-004,1e-005,1e-006,1e-007,1e-008,1e-009,1e-010,1e-011,1e-012,1e-013,1e-014,1e-015,1e-016,1e-017,1e-018,1e-019,1e-020,1e-021,1e-022}; -static double const stbsp__negboterr[22]={-5.551115123125783e-018,-2.0816681711721684e-019,-2.0816681711721686e-020,-4.7921736023859299e-021,-8.1803053914031305e-022,4.5251888174113741e-023,4.5251888174113739e-024,-2.0922560830128471e-025,-6.2281591457779853e-026,-3.6432197315497743e-027,6.0503030718060191e-028,2.0113352370744385e-029,-3.0373745563400371e-030,1.1806906454401013e-032,-7.7705399876661076e-032,2.0902213275965398e-033,-7.1542424054621921e-034,-7.1542424054621926e-035,2.4754073164739869e-036,5.4846728545790429e-037,9.2462547772103625e-038,-4.8596774326570872e-039}; -static double const stbsp__top[13]={1e+023,1e+046,1e+069,1e+092,1e+115,1e+138,1e+161,1e+184,1e+207,1e+230,1e+253,1e+276,1e+299}; -static double const stbsp__negtop[13]={1e-023,1e-046,1e-069,1e-092,1e-115,1e-138,1e-161,1e-184,1e-207,1e-230,1e-253,1e-276,1e-299}; -static double const stbsp__toperr[13]={8388608,6.8601809640529717e+028,-7.253143638152921e+052,-4.3377296974619174e+075,-1.5559416129466825e+098,-3.2841562489204913e+121,-3.7745893248228135e+144,-1.7356668416969134e+167,-3.8893577551088374e+190,-9.9566444326005119e+213,6.3641293062232429e+236,-5.2069140800249813e+259,-5.2504760255204387e+282}; -static double const stbsp__negtoperr[13]={3.9565301985100693e-040,-2.299904345391321e-063,3.6506201437945798e-086,1.1875228833981544e-109,-5.0644902316928607e-132,-6.7156837247865426e-155,-2.812077463003139e-178,-5.7778912386589953e-201,7.4997100559334532e-224,-4.6439668915134491e-247,-6.3691100762962136e-270,-9.436808465446358e-293,8.0970921678014997e-317}; +static double const stbsp__bot[23] = {1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022}; +static double const stbsp__negbot[22] = {1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022}; +static double const stbsp__negboterr[22] = { + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039}; +static double const stbsp__top[13] = {1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299}; +static double const stbsp__negtop[13] = {1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299}; +static double const stbsp__toperr[13] = {8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282}; +static double const stbsp__negtoperr[13] = {3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317}; -#if defined(_MSC_VER) && (_MSC_VER<=1200) -static stbsp__uint64 const stbsp__powten[20]={1,10,100,1000, 10000,100000,1000000,10000000, 100000000,1000000000,10000000000,100000000000, 1000000000000,10000000000000,100000000000000,1000000000000000, 10000000000000000,100000000000000000,1000000000000000000,10000000000000000000U }; +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +static stbsp__uint64 const stbsp__powten[20] = {1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U}; #define stbsp__tento19th ((stbsp__uint64)1000000000000000000) #else -static stbsp__uint64 const stbsp__powten[20]={1,10,100,1000, 10000,100000,1000000,10000000, 100000000,1000000000,10000000000ULL,100000000000ULL, 1000000000000ULL,10000000000000ULL,100000000000000ULL,1000000000000000ULL, 10000000000000000ULL,100000000000000000ULL,1000000000000000000ULL,10000000000000000000ULL }; +static stbsp__uint64 const stbsp__powten[20] = {1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL}; #define stbsp__tento19th (1000000000000000000ULL) #endif -#define stbsp__ddmulthi(oh,ol,xh,yh) \ -{ \ - double ahi=0,alo,bhi=0,blo; \ - stbsp__int64 bt; \ - oh = xh * yh; \ - STBSP__COPYFP(bt,xh); bt&=((~(stbsp__uint64)0)<<27); STBSP__COPYFP(ahi,bt); alo = xh-ahi; \ - STBSP__COPYFP(bt,yh); bt&=((~(stbsp__uint64)0)<<27); STBSP__COPYFP(bhi,bt); blo = yh-bhi; \ - ol = ((ahi*bhi-oh)+ahi*blo+alo*bhi)+alo*blo; \ +#define stbsp__ddmulthi(oh, ol, xh, yh) \ + \ +{ \ + double ahi = 0, alo, bhi = 0, blo; \ + stbsp__int64 bt; \ + oh = xh * yh; \ + STBSP__COPYFP(bt, xh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(ahi, bt); \ + alo = xh - ahi; \ + STBSP__COPYFP(bt, yh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(bhi, bt); \ + blo = yh - bhi; \ + ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ + \ } -#define stbsp__ddtoS64(ob,xh,xl) \ -{ \ - double ahi=0,alo,vh,t;\ - ob = (stbsp__int64)ph;\ - vh=(double)ob;\ - ahi = ( xh - vh );\ - t = ( ahi - xh );\ - alo = (xh-(ahi-t))-(vh+t);\ - ob += (stbsp__int64)(ahi+alo+xl);\ +#define stbsp__ddtoS64(ob, xh, xl) \ + \ +{ \ + double ahi = 0, alo, vh, t; \ + ob = (stbsp__int64)ph; \ + vh = (double)ob; \ + ahi = (xh - vh); \ + t = (ahi - xh); \ + alo = (xh - (ahi - t)) - (vh + t); \ + ob += (stbsp__int64)(ahi + alo + xl); \ + \ } +#define stbsp__ddrenorm(oh, ol) \ + { \ + double s; \ + s = oh + ol; \ + ol = ol - (s - oh); \ + oh = s; \ + } -#define stbsp__ddrenorm(oh,ol) { double s; s=oh+ol; ol=ol-(s-oh); oh=s; } +#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); -#define stbsp__ddmultlo(oh,ol,xh,xl,yh,yl) \ - ol = ol + ( xh*yl + xl*yh ); \ +#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); -#define stbsp__ddmultlos(oh,ol,xh,yl) \ - ol = ol + ( xh*yl ); \ - -static void stbsp__raise_to_power10( double *ohi, double *olo, double d, stbsp__int32 power ) // power can be -323 to +350 +static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 { - double ph, pl; - if ((power>=0) && (power<=22)) - { - stbsp__ddmulthi(ph,pl,d,stbsp__bot[power]); - } - else - { - stbsp__int32 e,et,eb; - double p2h,p2l; + double ph, pl; + if ((power >= 0) && (power <= 22)) { + stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); + } else { + stbsp__int32 e, et, eb; + double p2h, p2l; - e=power; if (power<0) e=-e; - et = (e*0x2c9)>>14;/* %23 */ if (et>13) et=13; eb = e-(et*23); + e = power; + if (power < 0) + e = -e; + et = (e * 0x2c9) >> 14; /* %23 */ + if (et > 13) + et = 13; + eb = e - (et * 23); - ph = d; pl = 0.0; - if (power<0) - { - if (eb) { --eb; stbsp__ddmulthi(ph,pl,d,stbsp__negbot[eb]); stbsp__ddmultlos(ph,pl,d,stbsp__negboterr[eb]); } - if (et) - { - stbsp__ddrenorm(ph,pl); - --et; stbsp__ddmulthi(p2h,p2l,ph,stbsp__negtop[et]); stbsp__ddmultlo(p2h,p2l,ph,pl,stbsp__negtop[et],stbsp__negtoperr[et]); ph=p2h;pl=p2l; + ph = d; + pl = 0.0; + if (power < 0) { + if (eb) { + --eb; + stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); + stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); + ph = p2h; + pl = p2l; + } + } else { + if (eb) { + e = eb; + if (eb > 22) + eb = 22; + e -= eb; + stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); + if (e) { + stbsp__ddrenorm(ph, pl); + stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); + stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); + ph = p2h; + pl = p2l; + } + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); + ph = p2h; + pl = p2l; + } } - } - else - { - if (eb) - { - e = eb; if (eb>22) eb=22; e -= eb; - stbsp__ddmulthi(ph,pl,d,stbsp__bot[eb]); - if ( e ) { stbsp__ddrenorm(ph,pl); stbsp__ddmulthi(p2h,p2l,ph,stbsp__bot[e]); stbsp__ddmultlos(p2h,p2l,stbsp__bot[e],pl); ph=p2h;pl=p2l; } - } - if (et) - { - stbsp__ddrenorm(ph,pl); - --et; stbsp__ddmulthi(p2h,p2l,ph,stbsp__top[et]); stbsp__ddmultlo(p2h,p2l,ph,pl,stbsp__top[et],stbsp__toperr[et]); ph=p2h;pl=p2l; - } - } - } - stbsp__ddrenorm(ph,pl); - *ohi = ph; *olo = pl; + } + stbsp__ddrenorm(ph, pl); + *ohi = ph; + *olo = pl; } // given a float value, returns the significant bits in bits, and the position of the // decimal point in decimal_pos. +/-INF and NAN are specified by special values // returned in the decimal_pos parameter. // frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 -static stbsp__int32 stbsp__real_to_str( char const * * start, stbsp__uint32 * len, char *out, stbsp__int32 * decimal_pos, double value, stbsp__uint32 frac_digits ) +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) { - double d; - stbsp__int64 bits = 0; - stbsp__int32 expo, e, ng, tens; + double d; + stbsp__int64 bits = 0; + stbsp__int32 expo, e, ng, tens; - d = value; - STBSP__COPYFP(bits,d); - expo = (stbsp__int32) ((bits >> 52) & 2047); - ng = (stbsp__int32)(bits >> 63); - if (ng) d=-d; + d = value; + STBSP__COPYFP(bits, d); + expo = (stbsp__int32)((bits >> 52) & 2047); + ng = (stbsp__int32)(bits >> 63); + if (ng) + d = -d; - if ( expo == 2047 ) // is nan or inf? - { - *start = (bits&((((stbsp__uint64)1)<<52)-1)) ? "NaN" : "Inf"; - *decimal_pos = STBSP__SPECIAL; - *len = 3; - return ng; - } - - if ( expo == 0 ) // is zero or denormal - { - if ((bits<<1)==0) // do zero - { - *decimal_pos = 1; - *start = out; - out[0] = '0'; *len = 1; + if (expo == 2047) // is nan or inf? + { + *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; + *decimal_pos = STBSP__SPECIAL; + *len = 3; return ng; - } - // find the right expo for denormals - { - stbsp__int64 v = ((stbsp__uint64)1)<<51; - while ((bits&v)==0) { --expo; v >>= 1; } - } - } + } - // find the decimal exponent as well as the decimal bits of the value - { - double ph,pl; + if (expo == 0) // is zero or denormal + { + if ((bits << 1) == 0) // do zero + { + *decimal_pos = 1; + *start = out; + out[0] = '0'; + *len = 1; + return ng; + } + // find the right expo for denormals + { + stbsp__int64 v = ((stbsp__uint64)1) << 51; + while ((bits & v) == 0) { + --expo; + v >>= 1; + } + } + } - // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 - tens=expo-1023; tens = (tens<0)?((tens*617)/2048):(((tens*1233)/4096)+1); + // find the decimal exponent as well as the decimal bits of the value + { + double ph, pl; - // move the significant bits into position and stick them into an int - stbsp__raise_to_power10( &ph, &pl, d, 18-tens ); + // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 + tens = expo - 1023; + tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); - // get full as much precision from double-double as possible - stbsp__ddtoS64( bits, ph,pl ); + // move the significant bits into position and stick them into an int + stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); - // check if we undershot - if ( ((stbsp__uint64)bits) >= stbsp__tento19th ) ++tens; - } + // get full as much precision from double-double as possible + stbsp__ddtoS64(bits, ph, pl); - // now do the rounding in integer land - frac_digits = ( frac_digits & 0x80000000 ) ? ( (frac_digits&0x7ffffff) + 1 ) : ( tens + frac_digits ); - if ( ( frac_digits < 24 ) ) - { - stbsp__uint32 dg = 1; if ((stbsp__uint64)bits >= stbsp__powten[9] ) dg=10; while( (stbsp__uint64)bits >= stbsp__powten[dg] ) { ++dg; if (dg==20) goto noround; } - if ( frac_digits < dg ) - { - stbsp__uint64 r; - // add 0.5 at the right position and round - e = dg - frac_digits; - if ( (stbsp__uint32)e >= 24 ) goto noround; - r = stbsp__powten[e]; - bits = bits + (r/2); - if ( (stbsp__uint64)bits >= stbsp__powten[dg] ) ++tens; - bits /= r; - } - noround:; - } + // check if we undershot + if (((stbsp__uint64)bits) >= stbsp__tento19th) + ++tens; + } - // kill long trailing runs of zeros - if ( bits ) - { - stbsp__uint32 n; - for(;;) { if ( bits<=0xffffffff ) break; if (bits%1000) goto donez; bits/=1000; } - n = (stbsp__uint32)bits; - while ((n%1000)==0) n/=1000; - bits=n; - donez:; - } + // now do the rounding in integer land + frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); + if ((frac_digits < 24)) { + stbsp__uint32 dg = 1; + if ((stbsp__uint64)bits >= stbsp__powten[9]) + dg = 10; + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + ++dg; + if (dg == 20) + goto noround; + } + if (frac_digits < dg) { + stbsp__uint64 r; + // add 0.5 at the right position and round + e = dg - frac_digits; + if ((stbsp__uint32)e >= 24) + goto noround; + r = stbsp__powten[e]; + bits = bits + (r / 2); + if ((stbsp__uint64)bits >= stbsp__powten[dg]) + ++tens; + bits /= r; + } + noround:; + } - // convert to string - out += 64; - e = 0; - for(;;) - { - stbsp__uint32 n; - char * o = out-8; - // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits>=100000000) { n = (stbsp__uint32)( bits % 100000000); bits /= 100000000; } else {n = (stbsp__uint32)bits; bits = 0; } - while(n) { out-=2; *(stbsp__uint16*)out=*(stbsp__uint16*)&stbsp__digitpair[(n%100)*2]; n/=100; e+=2; } - if (bits==0) { if ((e) && (out[0]=='0')) { ++out; --e; } break; } - while( out!=o ) { *--out ='0'; ++e; } - } - - *decimal_pos = tens; - *start = out; - *len = e; - return ng; + // kill long trailing runs of zeros + if (bits) { + stbsp__uint32 n; + for (;;) { + if (bits <= 0xffffffff) + break; + if (bits % 1000) + goto donez; + bits /= 1000; + } + n = (stbsp__uint32)bits; + while ((n % 1000) == 0) + n /= 1000; + bits = n; + donez:; + } + + // convert to string + out += 64; + e = 0; + for (;;) { + stbsp__uint32 n; + char *o = out - 8; + // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) + if (bits >= 100000000) { + n = (stbsp__uint32)(bits % 100000000); + bits /= 100000000; + } else { + n = (stbsp__uint32)bits; + bits = 0; + } + while (n) { + out -= 2; + *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; + n /= 100; + e += 2; + } + if (bits == 0) { + if ((e) && (out[0] == '0')) { + ++out; + --e; + } + break; + } + while (out != o) { + *--out = '0'; + ++e; + } + } + + *decimal_pos = tens; + *start = out; + *len = e; + return ng; } #undef stbsp__ddmulthi #undef stbsp__ddrenorm #undef stbsp__ddmultlo #undef stbsp__ddmultlos -#undef STBSP__SPECIAL +#undef STBSP__SPECIAL #undef STBSP__COPYFP - + #endif // STB_SPRINTF_NOFLOAT // clean up #undef stbsp__uint16 -#undef stbsp__uint32 -#undef stbsp__int32 +#undef stbsp__uint32 +#undef stbsp__int32 #undef stbsp__uint64 #undef stbsp__int64 #undef STBSP__UNALIGNED #endif // STB_SPRINTF_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 +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 +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 +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, +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 +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 +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. ------------------------------------------------------------------------------ */ From 7b8955bfaa8c681628a50e34eec0c4995e0adbbe Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Fri, 21 Jul 2017 20:23:50 -0700 Subject: [PATCH 29/95] stb_sprintf: More whitespace cleanups post clang-format --- stb_sprintf.h | 219 ++++++++++++++++++++++++++------------------------ 1 file changed, 116 insertions(+), 103 deletions(-) diff --git a/stb_sprintf.h b/stb_sprintf.h index 469dd5d..1a03997 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -131,9 +131,9 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): */ #if defined(__has_feature) -#if __has_feature(address_sanitizer) -#define STBI__ASAN __attribute__((no_sanitize("address"))) -#endif + #if __has_feature(address_sanitizer) + #define STBI__ASAN __attribute__((no_sanitize("address"))) + #endif #endif #ifndef STBI__ASAN #define STBI__ASAN @@ -271,33 +271,33 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, stbsp__int32 fw, pr, tz; stbsp__uint32 fl; -// macros for the callback buffer stuff -#define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } -#define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } -#define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer -#define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } + // macros for the callback buffer stuff + #define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } + #define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } + #define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer + #define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } // fast copy everything up to the next % (or end of string) for (;;) { @@ -465,7 +465,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // handle each replacement switch (f[0]) { -#define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 char num[STBSP__NUMSZ]; char lead[8]; char tail[8]; @@ -1427,84 +1427,100 @@ static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, return (stbsp__int32)(b >> 63); } -static double const stbsp__bot[23] = {1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022}; -static double const stbsp__negbot[22] = {1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022}; +static double const stbsp__bot[23] = { + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; +static double const stbsp__negbot[22] = { + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; static double const stbsp__negboterr[22] = { -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039}; -static double const stbsp__top[13] = {1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299}; -static double const stbsp__negtop[13] = {1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299}; -static double const stbsp__toperr[13] = {8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282}; -static double const stbsp__negtoperr[13] = {3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317}; + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; +static double const stbsp__top[13] = { + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; +static double const stbsp__negtop[13] = { + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; +static double const stbsp__toperr[13] = { + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; +static double const stbsp__negtoperr[13] = { + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; #if defined(_MSC_VER) && (_MSC_VER <= 1200) -static stbsp__uint64 const stbsp__powten[20] = {1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U}; +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; #define stbsp__tento19th ((stbsp__uint64)1000000000000000000) #else -static stbsp__uint64 const stbsp__powten[20] = {1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL}; +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; #define stbsp__tento19th (1000000000000000000ULL) #endif #define stbsp__ddmulthi(oh, ol, xh, yh) \ - \ -{ \ + { \ double ahi = 0, alo, bhi = 0, blo; \ stbsp__int64 bt; \ oh = xh * yh; \ @@ -1517,12 +1533,10 @@ static stbsp__uint64 const stbsp__powten[20] = {1, STBSP__COPYFP(bhi, bt); \ blo = yh - bhi; \ ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ - \ -} + } #define stbsp__ddtoS64(ob, xh, xl) \ - \ -{ \ + { \ double ahi = 0, alo, vh, t; \ ob = (stbsp__int64)ph; \ vh = (double)ob; \ @@ -1530,8 +1544,7 @@ static stbsp__uint64 const stbsp__powten[20] = {1, t = (ahi - xh); \ alo = (xh - (ahi - t)) - (vh + t); \ ob += (stbsp__int64)(ahi + alo + xl); \ - \ -} + } #define stbsp__ddrenorm(oh, ol) \ { \ From 481db7501ce7938ee79771acf4f4a83f548fd4d1 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Fri, 21 Jul 2017 20:31:58 -0700 Subject: [PATCH 30/95] stb_sprintf: Remove some gratuitous gotos --- stb_sprintf.h | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/stb_sprintf.h b/stb_sprintf.h index 1a03997..dc7992a 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -559,13 +559,9 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, cs = 0; goto scopy; #else - case 'A': // float - h = hexu; - goto hexfloat; - + case 'A': // hex float case 'a': // hex float - h = hex; - hexfloat: + h = (f[0] == 'A') ? hexu : hex; fv = va_arg(va, double); if (pr == -1) pr = 6; // default is 6 @@ -636,12 +632,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, goto scopy; case 'G': // float - h = hexu; - goto dosmallfloat; - case 'g': // float - h = hex; - dosmallfloat: + h = (f[0] == 'G') ? hexu : hex; fv = va_arg(va, double); if (pr == -1) pr = 6; @@ -677,12 +669,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, goto dofloatfromg; case 'E': // float - h = hexu; - goto doexp; - case 'e': // float - h = hex; - doexp: + h = (f[0] == 'E') ? hexu : hex; fv = va_arg(va, double); if (pr == -1) pr = 6; // default is 6 @@ -911,12 +899,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, #endif case 'B': // upper binary - h = hexu; - goto binary; - case 'b': // lower binary - h = hex; - binary: + h = (f[0] == 'B') ? hexu : hex; lead[0] = 0; if (fl & STBSP__LEADING_0X) { lead[0] = 2; @@ -942,13 +926,9 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros // drop through to X - case 'X': // upper binary - h = hexu; - goto dohexb; - - case 'x': // lower binary - h = hex; - dohexb: + case 'X': // upper hex + case 'x': // lower hex + h = (f[0] == 'X') ? hexu : hex; l = (4 << 4) | (4 << 8); lead[0] = 0; if (fl & STBSP__LEADING_0X) { From 067466045187a40f16534b7a1f35cf4fba82a76e Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Fri, 21 Jul 2017 21:55:37 -0700 Subject: [PATCH 31/95] stb_image: Relax raw_len validation for non-interlaced PNGs. We used to require exact match between img_len and raw_len for non-interlaced PNGs, but the PNG in issue #276 has extra bytes (all zeros) at the end of the compressed DEFLATE stream. The PNG spec doesn't have anything to say about it (that I can tell), and if libpng accepts this, who are we to judge. Fixes issue #276. --- stb_image.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/stb_image.h b/stb_image.h index ae2ada6..c9a5d59 100644 --- a/stb_image.h +++ b/stb_image.h @@ -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; From cc7f1d1e6d734e9d4b982be924f72504c4f0195e Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Fri, 21 Jul 2017 22:35:01 -0700 Subject: [PATCH 32/95] stb_image: Documentation fixes. req_comp is now desired_channels and *comp is *channels_in_file. Fixes issue #466. --- stb_image.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/stb_image.h b/stb_image.h index ae2ada6..8b4df10 100644 --- a/stb_image.h +++ b/stb_image.h @@ -134,11 +134,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 +151,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 +311,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, From 2da81a64339386bb1cb1548d2ebcbd3e997f0bbf Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 14:39:52 -0700 Subject: [PATCH 33/95] stb_vorbis: MinGW has alloca defined in malloc.h. Fixes issue #461. --- stb_vorbis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index 1181e6d..d7ee5e4 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -551,7 +551,7 @@ enum STBVorbisError #include // find definition of alloca if it's not in stdlib.h: - #ifdef _MSC_VER + #if defined(_MSC_VER) || defined(__MINGW32__) #include #endif #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) From 316571b3951e99fc46483d65aa3a2f5c5dd1204b Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 15:38:56 -0700 Subject: [PATCH 34/95] stb_image: 3-char indent and other minor formatting issues. --- stb_image.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/stb_image.h b/stb_image.h index 3644a0f..3ce80b0 100644 --- a/stb_image.h +++ b/stb_image.h @@ -98,7 +98,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 - + github:poppolopoppo */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -366,12 +366,12 @@ 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 (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_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); #endif -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); //////////////////////////////////// // @@ -1194,16 +1194,16 @@ STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, i 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); + 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); + 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) From 4868b5283bdd8f8f572ef7dc5a13a5c274af7348 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 15:40:27 -0700 Subject: [PATCH 35/95] stb_dxt: Update contributors list. --- stb_dxt.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stb_dxt.h b/stb_dxt.h index 593a979..8326f07 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -20,7 +20,8 @@ // v1.00 - (stb) first release // // contributors: -// Kevin Schmidt +// Kevin Schmidt (#defines for "freestanding" compilation) +// github:ppiastucki (BC4 support) // // LICENSE // From 25a2596b2fee5041f8a55fd7317d0ffe90abc198 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 15:59:41 -0700 Subject: [PATCH 36/95] stb_image: Fix rounding during unpremultiply. This is the same method as in pull request #455, but using integer arithmetic instead of converting to float. Fixes #455. --- stb_image.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/stb_image.h b/stb_image.h index a65c7f9..2e0b4c5 100644 --- a/stb_image.h +++ b/stb_image.h @@ -98,7 +98,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 - Kevin Schmidt github:poppolopoppo + Christian Floisand Kevin Schmidt github:poppolopoppo */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -4670,9 +4670,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; From 931662ae6ed9957be812a0bac134d9d856bcc0cf Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 16:04:07 -0700 Subject: [PATCH 37/95] stb_image_write: Warning fix. --- stb_image_write.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 4dc45d4..68c5f24 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -1267,9 +1267,9 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in for(i = 0; i < 64; ++i) { int uvti, yti = (YQT[i]*quality+50)/100; - YTable[stbiw__jpg_ZigZag[i]] = yti < 1 ? 1 : yti > 255 ? 255 : yti; + 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]] = uvti < 1 ? 1 : uvti > 255 ? 255 : uvti; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); } for(row = 0, k = 0; row < 8; ++row) { From 501812f307cd4b7609a1c6226f26bb7780cf08b8 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 18:03:52 -0700 Subject: [PATCH 38/95] stb_leakcheck: Fix warnings. 1. const char* for __FILE__ (string literals are const) 2. Use %zd to print size_t where available; the only real problem here is Visual C++. Use long long on the VC++ vers that support 64-bit targets but not %zd, int on the even older 32-bit-only VC++ vers that don't support "long long" either. Fixes #459. I think. (It's hard to be sure since the issue doesn't state the exact warning message.) --- stb_leakcheck.h | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/stb_leakcheck.h b/stb_leakcheck.h index 587c5e0..7322ab5 100644 --- a/stb_leakcheck.h +++ b/stb_leakcheck.h @@ -22,7 +22,7 @@ typedef struct malloc_info stb_leakcheck_malloc_info; struct malloc_info { - char *file; + const char *file; int line; size_t size; stb_leakcheck_malloc_info *next,*prev; @@ -30,7 +30,7 @@ struct malloc_info static stb_leakcheck_malloc_info *mi_head; -void *stb_leakcheck_malloc(size_t sz, char *file, int line) +void *stb_leakcheck_malloc(size_t sz, const char *file, int line) { stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi)); if (mi == NULL) return mi; @@ -62,7 +62,7 @@ void stb_leakcheck_free(void *ptr) } } -void *stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line) +void *stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line) { if (ptr == NULL) { return stb_leakcheck_malloc(sz, file, line); @@ -88,11 +88,30 @@ void *stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line) } } +static void stblkck_internal_print(const char *reason, const char *file, int line, size_t size, void *ptr) +{ +#if (defined(_MSC_VER) && _MSC_VER < 1900) /* 1900=VS 2015 */ || defined(__MINGW32__) + // Compilers that use the old MS C runtime library don't have %zd + // and the older ones don't even have %lld either... however, the old compilers + // without "long long" don't support 64-bit targets either, so here's the + // compromise: + #if defined(_MSC_VER) && _MSC_VER < 1400 // before VS 2005 + printf("%-6s: %s (%4d): %8d bytes at %p\n", reason, file, line, (int)size, ptr); + #else + printf("%-6s: %s (%4d): %8lld bytes at %p\n", reason, file, line, (long long)size, ptr); + #endif +#else + // Assume we have %zd on other targets. + printf("%-6s: %s (%4d): %zd bytes at %p\n", reason, file, line, size, ptr); +#endif +} + void stb_leakcheck_dumpmem(void) { stb_leakcheck_malloc_info *mi = mi_head; while (mi) { if ((ptrdiff_t) mi->size >= 0) + stblkck_internal_print("LEAKED", mi->file, mi->line, mi->size, mi+1); printf("LEAKED: %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) mi->size, mi+1); mi = mi->next; } @@ -100,6 +119,7 @@ void stb_leakcheck_dumpmem(void) mi = mi_head; while (mi) { if ((ptrdiff_t) mi->size < 0) + stblkck_internal_print("FREED", mi->file, mi->line, ~mi->size, mi+1); printf("FREED : %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) ~mi->size, mi+1); mi = mi->next; } From 49c7f1b397507d1af08073713673a7cda8eb954b Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 18:43:36 -0700 Subject: [PATCH 39/95] stb_image: Optimise vertical flip. This incorporates #462, but also factors everything into one function that is shared between 8-bit integer, 16-bit integer, and float pixels (vertical flip operates on rows of bytes and doesn't really care), and finally always uses a 2k on-stack buffer without dynamic memory allocation, doing multiple memcpys per row if necessary. Not only does this remove an out-of-memory failure mode, it is also preferable for large images, since it's more L1-cache-firendly this way. Fixes #462. --- stb_image.h | 72 +++++++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/stb_image.h b/stb_image.h index 2e0b4c5..19a7f97 100644 --- a/stb_image.h +++ b/stb_image.h @@ -83,6 +83,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 @@ -1031,6 +1032,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; @@ -1048,21 +1073,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; @@ -1086,21 +1098,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; @@ -1110,21 +1109,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 From 30c7c6b5832fca322319b04a55eb7a6181683f5f Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 19:24:41 -0700 Subject: [PATCH 40/95] stb_truetype: Support reading OS/2 vertical metrics ...as present in MS TrueType files. Since this table is optional, the new stbtt_GetFontVMetricsOS2 has a return value and can fail. This is a replacement for pull request #463. Fixes #463. --- stb_truetype.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/stb_truetype.h b/stb_truetype.h index 1d5eee4..df0dc5e 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -27,6 +27,7 @@ // Ryan Gordon // Simon Glass // github:IntellectualKitty +// Imanol Celaya // // Bug/warning reports/fixes: // "Zer" on mollyrocket @@ -112,6 +113,7 @@ // Character advance/positioning // stbtt_GetCodepointHMetrics() // stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() // stbtt_GetCodepointKernAdvance() // // Starting with version 1.06, the rasterizer was replaced with a new, @@ -729,6 +731,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 @@ -2278,6 +2286,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); From b1d058e5c766671fc805143fc6b2c4d73519e063 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 19:37:03 -0700 Subject: [PATCH 41/95] stb_truetype: Fix typo, as pointed out by oyvindjam. Fixes #471. --- stb_truetype.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stb_truetype.h b/stb_truetype.h index df0dc5e..6ce4760 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -53,6 +53,7 @@ // Thomas Fields // Derek Vinyard // Cort Stratton +// github:oyvindjam // // VERSION HISTORY // @@ -95,7 +96,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() From 5ebeb38edb3a1aceff44c142ab9eac832d6c6943 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 20:25:57 -0700 Subject: [PATCH 42/95] stb_rect_pack: Remove unused rect_width_compare(). Fixes #416. --- stb_rect_pack.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/stb_rect_pack.h b/stb_rect_pack.h index f5eb8d3..9faf578 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -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; From 5a5cf7f9ba936bb931ecde8df9465e250132fb75 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 22 Jul 2017 20:44:27 -0700 Subject: [PATCH 43/95] stb_leakcheck: Make stb_leakcheck_free actually free. Fixes issue #307. --- stb_leakcheck.h | 1 + 1 file changed, 1 insertion(+) diff --git a/stb_leakcheck.h b/stb_leakcheck.h index 7322ab5..e8ee8eb 100644 --- a/stb_leakcheck.h +++ b/stb_leakcheck.h @@ -59,6 +59,7 @@ void stb_leakcheck_free(void *ptr) if (mi->next) mi->next->prev = mi->prev; #endif + free(ptr); } } From 7725f8b9cd8ca1eedd10600e40a87b6ac79bb1f3 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sun, 23 Jul 2017 01:33:21 -0700 Subject: [PATCH 44/95] stb_leakcheck: Derp, I should free the right thing. Fixes #307, this time for real. --- stb_leakcheck.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_leakcheck.h b/stb_leakcheck.h index e8ee8eb..abc24fe 100644 --- a/stb_leakcheck.h +++ b/stb_leakcheck.h @@ -59,7 +59,7 @@ void stb_leakcheck_free(void *ptr) if (mi->next) mi->next->prev = mi->prev; #endif - free(ptr); + free(mi); } } From 0fbbda56fa829c226b425c51cc784cb425daee4d Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sun, 23 Jul 2017 01:41:12 -0700 Subject: [PATCH 45/95] stb_image: Account for tRNS chunk in non-paletted images. So we report channels_in_file correctly. Fixes #329. --- stb_image.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stb_image.h b/stb_image.h index 4851299..a42ebef 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4822,6 +4822,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; From 555efbedfc00f038c882bf6097e139864a3580e2 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 23 Jul 2017 14:09:39 -0700 Subject: [PATCH 46/95] Update version numbers --- README.md | 20 ++++++++++---------- stb_dxt.h | 3 ++- stb_image.h | 16 ++++++++++------ stb_image_resize.h | 3 ++- stb_image_write.h | 5 ++++- stb_leakcheck.h | 6 +++--- stb_sprintf.h | 5 ++++- stb_truetype.h | 3 ++- stb_vorbis.c | 3 ++- tests/stb.dsp | 2 +- 10 files changed, 40 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 7d6d82c..43602e6 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,17 @@ by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts. library | lastest version | category | LoC | description --------------------- | ---- | -------- | --- | -------------------------------- -**[stb_vorbis.c](stb_vorbis.c)** | 1.10 | audio | 5447 | decode ogg vorbis files from file/memory to float/16-bit signed output -**[stb_image.h](stb_image.h)** | 2.15 | graphics | 7177 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC -**[stb_truetype.h](stb_truetype.h)** | 1.15 | graphics | 4061 | parse, decode, and rasterize characters from truetype fonts -**[stb_image_write.h](stb_image_write.h)** | 1.05 | graphics | 1092 | image writing to disk: PNG, TGA, BMP -**[stb_image_resize.h](stb_image_resize.h)** | 0.94 | graphics | 2624 | resize images larger/smaller with good quality -**[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 635 | simple 2D rectangle packer with decent quality -**[stb_sprintf.h](stb_sprintf.h)** | 1.02 | utility | 1202 | fast sprintf, snprintf for C/C++ +**[stb_vorbis.c](stb_vorbis.c)** | 1.11 | audio | 5448 | decode ogg vorbis files from file/memory to float/16-bit signed output +**[stb_image.h](stb_image.h)** | 2.16 | graphics | 7187 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC +**[stb_truetype.h](stb_truetype.h)** | 1.17 | graphics | 4566 | parse, decode, and rasterize characters from truetype fonts +**[stb_image_write.h](stb_image_write.h)** | 1.06 | graphics | 1456 | image writing to disk: PNG, TGA, BMP +**[stb_image_resize.h](stb_image_resize.h)** | 0.95 | graphics | 2627 | resize images larger/smaller with good quality +**[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 624 | simple 2D rectangle packer with decent quality +**[stb_sprintf.h](stb_sprintf.h)** | 1.03 | utility | 1812 | fast sprintf, snprintf for C/C++ **[stretchy_buffer.h](stretchy_buffer.h)** | 1.02 | utility | 257 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ **[stb_textedit.h](stb_textedit.h)** | 1.11 | user interface | 1393 | guts of a text editor for games etc implementing them from scratch **[stb_voxel_render.h](stb_voxel_render.h)** | 0.85 | 3D graphics | 3803 | Minecraft-esque voxel rendering "engine" with many more features -**[stb_dxt.h](stb_dxt.h)** | 1.06 | 3D graphics | 687 | Fabian "ryg" Giesen's real-time DXT compressor +**[stb_dxt.h](stb_dxt.h)** | 1.07 | 3D graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor **[stb_perlin.h](stb_perlin.h)** | 0.3 | 3D graphics | 316 | revised Perlin noise (3D input, 1D output) **[stb_easy_font.h](stb_easy_font.h)** | 1.0 | 3D graphics | 303 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc **[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.38 | game dev | 4172 | embeddable tilemap editor @@ -30,10 +30,10 @@ library | lastest version | category | LoC | description **[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide" **[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids **[stb.h](stb.h)** | 2.29 | misc | 14324 | helper functions for C, mostly redundant in C++; basically author's personal stuff -**[stb_leakcheck.h](stb_leakcheck.h)** | 0.3 | misc | 165 | quick-and-dirty malloc/free leak-checking +**[stb_leakcheck.h](stb_leakcheck.h)** | 0.4 | misc | 186 | quick-and-dirty malloc/free leak-checking Total libraries: 20 -Total lines of C code: 51304 +Total lines of C code: 52839 FAQ diff --git a/stb_dxt.h b/stb_dxt.h index 8326f07..b53aca7 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -1,4 +1,4 @@ -// stb_dxt.h - v1.06 - DXT1/DXT5 compressor - public domain +// stb_dxt.h - v1.07 - DXT1/DXT5 compressor - public domain // original by fabian "ryg" giesen - ported to C by stb // use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation // @@ -9,6 +9,7 @@ // and "high quality" using mode. // // version history: +// v1.07 - bc4; allow not using libc; add STB_DXT_STATIC // v1.06 - (stb) fix to known-broken 1.05 // v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski) // v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec); diff --git a/stb_image.h b/stb_image.h index a42ebef..a056138 100644 --- a/stb_image.h +++ b/stb_image.h @@ -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. @@ -99,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 + Christian Floisand Kevin Schmidt github:poppolopoppo */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -6972,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; diff --git a/stb_image_resize.h b/stb_image_resize.h index 0168a29..031ca99 100644 --- a/stb_image_resize.h +++ b/stb_image_resize.h @@ -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 @@ -159,6 +159,7 @@ 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 diff --git a/stb_image_write.h b/stb_image_write.h index 68c5f24..1f4f37d 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h +/* stb_image_write - v1.06 - 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 @@ -1377,6 +1377,9 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? 1.04 (2017-03-03) monochrome BMP expansion 1.03 ??? diff --git a/stb_leakcheck.h b/stb_leakcheck.h index abc24fe..b8c8df1 100644 --- a/stb_leakcheck.h +++ b/stb_leakcheck.h @@ -1,4 +1,4 @@ -// stb_leakcheck.h - v0.3 - quick & dirty malloc leak-checking - public domain +// stb_leakcheck.h - v0.4 - quick & dirty malloc leak-checking - public domain // LICENSE // // See end of file. @@ -135,8 +135,8 @@ void stb_leakcheck_dumpmem(void) #define free(p) stb_leakcheck_free(p) #define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__) -extern void * stb_leakcheck_malloc(size_t sz, char *file, int line); -extern void * stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line); +extern void * stb_leakcheck_malloc(size_t sz, const char *file, int line); +extern void * stb_leakcheck_realloc(void *ptr, size_t sz, const char *file, int line); extern void stb_leakcheck_free(void *ptr); extern void stb_leakcheck_dumpmem(void); diff --git a/stb_sprintf.h b/stb_sprintf.h index dc7992a..3828445 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -1,10 +1,13 @@ -// stb_sprintf - v1.02 - public domain snprintf() implementation +// stb_sprintf - v1.03 - public domain snprintf() implementation // originally by Jeff Roberts / RAD Game Tools, 2015/10/20 // http://github.com/nothings/stb // // allowed types: sc uidBboXx p AaGgEef n // lengths : h ll j z t I64 I32 I // +// Contributors: +// Fabian "ryg" Giesen (reformatting) +// // Contributors (bugfixes): // github:d26435 // github:trex78 diff --git a/stb_truetype.h b/stb_truetype.h index 6ce4760..cec2425 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,4 +1,4 @@ -// stb_truetype.h - v1.16 - public domain +// stb_truetype.h - v1.17 - public domain // authored from 2009-2016 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: @@ -57,6 +57,7 @@ // // 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 diff --git a/stb_vorbis.c b/stb_vorbis.c index d7ee5e4..c0d410c 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -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. @@ -32,6 +32,7 @@ // manxorist@github saga musix // // 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 diff --git a/tests/stb.dsp b/tests/stb.dsp index 05f0a7f..7e20a14 100644 --- a/tests/stb.dsp +++ b/tests/stb.dsp @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "GRID_TEST" /FR /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" From dd039e8cc5227babbe6f3007943f3ac294f89b92 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 23 Jul 2017 14:13:07 -0700 Subject: [PATCH 47/95] credits for mingw fixes in #444 --- README.md | 6 +++--- stb.h | 6 ++++-- stb_vorbis.c | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 43602e6..c5fa7e7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts. library | lastest version | category | LoC | description --------------------- | ---- | -------- | --- | -------------------------------- -**[stb_vorbis.c](stb_vorbis.c)** | 1.11 | audio | 5448 | decode ogg vorbis files from file/memory to float/16-bit signed output +**[stb_vorbis.c](stb_vorbis.c)** | 1.11 | audio | 5449 | decode ogg vorbis files from file/memory to float/16-bit signed output **[stb_image.h](stb_image.h)** | 2.16 | graphics | 7187 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **[stb_truetype.h](stb_truetype.h)** | 1.17 | graphics | 4566 | parse, decode, and rasterize characters from truetype fonts **[stb_image_write.h](stb_image_write.h)** | 1.06 | graphics | 1456 | image writing to disk: PNG, TGA, BMP @@ -29,11 +29,11 @@ library | lastest version | category | LoC | description **[stb_c_lexer.h](stb_c_lexer.h)** | 0.09 | parsing | 962 | simplify writing parsers for C-like languages **[stb_divide.h](stb_divide.h)** | 0.91 | math | 419 | more useful 32-bit modulus e.g. "euclidean divide" **[stb_connected_comp...](stb_connected_components.h)** | 0.95 | misc | 1045 | incrementally compute reachability on grids -**[stb.h](stb.h)** | 2.29 | misc | 14324 | helper functions for C, mostly redundant in C++; basically author's personal stuff +**[stb.h](stb.h)** | 2.30 | misc | 14328 | helper functions for C, mostly redundant in C++; basically author's personal stuff **[stb_leakcheck.h](stb_leakcheck.h)** | 0.4 | misc | 186 | quick-and-dirty malloc/free leak-checking Total libraries: 20 -Total lines of C code: 52839 +Total lines of C code: 52844 FAQ diff --git a/stb.h b/stb.h index 70c0899..c1523d1 100644 --- a/stb.h +++ b/stb.h @@ -1,4 +1,4 @@ -/* stb.h - v2.29 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h +/* stb.h - v2.30 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h no warranty is offered or implied; use this code at your own risk This is a single header file with a bunch of useful utilities @@ -25,6 +25,7 @@ Version History + 2.30 MinGW fix 2.29 attempt to fix use of swprintf() 2.28 various new functionality 2.27 test _WIN32 not WIN32 in STB_THREADS @@ -185,12 +186,13 @@ CREDITS Robert Nix r-lyeh blackpawn - Mojofreem@github + github:Mojofreem Ryan Whitworth Vincent Isambart Mike Sartain Eugene Opalev Tim Sjostrand + github:infatum */ #include diff --git a/stb_vorbis.c b/stb_vorbis.c index 9b52850..14cebbf 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -29,7 +29,7 @@ // 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 @@ -577,7 +577,7 @@ enum STBVorbisError #undef __forceinline #endif #define __forceinline -#define alloca __builtin_alloca + #define alloca __builtin_alloca #elif !defined(_MSC_VER) #if __GNUC__ #define __forceinline inline From 961923b5a380037afa2743f21b6c32d446636435 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 24 Jul 2017 03:32:20 -0700 Subject: [PATCH 48/95] fix documentation --- stb_image_write.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 1f4f37d..9d553e0 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.06 - public domain - http://nothings.org/stb/stb_image_write.h +/* 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 @@ -35,7 +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_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) + 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: @@ -1377,6 +1377,8 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const #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 ??? From 9d9f75eb682dd98b34de08bb5c489c6c561c9fa6 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 24 Jul 2017 03:32:32 -0700 Subject: [PATCH 49/95] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c5fa7e7..0bc0844 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ library | lastest version | category | LoC | description **[stb_vorbis.c](stb_vorbis.c)** | 1.11 | audio | 5449 | decode ogg vorbis files from file/memory to float/16-bit signed output **[stb_image.h](stb_image.h)** | 2.16 | graphics | 7187 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **[stb_truetype.h](stb_truetype.h)** | 1.17 | graphics | 4566 | parse, decode, and rasterize characters from truetype fonts -**[stb_image_write.h](stb_image_write.h)** | 1.06 | graphics | 1456 | image writing to disk: PNG, TGA, BMP +**[stb_image_write.h](stb_image_write.h)** | 1.07 | graphics | 1458 | image writing to disk: PNG, TGA, BMP **[stb_image_resize.h](stb_image_resize.h)** | 0.95 | graphics | 2627 | resize images larger/smaller with good quality **[stb_rect_pack.h](stb_rect_pack.h)** | 0.11 | graphics | 624 | simple 2D rectangle packer with decent quality **[stb_sprintf.h](stb_sprintf.h)** | 1.03 | utility | 1812 | fast sprintf, snprintf for C/C++ @@ -33,7 +33,7 @@ library | lastest version | category | LoC | description **[stb_leakcheck.h](stb_leakcheck.h)** | 0.4 | misc | 186 | quick-and-dirty malloc/free leak-checking Total libraries: 20 -Total lines of C code: 52844 +Total lines of C code: 52846 FAQ From 747b8d8f71ed5b557234feffa44ff1ed98bed39b Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 27 Jul 2017 23:51:36 -0500 Subject: [PATCH 50/95] stb_sprintf.h: Don't compare uninitialized value when using zero. This prevents a "Conditional jump or move depends on uninitialised value(s)" error from valgrind when using zero as an argument in line 1045. --- stb_sprintf.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stb_sprintf.h b/stb_sprintf.h index 3828445..abf4371 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -12,6 +12,7 @@ // github:d26435 // github:trex78 // Jari Komppa (SI suffixes) +// Rohit Nirmal // // LICENSE: // @@ -1025,11 +1026,11 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, n64 = 0; } if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { + do { s -= 2; *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair[(n % 100) * 2]; n /= 100; - } + } while (n); } while (n) { if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { From 923c9c3debf0283c8a025f56174c6305c70392ee Mon Sep 17 00:00:00 2001 From: Benji Smith Date: Mon, 31 Jul 2017 22:22:56 -0700 Subject: [PATCH 51/95] Correct function signature in stbi_write_jpg usage documentation. --- stb_image_write.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image_write.h b/stb_image_write.h index 9d553e0..d9ab544 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -35,7 +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); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data, int quality); 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: From 2c7b00ac21c8936572c2b036695fc91063c01bb1 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 7 Aug 2017 14:52:53 +0300 Subject: [PATCH 52/95] Add force_filter and compression_level parameters to (new) `stbi_write_png_to_mem_ex` * `force_filter` being < 0 means the original behavior (i.e. figure out the best-performing filter per scanline); any other values 0 <= x <= 4 correspond to PNG filters (0 = none, 1 = sub, 2 = up, 3 = average, 4 = Paeth). * `compression_level` being < 0 equals `compression_level` 8 (the previous value). The higher this is, the better the compression should be (though it will use more memory). These new parameters are not (yet) exposed for the higher-level API functions. --- stb_image_write.h | 108 ++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 38 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 9d553e0..3d7b3dc 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -910,62 +910,90 @@ static unsigned char stbiw__paeth(int a, int b, int c) return STBIW_UCHAR(c); } -// @OPTIMIZE: provide an option that always forces left-predict or paeth predict -unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int x, int y, int n, int filter_type, signed char *line_buffer) { + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * y; + for (i = 0; i < n; ++i) { + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + for (i=n; i < x*n; ++i) { + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i] - z[i-n]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; + case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; + case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } + } +} + +unsigned char *stbi_write_png_to_mem_ex(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len, int force_filter, int compression_level) { int ctype[5] = { -1, 0, 4, 2, 6 }; unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; unsigned char *out,*o, *filt, *zlib; signed char *line_buffer; - int i,j,k,p,zlen; + int j,zlen; if (stride_bytes == 0) stride_bytes = x * n; + if (force_filter >= 5) { + force_filter = -1; + } + + if (compression_level < 0) { + // TODO: What's the upper limit for compression_level? + compression_level = 8; + } + 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 }; - int *mymap = (j != 0) ? mapping : firstmap; - int best = 0, bestval = 0x7fffffff; - for (p=0; p < 2; ++p) { - for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass - int type = mymap[k],est=0; - unsigned char *z = pixels + stride_bytes*j; - for (i=0; i < n; ++i) - switch (type) { - case 0: line_buffer[i] = z[i]; break; - case 1: line_buffer[i] = z[i]; break; - case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; - case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; - case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; - case 5: line_buffer[i] = z[i]; break; - case 6: line_buffer[i] = z[i]; break; - } - for (i=n; i < x*n; ++i) { - switch (type) { - case 0: line_buffer[i] = z[i]; break; - case 1: line_buffer[i] = z[i] - z[i-n]; break; - case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; - case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; - case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; - case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } - } - if (p) break; - for (i=0; i < x*n; ++i) + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line(pixels, stride_bytes, x, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line(pixels, stride_bytes, x, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { est += abs((signed char) line_buffer[i]); - if (est < bestval) { bestval = est; best = k; } + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line(pixels, stride_bytes, x, j, n, best_filter, line_buffer); + filter_type = best_filter; } } - // when we get here, best contains the filter type, and line_buffer contains the data - filt[j*(x*n+1)] = (unsigned char) best; + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); } STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, compression_level); STBIW_FREE(filt); if (!zlib) return 0; @@ -1003,6 +1031,10 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in return out; } +unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { + return stbi_write_png_to_mem_ex(pixels, stride_bytes, x, y, n, out_len, -1, -1); +} + #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) { From 7d80a8b44d5a25a922885c84e97bdcaf093195a5 Mon Sep 17 00:00:00 2001 From: Marcin Wojdyr Date: Fri, 11 Aug 2017 00:19:18 +0100 Subject: [PATCH 53/95] avoid GCC7 implicit-fallthrough warning (GCC recognizes certain strings in comments) --- stb_sprintf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_sprintf.h b/stb_sprintf.h index 3828445..d6a00b5 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -927,7 +927,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; pr = sizeof(void *) * 2; fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros - // drop through to X + // fall through - to X case 'X': // upper hex case 'x': // lower hex From f57bc38ff6e6af67bb7725a030cfa646180d305e Mon Sep 17 00:00:00 2001 From: Dave Butler Date: Fri, 25 Aug 2017 08:02:35 -0900 Subject: [PATCH 54/95] Made some changes to make Clang Happy Someone should double check that that I didn't change the behavior of any of the code. I'm not using most (if any) of the code I touched, just wanted it to compile... --- stb.h | 71 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/stb.h b/stb.h index c1523d1..9727edf 100644 --- a/stb.h +++ b/stb.h @@ -1795,7 +1795,7 @@ STB_EXTERN int stb_prefix (char *s, char *t); STB_EXTERN char * stb_strichr(char *s, char t); STB_EXTERN char * stb_stristr(char *s, char *t); STB_EXTERN int stb_prefix_count(char *s, char *t); -STB_EXTERN char * stb_plural(int n); // "s" or "" +STB_EXTERN const char * stb_plural(int n); // "s" or "" STB_EXTERN size_t stb_strscpy(char *d, const char *s, size_t n); STB_EXTERN char **stb_tokens(char *src, char *delimit, int *count); @@ -1822,7 +1822,7 @@ size_t stb_strscpy(char *d, const char *s, size_t n) return len + 1; } -char *stb_plural(int n) +const char *stb_plural(int n) { return n == 1 ? "" : "s"; } @@ -3362,7 +3362,7 @@ unsigned int stb_hashlen(char *str, int len) unsigned int stb_hashptr(void *p) { - unsigned int x = (unsigned int) p; + unsigned int x = (unsigned int)(size_t) p; // typically lacking in low bits and high bits x = stb_rehash(x); @@ -3411,7 +3411,7 @@ unsigned int stb_hash_fast(void *p, int len) if (len <= 0 || q == NULL) return 0; /* Main loop */ - if (((int) q & 1) == 0) { + if (((int)(size_t) q & 1) == 0) { for (;len > 3; len -= 4) { unsigned int val; hash += stb__get16(q); @@ -3737,7 +3737,7 @@ int stb_ischar(char c, char *set) static unsigned char (*tables)[256]; static char ** sets = NULL; - int z = stb_perfect_hash(&p, (int) set); + int z = stb_perfect_hash(&p, (int)(size_t) set); if (z < 0) { int i,k,n,j,f; // special code that means free all existing data @@ -3756,7 +3756,7 @@ int stb_ischar(char c, char *set) tables = (unsigned char (*)[256]) realloc(tables, sizeof(*tables) * k); memset(tables, 0, sizeof(*tables) * k); for (i=0; i < stb_arr_len(sets); ++i) { - k = stb_perfect_hash(&p, (int) sets[i]); + k = stb_perfect_hash(&p, (int)(size_t) sets[i]); assert(k >= 0); n = k >> 3; f = bit[k&7]; @@ -3764,7 +3764,7 @@ int stb_ischar(char c, char *set) tables[n][(unsigned char) sets[i][j]] |= f; } } - z = stb_perfect_hash(&p, (int) set); + z = stb_perfect_hash(&p, (int)(size_t) set); } return tables[z >> 3][(unsigned char) c] & bit[z & 7]; } @@ -7631,14 +7631,14 @@ static stb_ps_hash *stb_ps_makehash(int size, int old_size, void **old_data) h->any_offset = 0; memset(h->table, 0, size * sizeof(h->table[0])); for (i=0; i < old_size; ++i) - if (!stb_ps_empty(old_data[i])) + if (!stb_ps_empty((size_t)old_data[i])) stb_ps_add(EncodeHash(h), old_data[i]); return h; } void stb_ps_delete(stb_ps *ps) { - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: break; case STB_ps_bucket: stb_bucket_free(GetBucket(ps)); break; case STB_ps_array : free(GetArray(ps)); break; @@ -7650,7 +7650,7 @@ stb_ps *stb_ps_copy(stb_ps *ps) { int i; // not a switch: order based on expected performance/power-law distribution - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: return ps; case STB_ps_bucket: { stb_ps_bucket *n = (stb_ps_bucket *) malloc(sizeof(*n)); @@ -7677,8 +7677,8 @@ stb_ps *stb_ps_copy(stb_ps *ps) int stb_ps_find(stb_ps *ps, void *value) { - int i, code = 3 & (int) ps; - assert((3 & (int) value) == STB_ps_direct); + int i, code = 3 & (int)(size_t) ps; + assert((3 & (int)(size_t) value) == STB_ps_direct); assert(stb_ps_fastlist_valid(value)); // not a switch: order based on expected performance/power-law distribution if (code == STB_ps_direct) @@ -7719,11 +7719,11 @@ stb_ps * stb_ps_add (stb_ps *ps, void *value) assert(!stb_ps_find(ps,value)); #endif if (value == NULL) return ps; // ignore NULL adds to avoid bad breakage - assert((3 & (int) value) == STB_ps_direct); + assert((3 & (int)(size_t) value) == STB_ps_direct); assert(stb_ps_fastlist_valid(value)); assert(value != STB_DEL); // STB_DEL is less likely - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: if (ps == NULL) return (stb_ps *) value; return EncodeBucket(stb_bucket_create2(ps,value)); @@ -7772,11 +7772,11 @@ stb_ps * stb_ps_add (stb_ps *ps, void *value) stb_uint32 n = hash & h->mask; void **t = h->table; // find first NULL or STB_DEL entry - if (!stb_ps_empty(t[n])) { + if (!stb_ps_empty((size_t)t[n])) { stb_uint32 s = stb_rehash(hash) | 1; do { n = (n + s) & h->mask; - } while (!stb_ps_empty(t[n])); + } while (!stb_ps_empty((size_t)t[n])); } if (t[n] == STB_DEL) -- h->count_deletes; @@ -7803,9 +7803,9 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value) #ifdef STB_DEBUG assert(stb_ps_find(ps, value)); #endif - assert((3 & (int) value) == STB_ps_direct); + assert((3 & (int)(size_t) value) == STB_ps_direct); if (value == NULL) return ps; // ignore NULL removes to avoid bad breakage - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: return ps == value ? NULL : ps; case STB_ps_bucket: { @@ -7864,7 +7864,7 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value) stb_ps_array *a = (stb_ps_array *) malloc(sizeof(*a) + (n-1) * sizeof(a->p[0])); int i,j=0; for (i=0; i < h->size; ++i) - if (!stb_ps_empty(t[i])) + if (!stb_ps_empty((size_t)t[i])) a->p[j++] = t[i]; assert(j == h->count); a->count = j; @@ -7886,7 +7886,7 @@ stb_ps *stb_ps_remove(stb_ps *ps, void *value) stb_ps *stb_ps_remove_any(stb_ps *ps, void **value) { assert(ps != NULL); - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: *value = ps; return NULL; @@ -7919,7 +7919,7 @@ stb_ps *stb_ps_remove_any(stb_ps *ps, void **value) stb_ps_hash *h = GetHash(ps); void **t = h->table; stb_uint32 n = h->any_offset; - while (stb_ps_empty(t[n])) + while (stb_ps_empty((size_t)t[n])) n = (n + 1) & h->mask; *value = t[n]; h->any_offset = (n+1) & h->mask; @@ -7940,7 +7940,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count) { int i,n=0; void **p = NULL; - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: if (ps == NULL) { *count = 0; return NULL; } p = (void **) malloc(sizeof(*p) * 1); @@ -7966,7 +7966,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count) stb_ps_hash *h = GetHash(ps); p = (void **) malloc(sizeof(*p) * h->count); for (i=0; i < h->size; ++i) - if (!stb_ps_empty(h->table[i])) + if (!stb_ps_empty((size_t)h->table[i])) p[n++] = h->table[i]; break; } @@ -7978,7 +7978,7 @@ void ** stb_ps_getlist(stb_ps *ps, int *count) int stb_ps_writelist(stb_ps *ps, void **list, int size ) { int i,n=0; - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: if (ps == NULL || size <= 0) return 0; list[0] = ps; @@ -8000,7 +8000,7 @@ int stb_ps_writelist(stb_ps *ps, void **list, int size ) stb_ps_hash *h = GetHash(ps); if (size <= 0) return 0; for (i=0; i < h->count; ++i) { - if (!stb_ps_empty(h->table[i])) { + if (!stb_ps_empty((size_t)h->table[i])) { list[n++] = h->table[i]; if (n == size) break; } @@ -8014,7 +8014,7 @@ int stb_ps_writelist(stb_ps *ps, void **list, int size ) int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data)) { int i; - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: if (ps == NULL) return STB_TRUE; return func(ps, data); @@ -8036,7 +8036,7 @@ int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data)) case STB_ps_hash: { stb_ps_hash *h = GetHash(ps); for (i=0; i < h->count; ++i) - if (!stb_ps_empty(h->table[i])) + if (!stb_ps_empty((size_t)h->table[i])) if (!func(h->table[i], data)) return STB_FALSE; return STB_TRUE; @@ -8047,7 +8047,7 @@ int stb_ps_enum(stb_ps *ps, void *data, int (*func)(void *value, void *data)) int stb_ps_count (stb_ps *ps) { - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: return ps != NULL; case STB_ps_bucket: { @@ -8071,7 +8071,7 @@ void ** stb_ps_fastlist(stb_ps *ps, int *count) { static void *storage; - switch (3 & (int) ps) { + switch (3 & (int)(size_t) ps) { case STB_ps_direct: if (ps == NULL) { *count = 0; return NULL; } storage = ps; @@ -9118,7 +9118,7 @@ static void stb__add_epsilon(stb_matcher *matcher, int from, int to) static void stb__add_edge(stb_matcher *matcher, int from, int to, int type) { - stb_nfa_edge z = { type, to }; + stb_nfa_edge z = { (stb_int16)type, (stb_uint16)to }; if (matcher->nodes[from].out == NULL) stb_arr_malloc((void **) &matcher->nodes[from].out, matcher); stb_arr_push(matcher->nodes[from].out, z); @@ -9831,7 +9831,7 @@ int stb_regex(char *regex, char *str) static char ** regexps; static char ** regexp_cache; static unsigned short *mapping; - int z = stb_perfect_hash(&p, (int) regex); + int z = stb_perfect_hash(&p, (int)(size_t) regex); if (z >= 0) { if (strcmp(regex, regexp_cache[(int) mapping[z]])) { int i = mapping[z]; @@ -9862,8 +9862,8 @@ int stb_regex(char *regex, char *str) n = stb_perfect_create(&p, (unsigned int *) (char **) regexps, stb_arr_len(regexps)); mapping = (unsigned short *) realloc(mapping, n * sizeof(*mapping)); for (i=0; i < stb_arr_len(regexps); ++i) - mapping[stb_perfect_hash(&p, (int) regexps[i])] = i; - z = stb_perfect_hash(&p, (int) regex); + mapping[stb_perfect_hash(&p, (int)(size_t) regexps[i])] = i; + z = stb_perfect_hash(&p, (int)(size_t) regex); } return stb_matcher_find(matchers[(int) mapping[z]], str); } @@ -10357,7 +10357,7 @@ static void stb__write(unsigned char v) ++stb__outbytes; } -#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v))) +#define stb_out(v) (stb__out ? (void)(*stb__out++ = (stb_uchar) (v)) : stb__write((stb_uchar) (v))) static void stb_out2(stb_uint v) { @@ -10620,7 +10620,8 @@ static size_t stb_out_backpatch_id(void) static void stb_out_backpatch(size_t id, stb_uint value) { - stb_uchar data[4] = { value >> 24, value >> 16, value >> 8, value }; + + stb_uchar data[4] = { (stb_uchar)(value >> 24), (stb_uchar)(value >> 16), (stb_uchar)(value >> 8), (stb_uchar)(value) }; if (stb__out) { memcpy((void *) id, data, 4); } else { From 2545eee3efcc6ebb6c81857664559f1cf2ba262a Mon Sep 17 00:00:00 2001 From: Dave Butler Date: Fri, 25 Aug 2017 08:24:58 -0900 Subject: [PATCH 55/95] Added myself as a contributor for the pull request --- stb.h | 1 + 1 file changed, 1 insertion(+) diff --git a/stb.h b/stb.h index 9727edf..8e73781 100644 --- a/stb.h +++ b/stb.h @@ -193,6 +193,7 @@ CREDITS Eugene Opalev Tim Sjostrand github:infatum + Dave Butler (Croepha) */ #include From c8245bbf22aa2cf9056b346ab56ab4ee525a2905 Mon Sep 17 00:00:00 2001 From: Jonathan Adamczewski Date: Mon, 28 Aug 2017 23:13:39 -0700 Subject: [PATCH 56/95] Remove arg from memset macro My clang doesn't like the macro defined this way, choking at the callsite on line 195 with "too many arguments provided to function-like macro invocation" This change matches what is done for STBTT_memset in stb_truetype.h --- stb_dxt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_dxt.h b/stb_dxt.h index b53aca7..6504325 100644 --- a/stb_dxt.h +++ b/stb_dxt.h @@ -88,7 +88,7 @@ STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *sr #ifndef STBD_MEMSET #include -#define STBD_MEMSET(x) memset(x) +#define STBD_MEMSET memset #endif static unsigned char stb__Expand5[32]; From c06c9fe6bc907d58cb252be781373393999613ba Mon Sep 17 00:00:00 2001 From: lieff Date: Thu, 31 Aug 2017 19:33:28 +0300 Subject: [PATCH 57/95] place const tables to protected .rdata section --- stb_image.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/stb_image.h b/stb_image.h index a056138..031cb47 100644 --- a/stb_image.h +++ b/stb_image.h @@ -1790,7 +1790,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j) } // (1 << n) - 1 -static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; // decode a jpeg huffman value from the bitstream stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) @@ -1843,7 +1843,7 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) } // bias[n] = (-1<rgb = 0; for (i=0; i < s->img_n; ++i) { - static unsigned char rgb[3] = { 'R', 'G', 'B' }; + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; z->img_comp[i].id = stbi__get8(s); if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) ++z->rgb; @@ -3912,18 +3912,18 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room return 1; } -static int stbi__zlength_base[31] = { +static const int stbi__zlength_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; -static int stbi__zlength_extra[31]= +static const int stbi__zlength_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; -static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; -static int stbi__zdist_extra[32] = +static const int stbi__zdist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static int stbi__parse_huffman_block(stbi__zbuf *a) @@ -3970,7 +3970,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) static int stbi__compute_huffman_codes(stbi__zbuf *a) { - static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; stbi__zhuffman z_codelength; stbi_uc lencodes[286+32+137];//padding for maximum single op stbi_uc codelength_sizes[19]; @@ -4229,7 +4229,7 @@ static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) static int stbi__check_png_header(stbi__context *s) { - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; int i; for (i=0; i < 8; ++i) if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); @@ -4275,7 +4275,7 @@ static int stbi__paeth(int a, int b, int c) return c; } -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; // create the png data from post-deflated data static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) From 350173026a2b5296656d158267c81ee2a38ed90c Mon Sep 17 00:00:00 2001 From: Mikhail Morozov Date: Fri, 1 Sep 2017 02:06:06 +0300 Subject: [PATCH 58/95] stb_image: support for 1-bit BMP --- stb_image.h | 55 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/stb_image.h b/stb_image.h index a056138..6141a7f 100644 --- a/stb_image.h +++ b/stb_image.h @@ -5007,7 +5007,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); info->bpp = stbi__get16le(s); - if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); @@ -5125,29 +5124,47 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req pal[i][3] = 255; } stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 4) width = (s->img_x + 1) >> 1; + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.bpp == 8) width = s->img_x; else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } pad = (-width)&3; - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); } - stbi__skip(s, pad); } } else { int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; From b6b43df18635ccdb128f5c3708d2ae640f647ef4 Mon Sep 17 00:00:00 2001 From: darealshinji Date: Mon, 4 Sep 2017 14:01:43 +0200 Subject: [PATCH 59/95] Use stbi__mad4sizes_valid() only if STBI_NO_LINEAR or STBI_NO_HDR are defined --- stb_image.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index a056138..87ba98a 100644 --- a/stb_image.h +++ b/stb_image.h @@ -503,7 +503,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #include #include -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) && !defined(STBI_NO_HDR) #include // ldexp #endif @@ -893,11 +893,13 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add) } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) && !defined(STBI_NO_HDR) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); } +#endif // mallocs with size overflow checking static void *stbi__malloc_mad2(int a, int b, int add) @@ -912,11 +914,13 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add) return stbi__malloc(a*b*c + add); } +#if !defined(STBI_NO_LINEAR) && !defined(STBI_NO_HDR) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; return stbi__malloc(a*b*c*d + add); } +#endif // stbi__err - error // stbi__errpf - error returning pointer to float From 84fd09ea5383262c1993ab52981ad3a3186ee15b Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Sat, 14 Oct 2017 11:58:03 +1100 Subject: [PATCH 60/95] stb_truetype: Fix sign error in CFF push immediate --- stb_truetype.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_truetype.h b/stb_truetype.h index cec2425..6a6e584 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -2172,7 +2172,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st // push immediate if (b0 == 255) { - f = (float)stbtt__buf_get32(&b) / 0x10000; + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; } else { stbtt__buf_skip(&b, -1); f = (float)(stbtt_int16)stbtt__cff_int(&b); From 1f2b4271e3d6c4abc143d15ae4be6a47685f230b Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Sat, 14 Oct 2017 11:59:09 +1100 Subject: [PATCH 61/95] stb_truetype: Fix CFF GetGlyphBox optional params Fixes #404 --- stb_truetype.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 6a6e584..0cb2fdc 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -2210,12 +2210,10 @@ static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, in { stbtt__csctx c = STBTT__CSCTX_INIT(1); int r = stbtt__run_charstring(info, glyph_index, &c); - if (x0) { - *x0 = r ? c.min_x : 0; - *y0 = r ? c.min_y : 0; - *x1 = r ? c.max_x : 0; - *y1 = r ? c.max_y : 0; - } + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; return r ? c.num_vertices : 0; } From a981af59c5af476c2784ee101f9522a2c51272ae Mon Sep 17 00:00:00 2001 From: Aldo Culquicondor Date: Mon, 16 Oct 2017 12:30:27 -0500 Subject: [PATCH 62/95] Fix tests compilation --- stb_tilemap_editor.h | 4 ++-- tests/Makefile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/stb_tilemap_editor.h b/stb_tilemap_editor.h index 94cff66..352042b 100644 --- a/stb_tilemap_editor.h +++ b/stb_tilemap_editor.h @@ -1847,7 +1847,7 @@ static int stbte__minibutton(int colormode, int x, int y, int ch, int id) int x0 = x, y0 = y, x1 = x+8, y1 = y+7; int over = stbte__hittest(x0,y0,x1,y1,id); if (stbte__ui.event == STBTE__paint) { - char str[2] = { ch,0 }; + char str[2] = { (char)ch, 0 }; stbte__draw_textbox(x0,y0,x1,y1, str,1,0,colormode, STBTE__INDEX_FOR_ID(id,0,0)); } return stbte__button_core(id); @@ -1858,7 +1858,7 @@ static int stbte__layerbutton(int x, int y, int ch, int id, int toggled, int dis int x0 = x, y0 = y, x1 = x+10, y1 = y+11; int over = !disabled && stbte__hittest(x0,y0,x1,y1,id); if (stbte__ui.event == STBTE__paint) { - char str[2] = { ch,0 }; + char str[2] = { (char)ch, 0 }; int off = (9-stbte__get_char_width(ch))/2; stbte__draw_textbox(x0,y0,x1,y1, str, off+1,2, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled)); } diff --git a/tests/Makefile b/tests/Makefile index 055ffaf..53e2485 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -3,5 +3,5 @@ CFLAGS = -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DSTB_DIVIDE_TEST CPPFLAGS = -Wno-write-strings -DSTB_DIVIDE_TEST all: - $(CC) $(INCLUDES) $(CFLAGS) ../stb_vorbis.c test_c_compilation.c -lm - $(CC) $(INCLUDES) $(CPPFLAGS) test_cpp_compilation.cpp -lm + $(CC) $(INCLUDES) $(CFLAGS) ../stb_vorbis.c test_c_compilation.c -lm + $(CC) $(INCLUDES) $(CPPFLAGS) test_cpp_compilation.cpp -lm -lstdc++ From 5182622b1442c4e21e5e9b921a3a7b474ca3f9b1 Mon Sep 17 00:00:00 2001 From: Kenney Phillis Jr Date: Sat, 4 Nov 2017 03:28:03 -0500 Subject: [PATCH 63/95] tests: fix test_trutype.c on msvc 2015 This is 3 short fixes for the file test_truetype.c. 1. Fix the Visual Studio Secure CRT Errors by defining _CRT_SECURE_NO_WARNINGS 2. Fix signed/unsigned Character conversion warning/error. 3. Fix the Definitions for the Image packer. This now works as intended generating usable png files. --- tests/test_truetype.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/test_truetype.c b/tests/test_truetype.c index d18d3b5..b432fd4 100644 --- a/tests/test_truetype.c +++ b/tests/test_truetype.c @@ -1,13 +1,20 @@ +#ifndef _CRT_SECURE_NO_WARNINGS +// Fixes Compile Errors for Visual Studio 2005 or newer + #define _CRT_SECURE_NO_WARNINGS +#endif + +#define STB_RECT_PACK_IMPLEMENTATION #include "stb_rect_pack.h" #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" +#define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" #ifdef TT_TEST #include -char ttf_buffer[1<<25]; +unsigned char ttf_buffer[1 << 25]; unsigned char output[512*100]; void debug(void) @@ -66,12 +73,14 @@ int main(int argc, char **argv) stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); pr[0].chardata_for_range = pdata; - pr[0].first_unicode_char_in_range = 32; - pr[0].num_chars_in_range = 95; + pr[0].array_of_unicode_codepoints = NULL; + pr[0].first_unicode_codepoint_in_range = 32; + pr[0].num_chars = 95; pr[0].font_size = 20.0f; pr[1].chardata_for_range = pdata+256; - pr[1].first_unicode_char_in_range = 0xa0; - pr[1].num_chars_in_range = 0x100 - 0xa0; + pr[1].array_of_unicode_codepoints = NULL; + pr[1].first_unicode_codepoint_in_range = 0xa0; + pr[1].num_chars = 0x100 - 0xa0; pr[1].font_size = 20.0f; stbtt_PackSetOversampling(&pc, 2, 2); From 6e50ac78602bf441dd6136ecf6a5004e309d5109 Mon Sep 17 00:00:00 2001 From: Kenney Phillis Jr Date: Sat, 4 Nov 2017 03:35:02 -0500 Subject: [PATCH 64/95] stb_truetype: Fix undefined function warning This fixes the error in bug report #516. This should work as intended since the function definitions line up. --- stb_truetype.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stb_truetype.h b/stb_truetype.h index cec2425..5a191d6 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -3318,6 +3318,11 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo * return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); } +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) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(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 codepoint) { stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); From 9dfa8c7f31032644db68e5c756667d41ef5e904a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Fri, 24 Nov 2017 13:44:39 +0100 Subject: [PATCH 65/95] return comp info in bytes (support for 16 bit images) --- stb_image.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/stb_image.h b/stb_image.h index a056138..193ada1 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4902,7 +4902,7 @@ static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) } if (x) *x = p->s->img_x; if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; + if (comp) *comp = p->s->img_n * p->depth / 8; return 1; } @@ -6667,7 +6667,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PSD static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { - int channelCount, dummy; + int channelCount, dummy, depth; if (!x) x = &dummy; if (!y) y = &dummy; if (!comp) comp = &dummy; @@ -6687,7 +6687,8 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) } *y = stbi__get32be(s); *x = stbi__get32be(s); - if (stbi__get16be(s) != 8) { + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { stbi__rewind( s ); return 0; } @@ -6695,7 +6696,7 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) stbi__rewind( s ); return 0; } - *comp = 4; + *comp = 4 * depth / 8; return 1; } #endif From 4c1a786455523f9805816dfc9b40df4133988f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Fri, 24 Nov 2017 14:35:14 +0100 Subject: [PATCH 66/95] Revert "return comp info in bytes (support for 16 bit images)" This reverts commit 9dfa8c7f31032644db68e5c756667d41ef5e904a. --- stb_image.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/stb_image.h b/stb_image.h index 193ada1..a056138 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4902,7 +4902,7 @@ static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) } if (x) *x = p->s->img_x; if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n * p->depth / 8; + if (comp) *comp = p->s->img_n; return 1; } @@ -6667,7 +6667,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PSD static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { - int channelCount, dummy, depth; + int channelCount, dummy; if (!x) x = &dummy; if (!y) y = &dummy; if (!comp) comp = &dummy; @@ -6687,8 +6687,7 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) } *y = stbi__get32be(s); *x = stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 8 && depth != 16) { + if (stbi__get16be(s) != 8) { stbi__rewind( s ); return 0; } @@ -6696,7 +6695,7 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) stbi__rewind( s ); return 0; } - *comp = 4 * depth / 8; + *comp = 4; return 1; } #endif From fcf0b9960197e83a73d32c4931239bf558125d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Fri, 24 Nov 2017 14:36:37 +0100 Subject: [PATCH 67/95] add stbi_is_16 --- stb_image.h | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/stb_image.h b/stb_image.h index a056138..a4dc1c1 100644 --- a/stb_image.h +++ b/stb_image.h @@ -416,11 +416,14 @@ STBIDEF void stbi_image_free (void *retval_from_stbi_load); // get image dimensions & components without fully decoding STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_from_callbacks(stbi_io_callbacks const *clbk, void *user); #ifndef STBI_NO_STDIO STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); - +STBIDEF int stbi_is_16 (char const *filename); +STBIDEF int stbi_is_16_from_file (FILE *f); #endif @@ -784,6 +787,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__png_test(stbi__context *s); static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); #endif #ifndef STBI_NO_BMP @@ -802,6 +806,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__psd_test(stbi__context *s); static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); #endif #ifndef STBI_NO_HDR @@ -4912,6 +4917,19 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) p.s = s; return stbi__png_info_raw(&p, x, y, comp); } + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} #endif // Microsoft/Windows BMP image @@ -6667,7 +6685,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PSD static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { - int channelCount, dummy; + int channelCount, dummy, depth; if (!x) x = &dummy; if (!y) y = &dummy; if (!comp) comp = &dummy; @@ -6687,7 +6705,8 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) } *y = stbi__get32be(s); *x = stbi__get32be(s); - if (stbi__get16be(s) != 8) { + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { stbi__rewind( s ); return 0; } @@ -6698,6 +6717,33 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) *comp = 4; return 1; } + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, dummy, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + dummy = stbi__get32be(s); + dummy = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} #endif #ifndef STBI_NO_PIC @@ -6928,6 +6974,19 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) return stbi__err("unknown image type", "Image not of any known type, or corrupt"); } +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + #ifndef STBI_NO_STDIO STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) { @@ -6949,6 +7008,27 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) fseek(f,pos,SEEK_SET); return r; } + +STBIDEF int stbi_is_16(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} #endif // !STBI_NO_STDIO STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) @@ -6965,6 +7045,20 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int return stbi__info_main(&s,x,y,comp); } +STBIDEF int stbi_is_16_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + #endif // STB_IMAGE_IMPLEMENTATION /* From 4bffebc5f0f1b69e1ce579cfffc24cc62c07dd08 Mon Sep 17 00:00:00 2001 From: Julian Raschke Date: Sat, 25 Nov 2017 17:23:33 +0800 Subject: [PATCH 68/95] Avoid warning about unused stbi__float_postprocess --- stb_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index a056138..0e8ac15 100644 --- a/stb_image.h +++ b/stb_image.h @@ -1103,7 +1103,7 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, return (stbi__uint16 *) result; } -#ifndef STBI_NO_HDR +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { if (stbi__vertically_flip_on_load && result != NULL) { From 87a3143fb4ca2111d77b27edda2b91ae493cc9a5 Mon Sep 17 00:00:00 2001 From: Chris Forseth Date: Mon, 27 Nov 2017 22:41:51 -0600 Subject: [PATCH 69/95] GIF Loading - multiple frames; - Allow loading a gif as multiple frames into a single buffer. Each frame is a full image seperated by a (w * h * comp) stride. - Optionally, can pass in a pointer to a int, which will be filled with an array layers long contain ms for each frame. - Fix gif's not loading the initial transparent background - I believe also fix disposal rules for subsequent frames (though being somewhat inefficient with memory to do so) - Add a flip_vertical that takes into account slices as well. Compiled using VS2017, but nothing else as I'm not really setup for it. Apologies. --- stb_image.h | 290 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 214 insertions(+), 76 deletions(-) diff --git a/stb_image.h b/stb_image.h index a056138..aa25fb2 100644 --- a/stb_image.h +++ b/stb_image.h @@ -353,6 +353,10 @@ typedef struct 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_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + #ifndef STBI_NO_STDIO STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); @@ -819,6 +823,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); #ifndef STBI_NO_GIF static int stbi__gif_test(stbi__context *s); static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); #endif @@ -1054,6 +1059,18 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) } } +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} + static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi__result_info ri; @@ -1205,6 +1222,21 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); } +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + + unsigned char *result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + #ifndef STBI_NO_LINEAR static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) { @@ -6038,11 +6070,13 @@ typedef struct typedef struct { int w,h; - stbi_uc *out, *old_out; // output buffer (always 4 components) - int flags, bgindex, ratio, transparent, eflags, delay; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; - stbi__gif_lzw codes[4096]; + stbi__gif_lzw codes[8192]; stbi_uc *color_table; int parse, step; int lflags; @@ -6050,6 +6084,7 @@ typedef struct int max_x, max_y; int cur_x, cur_y; int line_size; + int delay; } stbi__gif; static int stbi__gif_test_raw(stbi__context *s) @@ -6125,6 +6160,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; + int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -6133,10 +6169,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) if (g->cur_y >= g->max_y) return; - p = &g->out[g->cur_x + g->cur_y]; - c = &g->color_table[g->codes[code].suffix * 4]; + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; - if (c[3] >= 128) { + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -6210,11 +6248,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) stbi__skip(s,len); return g->out; } else if (code <= avail) { - if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } if (oldcode >= 0) { p = &g->codes[avail++]; - if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + p->prefix = (stbi__int16) oldcode; p->first = g->codes[oldcode].first; p->suffix = (code == avail) ? p->first : g->codes[code].first; @@ -6236,62 +6279,72 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) } } -static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) -{ - int x, y; - stbi_uc *c = g->pal[g->bgindex]; - for (y = y0; y < y1; y += 4 * g->w) { - for (x = x0; x < x1; x += 4) { - stbi_uc *p = &g->out[y + x]; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = 0; - } - } -} - // this function is designed to support animated gifs, although stb_image doesn't support it -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { - int i; - stbi_uc *prev_out = 0; + int dispose; + int first_frame; + int pi; + int pcount; - if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) - return 0; // stbi__g_failure_reason set by stbi__gif_header + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->history = (stbi_uc *) stbi__malloc(g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0)) - return stbi__errpuc("too large", "GIF too large"); + // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to teh color that was there the previous frame. + memset( g->out, 0x00, 4 * g->w * g->h ); + memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; - prev_out = g->out; - g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + if ((dispose == 4) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } - switch ((g->eflags & 0x1C) >> 2) { - case 0: // unspecified (also always used on 1st frame) - stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); - break; - case 1: // do not dispose - if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); - g->old_out = prev_out; - break; - case 2: // dispose to background - if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); - stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); - break; - case 3: // dispose to previous - if (g->old_out) { - for (i = g->start_y; i < g->max_y; i += 4 * g->w) - memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); + if (dispose == 4) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } } - break; + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose? Same as 4? + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); } + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + for (;;) { - switch (stbi__get8(s)) { + int tag = stbi__get8(s); + switch (tag) { case 0x2C: /* Image Descriptor */ { - int prev_trans = -1; stbi__int32 x, y, w, h; stbi_uc *o; @@ -6324,19 +6377,24 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); g->color_table = (stbi_uc *) g->lpal; } else if (g->flags & 0x80) { - if (g->transparent >= 0 && (g->eflags & 0x01)) { - prev_trans = g->pal[g->transparent][3]; - g->pal[g->transparent][3] = 0; - } g->color_table = (stbi_uc *) g->pal; } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - + return stbi__errpuc("missing color table", "Corrupt GIF"); + o = stbi__process_gif_raster(s, g); if (o == NULL) return NULL; - if (prev_trans != -1) - g->pal[g->transparent][3] = (stbi_uc) prev_trans; + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex >= 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } return o; } @@ -6344,19 +6402,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { g->eflags = stbi__get8(s); - g->delay = stbi__get16le(s); - g->transparent = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } } else { stbi__skip(s, len); break; } - } - while ((len = stbi__get8(s)) != 0) + } + while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); + } break; } @@ -6367,28 +6441,92 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i return stbi__errpuc("unknown code", "Corrupt GIF"); } } +} - STBI_NOTUSED(req_comp); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + if (delays) { + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != nullptr); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } } static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *u = 0; - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - memset(g, 0, sizeof(*g)); - STBI_NOTUSED(ri); + stbi__gif g; + memset(&g, 0, sizeof(g)); - u = stbi__gif_load_next(s, g, comp, req_comp); + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker if (u) { - *x = g->w; - *y = g->h; + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g->w, g->h); + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); } - else if (g->out) - STBI_FREE(g->out); - STBI_FREE(g); + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + return u; } From 28c28b0bd23534f405938e29505fb47780fadd3d Mon Sep 17 00:00:00 2001 From: Chris Forseth Date: Mon, 27 Nov 2017 23:06:53 -0600 Subject: [PATCH 70/95] Per the contributor doc - added my name. Noticed urraka also did some work here, so hopefully didn't step on any toes. - Fix an issue where the spec of the gif for restore to previous uses code 3, not 4. - To get results that worked - made an assumption that "clear to background" meant "revert back to what was there before I drew", where mode 1 would revert back to the previous frame [slightly different]. If I clear to background color instead, I ended up with large opaque squares in gifs that changes their transparent colour each frame. - Background color is supposed to be used only for pixels not rendered by the image, so took that to mean it only really affected the previous frame, or potentially any frame that used full disposal. Since background color is allowed to be unspecified this is what lead me to believe I shouldn't use it for disposal. - Oh, also upped the codes table to 8192 as 4096 ended up being too small for a few of my test cases. Full disclaimer - I only read through the GIF format for this contribution, so competly could be misinterpreting the spec - but this gave me reuslts that matched Chrome. --- stb_image.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stb_image.h b/stb_image.h index aa25fb2..167904f 100644 --- a/stb_image.h +++ b/stb_image.h @@ -74,7 +74,7 @@ RECENT REVISION HISTORY: Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) github:urraka (animated gif) Junggon Kim (PNM comments) - Daniel Gibson (16-bit TGA) + github:tocchan (animated gif) Daniel Gibson (16-bit TGA) socks-the-fox (16-bit PNG) Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes @@ -6313,7 +6313,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i dispose = 2; // if I don't have an image to revert back to, default to the old background } - if (dispose == 4) { // use previous graphic + if (dispose == 3) { // use previous graphic for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); @@ -6329,7 +6329,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } else { // This is a non-disposal case eithe way, so just // leave the pixels as is, and they will become the new background - // 1: do not dispose? Same as 4? + // 1: do not dispose // 0: not specified. } From 03b4bbc5d2d51831baf6359c9527a1733de74cdd Mon Sep 17 00:00:00 2001 From: Chris Forseth Date: Mon, 27 Nov 2017 23:32:44 -0600 Subject: [PATCH 71/95] Fix a disposal flag mistype. Only clear to background color if index is non-zero. Fixed a the disposal test gif I was using - now renders properly (gif has no transparent set, but all renderers still considered it transparent. Spec says 0 should be ignored if 0, but was confusing by saying it only in the context of the pal not existing.. but seems to be the case always. --- stb_image.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stb_image.h b/stb_image.h index 167904f..4c297cc 100644 --- a/stb_image.h +++ b/stb_image.h @@ -6309,7 +6309,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i dispose = (g->eflags & 0x1C) >> 2; pcount = g->w * g->h; - if ((dispose == 4) && (two_back == 0)) { + if ((dispose == 3) && (two_back == 0)) { dispose = 2; // if I don't have an image to revert back to, default to the old background } @@ -6386,7 +6386,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i // if this was the first frame, pcount = g->w * g->h; - if (first_frame && (g->bgindex >= 0)) { + if (first_frame && (g->bgindex > 0)) { // if first frame, any pixel not drawn to gets the background color for (pi = 0; pi < pcount; ++pi) { if (g->history[pi] == 0) { From de75509b1c35f6d8a03c341364600922391d6b94 Mon Sep 17 00:00:00 2001 From: Chris Forseth Date: Mon, 27 Nov 2017 23:42:13 -0600 Subject: [PATCH 72/95] Remove a nullptr --- stb_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 4c297cc..4d6b959 100644 --- a/stb_image.h +++ b/stb_image.h @@ -6487,7 +6487,7 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, (*delays)[layers - 1U] = g.delay; } } - } while (u != nullptr); + } while (u != 0); // free temp buffer; STBI_FREE(g.out); From 3a969eb64c46326490f7307b834c71b601204b99 Mon Sep 17 00:00:00 2001 From: Marcin Wojdyr Date: Thu, 7 Dec 2017 15:30:43 +0000 Subject: [PATCH 73/95] remove duplicated `pr = 0` avoid warning: Variable 'pr' is reassigned a value before the old one has been used caused by: fw = pr = fl = 0; ... pr = 0; --- stb_sprintf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_sprintf.h b/stb_sprintf.h index 3828445..5d87b1a 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -1259,7 +1259,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, s = num + STBSP__NUMSZ - 1; *s = f[0]; l = 1; - fw = pr = fl = 0; + fw = fl = 0; lead[0] = 0; tail[0] = 0; pr = 0; From 5c2c826df9d8cc50df4eae1b6c807ef8d194848c Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sun, 24 Dec 2017 13:57:03 -0500 Subject: [PATCH 74/95] stb_truetype: Silence warnings of winding_lengths Coverty scan shows potential warnings of winding_lengths. Forcing it to be a NULL fixes the issue. --- stb_truetype.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index cec2425..9eec983 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -3229,8 +3229,9 @@ error: STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) { - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count, *winding_lengths; + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); if (windings) { stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); From 5e844ffe70ca88fe56777e73c4fe50b24cb722bd Mon Sep 17 00:00:00 2001 From: John Tullos Date: Mon, 1 Jan 2018 18:08:30 -0600 Subject: [PATCH 75/95] Using secure versions of CRT calls to avoid Microsoft Visual C/C++ compiler errors/warnings. --- stb_image_write.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/stb_image_write.h b/stb_image_write.h index 9d553e0..17f9f3f 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -230,7 +230,12 @@ static void stbi__stdio_write(void *context, void *data, int size) static int stbi__start_write_file(stbi__write_context *s, const char *filename) { - FILE *f = fopen(filename, "wb"); + FILE *f; +#ifdef _MSC_VER + fopen_s(&f, filename, "wb"); +#else + f = fopen(filename, "wb"); +#endif stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); return f != NULL; } @@ -626,7 +631,11 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); +#ifdef _MSC_VER + len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif s->func(s->context, buffer, len); for(i=0; i < y; i++) @@ -1010,7 +1019,11 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const int len; unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; +#ifdef _MSC_VER + fopen_s(&f, filename, "wb"); +#else f = fopen(filename, "wb"); +#endif if (!f) { STBIW_FREE(png); return 0; } fwrite(png, 1, len, f); fclose(f); From 32a7d5ab68bd35455b24aa852d6d6b7d0f55b494 Mon Sep 17 00:00:00 2001 From: John Tullos Date: Mon, 1 Jan 2018 18:54:26 -0600 Subject: [PATCH 76/95] Added STBI_MSC_SECURE_CRT to support newer MSVC compilers as optional For issue #533 --- stb_image_write.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 17f9f3f..b977440 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -10,6 +10,11 @@ Will probably not work correctly with strict-aliasing optimizations. + If using a modern Microsoft Compiler non-safe versions of CRT calls may cause + compilation warnings or even errors. To avoid this, aldo before #including, + + #define STBI_MSC_SECURE_CRT + ABOUT: This header file is a library for writing images to C stdio. It could be @@ -231,7 +236,7 @@ static void stbi__stdio_write(void *context, void *data, int size) static int stbi__start_write_file(stbi__write_context *s, const char *filename) { FILE *f; -#ifdef _MSC_VER +#ifdef STBI_MSC_SECURE_CRT fopen_s(&f, filename, "wb"); #else f = fopen(filename, "wb"); @@ -631,7 +636,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); -#ifdef _MSC_VER +#ifdef STBI_MSC_SECURE_CRT len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); @@ -1019,7 +1024,7 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const int len; unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; -#ifdef _MSC_VER +#ifdef STBI_MSC_SECURE_CRT fopen_s(&f, filename, "wb"); #else f = fopen(filename, "wb"); From eb17d8a6dd32a7b6ce8f345c75505df423be071a Mon Sep 17 00:00:00 2001 From: John Tullos Date: Mon, 1 Jan 2018 18:56:36 -0600 Subject: [PATCH 77/95] Fixed grammar, spelling issues in comments --- stb_image_write.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index b977440..2e644cf 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -10,8 +10,8 @@ Will probably not work correctly with strict-aliasing optimizations. - If using a modern Microsoft Compiler non-safe versions of CRT calls may cause - compilation warnings or even errors. To avoid this, aldo before #including, + If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause + compilation warnings or even errors. To avoid this, also before #including, #define STBI_MSC_SECURE_CRT From 841862a6225c891d32d194267ba4b81f1499755a Mon Sep 17 00:00:00 2001 From: John Tullos Date: Mon, 1 Jan 2018 18:56:36 -0600 Subject: [PATCH 78/95] Fixed grammar, spelling issues in comments issue #533 --- stb_image_write.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index b977440..2e644cf 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -10,8 +10,8 @@ Will probably not work correctly with strict-aliasing optimizations. - If using a modern Microsoft Compiler non-safe versions of CRT calls may cause - compilation warnings or even errors. To avoid this, aldo before #including, + If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause + compilation warnings or even errors. To avoid this, also before #including, #define STBI_MSC_SECURE_CRT From 244d83bc3d859293f55812d48b3db168e581f6ab Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 02:23:18 -0800 Subject: [PATCH 79/95] fix unchecked length in stb_vorbis that could crash on corrupt/invalid files --- stb_vorbis.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index 14cebbf..49829d2 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -3,9 +3,9 @@ // // Original version written by Sean Barrett in 2007. // -// Originally sponsored by RAD Game Tools. Seeking sponsored -// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software, -// Aras Pranckevicius, and Sean Barrett. +// Originally sponsored by RAD Game Tools. Seeking implementation +// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker, +// Elias Software, Aras Pranckevicius, and Sean Barrett. // // LICENSE // @@ -32,6 +32,7 @@ // manxorist@github saga musix github:infatum // // Partial history: +// 1.12 - 2017/11/21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files // 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 @@ -2042,6 +2043,8 @@ static int residue_decode(vorb *f, Codebook *book, float *target, int offset, in return TRUE; } +// n is 1/2 of the blocksize -- +// specification: "Correct per-vector decode length is [n]/2" static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) { int i,j,pass; @@ -2049,7 +2052,10 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int int rtype = f->residue_types[rn]; int c = r->classbook; int classwords = f->codebooks[c].dimensions; - int n_read = r->end - r->begin; + unsigned int actual_size = rtype == 2 ? n*2 : n; + unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size); + unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size); + int n_read = limit_r_end - limit_r_begin; int part_read = n_read / r->part_size; int temp_alloc_point = temp_alloc_save(f); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE @@ -4077,7 +4083,10 @@ static int start_decoder(vorb *f) int i,max_part_read=0; for (i=0; i < f->residue_count; ++i) { Residue *r = f->residue_config + i; - int n_read = r->end - r->begin; + unsigned int actual_size = f->blocksize_1 / 2; + unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size; + unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size; + int n_read = limit_r_end - limit_r_begin; int part_read = n_read / r->part_size; if (part_read > max_part_read) max_part_read = part_read; @@ -4088,6 +4097,8 @@ static int start_decoder(vorb *f) classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); #endif + // maximum reasonable partition size is f->blocksize_1 + f->temp_memory_required = classify_mem; if (imdct_mem > f->temp_memory_required) f->temp_memory_required = imdct_mem; @@ -5351,6 +5362,8 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in #endif // STB_VORBIS_NO_PULLDATA_API /* Version history + 1.12 - 2017/11/21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files + 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 'avoid discarding last frame' fix from previous version 1.08 - 2016/04/02 - fixed multiple warnings; fix setup memory leaks; From 68f857727cd602e636ebf825ec3a47e42dc42b44 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 02:24:05 -0800 Subject: [PATCH 80/95] add stb_ucharcmp to stb.h --- stb.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stb.h b/stb.h index c1523d1..cbbe425 100644 --- a/stb.h +++ b/stb.h @@ -1,4 +1,4 @@ -/* stb.h - v2.30 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h +/* stb.h - v2.31 - Sean's Tool Box -- public domain -- http://nothings.org/stb.h no warranty is offered or implied; use this code at your own risk This is a single header file with a bunch of useful utilities @@ -25,6 +25,7 @@ Version History + 2.31 stb_ucharcmp 2.30 MinGW fix 2.29 attempt to fix use of swprintf() 2.28 various new functionality @@ -1548,7 +1549,7 @@ STB_EXTERN int (*stb_doublecmp(int offset))(const void *a, const void *b); STB_EXTERN int (*stb_charcmp(int offset))(const void *a, const void *b); #ifdef STB_DEFINE -static int stb__intcmpoffset, stb__charcmpoffset, stb__strcmpoffset; +static int stb__intcmpoffset, stb__ucharcmpoffset, stb__strcmpoffset; static int stb__floatcmpoffset, stb__doublecmpoffset; int stb__intcmp(const void *a, const void *b) @@ -1558,10 +1559,10 @@ int stb__intcmp(const void *a, const void *b) return p < q ? -1 : p > q; } -int stb__charcmp(const void *a, const void *b) +int stb__ucharcmp(const void *a, const void *b) { - const int p = *(const unsigned char *) ((const char *) a + stb__charcmpoffset); - const int q = *(const unsigned char *) ((const char *) b + stb__charcmpoffset); + const int p = *(const unsigned char *) ((const char *) a + stb__ucharcmpoffset); + const int q = *(const unsigned char *) ((const char *) b + stb__ucharcmpoffset); return p < q ? -1 : p > q; } @@ -1599,10 +1600,10 @@ int (*stb_intcmp(int offset))(const void *, const void *) return &stb__intcmp; } -int (*stb_charcmp(int offset))(const void *, const void *) +int (*stb_ucharcmp(int offset))(const void *, const void *) { - stb__charcmpoffset = offset; - return &stb__charcmp; + stb__ucharcmpoffset = offset; + return &stb__ucharcmp; } int (*stb_qsort_strcmp(int offset))(const void *, const void *) @@ -1628,7 +1629,6 @@ int (*stb_doublecmp(int offset))(const void *, const void *) stb__doublecmpoffset = offset; return &stb__doublecmp; } - #endif ////////////////////////////////////////////////////////////////////////////// From 593c9b7192e81970caeefcd4d4868c524e8f0c32 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 02:30:34 -0800 Subject: [PATCH 81/95] rewrite stbi__shiftsigned to use a different, faster algorithm to avoid probelm with clang -O2 to outputting buggy code --- stb_image.h | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/stb_image.h b/stb_image.h index a056138..916d4bb 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4963,21 +4963,27 @@ static int stbi__bitcount(unsigned int a) return a & 0xff; } +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. static int stbi__shiftsigned(int v, int shift, int bits) { - int result; - int z=0; - - if (shift < 0) v <<= -shift; - else v >>= shift; - result = v; - - z = bits; - while (z < 8) { - result += v >> z; - z += bits; - } - return result; + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + assert(v >= 0 && v < 256); + v >>= (8-bits); + assert(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; } typedef struct From b056850ea9118b69325d973f8aef7f843527e299 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 02:52:49 -0800 Subject: [PATCH 82/95] stb_image_write can flip images vertically --- stb_image_write.h | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 9d553e0..94c4cf9 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h +/* stb_image_write - v1.08 - 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 @@ -29,7 +29,7 @@ BUILDING: USAGE: - There are four functions, one for each image file format: + There are five 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); @@ -37,7 +37,9 @@ USAGE: 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 + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are expected to open/close your file-equivalent before and after calling these: int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); @@ -151,6 +153,8 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, 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); +extern void stbi_flip_vertically_on_write(int flip_boolean); + #ifdef __cplusplus } #endif @@ -208,6 +212,13 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) +int stbi__flip_vertically_on_write=0; + +void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + typedef struct { stbi_write_func *func; @@ -341,6 +352,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i if (y <= 0) return; + if (stbi__flip_vertically_on_write) + vdir *= -1; + if (vdir < 0) j_end = -1, j = y-1; else @@ -412,11 +426,21 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); } else { int i,j,k; + int jend, jdir; stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); - for (j = y - 1; j >= 0; --j) { - unsigned char *row = (unsigned char *) data + j * x * comp; + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; int len; for (i = 0; i < x; i += len) { @@ -630,7 +654,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f s->func(s->context, buffer, len); for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x); STBIW_FREE(scratch); return 1; } @@ -932,7 +956,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in for (p=0; p < 2; ++p) { for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass int type = mymap[k],est=0; - unsigned char *z = pixels + stride_bytes*j; + unsigned char *z = pixels + stride_bytes*(stbi__flip_vertically_on_write ? y-1-j : j); for (i=0; i < n; ++i) switch (type) { case 0: line_buffer[i] = z[i]; break; @@ -954,7 +978,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; } } - if (p) break; + if (p != 0) break; for (i=0; i < x*n; ++i) est += abs((signed char) line_buffer[i]); if (est < bestval) { bestval = est; best = k; } @@ -1318,7 +1342,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in 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; + int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp; float r, g, b; if(row >= height) { p -= width*comp*(row+1 - height); @@ -1377,6 +1401,8 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write 1.07 (2017-07-24) doc fix 1.06 (2017-07-23) From 39241e492831b1e05aa1bafacbc937b189896251 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 02:53:14 -0800 Subject: [PATCH 83/95] update version number --- stb_image.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 916d4bb..dbbcb74 100644 --- a/stb_image.h +++ b/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h +/* stb_image - v2.17 - 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.17 (2018-01-29) bugfix 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 @@ -6975,6 +6976,7 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int /* revision history: + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug 2.16 (2017-07-23) all functions have 16-bit variants; STBI_NO_STDIO works again; compilation fixes; From 35a3bf41e8f4436c601c4b57030f947fc6a33449 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 02:55:56 -0800 Subject: [PATCH 84/95] Integrate ZLIB changed from Daniel Gibson, fixup credits --- stb_image_write.h | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 85b63d3..79bfc21 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -99,21 +99,16 @@ USAGE: CREDITS: - PNG/BMP/TGA - Sean Barrett - HDR - Baldur Karlsson - TGA monochrome: - Jean-Sebastien Guay - misc enhancements: - Tim Kelsey - TGA RLE - Alan Hickman - initial file IO callback implementation - Emmanuel Julien - JPEG - Jon Olick (original jo_jpeg.cpp code) - Daniel Gibson + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + bugfixes: github:Chribba Guillaume Chereau From 5f1a73fe4e169a65e73657b1c302d43df98ef490 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:18:40 -0800 Subject: [PATCH 85/95] credits, tests --- stb_sprintf.h | 1 + tests/test_c_compilation.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/stb_sprintf.h b/stb_sprintf.h index e8f2b38..a143838 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -13,6 +13,7 @@ // github:trex78 // Jari Komppa (SI suffixes) // Rohit Nirmal +// Marcin Wojdyr // // LICENSE: // diff --git a/tests/test_c_compilation.c b/tests/test_c_compilation.c index 2a54df5..dd31936 100644 --- a/tests/test_c_compilation.c +++ b/tests/test_c_compilation.c @@ -1,4 +1,15 @@ #include "stb_sprintf.h" +#include "stb_easy_font.h" +#include "stb_herringbone_wang_tile.h" +#include "stb_image.h" +#include "stb_image_write.h" +#include "stb_perlin.h" +#include "stb_dxt.h" +#include "stb_c_lexer.h" +#include "stb_divide.h" +#include "stb_image_resize.h" +#include "stb_rect_pack.h" + #define STB_SPRINTF_IMPLEMENTATION #include "stb_sprintf.h" From da4b342213b62d34d81e510f866cb43845ecdf3a Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:23:45 -0800 Subject: [PATCH 86/95] credits --- stb_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 0ff3d34..3aa402d 100644 --- a/stb_image.h +++ b/stb_image.h @@ -78,7 +78,7 @@ RECENT REVISION HISTORY: Daniel Gibson (16-bit TGA) socks-the-fox (16-bit PNG) Jeremy Sawicki (handle all ImageNet JPGs) - Optimizations & bugfixes + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Arseny Kapoulkine John-Mark Allen From 8cc624142b260c069db2a10f586b30a79dd19f5e Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:25:02 -0800 Subject: [PATCH 87/95] credits --- stb_image.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/stb_image.h b/stb_image.h index 29a26e6..6dae0e1 100644 --- a/stb_image.h +++ b/stb_image.h @@ -88,16 +88,16 @@ RECENT REVISION HISTORY: Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan Dave Moore Roy Eltham Hayaki Saito Nathan Reed Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson - Janez Zemva John Bartholomew Michal Cichon github:rlyeh - Jonathan Blow Ken Hamada Tero Hanninen github:romigrou - Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk - Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar - Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex - 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 + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Michaelangel007@github Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Blazej Dariusz Roszkowski Gregory Mullen github:poppolopoppo + Christian Floisand Kevin Schmidt Baldur Karlsson darealshinji */ #ifndef STBI_INCLUDE_STB_IMAGE_H From 72ef9dcbadd37562cfe75f5ca3e0346954f129f1 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:27:58 -0800 Subject: [PATCH 88/95] fix fall-through case warning, add credit --- stb_image.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/stb_image.h b/stb_image.h index 6dae0e1..e0cf014 100644 --- a/stb_image.h +++ b/stb_image.h @@ -97,7 +97,8 @@ RECENT REVISION HISTORY: Michaelangel007@github Philipp Wiesemann Dale Weiler github:sammyhw Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus Blazej Dariusz Roszkowski Gregory Mullen github:poppolopoppo - Christian Floisand Kevin Schmidt Baldur Karlsson darealshinji + Christian Floisand Kevin Schmidt Baldur Karlsson github:darealshinji + Aldo Culquicondor */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -5264,13 +5265,13 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) { // only RGB or RGBA (incl. 16bit) or grey allowed - if(is_rgb16) *is_rgb16 = 0; + if (is_rgb16) *is_rgb16 = 0; switch(bits_per_pixel) { case 8: return STBI_grey; case 16: if(is_grey) return STBI_grey_alpha; - // else: fall-through + // fall-through case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; + return STBI_rgb; case 24: // fall-through case 32: return bits_per_pixel/8; default: return 0; From 986a5eeeb1a3acdc71d65927177e731436f46c78 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:35:03 -0800 Subject: [PATCH 89/95] fix stb_truetype test file --- tests/stb.dsp | 2 +- tests/test_c_compilation.c | 11 ----------- tests/test_truetype.c | 5 +++-- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/stb.dsp b/tests/stb.dsp index 7e20a14..8e09df5 100644 --- a/tests/stb.dsp +++ b/tests/stb.dsp @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "VORBIS_TEST" /FR /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" diff --git a/tests/test_c_compilation.c b/tests/test_c_compilation.c index dd31936..2a54df5 100644 --- a/tests/test_c_compilation.c +++ b/tests/test_c_compilation.c @@ -1,15 +1,4 @@ #include "stb_sprintf.h" -#include "stb_easy_font.h" -#include "stb_herringbone_wang_tile.h" -#include "stb_image.h" -#include "stb_image_write.h" -#include "stb_perlin.h" -#include "stb_dxt.h" -#include "stb_c_lexer.h" -#include "stb_divide.h" -#include "stb_image_resize.h" -#include "stb_rect_pack.h" - #define STB_SPRINTF_IMPLEMENTATION #include "stb_sprintf.h" diff --git a/tests/test_truetype.c b/tests/test_truetype.c index b432fd4..1ac147b 100644 --- a/tests/test_truetype.c +++ b/tests/test_truetype.c @@ -3,11 +3,12 @@ #define _CRT_SECURE_NO_WARNINGS #endif -#define STB_RECT_PACK_IMPLEMENTATION +#include + +// this isn't meant to compile standalone; link with test_c_compilation.c as well #include "stb_rect_pack.h" #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" -#define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" #ifdef TT_TEST From 501e29b2451e514b60b1b7eea2535edbd6e39be7 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:36:23 -0800 Subject: [PATCH 90/95] stb_truetype.h docs --- stb_truetype.h | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 51406ab..e5b441e 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -30,33 +30,25 @@ // Imanol Celaya // // Bug/warning reports/fixes: -// "Zer" on mollyrocket -// Cass Everitt -// stoiko (Haemimont Games) -// Brian Hook -// Walter van Niftrik -// David Gow -// David Given -// Ivan-Assen Ivanov -// Anthony Pesch -// Johan Duparc -// Hou Qiming -// Fabian "ryg" Giesen -// Martins Mozeiko -// Cap Petschulat -// Omar Cornut -// github:aloucks -// Peter LaValle -// Sergey Popov -// Giumo X. Clanjor -// Higor Euripedes -// Thomas Fields -// Derek Vinyard -// Cort Stratton -// github:oyvindjam -// +// "Zer" on mollyrocket Fabian "ryg" Giesen +// Cass Everitt Martins Mozeiko +// stoiko (Haemimont Games) Cap Petschulat +// Brian Hook Omar Cornut +// Walter van Niftrik github:aloucks +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Cort Stratton +// github:oyvindjam +// Kenney Phillis Jr. +// +// // VERSION HISTORY // +// 1.18 (2018-01-29) add missing function // 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 From 0bd0d049e77ee8f589f8068f62e5391509abc233 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:42:34 -0800 Subject: [PATCH 91/95] stb_image docs --- stb_image.h | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/stb_image.h b/stb_image.h index 9017ed9..9cfcbd6 100644 --- a/stb_image.h +++ b/stb_image.h @@ -48,7 +48,7 @@ LICENSE RECENT REVISION HISTORY: - 2.17 (2018-01-29) bugfix + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query 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 @@ -79,7 +79,7 @@ RECENT REVISION HISTORY: socks-the-fox (16-bit PNG) Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) - Fabian "ryg" Giesen + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) Arseny Kapoulkine John-Mark Allen @@ -418,14 +418,14 @@ STBIDEF void stbi_image_free (void *retval_from_stbi_load); // get image dimensions & components without fully decoding STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_from_memory(stbi_uc const *buffer, int len); -STBIDEF int stbi_is_16_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); #ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -STBIDEF int stbi_is_16 (char const *filename); -STBIDEF int stbi_is_16_from_file (FILE *f); +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); #endif @@ -7038,17 +7038,17 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) return r; } -STBIDEF int stbi_is_16(char const *filename) +STBIDEF int stbi_is_16_bit(char const *filename) { FILE *f = stbi__fopen(filename, "rb"); int result; if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_is_16_from_file(f); + result = stbi_is_16_bit_from_file(f); fclose(f); return result; } -STBIDEF int stbi_is_16_from_file(FILE *f) +STBIDEF int stbi_is_16_bit_from_file(FILE *f) { int r; stbi__context s; @@ -7074,14 +7074,14 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int return stbi__info_main(&s,x,y,comp); } -STBIDEF int stbi_is_16_from_memory(stbi_uc const *buffer, int len) +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi__is_16_main(&s); } -STBIDEF int stbi_is_16_from_callbacks(stbi_io_callbacks const *c, void *user) +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); @@ -7093,6 +7093,9 @@ STBIDEF int stbi_is_16_from_callbacks(stbi_io_callbacks const *c, void *user) /* revision history: 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings 2.16 (2017-07-23) all functions have 16-bit variants; STBI_NO_STDIO works again; compilation fixes; From f9d78c05a928a7a036da685615fb1f0768e06788 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:49:53 -0800 Subject: [PATCH 92/95] stb_image credits --- stb_image.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stb_image.h b/stb_image.h index 2578204..7bbfac9 100644 --- a/stb_image.h +++ b/stb_image.h @@ -48,7 +48,7 @@ LICENSE RECENT REVISION HISTORY: - 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs @@ -94,11 +94,11 @@ RECENT REVISION HISTORY: Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Michaelangel007@github Philipp Wiesemann Dale Weiler github:sammyhw + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Blazej Dariusz Roszkowski Gregory Mullen github:poppolopoppo - Christian Floisand Kevin Schmidt Baldur Karlsson github:darealshinji - Aldo Culquicondor + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt github:darealshinji + Blazej Dariusz Roszkowski github:Michaelangel007 */ #ifndef STBI_INCLUDE_STB_IMAGE_H From ae00f3a5f0253e553fc03beb7427a2dad6b1fdfa Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:50:42 -0800 Subject: [PATCH 93/95] stb_image credits --- stb_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 1ffd829..57488ab 100644 --- a/stb_image.h +++ b/stb_image.h @@ -75,7 +75,7 @@ RECENT REVISION HISTORY: Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) github:urraka (animated gif) Junggon Kim (PNM comments) - github:tocchan (animated gif) Daniel Gibson (16-bit TGA) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) socks-the-fox (16-bit PNG) Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) From 4254a9f23798800c912608636ac94acd18cc7bb6 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 03:59:48 -0800 Subject: [PATCH 94/95] stb_truetype credits --- stb_truetype.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 07770f8..c0e2858 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -41,9 +41,8 @@ // Anthony Pesch Higor Euripedes // Johan Duparc Thomas Fields // Hou Qiming Derek Vinyard -// Cort Stratton -// github:oyvindjam -// Kenney Phillis Jr. +// Rob Loach Cort Stratton +// Kenney Phillis Jr. github:oyvindjam // // // VERSION HISTORY From 094cb31ec8a84962654a89002825e69dde43b805 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 29 Jan 2018 04:03:18 -0800 Subject: [PATCH 95/95] stb_image: compile as C; stb_image_write: credits --- stb_image.h | 3 ++- stb_image_write.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 57488ab..72fcfc8 100644 --- a/stb_image.h +++ b/stb_image.h @@ -1236,10 +1236,11 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u #ifndef STBI_NO_GIF STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { + unsigned char *result; stbi__context s; stbi__start_mem(&s,buffer,len); - unsigned char *result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); if (stbi__vertically_flip_on_load) { stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); } diff --git a/stb_image_write.h b/stb_image_write.h index 60a1396..49f9449 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -132,6 +132,7 @@ CREDITS: Thatcher Ulrich github:poppolopoppo Patrick Boettcher + github:xeekworx LICENSE