From 6e32d1e0102c7fba9ef21a5939f083e34e736eea Mon Sep 17 00:00:00 2001 From: castano Date: Sun, 9 May 2010 08:21:34 +0000 Subject: [PATCH] Update latest stb_dxt. --- extern/stb/stb_dxt.h | 1179 ++++++++++++++++++++++-------------------- extern/stb/stb_gl.h | 1098 --------------------------------------- 2 files changed, 624 insertions(+), 1653 deletions(-) delete mode 100644 extern/stb/stb_gl.h diff --git a/extern/stb/stb_dxt.h b/extern/stb/stb_dxt.h index 2000f6b..bec7279 100644 --- a/extern/stb/stb_dxt.h +++ b/extern/stb/stb_dxt.h @@ -1,555 +1,624 @@ -// stb_dxt.h - v1.03 - DXT1/DXT5 compressor - public domain -// original by fabian "ryg" giesen - ported to C by stb -// use '#define STB_DEFINE' before including to create the implementation -// -// USAGE: -// call stb_compress_dxt_block() for every block (you must pad) -// source should be a 4x4 block of RGBA data in row-major order; -// A is ignored if you specify alpha=0; you get dithering if -// quality=1 -// -// version history: -// v1.03 - endianness support -// v1.02 - fix alpha encoding bug -// v1.01 - fix bug converting to RGB that messed up quality, thanks ryg & cbloom -// v1.00 - first release - -#ifndef STB_INCLUDE_STB_DXT_H -#define STB_INCLUDE_STB_DXT_H - -void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int quality); -#define STB_COMPRESS_DXT_BLOCK - -#ifdef STB_DEFINE - -#include -#include -#include // memset - -static unsigned char stb__Expand5[32]; -static unsigned char stb__Expand6[64]; -static unsigned char stb__OMatch5[256][2]; -static unsigned char stb__OMatch6[256][2]; -static unsigned char stb__QuantRBTab[256+16]; -static unsigned char stb__QuantGTab[256+16]; - -static int stb__Mul8Bit(int a,int b) -{ - int t = a*b + 128; - return (t + (t >> 8)) >> 8; -} - -static void stb__From16Bit(unsigned char *out, unsigned short v) -{ - int rv = (v & 0xf800) >> 11; - int gv = (v & 0x07e0) >> 5; - int bv = (v & 0x001f) >> 0; - - out[0] = stb__Expand5[rv]; - out[1] = stb__Expand6[gv]; - out[2] = stb__Expand5[bv]; - out[3] = 0; -} - -static unsigned short stb__As16Bit(int r, int g, int b) -{ - return (stb__Mul8Bit(r,31) << 11) + (stb__Mul8Bit(g,63) << 5) + stb__Mul8Bit(b,31); -} - -static void stb__LerpRGB(unsigned char *out, unsigned char *p1, unsigned char *p2, int f) -{ - out[0] = p1[0] + stb__Mul8Bit(p2[0] - p1[0],f); - out[1] = p1[1] + stb__Mul8Bit(p2[1] - p1[1],f); - out[2] = p1[2] + stb__Mul8Bit(p2[2] - p1[2],f); -} - -/****************************************************************************/ - -// compute table to reproduce constant colors as accurately as possible -static void stb__PrepareOptTable(unsigned char *Table,const unsigned char *expand,int size) -{ - int i,mn,mx; - for (i=0;i<256;i++) { - int bestErr = 256; - for (mn=0;mn> 4)]; - ep1[0] = bp[ 0] - dp[ 0]; - dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)]; - ep1[1] = bp[ 4] - dp[ 4]; - dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)]; - ep1[2] = bp[ 8] - dp[ 8]; - dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)]; - ep1[3] = bp[12] - dp[12]; - bp += 16; - dp += 16; - et = ep1, ep1 = ep2, ep2 = et; // swap - } - } -} - -// The color matching function -static unsigned int stb__MatchColorsBlock(unsigned char *block, unsigned char *color,int dither) -{ - unsigned int mask = 0; - int dirr = color[0*4+0] - color[1*4+0]; - int dirg = color[0*4+1] - color[1*4+1]; - int dirb = color[0*4+2] - color[1*4+2]; - int dots[16]; - int stops[4]; - int i; - int c0Point, halfPoint, c3Point; - - for(i=0;i<16;i++) - dots[i] = block[i*4+0]*dirr + block[i*4+1]*dirg + block[i*4+2]*dirb; - - for(i=0;i<4;i++) - stops[i] = color[i*4+0]*dirr + color[i*4+1]*dirg + color[i*4+2]*dirb; - - c0Point = (stops[1] + stops[3]) >> 1; - halfPoint = (stops[3] + stops[2]) >> 1; - c3Point = (stops[2] + stops[0]) >> 1; - - if(!dither) { - // the version without dithering is straightforward - for (i=15;i>=0;i--) { - int dot = dots[i]; - mask <<= 2; - - if(dot < halfPoint) - mask |= (dot < c0Point) ? 1 : 3; - else - mask |= (dot < c3Point) ? 2 : 0; - } - } else { - // with floyd-steinberg dithering - int err[8],*ep1 = err,*ep2 = err+4; - int *dp = dots, y; - - c0Point <<= 4; - halfPoint <<= 4; - c3Point <<= 4; - for(i=0;i<8;i++) - err[i] = 0; - - for(y=0;y<4;y++) - { - int dot,lmask,step; - - dot = (dp[0] << 4) + (3*ep2[1] + 5*ep2[0]); - if(dot < halfPoint) - step = (dot < c0Point) ? 1 : 3; - else - step = (dot < c3Point) ? 2 : 0; - ep1[0] = dp[0] - stops[step]; - lmask = step; - - dot = (dp[1] << 4) + (7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]); - if(dot < halfPoint) - step = (dot < c0Point) ? 1 : 3; - else - step = (dot < c3Point) ? 2 : 0; - ep1[1] = dp[1] - stops[step]; - lmask |= step<<2; - - dot = (dp[2] << 4) + (7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]); - if(dot < halfPoint) - step = (dot < c0Point) ? 1 : 3; - else - step = (dot < c3Point) ? 2 : 0; - ep1[2] = dp[2] - stops[step]; - lmask |= step<<4; - - dot = (dp[3] << 4) + (7*ep1[2] + 5*ep2[3] + ep2[2]); - if(dot < halfPoint) - step = (dot < c0Point) ? 1 : 3; - else - step = (dot < c3Point) ? 2 : 0; - ep1[3] = dp[3] - stops[step]; - lmask |= step<<6; - - dp += 4; - mask |= lmask << (y*8); - { int *et = ep1; ep1 = ep2; ep2 = et; } // swap - } - } - - return mask; -} - -// The color optimization function. (Clever code, part 1) -static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16) -{ - int mind = 0x7fffffff,maxd = -0x7fffffff; - unsigned char *minp, *maxp; - double magn; - int v_r,v_g,v_b; - static const int nIterPower = 4; - float covf[6],vfr,vfg,vfb; - - // determine color distribution - int cov[6]; - int mu[3],min[3],max[3]; - int ch,i,iter; - - for(ch=0;ch<3;ch++) - { - const unsigned char *bp = ((const unsigned char *) block) + ch; - int muv,minv,maxv; - - muv = minv = maxv = bp[0]; - for(i=4;i<64;i+=4) - { - muv += bp[i]; - if (bp[i] < minv) minv = bp[i]; - else if (bp[i] > maxv) maxv = bp[i]; - } - - mu[ch] = (muv + 8) >> 4; - min[ch] = minv; - max[ch] = maxv; - } - - // determine covariance matrix - for (i=0;i<6;i++) - cov[i] = 0; - - for (i=0;i<16;i++) - { - int r = block[i*4+0] - mu[0]; - int g = block[i*4+1] - mu[1]; - int b = block[i*4+2] - mu[2]; - - cov[0] += r*r; - cov[1] += r*g; - cov[2] += r*b; - cov[3] += g*g; - cov[4] += g*b; - cov[5] += b*b; - } - - // convert covariance matrix to float, find principal axis via power iter - for(i=0;i<6;i++) - covf[i] = cov[i] / 255.0f; - - vfr = (float) (max[0] - min[0]); - vfg = (float) (max[1] - min[1]); - vfb = (float) (max[2] - min[2]); - - for(iter=0;iter magn) magn = fabs(vfg); - if (fabs(vfb) > magn) magn = fabs(vfb); - - if(magn < 4.0f) { // too small, default to luminance - v_r = 148; - v_g = 300; - v_b = 58; - } else { - magn = 512.0 / magn; - v_r = (int) (vfr * magn); - v_g = (int) (vfg * magn); - v_b = (int) (vfb * magn); - } - - // Pick colors at extreme points - for(i=0;i<16;i++) - { - int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b; - - if (dot < mind) { - mind = dot; - minp = block+i*4; - } - - if (dot > maxd) { - maxd = dot; - maxp = block+i*4; - } - } - - *pmax16 = stb__As16Bit(maxp[0],maxp[1],maxp[2]); - *pmin16 = stb__As16Bit(minp[0],minp[1],minp[2]); -} - -static int stb__sclamp(float y, int p0, int p1) -{ - int x = (int) y; - if (x < p0) return p0; - if (x > p1) return p1; - return x; -} - -// The refinement function. (Clever code, part 2) -// Tries to optimize colors to suit block contents better. -// (By solving a least squares system via normal equations+Cramer's rule) -static int stb__RefineBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16, unsigned int mask) -{ - static const int w1Tab[4] = { 3,0,2,1 }; - static const int prods[4] = { 0x090000,0x000900,0x040102,0x010402 }; - // ^some magic to save a lot of multiplies in the accumulating loop... - - float frb,fg; - unsigned short oldMin, oldMax, min16, max16; - int i, akku = 0, xx,xy,yy; - int At1_r,At1_g,At1_b; - int At2_r,At2_g,At2_b; - unsigned int cm = mask; - - oldMin = *pmin16; - oldMax = *pmax16; - - if((mask ^ (mask<<2)) < 4) // all pixels have the same index? - { - // yes, linear system would be singular; solve using optimal - // single-color match on average color - int r = 8, g = 8, b = 8; - for (i=0;i<16;++i) { - r += block[i*4+0]; - g += block[i*4+1]; - b += block[i*4+2]; - } - - r >>= 4; g >>= 4; b >>= 4; - - max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; - min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; - } else { - At1_r = At1_g = At1_b = 0; - At2_r = At2_g = At2_b = 0; - for (i=0;i<16;++i,cm>>=2) { - int step = cm&3; - int w1 = w1Tab[step]; - int r = block[i*4+0]; - int g = block[i*4+1]; - int b = block[i*4+2]; - - akku += prods[step]; - At1_r += w1*r; - At1_g += w1*g; - At1_b += w1*b; - At2_r += r; - At2_g += g; - At2_b += b; - } - - At2_r = 3*At2_r - At1_r; - At2_g = 3*At2_g - At1_g; - At2_b = 3*At2_b - At1_b; - - // extract solutions and decide solvability - xx = akku >> 16; - yy = (akku >> 8) & 0xff; - xy = (akku >> 0) & 0xff; - - frb = 3.0f * 31.0f / 255.0f / (xx*yy - xy*xy); - fg = frb * 63.0f / 31.0f; - - // solve. - max16 = stb__sclamp((At1_r*yy - At2_r*xy)*frb+0.5f,0,31) << 11; - max16 |= stb__sclamp((At1_g*yy - At2_g*xy)*fg +0.5f,0,63) << 5; - max16 |= stb__sclamp((At1_b*yy - At2_b*xy)*frb+0.5f,0,31) << 0; - - min16 = stb__sclamp((At2_r*xx - At1_r*xy)*frb+0.5f,0,31) << 11; - min16 |= stb__sclamp((At2_g*xx - At1_g*xy)*fg +0.5f,0,63) << 5; - min16 |= stb__sclamp((At2_b*xx - At1_b*xy)*frb+0.5f,0,31) << 0; - } - - *pmin16 = min16; - *pmax16 = max16; - return oldMin != min16 || oldMax != max16; -} - -// Color block compression -static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block,int quality) -{ - unsigned int mask; - int i; - unsigned short max16, min16; - unsigned char dblock[16*4],color[4*4]; - - // check if block is constant - for (i=1;i<16;i++) - if (((unsigned int *) block)[i] != ((unsigned int *) block)[0]) - break; - - if(i == 16) { // constant color - int r = block[0], g = block[1], b = block[2]; - mask = 0xaaaaaaaa; - max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; - min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; - } else { - // first step: compute dithered version for PCA if desired - if(quality) - stb__DitherBlock(dblock,block); - - // second step: pca+map along principal axis - stb__OptimizeColorsBlock(quality ? dblock : block,&max16,&min16); - if (max16 != min16) { - stb__EvalColors(color,max16,min16); - mask = stb__MatchColorsBlock(block,color,quality != 0); - } else - mask = 0; - - // third step: refine - if (stb__RefineBlock(quality ? dblock : block,&max16,&min16,mask)) { - if (max16 != min16) { - stb__EvalColors(color,max16,min16); - mask = stb__MatchColorsBlock(block,color,quality != 0); - } else - mask = 0; - } - } - - // write the color block - if(max16 < min16) - { - unsigned short t = min16; - min16 = max16; - max16 = t; - mask ^= 0x55555555; - } - - dest[0] = (unsigned char) (max16); - dest[1] = (unsigned char) (max16 >> 8); - dest[2] = (unsigned char) (min16); - dest[3] = (unsigned char) (min16 >> 8); - dest[4] = (unsigned char) (mask); - dest[5] = (unsigned char) (mask >> 8); - dest[6] = (unsigned char) (mask >> 16); - dest[7] = (unsigned char) (mask >> 24); -} - -// Alpha block compression (this is easy for a change) -static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int quality) -{ - int i,dist,bias,dist4,dist2,bits,mask; - - // find min/max color - int mn,mx; - mn = mx = src[3]; - - for (i=1;i<16;i++) - { - if (src[i*4+3] < mn) mn = src[i*4+3]; - else if (src[i*4+3] > mx) mx = src[i*4+3]; - } - - // encode them - ((unsigned char *)dest)[0] = mx; - ((unsigned char *)dest)[1] = mn; - dest += 2; - - // determine bias and emit color indices - dist = mx-mn; - bias = mn*7 - (dist >> 1); - dist4 = dist*4; - dist2 = dist*2; - bits = 0,mask=0; - - for (i=0;i<16;i++) { - int a = src[i*4+3]*7 - bias; - int ind,t; - - // select index (hooray for bit magic) - t = (dist4 - a) >> 31; ind = t & 4; a -= dist4 & t; - t = (dist2 - a) >> 31; ind += t & 2; a -= dist2 & t; - t = (dist - a) >> 31; ind += t & 1; - - ind = -ind & 7; - ind ^= (2 > ind); - - // write index - mask |= ind << bits; - if((bits += 3) >= 8) { - *dest++ = mask; - mask >>= 8; - bits -= 8; - } - } -} - -static void stb__InitDXT() -{ - int i; - for(i=0;i<32;i++) - stb__Expand5[i] = (i<<3)|(i>>2); - - for(i=0;i<64;i++) - stb__Expand6[i] = (i<<2)|(i>>4); - - for(i=0;i<256+16;i++) - { - int v = i-8 < 0 ? 0 : i-8 > 255 ? 255 : i-8; - stb__QuantRBTab[i] = stb__Expand5[stb__Mul8Bit(v,31)]; - stb__QuantGTab[i] = stb__Expand6[stb__Mul8Bit(v,63)]; - } - - stb__PrepareOptTable(&stb__OMatch5[0][0],stb__Expand5,32); - stb__PrepareOptTable(&stb__OMatch6[0][0],stb__Expand6,64); -} - -void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int quality) -{ - static int init=1; - if (init) { - stb__InitDXT(); - init=0; - } - - if (alpha) { - stb__CompressAlphaBlock(dest,(unsigned char*) src,quality); - dest += 8; - } - - stb__CompressColorBlock(dest,(unsigned char*) src,quality); -} -#endif // STB_DEFINE - -#endif // STB_INCLUDE_STB_DXT_H +// stb_dxt.h - v1.04 - 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 +// +// USAGE: +// call stb_compress_dxt_block() for every block (you must pad) +// source should be a 4x4 block of RGBA data in row-major order; +// A is ignored if you specify alpha=0; you can turn on dithering +// and "high quality" using mode. +// +// version history: +// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec); +// single color match fix (allow for inexact color interpolation); +// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps. +// v1.03 - (stb) endianness support +// v1.02 - (stb) fix alpha encoding bug +// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom +// v1.00 - (stb) first release + +#ifndef STB_INCLUDE_STB_DXT_H +#define STB_INCLUDE_STB_DXT_H + +// compression mode (bitflags) +#define STB_DXT_NORMAL 0 +#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like! +#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower. + +void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode); +#define STB_COMPRESS_DXT_BLOCK + +#ifdef STB_DXT_IMPLEMENTATION + +// configuration options for DXT encoder. set them in the project/makefile or just define +// them at the top. + +// STB_DXT_USE_ROUNDING_BIAS +// use a rounding bias during color interpolation. this is closer to what "ideal" +// interpolation would do but doesn't match the S3TC/DX10 spec. old versions (pre-1.03) +// implicitly had this turned on. +// +// in case you're targeting a specific type of hardware (e.g. console programmers): +// NVidia and Intel GPUs (as of 2010) as well as DX9 ref use DXT decoders that are closer +// to STB_DXT_USE_ROUNDING_BIAS. AMD/ATI, S3 and DX10 ref are closer to rounding with no bias. +// you also see "(a*5 + b*3) / 8" on some old GPU designs. +// #define STB_DXT_USE_ROUNDING_BIAS + +#include +#include +#include // memset + +static unsigned char stb__Expand5[32]; +static unsigned char stb__Expand6[64]; +static unsigned char stb__OMatch5[256][2]; +static unsigned char stb__OMatch6[256][2]; +static unsigned char stb__QuantRBTab[256+16]; +static unsigned char stb__QuantGTab[256+16]; + +static int stb__Mul8Bit(int a, int b) +{ + int t = a*b + 128; + return (t + (t >> 8)) >> 8; +} + +static void stb__From16Bit(unsigned char *out, unsigned short v) +{ + int rv = (v & 0xf800) >> 11; + int gv = (v & 0x07e0) >> 5; + int bv = (v & 0x001f) >> 0; + + out[0] = stb__Expand5[rv]; + out[1] = stb__Expand6[gv]; + out[2] = stb__Expand5[bv]; + out[3] = 0; +} + +static unsigned short stb__As16Bit(int r, int g, int b) +{ + return (stb__Mul8Bit(r,31) << 11) + (stb__Mul8Bit(g,63) << 5) + stb__Mul8Bit(b,31); +} + +// linear interpolation at 1/3 point between a and b, using desired rounding type +static int stb__Lerp13(int a, int b) +{ +#ifdef STB_DXT_USE_ROUNDING_BIAS + // with rounding bias + return a + stb__Mul8Bit(b-a, 0x55); +#else + // without rounding bias + // replace "/ 3" by "* 0xaaab) >> 17" if your compiler sucks or you really need every ounce of speed. + return (2*a + b) / 3; +#endif +} + +// lerp RGB color +static void stb__Lerp13RGB(unsigned char *out, unsigned char *p1, unsigned char *p2) +{ + out[0] = stb__Lerp13(p1[0], p2[0]); + out[1] = stb__Lerp13(p1[1], p2[1]); + out[2] = stb__Lerp13(p1[2], p2[2]); +} + +/****************************************************************************/ + +// compute table to reproduce constant colors as accurately as possible +static void stb__PrepareOptTable(unsigned char *Table,const unsigned char *expand,int size) +{ + int i,mn,mx; + for (i=0;i<256;i++) { + int bestErr = 256; + for (mn=0;mn> 4)]; + ep1[0] = bp[ 0] - dp[ 0]; + dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)]; + ep1[1] = bp[ 4] - dp[ 4]; + dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)]; + ep1[2] = bp[ 8] - dp[ 8]; + dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)]; + ep1[3] = bp[12] - dp[12]; + bp += 16; + dp += 16; + et = ep1, ep1 = ep2, ep2 = et; // swap + } + } +} + +// The color matching function +static unsigned int stb__MatchColorsBlock(unsigned char *block, unsigned char *color,int dither) +{ + unsigned int mask = 0; + int dirr = color[0*4+0] - color[1*4+0]; + int dirg = color[0*4+1] - color[1*4+1]; + int dirb = color[0*4+2] - color[1*4+2]; + int dots[16]; + int stops[4]; + int i; + int c0Point, halfPoint, c3Point; + + for(i=0;i<16;i++) + dots[i] = block[i*4+0]*dirr + block[i*4+1]*dirg + block[i*4+2]*dirb; + + for(i=0;i<4;i++) + stops[i] = color[i*4+0]*dirr + color[i*4+1]*dirg + color[i*4+2]*dirb; + + // think of the colors as arranged on a line; project point onto that line, then choose + // next color out of available ones. we compute the crossover points for "best color in top + // half"/"best in bottom half" and then the same inside that subinterval. + // + // relying on this 1d approximation isn't always optimal in terms of euclidean distance, + // but it's very close and a lot faster. + // http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html + + c0Point = (stops[1] + stops[3]) >> 1; + halfPoint = (stops[3] + stops[2]) >> 1; + c3Point = (stops[2] + stops[0]) >> 1; + + if(!dither) { + // the version without dithering is straightforward + for (i=15;i>=0;i--) { + int dot = dots[i]; + mask <<= 2; + + if(dot < halfPoint) + mask |= (dot < c0Point) ? 1 : 3; + else + mask |= (dot < c3Point) ? 2 : 0; + } + } else { + // with floyd-steinberg dithering + int err[8],*ep1 = err,*ep2 = err+4; + int *dp = dots, y; + + c0Point <<= 4; + halfPoint <<= 4; + c3Point <<= 4; + for(i=0;i<8;i++) + err[i] = 0; + + for(y=0;y<4;y++) + { + int dot,lmask,step; + + dot = (dp[0] << 4) + (3*ep2[1] + 5*ep2[0]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[0] = dp[0] - stops[step]; + lmask = step; + + dot = (dp[1] << 4) + (7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[1] = dp[1] - stops[step]; + lmask |= step<<2; + + dot = (dp[2] << 4) + (7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[2] = dp[2] - stops[step]; + lmask |= step<<4; + + dot = (dp[3] << 4) + (7*ep1[2] + 5*ep2[3] + ep2[2]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[3] = dp[3] - stops[step]; + lmask |= step<<6; + + dp += 4; + mask |= lmask << (y*8); + { int *et = ep1; ep1 = ep2; ep2 = et; } // swap + } + } + + return mask; +} + +// The color optimization function. (Clever code, part 1) +static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16) +{ + int mind = 0x7fffffff,maxd = -0x7fffffff; + unsigned char *minp, *maxp; + double magn; + int v_r,v_g,v_b; + static const int nIterPower = 4; + float covf[6],vfr,vfg,vfb; + + // determine color distribution + int cov[6]; + int mu[3],min[3],max[3]; + int ch,i,iter; + + for(ch=0;ch<3;ch++) + { + const unsigned char *bp = ((const unsigned char *) block) + ch; + int muv,minv,maxv; + + muv = minv = maxv = bp[0]; + for(i=4;i<64;i+=4) + { + muv += bp[i]; + if (bp[i] < minv) minv = bp[i]; + else if (bp[i] > maxv) maxv = bp[i]; + } + + mu[ch] = (muv + 8) >> 4; + min[ch] = minv; + max[ch] = maxv; + } + + // determine covariance matrix + for (i=0;i<6;i++) + cov[i] = 0; + + for (i=0;i<16;i++) + { + int r = block[i*4+0] - mu[0]; + int g = block[i*4+1] - mu[1]; + int b = block[i*4+2] - mu[2]; + + cov[0] += r*r; + cov[1] += r*g; + cov[2] += r*b; + cov[3] += g*g; + cov[4] += g*b; + cov[5] += b*b; + } + + // convert covariance matrix to float, find principal axis via power iter + for(i=0;i<6;i++) + covf[i] = cov[i] / 255.0f; + + vfr = (float) (max[0] - min[0]); + vfg = (float) (max[1] - min[1]); + vfb = (float) (max[2] - min[2]); + + for(iter=0;iter magn) magn = fabs(vfg); + if (fabs(vfb) > magn) magn = fabs(vfb); + + if(magn < 4.0f) { // too small, default to luminance + v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000. + v_g = 587; + v_b = 114; + } else { + magn = 512.0 / magn; + v_r = (int) (vfr * magn); + v_g = (int) (vfg * magn); + v_b = (int) (vfb * magn); + } + + // Pick colors at extreme points + for(i=0;i<16;i++) + { + int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b; + + if (dot < mind) { + mind = dot; + minp = block+i*4; + } + + if (dot > maxd) { + maxd = dot; + maxp = block+i*4; + } + } + + *pmax16 = stb__As16Bit(maxp[0],maxp[1],maxp[2]); + *pmin16 = stb__As16Bit(minp[0],minp[1],minp[2]); +} + +static int stb__sclamp(float y, int p0, int p1) +{ + int x = (int) y; + if (x < p0) return p0; + if (x > p1) return p1; + return x; +} + +// The refinement function. (Clever code, part 2) +// Tries to optimize colors to suit block contents better. +// (By solving a least squares system via normal equations+Cramer's rule) +static int stb__RefineBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16, unsigned int mask) +{ + static const int w1Tab[4] = { 3,0,2,1 }; + static const int prods[4] = { 0x090000,0x000900,0x040102,0x010402 }; + // ^some magic to save a lot of multiplies in the accumulating loop... + // (precomputed products of weights for least squares system, accumulated inside one 32-bit register) + + float frb,fg; + unsigned short oldMin, oldMax, min16, max16; + int i, akku = 0, xx,xy,yy; + int At1_r,At1_g,At1_b; + int At2_r,At2_g,At2_b; + unsigned int cm = mask; + + oldMin = *pmin16; + oldMax = *pmax16; + + if((mask ^ (mask<<2)) < 4) // all pixels have the same index? + { + // yes, linear system would be singular; solve using optimal + // single-color match on average color + int r = 8, g = 8, b = 8; + for (i=0;i<16;++i) { + r += block[i*4+0]; + g += block[i*4+1]; + b += block[i*4+2]; + } + + r >>= 4; g >>= 4; b >>= 4; + + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else { + At1_r = At1_g = At1_b = 0; + At2_r = At2_g = At2_b = 0; + for (i=0;i<16;++i,cm>>=2) { + int step = cm&3; + int w1 = w1Tab[step]; + int r = block[i*4+0]; + int g = block[i*4+1]; + int b = block[i*4+2]; + + akku += prods[step]; + At1_r += w1*r; + At1_g += w1*g; + At1_b += w1*b; + At2_r += r; + At2_g += g; + At2_b += b; + } + + At2_r = 3*At2_r - At1_r; + At2_g = 3*At2_g - At1_g; + At2_b = 3*At2_b - At1_b; + + // extract solutions and decide solvability + xx = akku >> 16; + yy = (akku >> 8) & 0xff; + xy = (akku >> 0) & 0xff; + + frb = 3.0f * 31.0f / 255.0f / (xx*yy - xy*xy); + fg = frb * 63.0f / 31.0f; + + // solve. + max16 = stb__sclamp((At1_r*yy - At2_r*xy)*frb+0.5f,0,31) << 11; + max16 |= stb__sclamp((At1_g*yy - At2_g*xy)*fg +0.5f,0,63) << 5; + max16 |= stb__sclamp((At1_b*yy - At2_b*xy)*frb+0.5f,0,31) << 0; + + min16 = stb__sclamp((At2_r*xx - At1_r*xy)*frb+0.5f,0,31) << 11; + min16 |= stb__sclamp((At2_g*xx - At1_g*xy)*fg +0.5f,0,63) << 5; + min16 |= stb__sclamp((At2_b*xx - At1_b*xy)*frb+0.5f,0,31) << 0; + } + + *pmin16 = min16; + *pmax16 = max16; + return oldMin != min16 || oldMax != max16; +} + +// Color block compression +static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, int mode) +{ + unsigned int mask; + int i; + int dither; + int refinecount; + unsigned short max16, min16; + unsigned char dblock[16*4],color[4*4]; + + dither = mode & STB_DXT_DITHER; + refinecount = (mode & STB_DXT_HIGHQUAL) ? 2 : 1; + + // check if block is constant + for (i=1;i<16;i++) + if (((unsigned int *) block)[i] != ((unsigned int *) block)[0]) + break; + + if(i == 16) { // constant color + int r = block[0], g = block[1], b = block[2]; + mask = 0xaaaaaaaa; + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else { + // first step: compute dithered version for PCA if desired + if(dither) + stb__DitherBlock(dblock,block); + + // second step: pca+map along principal axis + stb__OptimizeColorsBlock(dither ? dblock : block,&max16,&min16); + if (max16 != min16) { + stb__EvalColors(color,max16,min16); + mask = stb__MatchColorsBlock(block,color,dither); + } else + mask = 0; + + // third step: refine (multiple times if requested) + for (i=0;i> 8); + dest[2] = (unsigned char) (min16); + dest[3] = (unsigned char) (min16 >> 8); + dest[4] = (unsigned char) (mask); + dest[5] = (unsigned char) (mask >> 8); + dest[6] = (unsigned char) (mask >> 16); + dest[7] = (unsigned char) (mask >> 24); +} + +// Alpha block compression (this is easy for a change) +static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int mode) +{ + int i,dist,bias,dist4,dist2,bits,mask; + + // find min/max color + int mn,mx; + mn = mx = src[3]; + + for (i=1;i<16;i++) + { + if (src[i*4+3] < mn) mn = src[i*4+3]; + else if (src[i*4+3] > mx) mx = src[i*4+3]; + } + + // encode them + ((unsigned char *)dest)[0] = mx; + ((unsigned char *)dest)[1] = mn; + dest += 2; + + // determine bias and emit color indices + // given the choice of mx/mn, these indices are optimal: + // http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/ + dist = mx-mn; + dist4 = dist*4; + dist2 = dist*2; + bias = (dist < 8) ? (dist - 1) : (dist/2 + 2); + bias -= mn * 7; + bits = 0,mask=0; + + for (i=0;i<16;i++) { + int a = src[i*4+3]*7 + bias; + int ind,t; + + // select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max). + t = (a >= dist4) ? -1 : 0; ind = t & 4; a -= dist4 & t; + t = (a >= dist2) ? -1 : 0; ind += t & 2; a -= dist2 & t; + ind += (a >= dist); + + // turn linear scale into DXT index (0/1 are extremal pts) + ind = -ind & 7; + ind ^= (2 > ind); + + // write index + mask |= ind << bits; + if((bits += 3) >= 8) { + *dest++ = mask; + mask >>= 8; + bits -= 8; + } + } +} + +static void stb__InitDXT() +{ + int i; + for(i=0;i<32;i++) + stb__Expand5[i] = (i<<3)|(i>>2); + + for(i=0;i<64;i++) + stb__Expand6[i] = (i<<2)|(i>>4); + + for(i=0;i<256+16;i++) + { + int v = i-8 < 0 ? 0 : i-8 > 255 ? 255 : i-8; + stb__QuantRBTab[i] = stb__Expand5[stb__Mul8Bit(v,31)]; + stb__QuantGTab[i] = stb__Expand6[stb__Mul8Bit(v,63)]; + } + + stb__PrepareOptTable(&stb__OMatch5[0][0],stb__Expand5,32); + stb__PrepareOptTable(&stb__OMatch6[0][0],stb__Expand6,64); +} + +void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode) +{ + static int init=1; + if (init) { + stb__InitDXT(); + init=0; + } + + if (alpha) { + stb__CompressAlphaBlock(dest,(unsigned char*) src,mode); + dest += 8; + } + + stb__CompressColorBlock(dest,(unsigned char*) src,mode); +} +#endif // STB_DXT_IMPLEMENTATION + +#endif // STB_INCLUDE_STB_DXT_H diff --git a/extern/stb/stb_gl.h b/extern/stb/stb_gl.h deleted file mode 100644 index 802314c..0000000 --- a/extern/stb/stb_gl.h +++ /dev/null @@ -1,1098 +0,0 @@ -// stbgl - v0.04 - Sean Barrett 2008 - public domain -// -// Note that the gl extensions support requires glext.h. In fact, it works -// if you just concatenate glext.h onto the end of this file. In that case, -// this file is covered by the SGI FreeB license, and is not public domain. -// -// Extension usage: -// -// 1. Make a file called something like "extlist.txt" which contains stuff like: -// GLE(ShaderSourceARB,SHADERSOURCEARB) -// GLE(Uniform1iARB,UNIFORM1IARB) -// GLARB(ActiveTexture,ACTIVETEXTURE) // same as GLE(ActiveTextureARB,ACTIVETEXTUREARB) -// GLARB(ClientActiveTexture,CLIENTACTIVETEXTURE) -// GLE(MultiTexCoord2f,MULTITEXCOORD2F) -// -// 2. To declare functions (to make a header file), do this: -// #define STB_GLEXT_DECLARE "extlist.txt" -// #include "stb_gl.h" -// -// A good way to do this is to define STB_GLEXT_DECLARE project-wide. -// -// 3. To define functions (implement), do this in some C file: -// #define STB_GLEXT_DEFINE "extlist.txt" -// #include "stb_gl.h" -// -// If you've already defined STB_GLEXT_DECLARE, you can just do: -// #define STB_GLEXT_DEFINE_DECLARE -// #include "stb_gl.h" -// -// 4. Now you need to initialize: -// -// stbgl_initExtensions(); - - -#ifndef INCLUDE_STB_GL_H -#define INCLUDE_STB_GL_H - -#define STB_GL - -#ifdef _WIN32 -#ifndef WINGDIAPI -#define CALLBACK __stdcall -#define WINGDIAPI __declspec(dllimport) -#define APIENTRY __stdcall -#endif -#endif //_WIN32 - -#include - -#include -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846f -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// like gluPerspective, but: -// fov is chosen to satisfy both hfov <= max_hfov & vfov <= max_vfov; -// set one to 179 or 0 to ignore it -// zoom is applied separately, so you can do linear zoom without -// mucking with trig with fov; 1 -> use exact fov -// 'aspect' is inferred from the current viewport, and ignores the -// possibility of non-square pixels -extern void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar); -extern void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float max_hfov, float max_vfov, float znear, float zfar); -extern void stbgl_initCamera_zup_facing_x(void); -extern void stbgl_initCamera_zup_facing_y(void); -extern void stbgl_positionCameraWithEulerAngles(float *loc, float *ang); -extern void stbgl_drawRect(float x0, float y0, float x1, float y1); -extern void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1); -extern void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw); - -extern int stbgl_hasExtension(char *ext); -extern void stbgl_SimpleLight(int index, float bright, float x, float y, float z); -extern void stbgl_GlobalAmbient(float r, float g, float b); - -extern int stbgl_LoadTexture(char *filename, char *props); // only if stb_image is available - -extern int stbgl_TestTexture(int w); -extern int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2); -extern unsigned int stbgl_rand(void); // internal, but exposed just in case; LCG, so use middle bits - -extern int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props); -extern int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data); -// "props" is a series of characters (and blocks of characters), a la fopen()'s mode, -// e.g.: -// GLuint texid = stbgl_LoadTexture("myfile.jpg", "mbc") -// means: load the image "myfile.jpg", and do the following: -// generate mipmaps -// use bilinear filtering (not trilinear) -// use clamp-to-edge on both channels -// -// input descriptor: AT MOST ONE -// TEXT MEANING -// 1 1 channel of input (intensity/alpha) -// 2 2 channels of input (luminance, alpha) -// 3 3 channels of input (RGB) -// 4 4 channels of input (RGBA) -// l 1 channel of input (luminance) -// a 1 channel of input (alpha) -// la 2 channels of input (lum/alpha) -// rgb 3 channels of input (RGB) -// ycocg 3 channels of input (YCoCg - forces YCoCg output) -// ycocgj 4 channels of input (YCoCgJunk - forces YCoCg output) -// rgba 4 channels of input (RGBA) -// -// output descriptor: AT MOST ONE -// TEXT MEANING -// A 1 channel of output (alpha) -// I 1 channel of output (intensity) -// LA 2 channels of output (lum/alpha) -// RGB 3 channels of output (RGB) -// RGBA 4 channels of output (RGBA) -// DXT1 encode as a DXT1 texture (RGB unless input has RGBA) -// DXT3 encode as a DXT3 texture -// DXT5 encode as a DXT5 texture -// YCoCg encode as a DXT5 texture with Y in alpha, CoCg in RG -// D GL_DEPTH_COMPONENT -// NONE no input/output, don't call TexImage2D at all -// -// when reading from a file or using another interface with an explicit -// channel count, the input descriptor is ignored and instead the channel -// count is used as the input descriptor. if the file read is a DXT DDS, -// then it is passed directly to OpenGL in the file format. -// -// if an input descriptor is supplied but no output descriptor, the output -// is assumed to be the same as the input. if an output descriptor is supplied -// but no input descriptor, the input is assumed to be the same as the -// output. if neither is supplied, the input is assumed to be 4-channel. -// If DXT1 or YCoCG output is requested with no input, the input is assumed -// to be 4-channel but the alpha channel is ignored. -// -// filtering descriptor (default is no mipmaps) -// TEXT MEANING -// m generate mipmaps -// M mipmaps are provided, concatenated at end of data (from largest to smallest) -// t use trilinear filtering (default if mipmapped) -// b use bilinear filtering (default if not-mipmapped) -// n use nearest-neighbor sampling -// -// wrapping descriptor -// TEXT MEANING -// w wrap (default) -// c clamp-to-edge -// C GL_CLAMP (uses border color) -// -// If only one wrapping descriptor is supplied, it is applied to both channels. -// -// special: -// TEXT MEANING -// f input data is floats (default unsigned bytes) -// F input&output data is floats (default unsigned bytes) -// p explicitly pre-multiply the alpha -// P pad to power-of-two (default stretches) -// NP2 non-power-of-two -// + can overwrite the texture data with temp data -// ! free the texture data with "free" -// -// the properties string can also include spaces - -#ifdef __cplusplus -} -#endif - - -#ifdef STB_DEFINE -#include -#include -#include -#include - -int stbgl_hasExtension(char *ext) -{ - const char *s = glGetString(GL_EXTENSIONS); - for(;;) { - char *e = ext; - for (;;) { - if (*e == 0) { - if (*s == 0 || *s == ' ') return 1; - break; - } - if (*s != *e) - break; - ++s, ++e; - } - while (*s && *s != ' ') ++s; - if (!*s) return 0; - ++s; // skip space - } -} - -void stbgl_drawRect(float x0, float y0, float x1, float y1) -{ - glBegin(GL_POLYGON); - glTexCoord2f(0,0); glVertex2f(x0,y0); - glTexCoord2f(1,0); glVertex2f(x1,y0); - glTexCoord2f(1,1); glVertex2f(x1,y1); - glTexCoord2f(0,1); glVertex2f(x0,y1); - glEnd(); -} - -void stbgl_drawRectTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1) -{ - glBegin(GL_POLYGON); - glTexCoord2f(s0,t0); glVertex2f(x0,y0); - glTexCoord2f(s1,t0); glVertex2f(x1,y0); - glTexCoord2f(s1,t1); glVertex2f(x1,y1); - glTexCoord2f(s0,t1); glVertex2f(x0,y1); - glEnd(); -} - -void stbgl_drawBox(float x, float y, float z, float sx, float sy, float sz, int cw) -{ - float x0,y0,z0,x1,y1,z1; - sx /=2, sy/=2, sz/=2; - x0 = x-sx; y0 = y-sy; z0 = z-sz; - x1 = x+sx; y1 = y+sy; z1 = z+sz; - - glBegin(GL_QUADS); - if (cw) { - glNormal3f(0,0,-1); - glTexCoord2f(0,0); glVertex3f(x0,y0,z0); - glTexCoord2f(1,0); glVertex3f(x1,y0,z0); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - - glNormal3f(0,0,1); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - glTexCoord2f(1,1); glVertex3f(x0,y1,z1); - glTexCoord2f(0,1); glVertex3f(x1,y1,z1); - - glNormal3f(-1,0,0); - glTexCoord2f(0,0); glVertex3f(x0,y1,z1); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - glTexCoord2f(1,1); glVertex3f(x0,y0,z0); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - - glNormal3f(1,0,0); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(1,0); glVertex3f(x1,y1,z1); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(0,1); glVertex3f(x1,y0,z0); - - glNormal3f(0,-1,0); - glTexCoord2f(0,0); glVertex3f(x0,y0,z1); - glTexCoord2f(1,0); glVertex3f(x1,y0,z1); - glTexCoord2f(1,1); glVertex3f(x1,y0,z0); - glTexCoord2f(0,1); glVertex3f(x0,y0,z0); - - glNormal3f(0,1,0); - glTexCoord2f(0,0); glVertex3f(x1,y1,z1); - glTexCoord2f(1,0); glVertex3f(x0,y1,z1); - glTexCoord2f(1,1); glVertex3f(x0,y1,z0); - glTexCoord2f(0,1); glVertex3f(x1,y1,z0); - } else { - glNormal3f(0,0,-1); - glTexCoord2f(0,0); glVertex3f(x0,y0,z0); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(1,0); glVertex3f(x1,y0,z0); - - glNormal3f(0,0,1); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(0,1); glVertex3f(x1,y1,z1); - glTexCoord2f(1,1); glVertex3f(x0,y1,z1); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - - glNormal3f(-1,0,0); - glTexCoord2f(0,0); glVertex3f(x0,y1,z1); - glTexCoord2f(0,1); glVertex3f(x0,y1,z0); - glTexCoord2f(1,1); glVertex3f(x0,y0,z0); - glTexCoord2f(1,0); glVertex3f(x0,y0,z1); - - glNormal3f(1,0,0); - glTexCoord2f(0,0); glVertex3f(x1,y0,z1); - glTexCoord2f(0,1); glVertex3f(x1,y0,z0); - glTexCoord2f(1,1); glVertex3f(x1,y1,z0); - glTexCoord2f(1,0); glVertex3f(x1,y1,z1); - - glNormal3f(0,-1,0); - glTexCoord2f(0,0); glVertex3f(x0,y0,z1); - glTexCoord2f(0,1); glVertex3f(x0,y0,z0); - glTexCoord2f(1,1); glVertex3f(x1,y0,z0); - glTexCoord2f(1,0); glVertex3f(x1,y0,z1); - - glNormal3f(0,1,0); - glTexCoord2f(0,0); glVertex3f(x1,y1,z1); - glTexCoord2f(0,1); glVertex3f(x1,y1,z0); - glTexCoord2f(1,1); glVertex3f(x0,y1,z0); - glTexCoord2f(1,0); glVertex3f(x0,y1,z1); - } - glEnd(); -} - -void stbgl_SimpleLight(int index, float bright, float x, float y, float z) -{ - float d = (float) (1.0f/sqrt(x*x+y*y+z*z)); - float dir[4] = { x*d,y*d,z*d,0 }, zero[4] = { 0,0,0,0 }; - float c[4] = { bright,bright,bright,0 }; - GLuint light = GL_LIGHT0 + index; - glLightfv(light, GL_POSITION, dir); - glLightfv(light, GL_DIFFUSE, c); - glLightfv(light, GL_AMBIENT, zero); - glLightfv(light, GL_SPECULAR, zero); - glEnable(light); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); -} - -void stbgl_GlobalAmbient(float r, float g, float b) -{ - float v[4] = { r,g,b,0 }; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v); -} - - -#define stbgl_rad2deg(r) ((r)*180.0f / M_PI) -#define stbgl_deg2rad(r) ((r)/180.0f * M_PI) - -void stbgl_Perspective(float zoom, float max_hfov, float max_vfov, float znear, float zfar) -{ - float unit_width, unit_height, aspect, vfov; - int data[4],w,h; - glGetIntegerv(GL_VIEWPORT, data); - w = data[2]; - h = data[3]; - aspect = (float) w / h; - - if (max_hfov <= 0) max_hfov = 179; - if (max_vfov <= 0) max_vfov = 179; - - // convert max_hfov, max_vfov to worldspace width at depth=1 - unit_width = (float) tan(stbgl_deg2rad(max_hfov/2)) * 2; - unit_height = (float) tan(stbgl_deg2rad(max_vfov/2)) * 2; - // check if hfov = max_hfov is enough to satisfy it - if (unit_width <= aspect * unit_height) { - float height = unit_width / aspect; - vfov = (float) atan(( height/2) / zoom); - } else { - vfov = (float) atan((unit_height/2) / zoom); - } - vfov = stbgl_rad2deg(vfov * 2); - gluPerspective(vfov, aspect, znear, zfar); -} - -void stbgl_PerspectiveViewport(int x, int y, int w, int h, float zoom, float min_hfov, float min_vfov, float znear, float zfar) -{ - if (znear <= 0.0001f) znear = 0.0001f; - glViewport(x,y,w,h); - glScissor(x,y,w,h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - stbgl_Perspective(zoom, min_hfov, min_vfov, znear, zfar); - glMatrixMode(GL_MODELVIEW); -} - -// point the camera along the positive X axis, Z-up -void stbgl_initCamera_zup_facing_x(void) -{ - glRotatef(-90, 1,0,0); - glRotatef( 90, 0,0,1); -} - -// point the camera along the positive Y axis, Z-up -void stbgl_initCamera_zup_facing_y(void) -{ - glRotatef(-90, 1,0,0); -} - -// setup a camera using Euler angles -void stbgl_positionCameraWithEulerAngles(float *loc, float *ang) -{ - glRotatef(-ang[1], 0,1,0); - glRotatef(-ang[0], 1,0,0); - glRotatef(-ang[2], 0,0,1); - glTranslatef(-loc[0], -loc[1], -loc[2]); -} - -static int stbgl_m(char *a, char *b) -{ - // skip first character - do { ++a,++b; } while (*b && *a == *b); - return *b == 0; -} - -#ifdef STBI_VERSION -#ifndef STBI_NO_STDIO -int stbgl_LoadTexture(char *filename, char *props) -{ - // @TODO: handle DDS files directly - int res; - void *data; - int w,h,c; - #ifndef STBI_NO_HDR - if (stbi_is_hdr(filename)) { - data = stbi_loadf(filename, &w, &h, &c, 0); - if (!data) return 0; - res = stbgl_TexImage2D_Extra(0, w,h,data, -c, props, 0); - free(data); - return res; - } - #endif - - data = stbi_load(filename, &w, &h, &c, 0); - if (!data) return 0; - res = stbgl_TexImage2D_Extra(0, w,h,data, c, props, 0); - free(data); - return res; -} -#endif -#endif // STBI_VERSION - -int stbgl_TexImage2D(int texid, int w, int h, void *data, char *props) -{ - return stbgl_TexImage2D_Extra(texid, w, h, data, 0, props,1); -} - -int stbgl_TestTexture(int w) -{ - char scale_table[] = { 10,20,30,30,35,40,5,18,25,13,7,5,3,3,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0 }; - return stbgl_TestTextureEx(w, scale_table, 2, 150,120,220, 160,180,150); -} - -unsigned int stbgl_rand(void) -{ - static unsigned int stbgl__rand_seed = 3248980923; // random typing - return stbgl__rand_seed = stbgl__rand_seed * 2147001325 + 715136305; // BCPL generator -} - -// wish this could be smaller, since it's so frivolous -int stbgl_TestTextureEx(int w, char *scale_table, int checks_log2, int r1,int g1,int b1, int r2, int b2, int g2) -{ - int rt[2] = {r1,r2}, gt[2] = {g1,g2}, bt[2] = {b1,b2}; - signed char modded[256]; - int i,j, m = w-1, s,k,scale; - unsigned char *data = (unsigned char *) malloc(w*w*3); - assert((m & w) == 0); - data[0] = 128; - for (s=0; s < 16; ++s) if ((1 << s) == w) break; - assert(w == (1 << s)); - // plasma fractal noise - for (k=s-1; k >= 0; --k) { - int step = 1 << k; - // interpolate from "parents" - for (j=0; j < w; j += step*2) { - for (i=0; i < w; i += step*2) { - int i1 = i+step, j1=j+step; - int i2 = (i+step*2)&m, j2 = (j+step*2)&m; - int p00 = data[(j*w+i )*3], p01 = data[(j2*w+i )*3]; - int p10 = data[(j*w+i2)*3], p11 = data[(j2*w+i2)*3]; - data[(j*w+i1)*3] = (p00+p10)>>1; - data[(j1*w+i)*3] = (p00+p01)>>1; - data[(j1*w+i1)*3]= (p00+p01+p10+p11)>>2; - } - } - scale = scale_table[s-k+1]; - if (!scale) continue; // just interpolate down the remaining data - for (j=0,i=0; i < 256; i += 2, j == scale ? j=0 : ++j) - modded[i] = j, modded[i+1] = -j; // precompute i%scale (plus sign) - for (j=0; j < w; j += step) - for (i=0; i < w; i += step) { - int x = data[(j*w+i)*3] + modded[(stbgl_rand() >> 12) & 255]; - data[(j*w+i)*3] = x < 0 ? 0 : x > 255 ? 255 : x; - } - } - for (j=0; j < w; ++j) - for (i=0; i < w; ++i) { - int check = ((i^j) & (1 << (s-checks_log2))) == 0; - int v = data[(j*w+i)*3] >> 2; - data[(j*w+i)*3+0] = rt[check]-v; - data[(j*w+i)*3+1] = gt[check]-v; - data[(j*w+i)*3+2] = bt[check]-v; - } - return stbgl_TexImage2D(0, w, w, data, "3m!"); // 3 channels, mipmap, free -} - -#ifdef _WIN32 -#ifndef WINGDIAPI -typedef int (__stdcall *stbgl__voidfunc)(void); -__declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *); -#endif -#define STB__HAS_WGLPROC -static void (__stdcall *stbgl__CompressedTexImage2DARB)(int target, int level, - int internalformat, int width, - int height, int border, - int imageSize, void *data); -static void stbgl__initCompTex(void) -{ - *((void **) &stbgl__CompressedTexImage2DARB) = (void *) wglGetProcAddress("glCompressedTexImage2DARB"); -} -#else -static void (*stbgl__CompressedTexImage2DARB)(int target, int level, - int internalformat, int width, - int height, int border, - int imageSize, void *data); -static void stbgl__initCompTex(void) -{ -} -#endif // _WIN32 - -#define STBGL_COMPRESSED_RGB_S3TC_DXT1 0x83F0 -#define STBGL_COMPRESSED_RGBA_S3TC_DXT1 0x83F1 -#define STBGL_COMPRESSED_RGBA_S3TC_DXT3 0x83F2 -#define STBGL_COMPRESSED_RGBA_S3TC_DXT5 0x83F3 - -#ifdef STB_COMPRESS_DXT_BLOCK -static void stbgl__convert(uint8 *p, uint8 *q, int n, int input_desc, uint8 *end) -{ - int i; - switch (input_desc) { - case GL_RED: - case GL_LUMINANCE: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = q[0], p[3]=255, q+=1; break; - case GL_ALPHA: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = 0, p[3] = q[0], q+=1; break; - case GL_LUMINANCE_ALPHA: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = q[0], p[3]=q[1], q+=2; break; - case GL_RGB: for (i=0; i < n; ++i,p+=4) p[0]=q[0],p[1]=q[1],p[2]=q[2],p[3]=255,q+=3; break; - case GL_RGBA: memcpy(p, q, n*4); break; - case GL_INTENSITY: for (i=0; i < n; ++i,p+=4) p[0] = p[1] = p[2] = p[3] = q[0], q+=1; break; - } - assert(p <= end); -} - -static void stbgl__compress(uint8 *p, uint8 *rgba, int w, int h, int output_desc, uint8 *end) -{ - int i,j,y,y2; - int alpha = (output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT5); - for (j=0; j < w; j += 4) { - int x=4; - for (i=0; i < h; i += 4) { - uint8 block[16*4]; - if (i+3 >= w) x = w-i; - for (y=0; y < 4; ++y) { - if (j+y >= h) break; - memcpy(block+y*16, rgba + w*4*(j+y) + i*4, x*4); - } - if (x < 4) { - switch (x) { - case 0: assert(0); - case 1: - for (y2=0; y2 < y; ++y2) { - memcpy(block+y2*16+1*4, block+y2*16+0*4, 4); - memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); - } - break; - case 2: - for (y2=0; y2 < y; ++y2) - memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); - break; - case 3: - for (y2=0; y2 < y; ++y2) - memcpy(block+y2*16+3*4, block+y2*16+1*4, 4); - break; - } - } - y2 = 0; - for(; y<4; ++y,++y2) - memcpy(block+y*16, block+y2*16, 4*4); - stb_compress_dxt_block(p, block, alpha, 10); - p += alpha ? 16 : 8; - } - } - assert(p <= end); -} -#endif // STB_COMPRESS_DXT_BLOCK - -// use the reserved temporary-use enumerant range, since no -// OpenGL enumerants should fall in that range -enum -{ - STBGL_UNDEFINED = 0x6000, - STBGL_YCOCG, - STBGL_YCOCGJ, - STBGL_GEN_MIPMAPS, - STBGL_MIPMAPS, - STBGL_NO_DOWNLOAD, -}; - -#define STBGL_CLAMP_TO_EDGE 0x812F - -#define STBGL_DEPTH_COMPONENT16 0x81A5 -#define STBGL_DEPTH_COMPONENT24 0x81A6 -#define STBGL_DEPTH_COMPONENT32 0x81A7 - -int stbgl_TexImage2D_Extra(int texid, int w, int h, void *data, int chan, char *props, int preserve_data) -{ - static int has_s3tc = -1; // haven't checked yet - int free_data = 0, is_compressed = 0; - int pad_to_power_of_two = 0, non_power_of_two = 0; - int premultiply_alpha = 0; // @TODO - int float_tex = 0; // @TODO - int input_type = GL_UNSIGNED_BYTE; - int input_desc = STBGL_UNDEFINED; - int output_desc = STBGL_UNDEFINED; - int mipmaps = STBGL_UNDEFINED; - int filter = STBGL_UNDEFINED, mag_filter; - int wrap_s = STBGL_UNDEFINED, wrap_t = STBGL_UNDEFINED; - - // parse out the properties - if (props == NULL) props = ""; - while (*props) { - switch (*props) { - case '1' : input_desc = GL_LUMINANCE; break; - case '2' : input_desc = GL_LUMINANCE_ALPHA; break; - case '3' : input_desc = GL_RGB; break; - case '4' : input_desc = GL_RGBA; break; - case 'l' : if (props[1] == 'a') { input_desc = GL_LUMINANCE_ALPHA; ++props; } - else input_desc = GL_LUMINANCE; - break; - case 'a' : input_desc = GL_ALPHA; break; - case 'r' : if (stbgl_m(props, "rgba")) { input_desc = GL_RGBA; props += 3; break; } - if (stbgl_m(props, "rgb")) { input_desc = GL_RGB; props += 2; break; } - input_desc = GL_RED; - break; - case 'y' : if (stbgl_m(props, "ycocg")) { - if (props[5] == 'j') { props += 5; input_desc = STBGL_YCOCGJ; } - else { props += 4; input_desc = STBGL_YCOCG; } - break; - } - return 0; - case 'L' : if (props[1] == 'A') { output_desc = GL_LUMINANCE_ALPHA; ++props; } - else output_desc = GL_LUMINANCE; - break; - case 'I' : output_desc = GL_INTENSITY; break; - case 'A' : output_desc = GL_ALPHA; break; - case 'R' : if (stbgl_m(props, "RGBA")) { output_desc = GL_RGBA; props += 3; break; } - if (stbgl_m(props, "RGB")) { output_desc = GL_RGB; props += 2; break; } - output_desc = GL_RED; - break; - case 'Y' : if (stbgl_m(props, "YCoCg") || stbgl_m(props, "YCOCG")) { - props += 4; - output_desc = STBGL_YCOCG; - break; - } - return 0; - case 'D' : if (stbgl_m(props, "DXT")) { - switch (props[3]) { - case '1': output_desc = STBGL_COMPRESSED_RGB_S3TC_DXT1; break; - case '3': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT3; break; - case '5': output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5; break; - default: return 0; - } - props += 3; - } else if (stbgl_m(props, "D16")) { - output_desc = STBGL_DEPTH_COMPONENT16; - input_desc = GL_DEPTH_COMPONENT; - props += 2; - } else if (stbgl_m(props, "D24")) { - output_desc = STBGL_DEPTH_COMPONENT24; - input_desc = GL_DEPTH_COMPONENT; - props += 2; - } else if (stbgl_m(props, "D32")) { - output_desc = STBGL_DEPTH_COMPONENT32; - input_desc = GL_DEPTH_COMPONENT; - props += 2; - } else { - output_desc = GL_DEPTH_COMPONENT; - input_desc = GL_DEPTH_COMPONENT; - } - break; - case 'N' : if (stbgl_m(props, "NONE")) { - props += 3; - input_desc = STBGL_NO_DOWNLOAD; - output_desc = STBGL_NO_DOWNLOAD; - break; - } - if (stbgl_m(props, "NP2")) { - non_power_of_two = 1; - props += 2; - break; - } - return 0; - case 'm' : mipmaps = STBGL_GEN_MIPMAPS; break; - case 'M' : mipmaps = STBGL_MIPMAPS; break; - case 't' : filter = GL_LINEAR_MIPMAP_LINEAR; break; - case 'b' : filter = GL_LINEAR; break; - case 'n' : filter = GL_NEAREST; break; - case 'w' : if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT; else wrap_t = GL_REPEAT; break; - case 'C' : if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_CLAMP ; else wrap_t = GL_CLAMP ; break; - case 'c' : if (wrap_s == STBGL_UNDEFINED) wrap_s = STBGL_CLAMP_TO_EDGE; else wrap_t = STBGL_CLAMP_TO_EDGE; break; - case 'f' : input_type = GL_FLOAT; break; - case 'F' : input_type = GL_FLOAT; float_tex = 1; break; - case 'p' : premultiply_alpha = 1; break; - case 'P' : pad_to_power_of_two = 1; break; - case '+' : preserve_data = 0; break; - case '!' : preserve_data = 0; free_data = 1; break; - case ' ' : break; - case '-' : break; - default : if (free_data) free(data); - return 0; - } - ++props; - } - - // override input_desc based on channel count - if (output_desc != STBGL_NO_DOWNLOAD) { - switch (abs(chan)) { - case 1: input_desc = GL_LUMINANCE; break; - case 2: input_desc = GL_LUMINANCE_ALPHA; break; - case 3: input_desc = GL_RGB; break; - case 4: input_desc = GL_RGBA; break; - case 0: break; - default: return 0; - } - } - - // override input_desc based on channel info - if (chan > 0) { input_type = GL_UNSIGNED_BYTE; } - if (chan < 0) { input_type = GL_FLOAT; } - - if (output_desc == GL_ALPHA) { - if (input_desc == GL_LUMINANCE) - input_desc = GL_ALPHA; - if (input_desc == GL_RGB) { - // force a presumably-mono image to alpha - // @TODO handle 'preserve_data' case? - if (data && !preserve_data && input_type == GL_UNSIGNED_BYTE) { - int i; - unsigned char *p = (unsigned char *) data, *q = p; - for (i=0; i < w*h; ++i) { - *q = (p[0] + 2*p[1] + p[2]) >> 2; - p += 3; - q += 1; - } - input_desc = GL_ALPHA; - } - } - } - - // set undefined input/output based on the other - if (input_desc == STBGL_UNDEFINED && output_desc == STBGL_UNDEFINED) { - input_desc = output_desc = GL_RGBA; - } else if (output_desc == STBGL_UNDEFINED) { - switch (input_desc) { - case GL_LUMINANCE: - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_RGB: - case GL_RGBA: - output_desc = input_desc; - break; - case GL_RED: - output_desc = GL_INTENSITY; - break; - case STBGL_YCOCG: - case STBGL_YCOCGJ: - output_desc = STBGL_YCOCG; - break; - default: assert(0); return 0; - } - } else if (input_desc == STBGL_UNDEFINED) { - switch (output_desc) { - case GL_LUMINANCE: - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_RGB: - case GL_RGBA: - input_desc = output_desc; - break; - case GL_INTENSITY: - input_desc = GL_RED; - break; - case STBGL_YCOCG: - case STBGL_COMPRESSED_RGB_S3TC_DXT1: - case STBGL_COMPRESSED_RGBA_S3TC_DXT3: - case STBGL_COMPRESSED_RGBA_S3TC_DXT5: - input_desc = GL_RGBA; - break; - } - } else { - if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1) { - // if input has alpha, force output alpha - switch (input_desc) { - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - output_desc = STBGL_COMPRESSED_RGBA_S3TC_DXT5; - break; - } - } - } - - switch(input_desc) { - case GL_LUMINANCE: - case GL_RED: - case GL_ALPHA: - chan = 1; - break; - case GL_LUMINANCE_ALPHA: - chan = 2; - break; - case GL_RGB: - chan = 3; - break; - case GL_RGBA: - chan = 4; - break; - } - - if (pad_to_power_of_two && ((w & (w-1)) || (h & (h-1)))) { - if (output_desc != STBGL_NO_DOWNLOAD && input_type == GL_UNSIGNED_BYTE && chan > 0) { - unsigned char *new_data; - int w2 = w, h2 = h, j; - while (w & (w-1)) - w = (w | (w>>1))+1; - while (h & (h-1)) - h = (h | (h>>1))+1; - new_data = malloc(w * h * chan); - for (j=0; j < h2; ++j) { - memcpy(new_data + j * w * chan, (char *) data+j*w2*chan, w2*chan); - memset(new_data + (j * w+w2) * chan, 0, (w-w2)*chan); - } - for (; j < h; ++j) - memset(new_data + j*w*chan, 0, w*chan); - if (free_data) - free(data); - data = new_data; - free_data = 1; - } - } - - switch (output_desc) { - case STBGL_COMPRESSED_RGB_S3TC_DXT1: - case STBGL_COMPRESSED_RGBA_S3TC_DXT1: - case STBGL_COMPRESSED_RGBA_S3TC_DXT3: - case STBGL_COMPRESSED_RGBA_S3TC_DXT5: - is_compressed = 1; - if (has_s3tc == -1) { - has_s3tc = stbgl_hasExtension("GL_EXT_texture_compression_s3tc"); - if (has_s3tc) stbgl__initCompTex(); - } - if (!has_s3tc) { - is_compressed = 0; - if (output_desc == STBGL_COMPRESSED_RGB_S3TC_DXT1) - output_desc = GL_RGB; - else - output_desc = GL_RGBA; - } - } - - if (output_desc == STBGL_YCOCG) { - assert(0); - output_desc = GL_RGB; // @TODO! - if (free_data) free(data); - return 0; - } - - if (mipmaps != STBGL_UNDEFINED) { - switch (filter) { - case STBGL_UNDEFINED: filter = GL_LINEAR_MIPMAP_LINEAR; break; - case GL_NEAREST : filter = GL_NEAREST_MIPMAP_NEAREST; break; - case GL_LINEAR : filter = GL_LINEAR_MIPMAP_NEAREST; break; - } - } else { - if (filter == STBGL_UNDEFINED) - filter = GL_LINEAR; - } - - // update filtering - if (filter == GL_NEAREST) - mag_filter = GL_NEAREST; - else - mag_filter = GL_LINEAR; - - // update wrap/clamp - if (wrap_s == STBGL_UNDEFINED) wrap_s = GL_REPEAT; - if (wrap_t == STBGL_UNDEFINED) wrap_t = wrap_s; - - // if no texture id, generate one - if (texid == 0) { - GLuint tex; - glGenTextures(1, &tex); - if (tex == 0) { if (free_data) free(data); return 0; } - texid = tex; - } - - if (data == NULL && mipmaps == STBGL_GEN_MIPMAPS) - mipmaps = STBGL_MIPMAPS; - - if (output_desc == STBGL_NO_DOWNLOAD) - mipmaps = STBGL_NO_DOWNLOAD; - - glBindTexture(GL_TEXTURE_2D, texid); - -#ifdef STB_COMPRESS_DXT_BLOCK - if (!is_compressed || !stbgl__CompressedTexImage2DARB || output_desc == STBGL_COMPRESSED_RGBA_S3TC_DXT3 || data == NULL) -#endif - { - switch (mipmaps) { - case STBGL_NO_DOWNLOAD: - break; - - case STBGL_UNDEFINED: - // check if actually power-of-two - if (non_power_of_two || ((w & (w-1)) == 0 && (h & (h-1)) == 0)) - glTexImage2D(GL_TEXTURE_2D, 0, output_desc, w, h, 0, input_desc, input_type, data); - else - gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data); - // not power of two, so use glu to resize (generates mipmaps needlessly) - break; - - case STBGL_MIPMAPS: { - int level = 0; - int size = input_type == GL_FLOAT ? sizeof(float) : 1; - if (data == NULL) size = 0; // reuse same block of memory for all mipmaps - assert((w & (w-1)) == 0 && (h & (h-1)) == 0); // verify power-of-two - while (w > 1 && h > 1) { - glTexImage2D(GL_TEXTURE_2D, level, output_desc, w, h, 0, input_desc, input_type, data); - data = (void *) ((char *) data + w * h * size * chan); - if (w > 1) w >>= 1; - if (h > 1) h >>= 1; - ++level; - } - break; - } - case STBGL_GEN_MIPMAPS: - gluBuild2DMipmaps(GL_TEXTURE_2D, output_desc, w, h, input_desc, input_type, data); - break; - - default: - assert(0); - if (free_data) free(data); - return 0; - } -#ifdef STB_COMPRESS_DXT_BLOCK - } else { - uint8 *out, *rgba=0, *end_out, *end_rgba; - int level = 0, alpha = (output_desc != STBGL_COMPRESSED_RGB_S3TC_DXT1); - int size = input_type == GL_FLOAT ? sizeof(float) : 1; - int osize = alpha ? 16 : 8; - if (!free_data && mipmaps == STBGL_GEN_MIPMAPS) { - uint8 *temp = malloc(w*h*chan); - if (!temp) { if (free_data) free(data); return 0; } - memcpy(temp, data, w*h*chan); - if (free_data) free(data); - free_data = 1; - data = temp; - } - if (chan != 4 || size != 1) { - rgba = malloc(w*h*4); - if (!rgba) return 0; - end_rgba = rgba+w*h*4; - } - out = malloc((w+3)*(h+3)/16*osize); // enough storage for the s3tc data - if (!out) return 0; - end_out = out + ((w+3)*(h+3))/16*osize; - - for(;;) { - if (chan != 4) - stbgl__convert(rgba, data, w*h, input_desc, end_rgba); - stbgl__compress(out, rgba ? rgba : data, w, h, output_desc, end_out); - stbgl__CompressedTexImage2DARB(GL_TEXTURE_2D, level, output_desc, w, h, 0, ((w+3)&~3)*((h+3)&~3)/16*osize, out); - //glTexImage2D(GL_TEXTURE_2D, level, alpha?GL_RGBA:GL_RGB, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba ? rgba : data); - - if (mipmaps == STBGL_UNDEFINED) break; - if (w <= 1 && h <= 1) break; - if (mipmaps == STBGL_MIPMAPS) data = (void *) ((char *) data + w * h * size * chan); - if (mipmaps == STBGL_GEN_MIPMAPS) { - int w2 = w>>1, h2=h>>1, i,j,k, s=w*chan; - uint8 *p = data, *q=data; - if (w == 1) { - for (j=0; j < h2; ++j) { - for (k=0; k < chan; ++k) - *p++ = (q[k] + q[s+k] + 1) >> 1; - q += s*2; - } - } else if (h == 1) { - for (i=0; i < w2; ++i) { - for (k=0; k < chan; ++k) - *p++ = (q[k] + q[k+chan] + 1) >> 1; - q += chan*2; - } - } else { - for (j=0; j < h2; ++j) { - for (i=0; i < w2; ++i) { - for (k=0; k < chan; ++k) - *p++ = (q[k] + q[k+chan] + q[s+k] + q[s+k+chan] + 2) >> 2; - q += chan*2; - } - q += s; - } - } - } - if (w > 1) w >>= 1; - if (h > 1) h >>= 1; - ++level; - } - if (out) free(out); - if (rgba) free(rgba); -#endif // STB_COMPRESS_DXT_BLOCK - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - - if (free_data) free(data); - return texid; -} - -#endif // STB_DEFINE -#undef STB_EXTERN - -#endif //INCLUDE_STB_GL_H - -// Extension handling... must be outside the INCLUDE_ brackets - -#if defined(STB_GLEXT_DEFINE) || defined(STB_GLEXT_DECLARE) - -#ifndef STB_GLEXT_SKIP_DURING_RECURSION - -#ifndef GL_GLEXT_VERSION - - // First check if glext.h is concatenated on the end of this file - // (if it's concatenated on the beginning, we'll have GL_GLEXT_VERSION) - - #define STB_GLEXT_SKIP_DURING_RECURSION - #include __FILE__ - #undef STB_GLEXT_SKIP_DURING_RECURSION - - // now check if it's still undefined; if so, try going for it by name; - // if this errors, that's fine, since we can't compile without it - - #ifndef GL_GLEXT_VERSION - #include "glext.h" - #endif -#endif - -#define GLARB(a,b) GLE(a##ARB,b##ARB) -#define GLEXT(a,b) GLE(a##EXT,b##EXT) -#define GLNV(a,b) GLE(a##NV ,b##NV) -#define GLATI(a,b) GLE(a##ATI,b##ATI) - -#ifdef STB_GLEXT_DEFINE_DECLARE -#define STB_GLEXT_DEFINE STB_GLEXT_DECLARE -#endif - -#if defined(STB_GLEXT_DECLARE) && defined(STB_GLEXT_DEFINE) -#undef STB_GLEXT_DECLARE -#endif - -#if defined(STB_GLEXT_DECLARE) && !defined(STB_GLEXT_DEFINE) - #define GLE(a,b) extern PFNGL##b##PROC gl##a; - - #ifdef __cplusplus - extern "C" { - #endif - - extern void stbgl_initExtensions(void); - - #include STB_GLEXT_DECLARE - - #ifdef __cplusplus - }; - #endif - -#else - - #ifndef STB_GLEXT_DEFINE - #error "Header file is screwed up somehow" - #endif - - #ifdef _WIN32 - #ifndef WINGDIAPI - #ifndef STB__HAS_WGLPROC - typedef int (__stdcall *stbgl__voidfunc)(void); - __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *); - #endif - #endif - #define STBGL__GET_FUNC(x) wglGetProcAddress(x) - #endif - - #ifdef GLE - #undef GLE - #endif - - #define GLE(a,b) PFNGL##b##PROC gl##a; - #include STB_GLEXT_DEFINE - - #undef GLE - #define GLE(a,b) gl##a = (PFNGL##b##PROC) STBGL__GET_FUNC("gl" #a ); - - void stbgl_initExtensions(void) - { - #include STB_GLEXT_DEFINE - } - - #undef GLE - -#endif // STB_GLEXT_DECLARE - -#endif // STB_GLEXT_SKIP - -#endif // STB_GLEXT_DEFINE || STB_GLEXT_DECLARE