commit 482cee510a75a6e311706e884dd2ca1da87fe698 parent 2c5071a3ceebad61c9d7a33e4799eab8279beca5 Author: Michael Savage <mikejsavage@gmail.com> Date: Sun Oct 18 22:42:12 +0100 Compute horizons and implement some bad lighting Diffstat:
btt.cc | | | 17 | +++++++++++++---- |
game.h | | | 2 | ++ |
gpubtt.cc | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
gpubtt.h | | | 1 | + |
intrinsics.h | | | 4 | ++++ |
keys.h | | | 3 | +++ |
main.cc | | | 4 | ++++ |
diff --git a/btt.cc b/btt.cc @@ -34,8 +34,9 @@ static const GLchar * frag_src = GLSL( out vec4 colour; - uniform vec3 sun; + uniform float sun; uniform sampler2D normals; + uniform sampler2D horizons; uniform vec2 dimensions; void main() { @@ -49,8 +50,11 @@ static const GLchar * frag_src = GLSL( ground = vec3( 0.7, 0.7, 0.5 ); } - float d = max( 0, -dot( normal, sun ) ); - float light = max( 0.2, 1 * d ); + vec3 sunv = normalize( vec3( 1, 1, -sun ) ); + float l = sun > texture( horizons, smooth_position.xy / dimensions ).x ? 1.0 : 0.0; + + float d = max( 0, -dot( normal, sunv ) ); + float light = max( 0.2, l * d ); vec3 fog = vec3( 0.6, 0.6, 0.6 ); @@ -214,6 +218,8 @@ extern "C" GAME_INIT( game_init ) { state->pos = glm::vec3( 100, 100, 50 ); state->angles = glm::radians( glm::vec3( -90, 45, 0 ) ); + state->test_sun = 0.3f; + state->test_shader = compile_shader( vert_src, frag_src, "screen_colour" ); state->test_at_position = glGetAttribLocation( state->test_shader, "position" ); state->test_un_VP = glGetUniformLocation( state->test_shader, "vp" ); @@ -275,6 +281,9 @@ extern "C" GAME_FRAME( game_frame ) { const int lr = input->keys[ 'a' ] - input->keys[ 'd' ]; const int dz = input->keys[ KEY_SPACE ] - input->keys[ KEY_LEFTSHIFT ]; + const float dsun = ( input->keys[ KEY_EQUALS ] - input->keys[ KEY_MINUS ] ) * dt; + state->test_sun += dsun; + const int pitch = input->keys[ KEY_UPARROW ] - input->keys[ KEY_DOWNARROW ]; const int yaw = input->keys[ KEY_RIGHTARROW ] - input->keys[ KEY_LEFTARROW ]; @@ -305,7 +314,7 @@ extern "C" GAME_FRAME( game_frame ) { glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); glUseProgram( state->test_shader ); glUniformMatrix4fv( state->test_un_VP, 1, GL_FALSE, glm::value_ptr( VP ) ); - glUniform3fv( state->test_un_sun, 1, glm::value_ptr( sun ) ); + glUniform1f( state->test_un_sun, state->test_sun ); glUniform2f( state->test_un_dimensions, state->hm.width, state->hm.height ); gpubtt_render( &state->gpubtt, state->test_un_normals ); glUseProgram( 0 ); diff --git a/game.h b/game.h @@ -119,6 +119,8 @@ struct GameState { GLint test_outline_at_colour; GLint test_outline_un_vp; + float test_sun; + BTTs btt; GPUBTT gpubtt; Heightmap hm; diff --git a/gpubtt.cc b/gpubtt.cc @@ -42,6 +42,47 @@ static void gpubtt_build( } } +static float angle( glm::vec3 a, glm::vec3 b ) { + const glm::vec3 d = b - a; + + const float dist_xy = sqrtf( d.x * d.x + d.y * d.y ); + + return d.z / dist_xy; +} + +void compute_horizons( + MemoryArena * arena, + const Heightmap * hm, float * horizons, + glm::ivec2 start, glm::ivec2 step +) { + MEMARENA_SCOPED_CHECKPOINT( arena ); + + const u32 max_hull_size = 2 * max_u32( hm->width, hm->height ); + + glm::vec3 * hull = memarena_push_many( arena, glm::vec3, max_hull_size ); + u32 hull_size = 1; + + hull[ 0 ] = hm->point( start.x, start.y ); + horizons[ 0 ] = 0; + + start += step; + + while( ( u32 ) start.x < hm->width && ( u32 ) start.y < hm->height && start.x >= 0 && start.y >= 0 ) { + const glm::vec3 p = hm->point( start.x, start.y ); + + while( hull_size > 1 && angle( p, hull[ hull_size - 1 ] ) < angle( hull[ hull_size - 1 ], hull[ hull_size - 2 ] ) ) { + hull_size--; + } + + horizons[ start.y * hm->width + start.x ] = angle( p, hull[ hull_size - 1 ] ); + + hull[ hull_size ] = p; + hull_size++; + + start += step; + } +} + void gpubtt_init( MemoryArena * const arena, GPUBTT * const gpubtt, const OffsetHeightmap * const ohm, const BTTs btts, @@ -88,6 +129,18 @@ void gpubtt_init( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F, ohm->hm.width, ohm->hm.height, 0, GL_RGB, GL_FLOAT, normals ); + float * const horizons = memarena_push_many( arena, float, ohm->hm.width * ohm->hm.height ); + + for( u32 i = 0; i < ohm->hm.height; i++ ) { + compute_horizons( arena, &ohm->hm, horizons, glm::ivec2( 0, i ), glm::ivec2( 1, 0 ) ); + } + + glGenTextures( 1, &gpubtt->tex_horizons ); + glBindTexture( GL_TEXTURE_2D, gpubtt->tex_horizons ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, ohm->hm.width, ohm->hm.height, 0, GL_RED, GL_FLOAT, horizons ); + glBindVertexArray( 0 ); gpubtt->num_verts = i; diff --git a/gpubtt.h b/gpubtt.h @@ -10,6 +10,7 @@ struct GPUBTT { GLuint vao; GLuint vbo_verts; GLuint tex_normals; + GLuint tex_horizons; u32 num_verts; }; diff --git a/intrinsics.h b/intrinsics.h @@ -42,6 +42,10 @@ inline size_t gigabytes( const size_t gb ) { return megabytes( gb ) * 1024; } +inline u32 max_u32( u32 a, u32 b ) { + return a > b ? a : b; +} + #include "platform_backtrace.h" #ifdef assert diff --git a/keys.h b/keys.h @@ -82,6 +82,9 @@ enum KeyNames { KEY_F11, KEY_F12, + KEY_MINUS, + KEY_EQUALS, + KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, diff --git a/main.cc b/main.cc @@ -120,6 +120,10 @@ int main( int argc, char ** argv ) { input.keys[ KEY_DOWNARROW ] = glfwGetKey( window, GLFW_KEY_DOWN ); input.keys[ KEY_LEFTARROW ] = glfwGetKey( window, GLFW_KEY_LEFT ); input.keys[ KEY_RIGHTARROW ] = glfwGetKey( window, GLFW_KEY_RIGHT ); + input.keys[ KEY_LEFTARROW ] = glfwGetKey( window, GLFW_KEY_LEFT ); + input.keys[ KEY_RIGHTARROW ] = glfwGetKey( window, GLFW_KEY_RIGHT ); + input.keys[ KEY_MINUS ] = glfwGetKey( window, GLFW_KEY_MINUS ); + input.keys[ KEY_EQUALS ] = glfwGetKey( window, GLFW_KEY_EQUAL ); if( game.frame ) { game.frame( state, &mem, &input, dt );