texture loading
authorhgn <hgodden00@gmail.com>
Mon, 2 May 2022 03:53:00 +0000 (04:53 +0100)
committerhgn <hgodden00@gmail.com>
Mon, 2 May 2022 03:53:00 +0000 (04:53 +0100)
__init__.py
cxr/cxr_valve_bin.h
nbvtf/librgbcx.cpp
nbvtf/librgbcx.h
nbvtf/nbvtf.h
nbvtf/vtf_cmd.c

index 8d9254e69b49a1ba2e5971712fbc4f2f4bb173a8..05aefbcb1066a2c5592a6c5d9f1ac5c3e55bd0c0 100644 (file)
@@ -48,10 +48,10 @@ cxr_ui_draw_handler = None
 # Batches
 cxr_view_lines = None
 cxr_view_mesh = None
-cxr_mdl_mesh = None
 cxr_jobs_batch = None
 cxr_jobs_inf = []
 cxr_error_inf = None
+cxr_test_mdl = None
 
 cxr_asset_lib = \
 {
@@ -93,9 +93,11 @@ uniform mat4 viewProjectionMatrix;
 
 in vec3 aPos;
 in vec3 aNormal;
+in vec2 aUv;
 
 out vec3 lPos;
 out vec3 lNormal;
+out vec2 lUv;
 
 void main()
 {
@@ -105,14 +107,17 @@ void main()
    gl_Position = viewProjectionMatrix * pWorldPos;
    lNormal = normalize(mat3(transpose(inverse(modelMatrix))) * aNormal);
    lPos = worldPos;
+   lUv = aUv;
 }
 ""","""
 
 uniform vec4 colour;
 uniform vec3 testLightDir;
+uniform sampler2D uBasetexture;
 
 in vec3 lNormal;
 in vec3 lPos;
+in vec2 lUv;
 
 out vec4 FragColor;
 
@@ -146,11 +151,18 @@ vec3 LinearToGamma( vec3 f3linear )
        return pow( f3linear, vec3(1.0 / 2.2) );
 }
 
