diff --git a/extern/atitc/ATI_Compress.chm b/extern/atitc/ATI_Compress.chm new file mode 100644 index 0000000..1d17e28 Binary files /dev/null and b/extern/atitc/ATI_Compress.chm differ diff --git a/extern/atitc/ATI_Compress.h b/extern/atitc/ATI_Compress.h new file mode 100644 index 0000000..f81aa9b --- /dev/null +++ b/extern/atitc/ATI_Compress.h @@ -0,0 +1,175 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Advanced Micro Devices, Inc. +// 1 AMD Place +// Sunnyvale, CA +// USA 94088 +// +// File Name: ATI_Compress.h +// Description: A library to compress/decompress textures +// +// Copyright (c) 2007,2008 Advanced Micro Devices, Inc. +// Copyright (c) 2004-2006 ATI Technologies Inc. +// +// Version: 1.7 +// +// Developer: Seth Sowerby +// Email: gputools.support@amd.com +// +////////////////////////////////////////////////////////////////////////////// + +/// \file +/// ATI_Compress.h declares the interface to the ATI_Compress library. + +#ifndef ATI_COMPRESS +#define ATI_COMPRESS + +#define ATI_COMPRESS_VERSION_MAJOR 1 ///< The major version number of this release. +#define ATI_COMPRESS_VERSION_MINOR 7 ///< The minor version number of this release. + +typedef unsigned long ATI_TC_DWORD; ///< A 32-bit integer format. +typedef unsigned short ATI_TC_WORD; ///< A 16-bit integer format. +typedef unsigned char ATI_TC_BYTE; ///< An 8-bit integer format. + +#if defined(WIN32) || defined(_WIN64) +# define ATI_TC_API __cdecl +#else +# define ATI_TC_API +#endif + +#ifdef ATI_COMPRESS_INTERNAL_BUILD +# include "ATI_Compress_Internal.h" +#else // ATI_COMPRESS_INTERNAL_BUILD + +/// Texture format. +typedef enum +{ + ATI_TC_FORMAT_Unknown, ///< An undefined texture format. + ATI_TC_FORMAT_ARGB_8888, ///< An ARGB format with 8-bit fixed channels. + ATI_TC_FORMAT_RGB_888, ///< A RGB format with 8-bit fixed channels. + ATI_TC_FORMAT_RG_8, ///< A two component format with 8-bit fixed channels. + ATI_TC_FORMAT_R_8, ///< A single component format with 8-bit fixed channels. + ATI_TC_FORMAT_ARGB_2101010, ///< An ARGB format with 10-bit fixed channels for color & a 2-bit fixed channel for alpha. + ATI_TC_FORMAT_ARGB_16, ///< A ARGB format with 16-bit fixed channels. + ATI_TC_FORMAT_RG_16, ///< A two component format with 16-bit fixed channels. + ATI_TC_FORMAT_R_16, ///< A single component format with 16-bit fixed channels. + ATI_TC_FORMAT_ARGB_16F, ///< An ARGB format with 16-bit floating-point channels. + ATI_TC_FORMAT_RG_16F, ///< A two component format with 16-bit floating-point channels. + ATI_TC_FORMAT_R_16F, ///< A single component with 16-bit floating-point channels. + ATI_TC_FORMAT_ARGB_32F, ///< An ARGB format with 32-bit floating-point channels. + ATI_TC_FORMAT_RG_32F, ///< A two component format with 32-bit floating-point channels. + ATI_TC_FORMAT_R_32F, ///< A single component with 32-bit floating-point channels. + ATI_TC_FORMAT_DXT1, ///< An opaque (or 1-bit alpha) DXTC compressed texture format. Four bits per pixel. + ATI_TC_FORMAT_DXT3, ///< A DXTC compressed texture format with explicit alpha. Eight bits per pixel. + ATI_TC_FORMAT_DXT5, ///< A DXTC compressed texture format with interpolated alpha. Eight bits per pixel. + ATI_TC_FORMAT_DXT5_xGBR, ///< A DXT5 with the red component swizzled into the alpha channel. Eight bits per pixel. + ATI_TC_FORMAT_DXT5_RxBG, ///< A swizzled DXT5 format with the green component swizzled into the alpha channel. Eight bits per pixel. + ATI_TC_FORMAT_DXT5_RBxG, ///< A swizzled DXT5 format with the green component swizzled into the alpha channel & the blue component swizzled into the green channel. Eight bits per pixel. + ATI_TC_FORMAT_DXT5_xRBG, ///< A swizzled DXT5 format with the green component swizzled into the alpha channel & the red component swizzled into the green channel. Eight bits per pixel. + ATI_TC_FORMAT_DXT5_RGxB, ///< A swizzled DXT5 format with the blue component swizzled into the alpha channel. Eight bits per pixel. + ATI_TC_FORMAT_DXT5_xGxR, ///< A two-component swizzled DXT5 format with the red component swizzled into the alpha channel & the green component in the green channel. Eight bits per pixel. + ATI_TC_FORMAT_ATI1N, ///< A single component compression format using the same technique as DXT5 alpha. Four bits per pixel. + ATI_TC_FORMAT_ATI2N, ///< A two component compression format using the same technique as DXT5 alpha. Designed for compression object space normal maps. Eight bits per pixel. + ATI_TC_FORMAT_ATI2N_XY, ///< A two component compression format using the same technique as DXT5 alpha. The same as ATI2N but with the channels swizzled. Eight bits per pixel. + ATI_TC_FORMAT_ATI2N_DXT5, ///< An ATI2N like format using DXT5. Intended for use on GPUs that do not natively support ATI2N. Eight bits per pixel. + ATI_TC_FORMAT_BC1, ///< A four component opaque (or 1-bit alpha) compressed texture format for Microsoft DirectX10. Identical to DXT1. Four bits per pixel. + ATI_TC_FORMAT_BC2, ///< A four component compressed texture format with explicit alpha for Microsoft DirectX10. Identical to DXT3. Eight bits per pixel. + ATI_TC_FORMAT_BC3, ///< A four component compressed texture format with interpolated alpha for Microsoft DirectX10. Identical to DXT5. Eight bits per pixel. + ATI_TC_FORMAT_BC4, ///< A single component compressed texture format for Microsoft DirectX10. Identical to ATI1N. Four bits per pixel. + ATI_TC_FORMAT_BC5, ///< A two component compressed texture format for Microsoft DirectX10. Identical to ATI2N. Eight bits per pixel. + ATI_TC_FORMAT_ATC_RGB, ///< ATI_TC - a compressed RGB format for cellphones & hand-held devices. + ATI_TC_FORMAT_ATC_RGBA_Explicit, ///< ATI_TC - a compressed ARGB format with explicit alpha for cellphones & hand-held devices. + ATI_TC_FORMAT_ATC_RGBA_Interpolated, ///< ATI_TC - a compressed ARGB format with interpolated alpha for cellphones & hand-held devices. + ATI_TC_FORMAT_ETC_RGB, ///< ETC (aka Ericsson Texture Compression) - a compressed RGB format for cellphones. + ATI_TC_FORMAT_MAX = ATI_TC_FORMAT_ETC_RGB +} ATI_TC_FORMAT; + +/// An enum selecting the speed vs. quality trade-off. +typedef enum +{ + ATI_TC_Speed_Normal, ///< Highest quality mode + ATI_TC_Speed_Fast, ///< Slightly lower quality but much faster compression mode - DXTn & ATInN only + ATI_TC_Speed_SuperFast, ///< Slightly lower quality but much, much faster compression mode - DXTn & ATInN only +} ATI_TC_Speed; + +/// ATI_Compress error codes +typedef enum +{ + ATI_TC_OK = 0, ///< Ok. + ATI_TC_ABORTED, ///< The conversion was aborted. + ATI_TC_ERR_INVALID_SOURCE_TEXTURE, ///< The source texture is invalid. + ATI_TC_ERR_INVALID_DEST_TEXTURE, ///< The destination texture is invalid. + ATI_TC_ERR_UNSUPPORTED_SOURCE_FORMAT, ///< The source format is not a supported format. + ATI_TC_ERR_UNSUPPORTED_DEST_FORMAT, ///< The destination format is not a supported format. + ATI_TC_ERR_SIZE_MISMATCH, ///< The source and destination texture sizes do not match. + ATI_TC_ERR_UNABLE_TO_INIT_CODEC, ///< ATI_Compress was unable to initialize the codec needed for conversion. + ATI_TC_ERR_GENERIC ///< An unknown error occurred. +} ATI_TC_ERROR; + +/// Options for the compression. +/// Passing this structure is optional +typedef struct +{ + ATI_TC_DWORD dwSize; ///< The size of this structure. + BOOL bUseChannelWeighting; ///< Use channel weightings. With swizzled formats the weighting applies to the data within the specified channel not the channel itself. + double fWeightingRed; ///< The weighting of the Red or X Channel. + double fWeightingGreen; ///< The weighting of the Green or Y Channel. + double fWeightingBlue; ///< The weighting of the Blue or Z Channel. + BOOL bUseAdaptiveWeighting; ///< Adapt weighting on a per-block basis. + BOOL bDXT1UseAlpha; ///< Encode single-bit alpha data. Only valid when compressing to DXT1 & BC1. + ATI_TC_BYTE nAlphaThreshold; ///< The alpha threshold to use when compressing to DXT1 & BC1 with bDXT1UseAlpha. Texels with an alpha value less than the threshold are treated as transparent. + BOOL bDisableMultiThreading; ///< Disable multi-threading of the compression. This will slow the compression but can be useful if you're managing threads in your application. + ATI_TC_Speed nCompressionSpeed; ///< The trade-off between compression speed & quality. +} ATI_TC_CompressOptions; +#endif // !ATI_COMPRESS_INTERNAL_BUILD + +/// The structure describing a texture. +typedef struct +{ + ATI_TC_DWORD dwSize; ///< Size of this structure. + ATI_TC_DWORD dwWidth; ///< Width of the texture. + ATI_TC_DWORD dwHeight; ///< Height of the texture. + ATI_TC_DWORD dwPitch; ///< Distance to start of next line - necessary only for uncompressed textures. + ATI_TC_FORMAT format; ///< Format of the texture. + ATI_TC_DWORD dwDataSize; ///< Size of the allocated texture data. + ATI_TC_BYTE* pData; ///< Pointer to the texture data +} ATI_TC_Texture; + +#define MINIMUM_WEIGHT_VALUE 0.01f + + +#ifdef __cplusplus +extern "C" { +#endif + + /// ATI_TC_Feedback_Proc + /// Feedback function for conversion. + /// \param[in] fProgress The percentage progress of the texture compression. + /// \param[in] pUser1 User data as passed to ATI_TC_ConvertTexture. + /// \param[in] pUser2 User data as passed to ATI_TC_ConvertTexture. + /// \return non-NULL(true) value to abort conversion + typedef bool (ATI_TC_API * ATI_TC_Feedback_Proc)(float fProgress, DWORD_PTR pUser1, DWORD_PTR pUser2); + + /// Calculates the required buffer size for the specified texture + /// \param[in] pTexture A pointer to the texture. + /// \return The size of the buffer required to hold the texture data. + ATI_TC_DWORD ATI_TC_API ATI_TC_CalculateBufferSize(const ATI_TC_Texture* pTexture); + + /// Converts the source texture to the destination texture + /// This can be compression, decompression or converting between two uncompressed formats. + /// \param[in] pSourceTexture A pointer to the source texture. + /// \param[in] pDestTexture A pointer to the destination texture. + /// \param[in] pOptions A pointer to the compression options - can be NULL. + /// \param[in] pFeedbackProc A pointer to the feedback function - can be NULL. + /// \param[in] pUser1 User data to pass to the feedback function. + /// \param[in] pUser2 User data to pass to the feedback function. + /// \return ATI_TC_OK if successful, otherwise the error code. + ATI_TC_ERROR ATI_TC_API ATI_TC_ConvertTexture(const ATI_TC_Texture* pSourceTexture, ATI_TC_Texture* pDestTexture, + const ATI_TC_CompressOptions* pOptions, + ATI_TC_Feedback_Proc pFeedbackProc, DWORD_PTR pUser1, DWORD_PTR pUser2); + +#ifdef __cplusplus +}; +#endif + +#endif // !ATI_COMPRESS diff --git a/extern/atitc/VC7/MT DLL Debug/ATI_Compress_MT_DLL_VC7.lib b/extern/atitc/VC7/MT DLL Debug/ATI_Compress_MT_DLL_VC7.lib new file mode 100755 index 0000000..ba0c2a8 Binary files /dev/null and b/extern/atitc/VC7/MT DLL Debug/ATI_Compress_MT_DLL_VC7.lib differ diff --git a/extern/atitc/VC7/MT DLL Release/ATI_Compress_MT_DLL_VC7.lib b/extern/atitc/VC7/MT DLL Release/ATI_Compress_MT_DLL_VC7.lib new file mode 100755 index 0000000..920bb9e Binary files /dev/null and b/extern/atitc/VC7/MT DLL Release/ATI_Compress_MT_DLL_VC7.lib differ diff --git a/extern/atitc/VC7/MT Debug/ATI_Compress_MT_VC7.lib b/extern/atitc/VC7/MT Debug/ATI_Compress_MT_VC7.lib new file mode 100755 index 0000000..0827f14 Binary files /dev/null and b/extern/atitc/VC7/MT Debug/ATI_Compress_MT_VC7.lib differ diff --git a/extern/atitc/VC7/MT Release/ATI_Compress_MT_VC7.lib b/extern/atitc/VC7/MT Release/ATI_Compress_MT_VC7.lib new file mode 100755 index 0000000..5bfd78d Binary files /dev/null and b/extern/atitc/VC7/MT Release/ATI_Compress_MT_VC7.lib differ diff --git a/extern/atitc/VC8/DLL Debug/Win32/ATI_Compress_1_7.dll b/extern/atitc/VC8/DLL Debug/Win32/ATI_Compress_1_7.dll new file mode 100755 index 0000000..49cb743 Binary files /dev/null and b/extern/atitc/VC8/DLL Debug/Win32/ATI_Compress_1_7.dll differ diff --git a/extern/atitc/VC8/DLL Debug/Win32/ATI_Compress_1_7_DLL.lib b/extern/atitc/VC8/DLL Debug/Win32/ATI_Compress_1_7_DLL.lib new file mode 100755 index 0000000..ede0c4c Binary files /dev/null and b/extern/atitc/VC8/DLL Debug/Win32/ATI_Compress_1_7_DLL.lib differ diff --git a/extern/atitc/VC8/DLL Debug/x64/ATI_Compress_1_7.dll b/extern/atitc/VC8/DLL Debug/x64/ATI_Compress_1_7.dll new file mode 100755 index 0000000..0b8f7f8 Binary files /dev/null and b/extern/atitc/VC8/DLL Debug/x64/ATI_Compress_1_7.dll differ diff --git a/extern/atitc/VC8/DLL Debug/x64/ATI_Compress_1_7_DLL.lib b/extern/atitc/VC8/DLL Debug/x64/ATI_Compress_1_7_DLL.lib new file mode 100755 index 0000000..ab9802d Binary files /dev/null and b/extern/atitc/VC8/DLL Debug/x64/ATI_Compress_1_7_DLL.lib differ diff --git a/extern/atitc/VC8/DLL Release/Win32/ATI_Compress_1_7.dll b/extern/atitc/VC8/DLL Release/Win32/ATI_Compress_1_7.dll new file mode 100755 index 0000000..ccaa286 Binary files /dev/null and b/extern/atitc/VC8/DLL Release/Win32/ATI_Compress_1_7.dll differ diff --git a/extern/atitc/VC8/DLL Release/Win32/ATI_Compress_1_7_DLL.lib b/extern/atitc/VC8/DLL Release/Win32/ATI_Compress_1_7_DLL.lib new file mode 100755 index 0000000..d15c44e Binary files /dev/null and b/extern/atitc/VC8/DLL Release/Win32/ATI_Compress_1_7_DLL.lib differ diff --git a/extern/atitc/VC8/DLL Release/x64/ATI_Compress_1_7.dll b/extern/atitc/VC8/DLL Release/x64/ATI_Compress_1_7.dll new file mode 100755 index 0000000..70c5990 Binary files /dev/null and b/extern/atitc/VC8/DLL Release/x64/ATI_Compress_1_7.dll differ diff --git a/extern/atitc/VC8/DLL Release/x64/ATI_Compress_1_7_DLL.lib b/extern/atitc/VC8/DLL Release/x64/ATI_Compress_1_7_DLL.lib new file mode 100755 index 0000000..ed9a572 Binary files /dev/null and b/extern/atitc/VC8/DLL Release/x64/ATI_Compress_1_7_DLL.lib differ diff --git a/extern/atitc/VC8/MT DLL Debug/Win32/ATI_Compress_MT_DLL_VC8.lib b/extern/atitc/VC8/MT DLL Debug/Win32/ATI_Compress_MT_DLL_VC8.lib new file mode 100755 index 0000000..49be1aa Binary files /dev/null and b/extern/atitc/VC8/MT DLL Debug/Win32/ATI_Compress_MT_DLL_VC8.lib differ diff --git a/extern/atitc/VC8/MT DLL Debug/x64/ATI_Compress_MT_DLL_VC8.lib b/extern/atitc/VC8/MT DLL Debug/x64/ATI_Compress_MT_DLL_VC8.lib new file mode 100755 index 0000000..dc3f888 Binary files /dev/null and b/extern/atitc/VC8/MT DLL Debug/x64/ATI_Compress_MT_DLL_VC8.lib differ diff --git a/extern/atitc/VC8/MT DLL Release/Win32/ATI_Compress_MT_DLL_VC8.lib b/extern/atitc/VC8/MT DLL Release/Win32/ATI_Compress_MT_DLL_VC8.lib new file mode 100755 index 0000000..56d7df7 Binary files /dev/null and b/extern/atitc/VC8/MT DLL Release/Win32/ATI_Compress_MT_DLL_VC8.lib differ diff --git a/extern/atitc/VC8/MT DLL Release/x64/ATI_Compress_MT_DLL_VC8.lib b/extern/atitc/VC8/MT DLL Release/x64/ATI_Compress_MT_DLL_VC8.lib new file mode 100755 index 0000000..4824101 Binary files /dev/null and b/extern/atitc/VC8/MT DLL Release/x64/ATI_Compress_MT_DLL_VC8.lib differ diff --git a/extern/atitc/VC8/MT Debug/Win32/ATI_Compress_MT_VC8.lib b/extern/atitc/VC8/MT Debug/Win32/ATI_Compress_MT_VC8.lib new file mode 100755 index 0000000..bf185d8 Binary files /dev/null and b/extern/atitc/VC8/MT Debug/Win32/ATI_Compress_MT_VC8.lib differ diff --git a/extern/atitc/VC8/MT Debug/x64/ATI_Compress_MT_VC8.lib b/extern/atitc/VC8/MT Debug/x64/ATI_Compress_MT_VC8.lib new file mode 100755 index 0000000..ce545a6 Binary files /dev/null and b/extern/atitc/VC8/MT Debug/x64/ATI_Compress_MT_VC8.lib differ diff --git a/extern/atitc/VC8/MT Release/Win32/ATI_Compress_MT_VC8.lib b/extern/atitc/VC8/MT Release/Win32/ATI_Compress_MT_VC8.lib new file mode 100755 index 0000000..27a5d2d Binary files /dev/null and b/extern/atitc/VC8/MT Release/Win32/ATI_Compress_MT_VC8.lib differ diff --git a/extern/atitc/VC8/MT Release/x64/ATI_Compress_MT_VC8.lib b/extern/atitc/VC8/MT Release/x64/ATI_Compress_MT_VC8.lib new file mode 100755 index 0000000..40e31db Binary files /dev/null and b/extern/atitc/VC8/MT Release/x64/ATI_Compress_MT_VC8.lib differ diff --git a/extern/stb/stb_dxt.h b/extern/stb/stb_dxt.h new file mode 100644 index 0000000..2000f6b --- /dev/null +++ b/extern/stb/stb_dxt.h @@ -0,0 +1,555 @@ +// 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 diff --git a/extern/stb/stb_gl.h b/extern/stb/stb_gl.h new file mode 100644 index 0000000..802314c --- /dev/null +++ b/extern/stb/stb_gl.h @@ -0,0 +1,1098 @@ +// 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