# 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 = \
{
in vec3 aPos;
in vec3 aNormal;
+in vec2 aUv;
out vec3 lPos;
out vec3 lNormal;
+out vec2 lUv;
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;
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;
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()
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
# 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 )
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 ]
[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
# --------------------------
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']:
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 ):
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 )
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'}
#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
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",
#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 )
{
}
}
-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 ++ )
{
}
}
-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 )
}
}
+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")))
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
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;
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