Major API revision
[convexer.git] / src / nbvtf / nbvtf.h
diff --git a/src/nbvtf/nbvtf.h b/src/nbvtf/nbvtf.h
deleted file mode 100644 (file)
index 3ed8536..0000000
+++ /dev/null
@@ -1,799 +0,0 @@
-// nbvtf.h - v1.02 - Writer for Valve Texture Format - public domain
-// Written by Harry 'hgn' Godden
-//
-// Credits:
-//   Rich Geldreich - bc7enc (BC1/BC3 High Quality texture compression)
-//   Fabian "ryg" Giesen, stb - stb_dxt (BC1/BC3 realtime compressors)
-//   Sean Barrett - stb_image.h, stb_image_write.h (Image I/O)
-//
-// Note:
-//   This library assumes normal maps are input in OpenGL(correct) format, and will be converted into DirectX(incorrect) at
-//   compile time automatically. Do not submit DirectX normals into this software.
-//
-// Since this project uses stb_image, use '#define STB_IMAGE_IMPLEMENTATION' before including
-// Additionally, to use high quality DXT, '#define USE_LIBRGBCX'
-//
-// USAGE:
-//   Call these functions:
-//     int nbvtf_convert( const char *src, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest );
-//     int nbvtf_write( uint8_t *src, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest );
-//
-// Param definitions:
-//   src - RGBA byte data of image
-//   w - width of image
-//   h - height of image
-//   mipmap - enable mipmap generation (box filter), 1/0
-//   format - Choose from: k_EImageFormat_DXT1, compressedk_EImageFormat_DXT5, k_EImageFormat_BGR888, k_EImageFormat_ABGR8888
-//   usr_flags - You can append any flags but only really need TEXTUREFLAGS_NORMAL if texture is normal map
-//   dest - file path to write vtf to
-//  
-// Convert specific:
-//   src - file path of source image to convert
-//   w, h - MAXIMUM image dimentions of final product. Set as 0 to be automatic
-//
-// version history:
-//   v1.02  - Improved box filtering, small bug fixes
-//   v1.01  - switch to OpenGL normal format for input
-//   v1.00  - (hgn) first release
-//
-// LICENSE
-//   See end of file for license information.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define NBVTF_MAX_MIPLEVELS 9
-#define nbvtf__min(a,b) (((a)<(b))?(a):(b))
-#define nbvtf__max(a,b) (((a)>(b))?(a):(b))
-
-#ifdef NBVTF_AS_SO
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <math.h>
- #define NBVTF_SHOW_STDERR
- #define STB_IMAGE_IMPLEMENTATION
-#endif
-
-#include "stb/stb_image.h"
-
-#ifdef USE_LIBRGBCX
- #include "librgbcx.h"
-#else
- #define STB_DXT_IMPLEMENTATION
- #include "stb/stb_dxt.h"
-#endif
-
-#ifdef NBVTF_SHOW_STDERR
- #define NBVTF_ERR(...)
-#else
- #define NBVTF_ERR(...) fprintf( stderr, __VA_ARGS__ )
-#endif
-
-#pragma pack(push, 1)
-
-typedef enum EImageFormat
-{
-       // Name                                                                 // Supported?
-       k_EImageFormat_NONE = -1,
-       k_EImageFormat_RGBA8888 = 0,            // YES
-       k_EImageFormat_ABGR8888, 
-       k_EImageFormat_RGB888,                          // YES
-       k_EImageFormat_BGR888,
-       k_EImageFormat_RGB565,
-       k_EImageFormat_I8,
-       k_EImageFormat_IA88,
-       k_EImageFormat_P8,
-       k_EImageFormat_A8,
-       k_EImageFormat_RGB888_BLUESCREEN,
-       k_EImageFormat_BGR888_BLUESCREEN,
-       k_EImageFormat_ARGB8888,
-       k_EImageFormat_BGRA8888,
-       k_EImageFormat_DXT1,                                    // YES
-       k_EImageFormat_DXT3,
-       k_EImageFormat_DXT5,                                    // YES
-       k_EImageFormat_BGRX8888,
-       k_EImageFormat_BGR565,
-       k_EImageFormat_BGRX5551,
-       k_EImageFormat_BGRA4444,
-       k_EImageFormat_DXT1_ONEBITALPHA,
-       k_EImageFormat_BGRA5551,
-       k_EImageFormat_UV88,
-       k_EImageFormat_UVWQ8888,
-       k_EImageFormat_RGBA16161616F,
-       k_EImageFormat_RGBA16161616,
-       k_EImageFormat_UVLX8888
-} EImageFormat_t;
-
-const char *vtf_format_strings[] = 
-{
-       // Name                                                                 // Supported?
-       "RGBA8888",
-       "ABGR8888",
-       "RGB888",
-       "BGR888",
-       "RGB565",
-       "I8",
-       "IA88",
-       "P8",
-       "A8",
-       "RGB888_BLUESCREEN",
-       "BGR888_BLUESCREEN",
-       "ARGB8888",
-       "BGRA8888",
-#ifdef USE_LIBRGBCX
-       "DXT1 (rgbcx.h)",
-#else
-       "DXT1 (stb_dxt.h)",
-#endif
-       "DXT3",
-#ifdef USE_LIBRGBCX
-       "DXT5 (rgbcx.h)",
-#else
-       "DXT5 (stb_dxt.h)",
-#endif
-       "BGRX8888",
-       "BGR565",
-       "BGRX5551",
-       "BGRA4444",
-       "DXT1_ONEBITALPHA",
-       "BGRA5551",
-       "UV88",
-       "UVWQ8888",
-       "RGBA16161616F",
-       "RGBA16161616",
-       "UVLX8888"
-};
-
-enum flag
-{
-       // Flags from the *.txt config file
-       TEXTUREFLAGS_POINTSAMPLE = 0x00000001,
-       TEXTUREFLAGS_TRILINEAR = 0x00000002,
-       TEXTUREFLAGS_CLAMPS = 0x00000004,
-       TEXTUREFLAGS_CLAMPT = 0x00000008,
-       TEXTUREFLAGS_ANISOTROPIC = 0x00000010,
-       TEXTUREFLAGS_HINT_DXT5 = 0x00000020,
-       TEXTUREFLAGS_PWL_CORRECTED = 0x00000040,
-       TEXTUREFLAGS_NORMAL = 0x00000080,
-       TEXTUREFLAGS_NOMIP = 0x00000100,
-       TEXTUREFLAGS_NOLOD = 0x00000200,
-       TEXTUREFLAGS_ALL_MIPS = 0x00000400,
-       TEXTUREFLAGS_PROCEDURAL = 0x00000800,
-
-       // These are automatically generated by vtex from the texture data.
-       TEXTUREFLAGS_ONEBITALPHA = 0x00001000,
-       TEXTUREFLAGS_EIGHTBITALPHA = 0x00002000,
-
-       // Newer flags from the *.txt config file
-       TEXTUREFLAGS_ENVMAP = 0x00004000,
-       TEXTUREFLAGS_RENDERTARGET = 0x00008000,
-       TEXTUREFLAGS_DEPTHRENDERTARGET = 0x00010000,
-       TEXTUREFLAGS_NODEBUGOVERRIDE = 0x00020000,
-       TEXTUREFLAGS_SINGLECOPY = 0x00040000,
-       TEXTUREFLAGS_PRE_SRGB = 0x00080000,
-
-       TEXTUREFLAGS_UNUSED_00100000 = 0x00100000,
-       TEXTUREFLAGS_UNUSED_00200000 = 0x00200000,
-       TEXTUREFLAGS_UNUSED_00400000 = 0x00400000,
-
-       TEXTUREFLAGS_NODEPTHBUFFER = 0x00800000,
-
-       TEXTUREFLAGS_UNUSED_01000000 = 0x01000000,
-
-       TEXTUREFLAGS_CLAMPU = 0x02000000,
-       TEXTUREFLAGS_VERTEXTEXTURE = 0x04000000,
-       TEXTUREFLAGS_SSBUMP = 0x08000000,
-
-       TEXTUREFLAGS_UNUSED_10000000 = 0x10000000,
-
-       TEXTUREFLAGS_BORDER = 0x20000000,
-
-       TEXTUREFLAGS_UNUSED_40000000 = 0x40000000,
-       TEXTUREFLAGS_UNUSED_80000000 = 0x80000000,
-};
-
-typedef struct vtfheader
-{
-       union
-       {
-       char                            signature[4];                   // File signature ("VTF\0"). (or as little-endian integer, 0x00465456)
-       uint32_t                        usig;
-       };
-       
-       unsigned int    version[2];                             // version[0].version[1] (currently 7.2).
-       unsigned int    headerSize;                             // Size of the header struct  (16 byte aligned; currently 80 bytes) + size of the resources dictionary (7.3+).
-       unsigned short  width;                                  // Width of the largest mipmap in pixels. Must be a power of 2.
-       unsigned short  height;                                 // Height of the largest mipmap in pixels. Must be a power of 2.
-       unsigned int    flags;                                  // VTF flags.
-       unsigned short  frames;                                 // Number of frames, if animated (1 for no animation).
-       unsigned short  firstFrame;                             // First frame in animation (0 based).
-       unsigned char   padding0[4];                    // reflectivity padding (16 byte alignment).
-       float                           reflectivity[3];                // reflectivity vector.
-       unsigned char   padding1[4];                    // reflectivity padding (8 byte packing).
-       float                           bumpmapScale;                   // Bumpmap scale.
-       unsigned int    highResImageFormat;     // High resolution image format.
-       unsigned char   mipmapCount;                    // Number of mipmaps.
-       unsigned int    lowResImageFormat;      // Low resolution image format (always DXT1).
-       unsigned char   lowResImageWidth;               // Low resolution image width.
-       unsigned char   lowResImageHeight;      // Low resolution image height.
-
-       // 7.2+
-       unsigned short  depth;                                  // Depth of the largest mipmap in pixels.
-                                                                                                       // Must be a power of 2. Can be 0 or 1 for a 2D texture (v7.2 only).
-
-       // 7.3+
-       unsigned char   padding2[3];                    // depth padding (4 byte alignment).
-       unsigned int    numResources;                   // Number of resources this vtf has
-       
-       unsigned char  padding3[8];        // Necessary on certain compilers
-} vtfheader_t;
-
-#pragma pack(pop)
-
-typedef struct mipimg
-{
-       uint32_t w;
-       uint32_t h;
-       uint32_t src_offset;
-} mipimg_t;
-
-int nbvtf_power2( uint32_t x )
-{
-    return (x != 0) && ((x & (x - 1)) == 0);
-}
-
-int nbvtf_power2x( uint32_t y, uint32_t x )
-{
-       return nbvtf_power2( y ) && nbvtf_power2( x );
-}
-
-int nbvtf_lower( int *x, int *y )
-{
-       if( *x == 1 && *y == 1 )
-       {
-               return 0;
-       }
-
-       *x = nbvtf__max( 1, (*x)/2 );
-       *y = nbvtf__max( 1, (*y)/2 );
-       
-       return 1;
-}
-
-int nbvtf_lowres_index( int w, int h )
-{
-       int x, y;
-       int i = 0;
-       
-       x = w;
-       y = h;
-       
-       while(1)
-       {
-               if( (x <= 16) && ( y <= 16 ) )
-               {
-                       return i;
-               }
-               
-               i ++;
-               
-               nbvtf_lower( &x, &y );
-       }
-}
-
-// Simple box filter downscale
-void nbvtf_downscale( uint8_t *src, int w, int h, int dw, int dh, uint8_t *dest )
-{
-   int bx = w/dw;
-   int by = h/dh;
-   int div = bx*by;
-
-       for( int y = 0; y < dh; y ++ )
-   for( int x = 0; x < dw; x ++ )
-   {
-      // Average block colours
-      uint32_t tr = 0, tg = 0, tb = 0, ta = 0;
-
-      for( int yy = 0; yy < by; yy ++ )
-      for( int xx = 0; xx < bx; xx ++ )
-      {
-         uint8_t *psrc = &src[ (x*bx+xx + (y*by+yy)*w)*4 ];
-         tr+=psrc[0];
-         tg+=psrc[1];
-         tb+=psrc[2];
-         ta+=psrc[3];
-      }
-      
-      uint8_t *pdst = &dest[ (y*dw + x)*4 ];
-      pdst[0] = tr / div;
-      pdst[1] = tg / div;
-      pdst[2] = tb / div;
-      pdst[3] = ta / div;
-       }
-}
-
-uint8_t *nbvtf_create_mipmaps( uint8_t *src, int w, int h, mipimg_t *offsets, int *num )
-{
-       int memory = 0;
-       int x, y, i;
-       uint32_t offset;
-       
-       x = w;
-       y = h;
-       while( nbvtf_lower( &x, &y ) )
-               memory += x*y*4;
-       
-       uint8_t *mipmem = (uint8_t *)malloc( memory );
-       
-       if( mipmem )
-       {
-               x = w;
-               y = h;
-               i = 0;
-               offset = 0;
-               
-               uint8_t *dest = mipmem;
-               
-               while(1)
-               {
-                       if( !nbvtf_lower( &x, &y ) )
-                               break;
-
-                       nbvtf_downscale( src, w, h, x, y, dest );
-                       
-                       offsets[ i ].src_offset = offset;
-                       offsets[ i ].w = x;
-                       offsets[ i ].h = y;
-                       i ++;
-                       
-                       offset += x*y*4;
-                       dest = mipmem + offset;
-               }
-               
-               *num = i;
-               return mipmem;
-       }
-       else
-       {
-               NBVTF_ERR( "nbvtf_write:err out of memory allocating mipmap buffer!\n" );
-               return NULL;
-       }
-}
-
-void nbvtf_reflectivity( uint8_t *src, int w, int h, float *dest )
-{
-       uint32_t totals[3] = {0,0,0};
-       
-       for( int i = 0; i < w*h; i ++ )
-       {
-               totals[0] += src[i*4+0];
-               totals[1] += src[i*4+1];
-               totals[2] += src[i*4+2];
-       }
-       
-       dest[0] = (float)( totals[0] / (w*h) ) / 255.0f;
-       dest[1] = (float)( totals[1] / (w*h) ) / 255.0f;
-       dest[2] = (float)( totals[2] / (w*h) ) / 255.0f;
-}
-
-#ifdef NBVTF_ALLOW_EXPORT
-void nbvtf_debug_view_mips( uint8_t *src, int w, int h )
-{
-       int x, y, i;
-       char fnbuf[512];
-       
-       x = w;
-       y = h;
-       i = 1;
-
-       uint8_t *dest = src;
-
-       while( nbvtf_lower( &x, &y ) )
-       {
-               sprintf( fnbuf, "mip_%d.png", i ++ );
-       
-               stbi_write_png( fnbuf, x,y, 4, dest, x*4 );
-               dest += x*y*4;
-       }
-}
-#endif
-
-void nbvtf_dxt_pad( uint8_t *src, int bx, int by, int w, int h, uint8_t *dest )
-{
-       int px = bx*4;
-       int py = by*4;
-       
-       uint32_t *stream = (uint32_t *)src;
-       uint32_t *stream_out = (uint32_t *)dest;
-
-       for( int y = 0; y < 4; y ++ )
-       {
-               for( int x = 0; x < 4; x ++ )
-               {
-                       stream_out[ y*4+x ] = stream[ nbvtf__min( py+y, h-1 )*w + nbvtf__min( px+x, w-1 ) ];
-               }
-       }
-}
-
-uint32_t nbvtf_dxt_sizeimg( int w, int h, int alpha )
-{
-       uint32_t blocks_x, blocks_y;
-       int block_size = alpha? 16: 8;
-
-       blocks_x = ((uint32_t)w) >> 2;
-       blocks_y = ((uint32_t)h) >> 2;
-       
-       int padx = w % 4 != 0? 1: 0;
-       int pady = h % 4 != 0? 1: 0;
-       
-       return (blocks_x+padx)*(blocks_y+pady)*block_size;
-}
-
-uint32_t nbvtf_sizeimg( int w, int h, EImageFormat_t format )
-{
-       if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_DXT1 )
-       {
-               return nbvtf_dxt_sizeimg( w, h, format == k_EImageFormat_DXT1? 0: 1 );
-       }
-       
-       if( format == k_EImageFormat_BGR888 )
-               return w*h*3;
-               
-       if( format == k_EImageFormat_ABGR8888 )
-               return w*h*4;
-               
-       return 0;
-}
-
-void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha )
-{
-#ifdef USE_LIBRGBCX
-       // TODO: move this somewehre else
-       static int init = 0;
-       if( !init )
-       {
-               rgbcx__init();
-               init = 1;
-       }
-
-       if( alpha )
-       {
-               rgbcx__encode_bc3( 12, dest, src );
-       }
-       else
-       {
-               rgbcx__encode_bc1( 12, dest, src, 0, 0 );
-       }
-#else
-       stb_compress_dxt_block( dest, src, alpha, STB_DXT_HIGHQUAL );
-#endif
-}
-
-void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, uint8_t *dest )
-{
-       uint32_t blocks_x, blocks_y;
-
-       blocks_x = ((uint32_t)w) >> 2;
-       blocks_y = ((uint32_t)h) >> 2;
-       
-       int padx = w % 4 != 0? 1: 0;
-       int pady = h % 4 != 0? 1: 0;
-       
-       int block_size = alpha? 16: 8;
-       
-       uint8_t *dest_block = dest;
-       
-       uint8_t working_block[ 4*4*4 ];
-       
-       // Compress rows
-       for( int y = 0; y < blocks_y; y ++ )
-       {
-               for( int x = 0; x < blocks_x; x ++ )
-               {
-                       uint8_t *src_begin = src + (y*w*4 + x*4)*4;
-                       for( int i = 0; i < 4; i ++ )
-                       {
-                               memcpy( working_block + i*4*4, src_begin + w*4*i, 4*4 );
-                       }
-                       
-                       nbvtf_dxt_block( dest_block, working_block, alpha );
-                       dest_block += block_size;
-               }
-               
-               if( padx )
-               {
-                       nbvtf_dxt_pad( src, blocks_x, y, w, h, working_block );
-                       nbvtf_dxt_block( dest_block, working_block, alpha );
-                       dest_block += block_size;
-               }
-       }
-       
-       // Compress remainder row
-       if( pady )
-       {
-               for( int x = 0; x < blocks_x; x ++ )
-               {
-                       nbvtf_dxt_pad( src, x, blocks_y, w, h, working_block );
-                       nbvtf_dxt_block( dest_block, working_block, alpha );
-                       dest_block += block_size;
-               }
-       }
-       
-       // Compress last little corner
-       if( padx && pady )
-       {
-               nbvtf_dxt_pad( src, blocks_x, blocks_y, w, h, working_block );
-               nbvtf_dxt_block( dest_block, working_block, alpha );
-       }
-}
-
-void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest )
-{
-       for( int i = 0; i < n; i ++ )
-       {
-               for( int j = 0; j < nc; j ++ )
-               {
-                       dest[ i*nc+nc-j-1 ] = src[ i*4+j ];
-               }
-       }
-}
-
-void nbvtf_write_img_data( uint8_t *src, int w, int h, EImageFormat_t format, uint8_t *wb, FILE *file )
-{
-       switch( format )
-       {
-               case k_EImageFormat_DXT1:
-                       nbvtf_compress_dxt( src, w, h, 0, wb );
-                       fwrite( wb, nbvtf_dxt_sizeimg( w, h, 0 ), 1, file );
-               break;
-               case k_EImageFormat_DXT5:
-                       nbvtf_compress_dxt( src, w, h, 1, wb );
-                       fwrite( wb, nbvtf_dxt_sizeimg( w, h, 1 ), 1, file );
-               break;
-               case k_EImageFormat_ABGR8888:
-                       nbvtf_swizzle_to( src, w*h, 4, wb );
-                       fwrite( wb, w*h*4, 1, file );
-               break;
-               case k_EImageFormat_BGR888:
-                       nbvtf_swizzle_to( src, w*h, 3, wb );
-                       fwrite( wb, w*h*3, 1, file );
-               break;
-               
-               default:
-               break;
-       }
-}
-
-#ifdef NBVTF_AS_SO
-__attribute__((visibility("default")))
-#endif
-int nbvtf_write( uint8_t *reference, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest )
-{
-       if( !nbvtf_power2x(w,h) )
-       {
-               NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w, h );
-               return 0;
-       }
-
-       mipimg_t mip_offsets[ 16 ];
-       int num_mips;
-       
-   uint8_t *src;
-
-   // Convert to directx normal
-   if( usr_flags & TEXTUREFLAGS_NORMAL )
-   {
-      src = malloc( w*h*4 );
-      for( int i = 0; i < w*h; i ++ )
-      {
-         src[i*4+0] = reference[i*4+0];
-         src[i*4+1] = 0xFF-reference[i*4+1];
-         src[i*4+2] = reference[i*4+2];
-         src[i*4+3] = reference[i*4+3];
-      }
-   }
-   else
-      src = reference;
-       
-       uint8_t *mip_data = nbvtf_create_mipmaps( src, w, h, mip_offsets, &num_mips );
-       
-       if( !mip_data )
-       {
-               NBVTF_ERR( "nbvtf_write:err mipmap data failed to generate" );
-
-      if( usr_flags & TEXTUREFLAGS_NORMAL )
-         free( src );
-
-               return 0;
-       }
-       
-       vtfheader_t header = {0};
-       
-       header.usig = 0x00465456;
-       header.headerSize = sizeof( vtfheader_t );
-       header.version[0] = 7;
-       header.version[1] = 2;
-       
-       header.width = w;
-       header.height = h;
-       header.flags = usr_flags;
-       
-       // Append format flags
-       if( !mipmap )
-       {
-               header.flags |= TEXTUREFLAGS_NOLOD;
-               header.flags |= TEXTUREFLAGS_NOMIP;
-       }
-       
-       if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_ABGR8888 )
-       {
-               header.flags |= TEXTUREFLAGS_EIGHTBITALPHA;
-       }
-       
-       header.frames = 1;
-       header.firstFrame = 0;
-       nbvtf_reflectivity( mip_data + mip_offsets[ num_mips-1 ].src_offset, 1,1, header.reflectivity );
-       header.bumpmapScale = 1.0f;
-       
-       header.highResImageFormat = format;
-       header.mipmapCount = mipmap? 
-      nbvtf__min(num_mips,NBVTF_MAX_MIPLEVELS)+1: 1;
-       
-       header.lowResImageFormat = k_EImageFormat_DXT1;
-
-       header.depth = 1;
-       header.numResources = 0;
-       
-       int lr_index = nbvtf_lowres_index( w, h );
-       
-       uint8_t *lr_src;
-       
-       if( lr_index )
-       {
-               mipimg_t *mip = mip_offsets + (lr_index-1);
-               lr_src = mip_data + mip->src_offset;
-               
-               header.lowResImageWidth = mip->w;
-               header.lowResImageHeight = mip->h;
-       }
-       else
-       {
-               lr_src = src;
-               
-               header.lowResImageWidth = w;
-               header.lowResImageHeight = h;
-       }
-       
-       uint32_t size_highres = nbvtf_sizeimg( w, h, format );
-       uint32_t size_lowres = nbvtf_dxt_sizeimg( header.lowResImageWidth, header.lowResImageHeight, 0 );
-       
-       uint8_t *working_buffer = (uint8_t *)malloc( nbvtf__max( size_highres, size_lowres ) );
-       
-       if( !working_buffer )
-       {
-               NBVTF_ERR( "nbvtf_write:err out of memory allocating working buffer\n" );
-               free( mip_data );
-
-      if( usr_flags & TEXTUREFLAGS_NORMAL )
-         free( src );
-
-               return 0;
-       }
-       
-       FILE *file = fopen( dest, "wb" );
-       
-       if( !file )
-       {
-               NBVTF_ERR( "nbvtf_write:err could not open file stream for writing\n" );
-               
-               free( working_buffer );
-               free( mip_data );
-               
-      if( usr_flags & TEXTUREFLAGS_NORMAL )
-         free( src );
-
-               return 0;
-       }
-       
-       // Write header
-       fwrite( &header, sizeof( vtfheader_t ), 1, file );
-       
-       // Write low res
-       nbvtf_write_img_data( 
-               lr_src, header.lowResImageWidth, header.lowResImageHeight, k_EImageFormat_DXT1, working_buffer, file 
-       );
-       
-       // Write texture data
-       if( mipmap )
-       {
-      // !! Experimental !!
-      int start = nbvtf__max( 0, num_mips-NBVTF_MAX_MIPLEVELS );
-      
-               for( int i = start; i < num_mips; i ++ )
-               {
-                       mipimg_t *mip = mip_offsets + (num_mips - i -1);
-                       nbvtf_write_img_data( mip_data + mip->src_offset, mip->w, mip->h, format, working_buffer, file );
-               }
-       }
-       
-       // Write high resolution
-       nbvtf_write_img_data( src, w, h, format, working_buffer, file );
-       
-       fclose( file );
-
-       free( working_buffer );
-       free( mip_data );
-
-   if( usr_flags & TEXTUREFLAGS_NORMAL )
-      free( src );
-       
-       return 1;
-}
-
-#ifdef NBVTF_AS_SO
-__attribute__((visibility("default")))
-#endif
-int nbvtf_convert( const char *src, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest )
-{
-       if( (w && h) && !nbvtf_power2x(w,h) )
-       {
-               NBVTF_ERR( "nbvtf_convert:err requested dimentions were not power of two (%d %d)\n", w, h );
-               return 0;
-       }
-       
-       int x,y,n;
-       uint8_t *data = stbi_load( src, &x, &y, &n, 4 );
-       
-       if( data )
-       {
-               if( !nbvtf_power2x(x,y) )
-               {
-                       NBVTF_ERR( "nbvtf_convert:err loaded image dimentions were not power two (%d %d)\n", x, y );
-                       stbi_image_free( data );
-                       return 0;
-               }
-               
-               // Image size needs retargeting
-               if( (w && h) && ( x > w || y > h ) )
-         nbvtf_downscale( data, x, y, w, h, data );
-               
-               int status = nbvtf_write( data, w, h, mipmap, format, usr_flags, dest );
-               stbi_image_free( data );
-               
-               return status;
-       }
-       else
-       {
-               return 0;
-       }
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-/*
-LICENSE - Applies to nbvtf.h, pynbvtf.py, librgbcx.cc, librgbcx.h, vtf_cmd.c
-------------------------------------------------------------------------------
-Public Domain (www.unlicense.org)
-This is free and unencumbered software released into the public domain.
-Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
-software, either in source code form or as a compiled binary, for any purpose,
-commercial or non-commercial, and by any means.
-In jurisdictions that recognize copyright laws, the author or authors of this
-software dedicate any and all copyright interest in the software to the public
-domain. We make this dedication for the benefit of the public at large and to
-the detriment of our heirs and successors. We intend this dedication to be an
-overt act of relinquishment in perpetuity of all present and future rights to
-this software under copyright law.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------------------
-*/