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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

k*QNRvtVEN<}Sf}bga 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 C3#%Rg 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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�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 Q7#J8lUHx3vIVCg!0BNiJVgLXD 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