commit cde158d1aef0a788c72490185217d42346a47e0b
parent f28eac3058adc63af6c2660636d93f4a0fff7c55
Author: Michael Savage <mikejsavage@gmail.com>
Date: Fri, 10 Nov 2017 20:39:46 +0200
Update TerrainManager to use the new heightmap stuff
Diffstat:
11 files changed, 66 insertions(+), 92 deletions(-)
diff --git a/btt.cc b/btt.cc
@@ -68,7 +68,7 @@ static s32 square_distance( v2s32 u, v2s32 v ) {
return dot( d, d );
}
-static bool btt_should_split( const Heightmap * hm, v2s32 v0, v2s32 v1, v2s32 v2, v2s32 mid ) {
+static bool btt_should_split( const array2d< u16 > hm, v2s32 v0, v2s32 v1, v2s32 v2, v2s32 mid ) {
if( square_distance( v0, v2 ) <= 4 ) return false;
const float avg_height = ( heightmap_height( hm, v0.x, v0.y ) + heightmap_height( hm, v2.x, v2.y ) ) * 0.5f;
@@ -80,7 +80,7 @@ static bool btt_should_split( const Heightmap * hm, v2s32 v0, v2s32 v1, v2s32 v2
}
static void btt_build(
- const Heightmap * hm, MemoryArena * arena,
+ const array2d< u16 > hm, MemoryArena * arena,
BTT * node, v2s32 v0, v2s32 v1, v2s32 v2
) {
v2s32 mid = ( v0 + v2 ) / 2;
@@ -101,7 +101,7 @@ static void btt_build(
}
}
-BTTs btt_from_heightmap( const Heightmap * hm, MemoryArena * arena ) {
+BTTs btt_from_heightmap( const array2d< u16 > hm, MemoryArena * arena ) {
BTTs roots;
roots.left_root = alloc< BTT >( arena );
@@ -113,8 +113,8 @@ BTTs btt_from_heightmap( const Heightmap * hm, MemoryArena * arena ) {
roots.left_root->bottom = roots.right_root;
roots.right_root->bottom = roots.left_root;
- btt_build( hm, arena, roots.left_root, v2s32( 0, 0 ), v2s32( 0, hm->height - 1 ), v2s32( hm->width - 1, hm->height - 1 ) );
- btt_build( hm, arena, roots.right_root, v2s32( hm->width - 1, hm->height - 1 ), v2s32( hm->width - 1, 0 ), v2s32( 0, 0 ) );
+ btt_build( hm, arena, roots.left_root, v2s32( 0, 0 ), v2s32( 0, hm.h - 1 ), v2s32( hm.w - 1, hm.h - 1 ) );
+ btt_build( hm, arena, roots.right_root, v2s32( hm.w - 1, hm.h - 1 ), v2s32( hm.w - 1, 0 ), v2s32( 0, 0 ) );
return roots;
}
diff --git a/btt.h b/btt.h
@@ -19,4 +19,4 @@ struct BTTs {
BTT * right_root;
};
-BTTs btt_from_heightmap( const Heightmap * hm, MemoryArena * arena );
+BTTs btt_from_heightmap( const array2d< u16 > hm, MemoryArena * arena );
diff --git a/clipmap.cc b/clipmap.cc
@@ -120,7 +120,6 @@ GAME_INIT( game_init ) {
array< QuadTreeNode > nodes = alloc_array< QuadTreeNode >( &mem->persistent_arena, 4096 * 4096 / 3 );
file_get_contents_and_decompress( "terrains/gta16.png.parts/quadtree.lz4", ( u8 * ) nodes.ptr(), nodes.num_bytes() );
- clipmap.quadtree.nodes_memory = nodes.ptr();
clipmap.quadtree.nodes = nodes;
clipmap.quadtree.heightmap = clipmap.heightmap;
}
diff --git a/game.h b/game.h
@@ -3,9 +3,9 @@
// TODO: this whole file blows
#include "intrinsics.h"
#include "linear_algebra.h"
-// #include "terrain_manager.h"
-// #include "btt.h"
-// #include "gpubtt.h"
+#include "terrain_manager.h"
+#include "btt.h"
+#include "gpubtt.h"
#include "heightmap.h"
#include "bsp.h"
#include "bsp_renderer.h"
@@ -28,7 +28,7 @@ struct GameState {
bool noclip;
float pitch, yaw;
- // TerrainManager tm;
+ TerrainManager tm;
BSP bsp;
BSPRenderer bspr;
@@ -39,9 +39,8 @@ struct GameState {
float sun_angle;
- // BTTs btt;
- // GPUBTT gpubtt;
- // Heightmap hm;
+ BTTs btt;
+ GPUBTT gpubtt;
bool draw_wireframe;
bool draw_quadtree;
diff --git a/gpubtt.cc b/gpubtt.cc
@@ -16,58 +16,57 @@ static u32 btt_count_leaves( const BTT * btt ) {
}
static void gpubtt_build(
- v3 * verts, u32 * i, const OffsetHeightmap * ohm, const BTT * btt,
- v2s32 p0, v2s32 p1, v2s32 p2
+ v3 * verts, u32 * i, const array2d< u16 > hm, v3 offset,
+ const BTT * btt, v2s32 p0, v2s32 p1, v2s32 p2
) {
- v3 offset( ohm->x_offset, ohm->y_offset, 0.0f );
-
if( btt->left != NULL ) {
v2s32 mid = ( p0 + p2 ) / 2;
- gpubtt_build( verts, i, ohm, btt->left, p1, mid, p0 );
+ gpubtt_build( verts, i, hm, offset, btt->left, p1, mid, p0 );
ASSERT( btt->right != NULL );
- gpubtt_build( verts, i, ohm, btt->right, p2, mid, p1 );
+ gpubtt_build( verts, i, hm, offset, btt->right, p2, mid, p1 );
}
else {
- verts[ *i + 0 ] = ohm->hm.point( p0.x, p0.y ) + offset;
- verts[ *i + 1 ] = ohm->hm.point( p1.x, p1.y ) + offset;
- verts[ *i + 2 ] = ohm->hm.point( p2.x, p2.y ) + offset;
+ verts[ *i + 0 ] = heightmap_point( hm, p0.x, p0.y ) + offset;
+ verts[ *i + 1 ] = heightmap_point( hm, p1.x, p1.y ) + offset;
+ verts[ *i + 2 ] = heightmap_point( hm, p2.x, p2.y ) + offset;
*i += 3;
}
}
void gpubtt_init(
MemoryArena * arena, GPUBTT * gpubtt, BTTs btts,
- const OffsetHeightmap * ohm, const v3 * normals, const u8 * horizons
+ const array2d< u16 > hm, v2u32 offset, const v3 * normals, const u8 * horizons
) {
PROFILE_FUNCTION();
MEMARENA_SCOPED_CHECKPOINT( arena );
- const u32 num_leaves = btt_count_leaves( btts.left_root )
- + btt_count_leaves( btts.right_root );
+ const u32 num_leaves = btt_count_leaves( btts.left_root ) + btt_count_leaves( btts.right_root );
v3 * verts = memarena_push_many( arena, v3, num_leaves * 3 );
u32 num_vertices = 0;
// bottom left, bottom right, top left, top right
const v2s32 bl( 0, 0 );
- const v2s32 br( ohm->hm.width - 1, 0 );
- const v2s32 tl( 0, ohm->hm.height - 1 );
- const v2s32 tr( ohm->hm.width - 1, ohm->hm.height - 1 );
+ const v2s32 br( hm.w - 1, 0 );
+ const v2s32 tl( 0, hm.h - 1 );
+ const v2s32 tr( hm.w - 1, hm.h - 1 );
+
+ v3 offset_v3( offset.x, offset.y, 0 );
{
PROFILE_BLOCK( "Convert BTT to mesh" );
- gpubtt_build( verts, &num_vertices, ohm, btts.left_root, tr, tl, bl );
- gpubtt_build( verts, &num_vertices, ohm, btts.right_root, bl, br, tr );
+ gpubtt_build( verts, &num_vertices, hm, offset_v3, btts.left_root, tr, tl, bl );
+ gpubtt_build( verts, &num_vertices, hm, offset_v3, btts.right_root, bl, br, tr );
ASSERT( num_leaves * 3 == num_vertices );
}
{
PROFILE_BLOCK( "Upload normal map" );
TextureConfig normals_config;
- normals_config.width = ohm->hm.width;
- normals_config.height = ohm->hm.height;
+ normals_config.width = hm.w;
+ normals_config.height = hm.h;
normals_config.format = TEXFMT_RGB_FLOAT;
normals_config.data = normals;
normals_config.wrap = TEXWRAP_CLAMP; // TODO: this is a hack and should be removed
@@ -77,8 +76,8 @@ void gpubtt_init(
{
PROFILE_BLOCK( "Upload horizon map" );
TextureConfig horizons_config;
- horizons_config.width = ohm->hm.width;
- horizons_config.height = ohm->hm.height;
+ horizons_config.width = hm.w;
+ horizons_config.height = hm.h;
horizons_config.format = TEXFMT_R_U8;
horizons_config.data = horizons;
horizons_config.wrap = TEXWRAP_CLAMP; // TODO: this is a hack and should be removed
diff --git a/gpubtt.h b/gpubtt.h
@@ -12,6 +12,6 @@ struct GPUBTT {
};
void gpubtt_init( MemoryArena * arena, GPUBTT * gpubtt, BTTs btts,
- const OffsetHeightmap * ohm, const v3 * normals, const u8 * horizons );
+ const array2d< u16 > hm, v2u32 offset, const v3 * normals, const u8 * horizons );
void gpubtt_destroy( GPUBTT * gpubtt );
void gpubtt_render( const GPUBTT * gpubtt, RenderState render_state );
diff --git a/heightmap.h b/heightmap.h
@@ -10,7 +10,6 @@ struct QuadTreeNode {
};
struct QuadTree {
- QuadTreeNode * nodes_memory;
array< QuadTreeNode > nodes;
array2d< u16 > heightmap;
};
diff --git a/intrinsics.h b/intrinsics.h
@@ -226,7 +226,6 @@ DEF_VISIT( double )
#undef DEF_VISIT
-#if !PLATFORM_RELACY
template< typename T >
inline T * malloc_array( size_t count ) {
ASSERT( SIZE_MAX / count >= sizeof( T ) );
@@ -238,7 +237,6 @@ inline T * realloc_array( T * old, size_t count ) {
ASSERT( SIZE_MAX / count >= sizeof( T ) );
return ( T * ) realloc( old, count * sizeof( T ) );
}
-#endif
template< typename T >
static T lerp( T a, float t, T b ) {
diff --git a/make.lua b/make.lua
@@ -18,9 +18,9 @@ if OS == "macos" then
game_ldflags = "-framework Cocoa -framework CoreVideo -framework IOKit"
end
--- bin( "medfall", { "main", "hm", "heightmap", "terrain_manager", "btt", "gpubtt", "skybox", "http", "platform_network", game_objs }, { "lz4", game_libs } )
--- msvc_bin_ldflags( "medfall", "opengl32.lib gdi32.lib Ws2_32.lib" )
--- gcc_bin_ldflags( "medfall", game_ldflags )
+bin( "medfall", { "main", "hm", "heightmap", "terrain_manager", "btt", "gpubtt", "decompress_bc", "skybox", "http", "platform_network", game_objs }, { "lz4", game_libs } )
+msvc_bin_ldflags( "medfall", "opengl32.lib gdi32.lib Ws2_32.lib" )
+gcc_bin_ldflags( "medfall", game_ldflags )
bin( "launch", { "launcher/main", "http", "sha2", "platform_network", game_objs }, { "imgui", "monocypher", "whereami", game_libs } )
msvc_bin_ldflags( "launch", "opengl32.lib gdi32.lib Ws2_32.lib" )
@@ -68,7 +68,7 @@ end
-- gcc_obj_cxxflags( "pp", "-O2" )
-- msvc_obj_cxxflags( "pp", "/O2" )
-bin( "pp2", { "pp2", "heightmap", "decompress_bc", common_objs }, { "lz4", "squish", "stb_image", "stb_image_write" } )
+bin( "pp2", { "pp2", "decompress_bc", common_objs }, { "lz4", "squish", "stb_image", "stb_image_write" } )
gcc_obj_cxxflags( "pp2", "-O2" )
msvc_obj_cxxflags( "pp2", "/O2" )
diff --git a/terrain_manager.cc b/terrain_manager.cc
@@ -27,6 +27,12 @@ struct AsyncLoadTile {
s32 tx, ty;
};
+static size_t quadtree_max_nodes( size_t w, size_t h ) {
+ // with a power of 2 + 1 sized quadtree with a 2x2 bottom level it
+ // should be exactly 1/3 (1/4 + 1/16 + ...)
+ return ( ( w - 1 ) * ( h - 1 ) ) / 3;
+}
+
static WORK_QUEUE_CALLBACK( async_load_tile ) {
AsyncLoadTile * alt = ( AsyncLoadTile * ) data;
TerrainManager * tm = alt->tm;
@@ -40,23 +46,20 @@ static WORK_QUEUE_CALLBACK( async_load_tile ) {
size_t num_points = ( TILE_SIZE + 1 ) * ( TILE_SIZE + 1 );
// heightmap
- size_t decompressed_heightmap_size = num_points * sizeof( u16 );
- u16 * decompressed_heightmap = ( u16 * ) malloc( decompressed_heightmap_size );
- ASSERT( decompressed_heightmap != NULL );
+ dt.heightmap = array2d< u16 >( malloc_array< u16 >( num_points ), TILE_SIZE + 1, TILE_SIZE + 1 );
+ ASSERT( dt.heightmap.ptr() != NULL );
int ok_heightmap = LZ4_decompress_safe(
ct.heightmap.ptr(),
- ( char * ) decompressed_heightmap,
- ct.heightmap.num_bytes(), decompressed_heightmap_size );
+ ( char * ) dt.heightmap.ptr(),
+ ct.heightmap.num_bytes(), dt.heightmap.num_bytes() );
ASSERT( ok_heightmap > 0 );
- heightmap_init( &dt.heightmap, decompressed_heightmap, TILE_SIZE + 1, TILE_SIZE + 1 );
-
// normalmap
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 );
+ array2d< v3 > normals( decompressed_normalmap, dt.heightmap.w, dt.heightmap.h );
// compute centre region
for( size_t y = 1; y < normals.h - 1; y++ ) {
@@ -64,11 +67,11 @@ static WORK_QUEUE_CALLBACK( async_load_tile ) {
v3 tangent(
2.0f,
0,
- heightmap_height( &dt.heightmap, x + 1, y ) - heightmap_height( &dt.heightmap, x - 1, y ) );
+ 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 ) );
+ heightmap_height( dt.heightmap, x, y + 1 ) - heightmap_height( dt.heightmap, x, y - 1 ) );
normals( x, y ) = normalize( cross( tangent, bitangent ) );
}
@@ -107,20 +110,16 @@ static WORK_QUEUE_CALLBACK( async_load_tile ) {
ASSERT( decompressed_horizonmap != NULL );
// quadtree
- size_t max_decompressed_quadtree_size = heightmap_quadtree_max_nodes( &dt.heightmap ) * sizeof( HeightmapQuadTreeNode );
- HeightmapQuadTreeNode * decompressed_quadtree = ( HeightmapQuadTreeNode * ) malloc( max_decompressed_quadtree_size );
- ASSERT( decompressed_quadtree != NULL );
+ size_t num_nodes = quadtree_max_nodes( dt.heightmap.w, dt.heightmap.h );
+ dt.quadtree.nodes = array< QuadTreeNode >( malloc_array< QuadTreeNode >( num_nodes ), num_nodes );
+ ASSERT( dt.quadtree.nodes.ptr() != NULL );
int ok_quadtree = LZ4_decompress_safe(
ct.quadtree.ptr(),
- ( char * ) decompressed_quadtree,
- ct.quadtree.num_bytes(), max_decompressed_quadtree_size );
+ ( char * ) dt.quadtree.nodes.ptr(),
+ ct.quadtree.num_bytes(), dt.quadtree.nodes.num_bytes() );
ASSERT( ok_quadtree > 0 );
- size_t decompressed_quadtree_size = checked_cast< size_t >( ok_quadtree );
- dt.quadtree.dim = TILE_SIZE;
- dt.quadtree.nodes_memory = decompressed_quadtree;
- dt.quadtree.nodes = array< HeightmapQuadTreeNode >( decompressed_quadtree, decompressed_quadtree_size / sizeof( HeightmapQuadTreeNode ) );
- dt.quadtree.hm = &dt.heightmap;
+ dt.quadtree.heightmap = dt.heightmap;
// generate btt
// TODO: should generate a triangle mesh here instead of in gpubtt_init
@@ -128,7 +127,7 @@ static WORK_QUEUE_CALLBACK( async_load_tile ) {
void * btt_memory = malloc( megabytes( 16 ) );
memarena_init( &btt_arena, ( u8 * ) btt_memory, megabytes( 16 ) );
GPUTileData gpu_tile_data;
- BTTs btt = btt_from_heightmap( &dt.heightmap, &btt_arena );
+ BTTs btt = btt_from_heightmap( dt.heightmap, &btt_arena );
gpu_tile_data.btt = btt;
gpu_tile_data.btt_memory = btt_memory;
@@ -173,9 +172,9 @@ static void terrain_unload_tile( TerrainManager * tm, s32 tx, s32 ty ) {
return;
}
- heightmap_destroy( &tm->decompressed_tiles[ tx ][ ty ].heightmap );
+ free( tm->decompressed_tiles[ tx ][ ty ].heightmap.ptr() );
free( tm->decompressed_tiles[ tx ][ ty ].normalmap );
- free( tm->decompressed_tiles[ tx ][ ty ].quadtree.nodes_memory );
+ free( tm->decompressed_tiles[ tx ][ ty ].quadtree.nodes.ptr() );
gpubtt_destroy( &tm->gpubtts[ tx ][ ty ] );
tm->tile_states[ tx ][ ty ] = TILE_EMPTY;
@@ -308,13 +307,13 @@ void terrain_render( TerrainManager * tm, const m4 & V, const m4 & P, float sun_
s32 ty = ready_tile.ty;
const GPUTileData & gpu_tile_data = tm->gpu_tiles[ tx ][ ty ];
- const Heightmap * hm = &tm->decompressed_tiles[ tx ][ ty ].heightmap;
- const OffsetHeightmap ohm = { *hm, checked_cast< float >( tx * TILE_SIZE ), checked_cast< float >( ty * TILE_SIZE ) };
+ const array2d< u16 > hm = tm->decompressed_tiles[ tx ][ ty ].heightmap;
+ v2u32 offset( tx * TILE_SIZE, ty * TILE_SIZE );
gpubtt_init(
tm->arena,
&tm->gpubtts[ tx ][ ty ],
gpu_tile_data.btt,
- &ohm,
+ hm, offset,
tm->decompressed_tiles[ tx ][ ty ].normalmap,
gpu_tile_data.horizonmap
);
@@ -366,23 +365,6 @@ void terrain_render( TerrainManager * tm, const m4 & V, const m4 & P, float sun_
}
}
-float terrain_height( const TerrainManager * tm, v3 position ) {
- ASSERT( position.x >= 0 );
- ASSERT( position.y >= 0 );
- ASSERT( position.x < tm->width );
- ASSERT( position.y < tm->height );
-
- s32 tx = s32( position.x / TILE_SIZE );
- s32 ty = s32( position.y / TILE_SIZE );
-
- if( tm->tile_states[ tx ][ ty ] != TILE_LOADED ) {
- return 0.0f;
- }
-
- const Heightmap * hm = &tm->decompressed_tiles[ tx ][ ty ].heightmap;
- return hm->bilerp_height( position.x - tx * TILE_SIZE, position.y - ty * TILE_SIZE );
-}
-
v3 terrain_normal( const TerrainManager * tm, v3 position ) {
ASSERT( position.x >= 0 );
ASSERT( position.y >= 0 );
@@ -433,10 +415,10 @@ bool segment_vs_terrain( const TerrainManager * tm, v3 seg_origin, v3 seg_end, f
v3 local_seg_origin = seg_origin - v3( checked_cast< float >( tx * TILE_SIZE ), checked_cast< float >( ty * TILE_SIZE ), 0 );
ray.origin = local_seg_origin;
- const HeightmapQuadTree * qt = &tm->decompressed_tiles[ tx ][ ty ].quadtree;
+ const QuadTree * qt = &tm->decompressed_tiles[ tx ][ ty ].quadtree;
// TODO: convert from tile t to global t
float tile_t;
- bool tile_hit = ray_vs_quadtree( qt, ray, &tile_t, xnormal );
+ bool tile_hit = ray_vs_quadtree( *qt, ray, &tile_t, xnormal );
if( tile_hit && tile_t <= segment_length && tile_t < *t ) {
*t = tile_t;
diff --git a/terrain_manager.h b/terrain_manager.h
@@ -30,10 +30,9 @@ struct GPUTileData {
};
struct DecompressedTile {
- // TODO: merge this + Heightmap
- Heightmap heightmap;
+ array2d< u16 > heightmap;
v3 * normalmap;
- HeightmapQuadTree quadtree;
+ QuadTree quadtree;
};
enum TileState {
@@ -76,7 +75,6 @@ void terrain_init( TerrainManager * tm, const char * tiles_dir, MemoryArena * ar
void terrain_teleport( TerrainManager * tm, v3 position );
void terrain_update( TerrainManager * tm, v3 position );
void terrain_render( TerrainManager * tm, const m4 & V, const m4 & P, float sun_angle, v3 sun_dir, double current_time );
-float terrain_height( const TerrainManager * tm, v3 position );
v3 terrain_normal( const TerrainManager * tm, v3 position );
bool segment_vs_terrain( const TerrainManager * tm, v3 seg_origin, v3 seg_end, float * t, v3 * xnormal );