+vec3 GammaToLinear( vec3 f3gamma )
+{
+   return pow( f3gamma, vec3(2.2) );
+}
+
 void main()
 {
    vec3 tangentSpaceNormal = vec3( 0.0, 0.0, 1.0 );
    vec4 normalTexel = vec4(1.0,1.0,1.0,1.0);
-   vec4 baseColor = colour;
+   vec3 colorInput = GammaToLinear( texture( uBasetexture, lUv ).rgb );
+
+   vec4 baseColor = vec4( colorInput * colour.rgb, 1.0 );
 
        //normalTexel = tex2D( BumpmapSampler, i.detailOrBumpTexCoord );
        //tangentSpaceNormal = 2.0 * normalTexel - 1.0;
@@ -229,7 +241,7 @@ def cxr_ui(_,context):
 
 def cxr_draw():
    global cxr_view_shader, cxr_view_mesh, cxr_view_lines, cxr_mdl_shader,\
-          cxr_mdl_mesh
+          cxr_mdl_mesh, cxr_test_mdl
 
    cxr_view_shader.bind()
 
@@ -245,29 +257,33 @@ def cxr_draw():
    if cxr_view_mesh != None:
       gpu.state.depth_test_set('LESS_EQUAL')
       gpu.state.blend_set('ADDITIVE')
-
+      
       cxr_view_mesh.draw( cxr_view_shader )
 
-   if cxr_mdl_mesh != None:
-      gpu.state.depth_mask_set(True)
-      gpu.state.depth_test_set('LESS_EQUAL')
-      gpu.state.face_culling_set('FRONT')
-      gpu.state.blend_set('NONE')
-      cxr_mdl_shader.bind()
-      cxr_mdl_shader.uniform_float('colour',(0.5,0.5,0.5,1.0))
-      cxr_mdl_shader.uniform_float("viewProjectionMatrix", \
-            bpy.context.region_data.perspective_matrix)
+   # Models
+   gpu.state.depth_mask_set(True)
+   gpu.state.depth_test_set('LESS_EQUAL')
+   gpu.state.face_culling_set('FRONT')
+   gpu.state.blend_set('NONE')
 
+   cxr_mdl_shader.bind()
+   cxr_mdl_shader.uniform_float("viewProjectionMatrix", \
+         bpy.context.region_data.perspective_matrix)
+
+   if cxr_test_mdl != None:
+      cxr_mdl_shader.uniform_float('colour',(1.0,1.0,1.0,1.0))
+
+      #temp light dir
       testmdl = bpy.context.scene.objects['target']
       light = bpy.context.scene.objects['point']
       relative = light.location - testmdl.location 
       relative.normalize()
-
       cxr_mdl_shader.uniform_float("modelMatrix", testmdl.matrix_world)
       cxr_mdl_shader.uniform_float("testLightDir", relative)
 
-
-      cxr_mdl_mesh.draw( cxr_mdl_shader )
+      for part in cxr_test_mdl:
+         cxr_mdl_shader.uniform_sampler("uBasetexture", part[0]['basetexture'])
+         part[1].draw( cxr_mdl_shader )
 
 def cxr_jobs_update_graph(jobs):
    global cxr_jobs_batch, cxr_ui_shader, cxr_jobs_inf
@@ -627,7 +643,8 @@ libcxr_lightpatch_bsp = extern( "cxr_lightpatch_bsp", [c_char_p], None )
 # Binary file formats and FS
 libcxr_fs_set_gameinfo = extern( "cxr_fs_set_gameinfo", [c_char_p], c_int32 )
 libcxr_fs_exit = extern( "cxr_fs_exit", [], None )
-libcxr_fs_get = extern( "cxr_fs_get", [c_char_p, c_int32], c_char_p )
+libcxr_fs_get = extern( "cxr_fs_get", [c_char_p, c_int32], c_void_p )
+libcxr_fs_free = extern( "cxr_fs_free", [c_void_p], None )
 libcxr_fs_find = extern( "cxr_fs_find", [c_char_p, POINTER(fs_locator)],\
       c_int32 )
 
@@ -648,7 +665,7 @@ libcxr_funcs = [ libcxr_decompose, libcxr_free_world, libcxr_begin_vmf, \
                  libcxr_vdf_kv, libcxr_lightpatch_bsp, libcxr_write_test_data,\
                  libcxr_world_preview, libcxr_free_tri_mesh, \
                  libcxr_fs_set_gameinfo, libcxr_fs_exit, libcxr_fs_get, \
-                 libcxr_fs_find,\
+                 libcxr_fs_find, libcxr_fs_free, \
                  libcxr_valve_load_model, libcxr_valve_free_model,\
                  libcxr_valve_load_material, libcxr_valve_free_material ]
 
@@ -717,8 +734,15 @@ libnbvtf_convert = extern( "nbvtf_convert", \
       [c_char_p,c_int32,c_int32,c_int32,c_int32,c_int32,c_uint32,c_char_p], \
       c_int32 )
 
+libnbvtf_read = extern( "nbvtf_read", \
+      [c_void_p,POINTER(c_int32),POINTER(c_int32), c_int32], \
+      POINTER(c_uint8) )
+
+libnbvtf_free = extern( "nbvtf_free", [POINTER(c_uint8)], None )
+
 libnbvtf_init = extern( "nbvtf_init", [], None )
-libnbvtf_funcs = [ libnbvtf_convert, libnbvtf_init ]
+libnbvtf_funcs = [ libnbvtf_convert, libnbvtf_init, libnbvtf_read, \
+                   libnbvtf_free ]
 
 # Loading
 # --------------------------
@@ -1770,7 +1794,7 @@ class CXR_INIT_FS_OPERATOR(bpy.types.Operator):
 
       return {'FINISHED'}
 
-def cxr_load_texture( path ):
+def cxr_load_texture( path, is_normal ):
    global cxr_asset_lib
 
    if path in cxr_asset_lib['textures']:
@@ -1778,9 +1802,36 @@ def cxr_load_texture( path ):
 
    print( F"cxr_load_texture( '{path}' )" )
 
-   # TODO
+   pvtf = libcxr_fs_get.call( path.encode('utf-8'), 0 )
+
+   if not pvtf:
+      print( "vtf failed to load" )
+      cxr_asset_lib['textures'][path] = None
+      return None
+
+   x = c_int32(0)
+   y = c_int32(0)
+
+   img_data = libnbvtf_read.call( pvtf, pointer(x), pointer(y), \
+         c_int32(is_normal) )
+
+   x = x.value
+   y = y.value
+
+   if not img_data:
+      print( "vtf failed to decode" )
+      libcxr_fs_free.call( pvtf )
+      cxr_asset_lib['textures'][path] = None
+      return None
+
+   img_buf = gpu.types.Buffer('FLOAT', [x*y*4], [_/255.0 for _ in img_data[:x*y*4]])
 
-   tex = cxr_asset_lib['textures'][path] = None
+   tex = cxr_asset_lib['textures'][path] = \
+         gpu.types.GPUTexture( size=(x,y), layers=0, is_cubemap=False,\
+                               format='RGBA8', data=img_buf )
+   
+   libnbvtf_free.call( img_data )
+   libcxr_fs_free.call( pvtf )
    return tex
 
 def cxr_load_material( path ):
@@ -1792,15 +1843,19 @@ def cxr_load_material( path ):
    print( F"cxr_load_material( '{path}' )" )
    
    pvmt = libcxr_valve_load_material.call( path.encode( 'utf-8') )
-   vmt = pvmt[0]
+   
+   if not pvmt:
+      cxr_asset_lib['materials'][path] = None
+      return None
 
+   vmt = pvmt[0]
    mat = cxr_asset_lib['materials'][path] = {}
 
    if vmt.basetexture:
-      mat['basetexture'] = cxr_load_texture( vmt.basetexture.decode('utf-8') )
+      mat['basetexture'] = cxr_load_texture( vmt.basetexture.decode('utf-8'), 0)
    
    if vmt.bumpmap:
-      mat['bumpmap'] = cxr_load_texture( vmt.bumpmap.decode('utf-8') )
+      mat['bumpmap'] = cxr_load_texture( vmt.bumpmap.decode('utf-8'), 1)
 
    libcxr_valve_free_material.call( pvmt )
 
@@ -1870,15 +1925,9 @@ class CXR_LOAD_MODEL_OPERATOR(bpy.types.Operator):
    bl_label="Load model"
 
    def execute(_,context):
-      global cxr_mdl_mesh, cxr_mdl_shader, cxr_asset_lib
-
-      test_mdl = cxr_load_model_full( bpy.context.scene.cxr_data.dev_mdl )
+      global cxr_test_mdl, cxr_mdl_shader, cxr_asset_lib
 
-      if test_mdl != None:
-         # just draw first batch part for now
-         cxr_mdl_mesh = test_mdl[0][1]
-      else:
-         cxr_mdl_mesh = None
+      cxr_test_mdl = cxr_load_model_full( bpy.context.scene.cxr_data.dev_mdl )
 
       scene_redraw()
       return {'FINISHED'}
index b11f71f5d7f1cd00b067fcd9a4af5851d3b0828e..8d0bf9c33c6702daa9ee5c5c7f0a91813c3b4f9e 100644 (file)
@@ -40,6 +40,7 @@ typedef struct valve_material valve_material;
 CXR_API i32 cxr_fs_set_gameinfo( const char *path ); /* Setup system */
 CXR_API void cxr_fs_exit(void);                       /* Clean up */
 CXR_API void *cxr_fs_get( const char *path, i32 stringbuffer ); /* Get a file */
+CXR_API void cxr_fs_free( void *data );
 CXR_API i32 cxr_fs_find( const char *path, fs_locator *locator );
 
 CXR_API valve_model *valve_load_model( const char *relpath );
@@ -997,6 +998,11 @@ CXR_API i32 cxr_fs_find( const char *path, fs_locator *locator )
        return 0;
 }
 
