medfall

A super great game engine
Log | Files | Refs

commit b30220f10c6dafb090e8880a904b72e36f280182
parent c4b41c51451943de10a946b941e51bf77a9f6e33
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Sun, 19 Nov 2017 14:23:17 +0200

Draw trim between clipmap levels

Diffstat:
clipmap.cc | 122++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
linear_algebra.h | 4++++
renderer.cc | 2+-
shaders/clipmap.glsl | 6+++++-
4 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/clipmap.cc b/clipmap.cc @@ -25,6 +25,7 @@ struct ClipmapTerrain { Mesh empty_tile; Mesh horizontal_filler; Mesh vertical_filler; + Mesh trim; Mesh seam; Mesh skirt; Texture heightmap; @@ -196,31 +197,26 @@ GAME_INIT( game_init ) { MEMARENA_SCOPED_CHECKPOINT( &mem->persistent_arena ); array< v3 > vertices = alloc_array< v3 >( &mem->persistent_arena, ( PATCH_RESOLUTION + 1 ) * ( PATCH_RESOLUTION + 1 ) ); - { - size_t i = 0; - for( u32 y = 0; y < PATCH_RESOLUTION + 1; y++ ) { - for( u32 x = 0; x < PATCH_RESOLUTION + 1; x++ ) { - vertices[ i ] = v3( x, y, 0 ); - i++; - } + size_t n = 0; + + for( u32 y = 0; y < PATCH_RESOLUTION + 1; y++ ) { + for( u32 x = 0; x < PATCH_RESOLUTION + 1; x++ ) { + vertices[ n++ ] = v3( x, y, 0 ); } } array< u32 > indices = alloc_array< u32 >( &mem->persistent_arena, PATCH_RESOLUTION * PATCH_RESOLUTION * 6 ); - { - size_t i = 0; - for( u32 y = 0; y < PATCH_RESOLUTION; y++ ) { - for( u32 x = 0; x < PATCH_RESOLUTION; x++ ) { - indices[ i + 0 ] = patch2d( x, y ); - indices[ i + 1 ] = patch2d( x + 1, y + 1 ); - indices[ i + 2 ] = patch2d( x, y + 1 ); - - indices[ i + 3 ] = patch2d( x, y ); - indices[ i + 4 ] = patch2d( x + 1, y ); - indices[ i + 5 ] = patch2d( x + 1, y + 1 ); - - i += 6; - } + n = 0; + + for( u32 y = 0; y < PATCH_RESOLUTION; y++ ) { + for( u32 x = 0; x < PATCH_RESOLUTION; x++ ) { + indices[ n++ ] = patch2d( x, y ); + indices[ n++ ] = patch2d( x + 1, y + 1 ); + indices[ n++ ] = patch2d( x, y + 1 ); + + indices[ n++ ] = patch2d( x, y ); + indices[ n++ ] = patch2d( x + 1, y ); + indices[ n++ ] = patch2d( x + 1, y + 1 ); } } @@ -238,7 +234,7 @@ GAME_INIT( game_init ) { array< v3 > vertices = alloc_array< v3 >( &mem->persistent_arena, PATCH_RESOLUTION * 4 + 1 ); // vertices[ 0 ] is the centre of the fan - vertices[ 0 ] = v3( PATCH_RESOLUTION / 2.0f, PATCH_RESOLUTION / 2.0f, 0 ); + vertices[ 0 ] = v3( v2( PATCH_RESOLUTION / 2.0f ), 0 ); for( u32 i = 0; i < PATCH_RESOLUTION; i++ ) { vertices[ i + 1 + 0 * PATCH_RESOLUTION ] = v3( i, 0, 0 ); @@ -317,6 +313,58 @@ GAME_INIT( game_init ) { clipmap.gpu.vertical_filler = renderer_new_mesh( vertical_mesh_config ); } + // generate trim mesh + { + MEMARENA_SCOPED_CHECKPOINT( &mem->persistent_arena ); + + array< v3 > vertices = alloc_array< v3 >( &mem->persistent_arena, ( PATCH_RESOLUTION * 4 + 2 ) * 4 ); + size_t n = 0; + for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 2; i++ ) { + vertices[ n++ ] = v3( 0, PATCH_RESOLUTION * 4 + 1 - i, 0 ); + vertices[ n++ ] = v3( 1, PATCH_RESOLUTION * 4 + 1 - i, 0 ); + } + + size_t start_of_second_set = n; + + for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 2; i++ ) { + vertices[ n++ ] = v3( i + 1, 0, 0 ); + vertices[ n++ ] = v3( i + 1, 1, 0 ); + } + + for( v3 & v : vertices ) { + v -= v3( 0.5f * v2( PATCH_RESOLUTION * 4.0f + 3.0f ), 0 ); + } + + array< u32 > indices = alloc_array< u32 >( &mem->persistent_arena, ( PATCH_RESOLUTION * 8 + 3 ) * 6 ); + n = 0; + + for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 2; i++ ) { + indices[ n++ ] = ( i + 0 ) * 2 + 1; + indices[ n++ ] = ( i + 0 ) * 2 + 0; + indices[ n++ ] = ( i + 1 ) * 2 + 0; + + indices[ n++ ] = ( i + 1 ) * 2 + 1; + indices[ n++ ] = ( i + 0 ) * 2 + 1; + indices[ n++ ] = ( i + 1 ) * 2 + 0; + } + + for( u32 i = 0; i < PATCH_RESOLUTION * 4 + 1; i++ ) { + indices[ n++ ] = start_of_second_set + ( i + 0 ) * 2 + 1; + indices[ n++ ] = start_of_second_set + ( i + 0 ) * 2 + 0; + indices[ n++ ] = start_of_second_set + ( i + 1 ) * 2 + 0; + + indices[ n++ ] = start_of_second_set + ( i + 1 ) * 2 + 1; + indices[ n++ ] = start_of_second_set + ( i + 0 ) * 2 + 1; + indices[ n++ ] = start_of_second_set + ( i + 1 ) * 2 + 0; + } + + MeshConfig mesh_config; + mesh_config.positions = renderer_new_vb( vertices ); + mesh_config.indices = renderer_new_ib( indices ); + mesh_config.num_vertices = indices.n; + clipmap.gpu.trim = renderer_new_mesh( mesh_config ); + } + // generate skirt mesh { float scale = checked_cast< float >( u32( 1 ) << ( NUM_LODS - 1 ) ); @@ -584,6 +632,13 @@ GAME_FRAME( game_frame ) { UniformBinding inf_view_uniforms = renderer_uniforms( V, Pinf, game->pos ); UniformBinding sun_uniforms = renderer_uniforms( sun_dir, game->sun_angle ); + // TODO: these need to be exact or there could be cracks in the terrain + StaticArray< UniformBinding, 4 > rotation_uniforms; + rotation_uniforms[ 0 ] = renderer_uniforms( m4_identity() ); + rotation_uniforms[ 1 ] = renderer_uniforms( m4_rotz( deg_to_rad( 270 ) ) ); + rotation_uniforms[ 2 ] = renderer_uniforms( m4_rotz( deg_to_rad( 90 ) ) ); + rotation_uniforms[ 3 ] = renderer_uniforms( m4_rotz( deg_to_rad( 180 ) ) ); + // draw terrain { RenderState render_state; @@ -622,6 +677,7 @@ GAME_FRAME( game_frame ) { inside = false; Mesh mesh = inside ? clipmap.gpu.tile : clipmap.gpu.empty_tile; + render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ]; render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_tl, scale ); renderer_draw_mesh( mesh, render_state ); } @@ -633,6 +689,7 @@ GAME_FRAME( game_frame ) { { v2 tile_tl = base + v2( i * 3, 2 ) * tile_size + v2( i * scale, 0 ); + render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ]; render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_tl, scale ); renderer_draw_mesh( clipmap.gpu.horizontal_filler, render_state ); } @@ -641,12 +698,31 @@ GAME_FRAME( game_frame ) { { v2 tile_tl = base + v2( 2, i * 3 ) * tile_size + v2( 0, i * scale ); + render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ 0 ]; render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_tl, scale ); renderer_draw_mesh( clipmap.gpu.vertical_filler, render_state ); } } - // TODO draw seams + // draw trim + if( l != NUM_LODS - 1 && !break1 ) { + float next_scale = checked_cast< float >( u32( 1 ) << ( l + 1 ) ); + v2 next_snapped_pos = floorf( game->pos.xy() / next_scale ) * next_scale; + + v2 d = game->pos.xy() - next_snapped_pos; + + u32 r = 0; + // TODO: check > vs >= + r |= d.x > scale ? 0 : 2; + r |= d.y > scale ? 0 : 1; + + v2 tile_centre = snapped_pos + v2( scale * 0.5f ); + render_state.uniforms[ UNIFORMS_MODEL ] = rotation_uniforms[ r ]; + render_state.uniforms[ UNIFORMS_CLIPMAP ] = renderer_uniforms( tile_centre, scale ); + renderer_draw_mesh( clipmap.gpu.trim, render_state ); + } + + // TODO draw seam } } diff --git a/linear_algebra.h b/linear_algebra.h @@ -422,6 +422,10 @@ forceinline v3 operator-( v3 lhs, v3 rhs ) { return v3( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z ); } +forceinline void operator-=( v3 & lhs, v3 rhs ) { + lhs = lhs - rhs; +} + forceinline v3 operator*( v3 v, float scale ) { return v3( v.x * scale, v.y * scale, v.z * scale ); } diff --git a/renderer.cc b/renderer.cc @@ -24,7 +24,7 @@ static const GLuint ATTR_TEX_COORD1 = 3; static const GLuint ATTR_COLOUR = 4; static const GLuint ATTR_MODEL_TO_WORLD_COL0 = 5; -static const u32 UNIFORM_BUFFER_SIZE = kilobytes( 32 ); +static const u32 UNIFORM_BUFFER_SIZE = kilobytes( 64 ); struct DrawCall { RenderState render_state; diff --git a/shaders/clipmap.glsl b/shaders/clipmap.glsl @@ -4,6 +4,10 @@ layout( std140 ) uniform view { vec3 camera_pos; }; +layout( std140 ) uniform model { + mat4 M; +}; + layout( std140 ) uniform sun { vec3 sun_dir; float sun_angle; @@ -31,7 +35,7 @@ in vec3 position; out VSOut v2f; void main() { - vec2 xy = offset + position.xy * scale; + vec2 xy = offset + ( M * vec4( position, 1.0 ) ).xy * scale; vec2 uv = ( xy + 0.5 ) / textureSize( heightmap, 0 ); vec2 height_sample = texelFetch( heightmap, ivec2( xy ), 0 ).rg; float z = 256.0 * height_sample.r + height_sample.g;