medfall

A super great game engine
Log | Files | Refs

commit 236e4df4c19f2205c579f05696a4f31e6be03305
parent ffa0a0b157b2c1c377c2cc2d5c63911fc259ba27
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Sun Jul  2 21:50:51 +0300

Only save normal borders. Fill in the middle at runtime

Reduces normal maps from 50MB to < 1MB

Diffstat:
pp.cc | 38++++++++++++++++++++++++++++++++++++--
terrain_manager.cc | 41+++++++++++++++++++++++++++++++++++++++--
2 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/pp.cc b/pp.cc @@ -221,6 +221,41 @@ static void write_tile( "{}/{}_{}{}", dir.c_str(), tx, ty, extension.c_str() ); } +static void write_normal_border( + MemoryArena * arena, const std::string & dir, + const array2d< v3 > normals, int tx, int ty +) { + MEMARENA_SCOPED_CHECKPOINT( arena ); + + size_t border_size = OUT_SIZE * 4 - 4; + array< v3 > border = memarena_push_array( arena, v3, border_size ); + + const u32 left = tx * TILE_SIZE; + const u32 top = ty * TILE_SIZE; + + v3 up = v3( 0, 0, 1 ); + + size_t n = 0; + for( size_t x = 0; x < OUT_SIZE; x++ ) { + border[ n++ ] = normals.try_get( left + x, top, up ); + } + for( size_t x = 0; x < OUT_SIZE; x++ ) { + border[ n++ ] = normals.try_get( left + x, top + OUT_SIZE - 1, up ); + } + for( size_t y = 1; y < OUT_SIZE - 1; y++ ) { + border[ n++ ] = normals.try_get( left, top + y, up ); + } + for( size_t y = 1; y < OUT_SIZE - 1; y++ ) { + border[ n++ ] = normals.try_get( left + OUT_SIZE - 1, top + y, up ); + } + + ASSERT( n == border.n ); + + ggprint( "writing {}_{}_normals.lz4... ", tx, ty ); + write_compressed_file( arena, border.ptr(), border.num_bytes(), + "{}/{}_{}_normals.lz4", dir.c_str(), tx, ty ); +} + static void write_quadtree( MemoryArena * arena, const std::string & dir, const array2d< u16 > heightmap, int tx, int ty @@ -327,12 +362,11 @@ int main( int argc, char ** argv ) { MEMARENA_SCOPED_CHECKPOINT( &arena ); array2d< v3 > normals = memarena_push_array2d( &arena, v3, w, h ); - // TODO: normals can be v2 since z >= 0 on a heightmap compute_normals( heightmap, normals ); for( int ty = 0; ty < ytiles; ty++ ) { for( int tx = 0; tx < xtiles; tx++ ) { - write_tile( &arena, dir, "_normals.lz4", normals, v3( 0.0f, 0.0f, 1.0f ), tx, ty ); + write_normal_border( &arena, dir, normals, tx, ty ); } } diff --git a/terrain_manager.cc b/terrain_manager.cc @@ -51,12 +51,49 @@ static WORK_QUEUE_CALLBACK( async_load_tile ) { size_t decompressed_normalmap_size = num_points * sizeof( v3 ); v3 * decompressed_normalmap = ( v3 * ) malloc( decompressed_normalmap_size ); ASSERT( decompressed_normalmap != NULL ); + + array2d< v3 > normals( decompressed_normalmap, dt.heightmap.width, dt.heightmap.height ); + + // compute centre region + for( size_t y = 1; y < normals.h - 1; y++ ) { + for( size_t x = 1; x < normals.w - 1; x++ ) { + v3 tangent( + 2.0f, + 0, + heightmap_height( &dt.heightmap, x + 1, y ) - heightmap_height( &dt.heightmap, x - 1, y ) ); + v3 bitangent( + 0, + 2.0f, + heightmap_height( &dt.heightmap, x, y + 1 ) - heightmap_height( &dt.heightmap, x, y - 1 ) ); + + normals( x, y ) = normalize( cross( tangent, bitangent ) ); + } + } + + // load border + array< v3 > normals_border = memarena_push_array( arena, v3, ( TILE_SIZE + 1 ) * 4 - 4 ); int ok_normalmap = LZ4_decompress_safe( ct.normalmap.ptr(), - ( char * ) decompressed_normalmap, - ct.normalmap.num_bytes(), decompressed_normalmap_size ); + ( char * ) normals_border.ptr(), + ct.normalmap.num_bytes(), normals_border.num_bytes() ); ASSERT( ok_normalmap > 0 ); + { + size_t n = 0; + for( size_t x = 0; x < normals.w; x++ ) { + normals( x, 0 ) = normals_border[ n++ ]; + } + for( size_t x = 0; x < normals.w; x++ ) { + normals( x, normals.h - 1 ) = normals_border[ n++ ]; + } + for( size_t y = 1; y < normals.h - 1; y++ ) { + normals( 0, y ) = normals_border[ n++ ]; + } + for( size_t y = 1; y < normals.h - 1; y++ ) { + normals( normals.w - 1, y ) = normals_border[ n++ ]; + } + } + dt.normalmap = decompressed_normalmap; // horizonmap