+CXR_API void cxr_fs_free( void *data )
+{
+   free( data );
+}
+
 CXR_API void *cxr_fs_get( const char *path, i32 stringbuffer )
 {
        valve_file_system *fs = &fs_global;
@@ -1711,9 +1717,12 @@ static char *valve_texture_path( const char *path )
    if( !path )
       return NULL;
 
-   char *buf = cxr_str_clone( path, 4 );
-
+   char *buf = 
+      malloc( strlen( path ) + strlen(".vtf") + strlen("materials/") +1 );
+   strcpy( buf, "materials/" );
+   strcat( buf, path );
    strcat( buf, ".vtf" );
+
    cxr_unixpath( buf );
    cxr_lowercase( buf );
 
index ae6e72ccab759b43582a856d630760494862d716..958b99e43a24e12b46dc934d59989b8a979d938f 100644 (file)
@@ -21,4 +21,14 @@ extern "C"
        {
                rgbcx::encode_bc3( level, pDst, pPixels );
        }
+
+   int rgbcx__unpack_bc1( const void *pSrc, uint8_t *pDst )
+   {
+      return rgbcx::unpack_bc1( pSrc, pDst );
+   }
+
+   int rgbcx__unpack_bc3( const void *pSrc, uint8_t *pDst )
+   {
+      return rgbcx::unpack_bc3( pSrc, pDst );
+   }
 }
index 31ded0cc51947222347fc20078eddef03a7e8367..04a0c12f7ed2661300dc6b9fe2056b39f2975674 100644 (file)
@@ -12,6 +12,8 @@ void rgbcx__init(void);
 void rgbcx__encode_bc1( uint32_t level, void* pDst, const uint8_t* pPixels, int allow_3color, int use_transparent_texels_for_black );
 void rgbcx__encode_bc3( uint32_t level, void* pDst, const uint8_t* pPixels );
 
+int rgbcx__unpack_bc1( const void *pSrc, uint8_t *pDst );
+int rgbcx__unpack_bc3( const void *pSrc, uint8_t *pDst );
 #ifdef __cplusplus
 }
 #endif
index aa82cbf6a302823416a011f99a956e89e0f43383..5db305b812d8620e8db6270ee3ce4727f82d4360 100644 (file)
@@ -57,10 +57,12 @@ extern "C" {
  
  #define NBVTF_SHOW_STDERR
  #define STB_IMAGE_IMPLEMENTATION
+ #define STB_IMAGE_WRITE_IMPLEMENTATION
 #endif
 
 #define STBI_NO_THREAD_LOCALS
 #include "stb/stb_image.h"
+#include "stb/stb_image_write.h"
 
 #ifdef USE_LIBRGBCX
  // #define RGBCX_NO_ALGORITHM
@@ -88,40 +90,39 @@ extern "C" {
 
 typedef enum EImageFormat
 {
-       // Name                                                                 // Supported?
+   /* Format                           Export   Import */
        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
+       k_EImageFormat_RGBA8888 = 0,       // -        yes
+       k_EImageFormat_ABGR8888,         // yes      yes
+       k_EImageFormat_RGB888,                          // -        yes
+       k_EImageFormat_BGR888,           // yes      yes
+       k_EImageFormat_RGB565,           // -        planned
+       k_EImageFormat_I8,               // -        planned
+       k_EImageFormat_IA88,             // -        planned
+       k_EImageFormat_P8,               // -        -
+       k_EImageFormat_A8,               // -        -
+       k_EImageFormat_RGB888_BLUESCREEN,// -        -
+       k_EImageFormat_BGR888_BLUESCREEN,// -        -
+       k_EImageFormat_ARGB8888,         // -        yes
+       k_EImageFormat_BGRA8888,         // -        yes
+       k_EImageFormat_DXT1,                                    // yes      yes
+       k_EImageFormat_DXT3,             // -        -
+       k_EImageFormat_DXT5,                                    // yes      yes
+       k_EImageFormat_BGRX8888,         // -        -
+       k_EImageFormat_BGR565,           // -        planned
+       k_EImageFormat_BGRX5551,         // -        -
+       k_EImageFormat_BGRA4444,         // -        -
+       k_EImageFormat_DXT1_ONEBITALPHA, // -        planned
+       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",
@@ -564,6 +565,29 @@ void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha, int qual )
 #endif
 }
 
+void nbvtf_dxt_block_unpack( uint8_t *src, uint8_t *dest, int alpha )
+{
+#ifdef USE_LIBRGBCX
+       if( alpha )
+       {
+               rgbcx__unpack_bc3( src, dest );
+       }
+       else
+       {
+               rgbcx__unpack_bc1( src, dest );
+       }
+#endif
+
+#if USE_STB_DXT
+   stb_decompress_dxt_block( src, dest, alpha );
+#endif
+
+#ifndef HAS_DXT_COMPRESSOR
+   for( int i=0; i<alpha? 128: 64; i++ )
+      dest[i] = i%1? 0xff: 0x00;
+#endif
+}
+
 void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, int qual,
       uint8_t *dest )
 {
@@ -623,7 +647,49 @@ void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, int qual,
        }
 }
 
-void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest )
+/* Decompress block to rgba, padding currently doesn't get read */
+void nbvtf_decompress_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 *dxt_block = src;
+       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 ++ )
+               {
+         nbvtf_dxt_block_unpack( dxt_block, working_block, alpha );
+
+                       uint8_t *dest_begin = dest + (y*w*4 + x*4)*4;
+                       for( int i = 0; i < 4; i ++ )
+                               memcpy( dest_begin + w*4*i, working_block + i*4*4, 4*4 );
+                       
+                       dxt_block += block_size;
+               }
+               
+               if( padx )
+                       dxt_block += block_size;
+       }
+       
+       if( pady )
+               for( int x = 0; x < blocks_x; x ++ )
+                       dxt_block += block_size;
+       
+       if( padx && pady )
+       {
+       }
+}
+static void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest )
 {
        for( int i = 0; i < n; i ++ )
        {
@@ -634,7 +700,7 @@ void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest )
        }
 }
 
-void nbvtf_write_img_data( uint8_t *src, int w, int h, 
+static void nbvtf_write_img_data( uint8_t *src, int w, int h, 
       EImageFormat_t format, int qual, uint8_t *wb, FILE *file )
 {
        switch( format )
@@ -661,7 +727,119 @@ void nbvtf_write_img_data( uint8_t *src, int w, int h,
        }
 }
 
+static size_t nbvtf_img_size( int w, int h, EImageFormat_t format )
+{
+   int block_count = nbvtf__max(1, ((w + 3) / 4)) * 
+                     nbvtf__max(1, ((h + 3) / 4));
 
+   switch( format )
+   {
+      case k_EImageFormat_RGBA8888:
+      case k_EImageFormat_ABGR8888:
+      case k_EImageFormat_ARGB8888:
+      case k_EImageFormat_BGRA8888:
+         return 4*w*h;
+
+      case k_EImageFormat_RGB888:
+      case k_EImageFormat_BGR888:
+         return 3*w*h;
+
+      case k_EImageFormat_RGB565:
+      case k_EImageFormat_IA88:
+         return 2*w*h;
+
+      case k_EImageFormat_I8:
+         return w*h;
+      
+      case k_EImageFormat_DXT1:
+         return block_count * BLOCK_SIZE_DXT1;
+
+      case k_EImageFormat_DXT5:
+         return block_count * BLOCK_SIZE_DXT5;
+
+      default:
+         break;
+   }
+}
+
+static void nbvtf_read_img_data( uint8_t *src, int w, int h, 
+      EImageFormat_t format, uint8_t *dst )
+{
+   switch( format )
+   {
+      case k_EImageFormat_RGBA8888:
+         for( int i=0; i<w*h*4; i++ )
+            dst[i] = src[i];
+         break;
+
+      case k_EImageFormat_ABGR8888:
+         for( int i=0; i<w*h; i++ )
+         {
+            dst[i*4+0] = src[i*4+3];
+            dst[i*4+1] = src[i*4+2];
+            dst[i*4+2] = src[i*4+1];
+            dst[i*4+3] = src[i*4+0];
+         }
+         break;
+
+      case k_EImageFormat_RGB888:
+         for( int i=0; i<w*h; i++ )
+         {
+            dst[i*4+0] = src[i*3+0];
+            dst[i*4+1] = src[i*3+1];
+            dst[i*4+2] = src[i*3+2];
+            dst[i*4+3] = 0xFF;
+         }
+         break;
+
+      case k_EImageFormat_BGR888:
+         for( int i=0; i<w*h; i++ )
+         {
+            dst[i*4+0] = src[i*3+2];
+            dst[i*4+1] = src[i*3+1];
+            dst[i*4+2] = src[i*3+0];
+            dst[i*4+3] = 0xFF;
+         }
+         break;
+
+      case k_EImageFormat_RGB565:
+      case k_EImageFormat_I8:
+      case k_EImageFormat_IA88:
+         /* Planned */
+         break;
+      
+      case k_EImageFormat_ARGB8888:
+         for( int i=0; i<w*h; i++ )
+         {
+            dst[i*4+0] = src[i*4+1];
+            dst[i*4+1] = src[i*4+2];
+            dst[i*4+2] = src[i*4+3];
+            dst[i*4+3] = src[i*4+0];
+         }
+         break;
+
+      case k_EImageFormat_BGRA8888:
+         for( int i=0; i<w*h; i++ )
+         {
+            dst[i*4+0] = src[i*4+2];
+            dst[i*4+1] = src[i*4+1];
+            dst[i*4+2] = src[i*4+0];
+            dst[i*4+3] = src[i*4+3];
+         }
+         break;
+      
+      case k_EImageFormat_DXT1:
+         nbvtf_decompress_dxt( src, w, h, 0, dst );
+         break;
+
+      case k_EImageFormat_DXT5:
+         nbvtf_decompress_dxt( src, w, h, 1, dst );
+         break;
+
+      default:
+         break;
+   }
+}
 
 #ifdef NBVTF_AS_SO
 __attribute__((visibility("default")))
@@ -709,6 +887,17 @@ int nbvtf_write_dds_dxt1( uint8_t *reference, int w, int h, int qual, const char
    return 1;
 }
 
+static void nbvtf_correct_normal( uint8_t *src, uint8_t *dst, int w, int h )
+{
+   for( int i=0; i < w*h; i++ )
+   {
+      dst[i*4+0] = src[i*4+0];
+      dst[i*4+1] = 0xFF-src[i*4+1];
+      dst[i*4+2] = src[i*4+2];
+      dst[i*4+3] = src[i*4+3];
+   }
+}
+
 #ifdef NBVTF_AS_SO
 __attribute__((visibility("default")))
 #endif
@@ -730,13 +919,7 @@ int nbvtf_write( uint8_t *reference, int w, int h, int mipmap,
    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];
-      }
+      nbvtf_correct_normal( reference, src, w, h );
    }
    else
       src = reference;
@@ -880,6 +1063,84 @@ int nbvtf_write( uint8_t *reference, int w, int h, int mipmap,
        return 1;
 }
 
+#ifdef NBVTF_AS_SO
+__attribute__((visibility("default")))
+#endif
+uint8_t *nbvtf_read( vtfheader_t *header, int32_t *w, int32_t *h, int normal )
+{
+   *w = header->width;
+   *h = header->height;
+
+   uint8_t *rgba = malloc( header->width * header->height * 4 );
+   
+   if( !rgba )
+      return NULL;
+   
+       size_t memory = 0;
+   int x = header->width,
+       y = header->height;
+
+   int mip_iter = 0;
+       
+       while( nbvtf_lower( &x, &y ) )
+   {
+      if( mip_iter == header->mipmapCount )
+         break;
+
+      mip_iter ++;
+               memory += nbvtf_img_size( x, y, header->highResImageFormat );
+   }
+
+       if( header->lowResImageWidth == 0 || header->lowResImageHeight == 0 ||
+         header->lowResImageFormat == 0xffffffff )
+   {
+      /* no thumbnail? */
+   }
+   else
+      memory += nbvtf_img_size( header->lowResImageWidth,
+                                header->lowResImageHeight,
+                                header->lowResImageFormat );
+
+   /* Decode high res image into rgba */
+   nbvtf_read_img_data( ((uint8_t *)header) + header->headerSize + memory,
+                        header->width, header->height,
+                        header->highResImageFormat,
+                        rgba );
+
+   if( normal )
+   {
+      nbvtf_correct_normal( rgba, rgba, header->width, header->height );
+      stbi_write_png( "/tmp/cxr_hello_n.png", header->width, header->height,
+            4, rgba, header->width*4 );
+   }
+   else
+      stbi_write_png( "/tmp/cxr_hello.png", header->width, header->height,
+            4, rgba, header->width*4 );
+
+
+   return rgba;
+}
+
+#ifdef NBVTF_AS_SO
+__attribute__((visibility("default")))
+#endif
+uint8_t *nbvtf_raw_data( vtfheader_t *header, int32_t *w, int32_t *h, int32_t *format )
+{
+   *w = header->width;
+   *h = header->height;
+   *format = header->highResImageFormat;
+
+   return ((uint8_t *)header) + header->headerSize;
+}
+
+#ifdef NBVTF_AS_SO
+__attribute__((visibility("default")))
+#endif
+void nbvtf_free( uint8_t *data )
+{
+   free(data);
+}
+
 #ifdef NBVTF_AS_SO
 __attribute__((visibility("default")))
 #endif
index d5012791fea0192b11988ece056d3614a3328ca6..37bf0aaae86ce4ff2c2663075dbdf91372a37147 100644 (file)
@@ -5,6 +5,7 @@
 
 #define STB_IMAGE_IMPLEMENTATION
 #define NBVTF_SHOW_STDERR
+#define NBVTF_AS_SO
 #include "nbvtf.h"
 
 // Find file path extension, returns NULL if no ext (0x00)