commit e76475d0529df8d22da10242f06ad343bcb9f357 parent 293ab5403110e0c781a8c16a751166b805009aa2 Author: Michael Savage <mikejsavage@gmail.com> Date: Wed Sep 16 21:46:33 +0100 Steps towards Heightmap cleanup Diffstat:
btt.cc | | | 16 | ++++++++++------ |
gpubtt.cc | | | 4 | ++-- |
heightmap.cc | | | 146 | ++++++++++++++++++++++++++++++++++++++----------------------------------------- |
heightmap.h | | | 19 | +++++++++++-------- |
terrain_manager.cc | | | 23 | +++++++++++++++++++---- |
diff --git a/btt.cc b/btt.cc @@ -8,6 +8,7 @@ #include "btt.h" #include "heightmap.h" #include "gl.h" +#include "stb_image.h" static ImmediateTriangle triangles[ 512000 ]; static ImmediateContext imm; @@ -202,8 +203,8 @@ BTTs btt_from_heightmap( const Heightmap * const hm, MemoryArena * const arena ) roots.left_root->bottom = roots.right_root; roots.right_root->bottom = roots.left_root; - btt_build( hm, arena, roots.left_root, glm::ivec2( 0, 0 ), glm::ivec2( 0, hm->h - 1 ), glm::ivec2( hm->w - 1, hm->h - 1 ) ); - btt_build( hm, arena, roots.right_root, glm::ivec2( hm->w - 1, hm->h - 1 ), glm::ivec2( hm->w - 1, 0 ), glm::ivec2( 0, 0 ) ); + btt_build( hm, arena, roots.left_root, glm::ivec2( 0, 0 ), glm::ivec2( 0, hm->height - 1 ), glm::ivec2( hm->width - 1, hm->height - 1 ) ); + btt_build( hm, arena, roots.right_root, glm::ivec2( hm->width - 1, hm->height - 1 ), glm::ivec2( hm->width - 1, 0 ), glm::ivec2( 0, 0 ) ); return roots; } @@ -226,8 +227,11 @@ extern "C" GAME_INIT( game_init ) { state->test_outline_at_colour = glGetAttribLocation( state->test_outline_shader, "colour" ); state->test_outline_un_vp = glGetUniformLocation( state->test_outline_shader, "vp" ); - state->hm.load( "mountains512.png", 0, 0, state->test_at_position, - state->test_at_normal, state->test_at_lit ); + int w, h; + u8 * pixels = stbi_load( "mountains512.png", &w, &h, nullptr, 1 ); + heightmap_init( &state->hm, pixels, w, h, 0, 0, + state->test_at_position, state->test_at_normal, state->test_at_lit ); + state->btt = btt_from_heightmap( &state->hm, &mem->persistent_arena ); const OffsetHeightmap ohm = { state->hm, 0, 0 }; @@ -307,8 +311,8 @@ extern "C" GAME_FRAME( game_frame ) { glUseProgram( 0 ); immediate_init( &imm, triangles, array_count( triangles ) ); - draw_btt( state->btt.left_root, &state->hm, &imm, glm::ivec2( 0, 0 ), glm::ivec2( 0, state->hm.h - 1 ), glm::ivec2( state->hm.w - 1, state->hm.h - 1 ) ); - draw_btt( state->btt.right_root, &state->hm, &imm, glm::ivec2( state->hm.w - 1, state->hm.h - 1 ), glm::ivec2( state->hm.w - 1, 0 ), glm::ivec2( 0, 0 ) ); + draw_btt( state->btt.left_root, &state->hm, &imm, glm::ivec2( 0, 0 ), glm::ivec2( 0, state->hm.height - 1 ), glm::ivec2( state->hm.width - 1, state->hm.height - 1 ) ); + draw_btt( state->btt.right_root, &state->hm, &imm, glm::ivec2( state->hm.width - 1, state->hm.height - 1 ), glm::ivec2( state->hm.width - 1, 0 ), glm::ivec2( 0, 0 ) ); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); diff --git a/gpubtt.cc b/gpubtt.cc @@ -55,8 +55,8 @@ void gpubtt_init( glm::vec3 * const verts = memarena_push_many( mem, glm::vec3, num_leaves * 3 ); u32 i = 0; - gpubtt_build( verts, &i, ohm, btts.left_root, glm::ivec2( 0, 0 ), glm::ivec2( 0, ohm->hm.h - 1 ), glm::ivec2( ohm->hm.w - 1, ohm->hm.h - 1 ) ); - gpubtt_build( verts, &i, ohm, btts.right_root, glm::ivec2( ohm->hm.w - 1, ohm->hm.h - 1 ), glm::ivec2( ohm->hm.w - 1, 0 ), glm::ivec2( 0, 0 ) ); + gpubtt_build( verts, &i, ohm, btts.left_root, glm::ivec2( 0, 0 ), glm::ivec2( 0, ohm->hm.height - 1 ), glm::ivec2( ohm->hm.width - 1, ohm->hm.height - 1 ) ); + gpubtt_build( verts, &i, ohm, btts.right_root, glm::ivec2( ohm->hm.width - 1, ohm->hm.height - 1 ), glm::ivec2( ohm->hm.width - 1, 0 ), glm::ivec2( 0, 0 ) ); glGenVertexArrays( 1, &gpubtt->vao ); glBindVertexArray( gpubtt->vao ); diff --git a/heightmap.cc b/heightmap.cc @@ -43,71 +43,67 @@ static glm::vec3 triangle_perp_ccw( const glm::vec3 & a, const glm::vec3 & b, co return glm::cross( b - a, c - a ); } -void Heightmap::load( const std::string & image, const int ox, const int oy, - const GLint at_pos, const GLint at_normal, const GLint at_lit ) { - pixels = stbi_load( image.c_str(), &w, &h, nullptr, 1 ); - - if( !pixels ) { - err( 1, "stbi_load failed (%s)", stbi_failure_reason() ); - } - - // printf( "begin lit calculations\n" ); +void heightmap_init( + Heightmap * const hm, + u8 * const pixels, const u32 width, const u32 height, + const float ox, const float oy, + const GLint at_pos, const GLint at_normal, const GLint at_lit +) { + hm->pixels = pixels; + hm->width = width; + hm->height = height; - float * const lit = new GLfloat[ w * h ]; - for( int i = 0; i < w * h; i++ ) { + float * const lit = new GLfloat[ width * height ]; + for( u32 i = 0; i < width * height; i++ ) { lit[ i ] = 0; } - for( int y = 0; y < h; y++ ) { - lit[ y * w ] = -1; + for( u32 y = 0; y < height; y++ ) { + lit[ y * width ] = -1; - for( int x = 1; x < w; x++ ) { - const float h = point( x, y ).z; - const float al = lit[ y * w + x - 1 ]; + for( u32 x = 1; x < width; x++ ) { + const float h = hm->point( x, y ).z; + const float al = lit[ y * width + x - 1 ]; float dh; if( al == -1 ) { - dh = point( x - 1, y ).z - ( h + SLOPE ); + dh = hm->point( x - 1, y ).z - ( h + SLOPE ); } else { dh = al - ( h + SLOPE ); } if( dh > 0 ) { - lit[ y * w + x ] = h + dh; + lit[ y * width + x ] = h + dh; } else { - lit[ y * w + x ] = -1; + lit[ y * width + x ] = -1; } } } - for( int y = 0; y < h; y++ ) { - for( int x = 0; x < w; x++ ) { - const int i = y * w + x; + for( u32 y = 0; y < height; y++ ) { + for( u32 x = 0; x < width; x++ ) { + const u32 i = y * width + x; lit[ i ] = lit[ i ] == -1 ? 1 : 0; } } - // printf( "end lit calculations\n" ); - // - // printf( "sending data to gpu\n" ); + GLfloat * const vertices = new GLfloat[ width * height * 3 ]; + GLfloat * const normals = new GLfloat[ width * height * 3 ]; + GLuint * const indices = new GLuint[ width * height * 6 ]; - GLfloat * const vertices = new GLfloat[ w * h * 3 ]; - GLfloat * const normals = new GLfloat[ w * h * 3 ]; - GLuint * const indices = new GLuint[ w * h * 6 ]; - - for( int y = 0; y < h; y++ ) { - for( int x = 0; x < w; x++ ) { - const int base = 3 * ( y * w + x ); - const float height = point( x, y ).z; + for( u32 y = 0; y < height; y++ ) { + for( u32 x = 0; x < width; x++ ) { + const u32 base = 3 * ( y * width + x ); + const float height = hm->point( x, y ).z; vertices[ base ] = x + ox; vertices[ base + 1 ] = y + oy; vertices[ base + 2 ] = height; - const glm::vec3 normal = point_normal( x, y ); + const glm::vec3 normal = hm->point_normal( x, y ); normals[ base ] = normal.x; normals[ base + 1 ] = normal.y; @@ -115,43 +111,43 @@ void Heightmap::load( const std::string & image, const int ox, const int oy, } } - for( int y = 0; y < h - 1; y++ ) { - for( int x = 0; x < w - 1; x++ ) { - const int base = 6 * ( y * w + x ); + for( u32 y = 0; y < height - 1; y++ ) { + for( u32 x = 0; x < width - 1; x++ ) { + const u32 base = 6 * ( y * width + x ); - indices[ base + 0 ] = ( y + 0 ) * w + ( x + 0 ); - indices[ base + 1 ] = ( y + 1 ) * w + ( x + 0 ); - indices[ base + 2 ] = ( y + 0 ) * w + ( x + 1 ); - indices[ base + 3 ] = ( y + 1 ) * w + ( x + 1 ); - indices[ base + 4 ] = ( y + 0 ) * w + ( x + 1 ); - indices[ base + 5 ] = ( y + 1 ) * w + ( x + 0 ); + indices[ base + 0 ] = ( y + 0 ) * width + ( x + 0 ); + indices[ base + 1 ] = ( y + 1 ) * width + ( x + 0 ); + indices[ base + 2 ] = ( y + 0 ) * width + ( x + 1 ); + indices[ base + 3 ] = ( y + 1 ) * width + ( x + 1 ); + indices[ base + 4 ] = ( y + 0 ) * width + ( x + 1 ); + indices[ base + 5 ] = ( y + 1 ) * width + ( x + 0 ); } } - glGenVertexArrays( 1, &vao ); - glBindVertexArray( vao ); + glGenVertexArrays( 1, &hm->vao ); + glBindVertexArray( hm->vao ); - glGenBuffers( 1, &vbo_verts ); - glBindBuffer( GL_ARRAY_BUFFER, vbo_verts ); - glBufferData( GL_ARRAY_BUFFER, w * h * sizeof( GLfloat ) * 3, vertices, GL_STATIC_DRAW ); + glGenBuffers( 1, &hm->vbo_verts ); + glBindBuffer( GL_ARRAY_BUFFER, hm->vbo_verts ); + glBufferData( GL_ARRAY_BUFFER, width * height * sizeof( GLfloat ) * 3, vertices, GL_STATIC_DRAW ); glEnableVertexAttribArray( at_pos ); glVertexAttribPointer( at_pos, 3, GL_FLOAT, GL_FALSE, 0, 0 ); - glGenBuffers( 1, &vbo_normals ); - glBindBuffer( GL_ARRAY_BUFFER, vbo_normals ); - glBufferData( GL_ARRAY_BUFFER, w * h * sizeof( GLfloat ) * 3, normals, GL_STATIC_DRAW ); + glGenBuffers( 1, &hm->vbo_normals ); + glBindBuffer( GL_ARRAY_BUFFER, hm->vbo_normals ); + glBufferData( GL_ARRAY_BUFFER, width * height * sizeof( GLfloat ) * 3, normals, GL_STATIC_DRAW ); glEnableVertexAttribArray( at_normal ); glVertexAttribPointer( at_normal, 3, GL_FLOAT, GL_FALSE, 0, 0 ); - glGenBuffers( 1, &vbo_lit ); - glBindBuffer( GL_ARRAY_BUFFER, vbo_lit ); - glBufferData( GL_ARRAY_BUFFER, w * h * sizeof( GLfloat ), lit, GL_STATIC_DRAW ); + glGenBuffers( 1, &hm->vbo_lit ); + glBindBuffer( GL_ARRAY_BUFFER, hm->vbo_lit ); + glBufferData( GL_ARRAY_BUFFER, width * height * sizeof( GLfloat ), lit, GL_STATIC_DRAW ); glEnableVertexAttribArray( at_lit ); glVertexAttribPointer( at_lit, 1, GL_FLOAT, GL_FALSE, 0, 0 ); - glGenBuffers( 1, &ebo ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, w * h * sizeof( GLuint ) * 6, indices, GL_STATIC_DRAW ); + glGenBuffers( 1, &hm->ebo ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, hm->ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, width * height * sizeof( GLuint ) * 6, indices, GL_STATIC_DRAW ); glBindVertexArray( 0 ); @@ -159,29 +155,27 @@ void Heightmap::load( const std::string & image, const int ox, const int oy, delete normals; delete indices; delete lit; - - // printf( "sent\n" ); } -void Heightmap::unload() { - if( vbo_verts != 0 ) { - glDeleteBuffers( 1, &vbo_verts ); - glDeleteBuffers( 1, &vbo_normals ); - glDeleteBuffers( 1, &vbo_lit ); - glDeleteBuffers( 1, &ebo ); - glDeleteVertexArrays( 1, &vao ); +void heightmap_destroy( Heightmap * const hm ) { + if( hm->vbo_verts != 0 ) { + glDeleteBuffers( 1, &hm->vbo_verts ); + glDeleteBuffers( 1, &hm->vbo_normals ); + glDeleteBuffers( 1, &hm->vbo_lit ); + glDeleteBuffers( 1, &hm->ebo ); + glDeleteVertexArrays( 1, &hm->vao ); - stbi_image_free( pixels ); + stbi_image_free( hm->pixels ); - vbo_verts = 0; + hm->vbo_verts = 0; } } -glm::vec3 Heightmap::point( int x, int y ) const { - return glm::vec3( x, y, pixels[ y * w + x ] / 4.0f ); +glm::vec3 Heightmap::point( u32 x, u32 y ) const { + return glm::vec3( x, y, pixels[ y * width + x ] / 4.0f ); } -glm::vec3 Heightmap::point_normal( int x, int y ) const { +glm::vec3 Heightmap::point_normal( u32 x, u32 y ) const { glm::vec3 bent_normal = glm::vec3( 0 ); /* @@ -209,7 +203,7 @@ glm::vec3 Heightmap::point_normal( int x, int y ) const { bent_normal += triangle_normal_ccw( tri2a, tri2b, tri2c ); } - if( y < h - 1 ) { // top left + if( y < height - 1 ) { // top left const glm::vec3 tri5a = point( x, y ); const glm::vec3 tri5b = point( x - 1, y + 1 ); const glm::vec3 tri5c = point( x - 1, y ); @@ -223,7 +217,7 @@ glm::vec3 Heightmap::point_normal( int x, int y ) const { } } - if( x < w - 1 ) { + if( x < width - 1 ) { if( y > 0 ) { // bottom right const glm::vec3 tri3a = point( x, y ); const glm::vec3 tri3b = point( x, y - 1 ); @@ -236,7 +230,7 @@ glm::vec3 Heightmap::point_normal( int x, int y ) const { bent_normal += triangle_normal_ccw( tri3a, tri3b, tri3c ); bent_normal += triangle_normal_ccw( tri4a, tri4b, tri4c ); } - if( y < h - 1 ) { // top right + if( y < height - 1 ) { // top right const glm::vec3 tri1a = point( x, y ); const glm::vec3 tri1b = point( x + 1, y ); const glm::vec3 tri1c = point( x, y + 1 ); @@ -248,7 +242,7 @@ glm::vec3 Heightmap::point_normal( int x, int y ) const { return glm::normalize( bent_normal ); } -float Heightmap::height( const float x, const float y ) const { +float Heightmap::bilerp_height( const float x, const float y ) const { const float ix = floorf( x ); const float iy = floorf( y ); @@ -265,6 +259,6 @@ void Heightmap::render() const { assert( vbo_verts != 0 ); glBindVertexArray( vao ); - glDrawElements( GL_TRIANGLES, w * h * 6, GL_UNSIGNED_INT, 0 ); + glDrawElements( GL_TRIANGLES, width * height * 6, GL_UNSIGNED_INT, 0 ); glBindVertexArray( 0 ); } diff --git a/heightmap.h b/heightmap.h @@ -11,7 +11,7 @@ class Heightmap { public: u8 * pixels; - int w, h; + u32 width, height; GLuint vbo_verts = 0; GLuint vbo_normals; @@ -19,14 +19,10 @@ public: GLuint ebo; GLuint vao; - void load( const std::string & image, const int ox, const int oy, - const GLint at_pos, const GLint at_normal, const GLint at_lit ); - void unload(); + glm::vec3 point( u32 x, u32 y ) const; + glm::vec3 point_normal( u32 x, u32 y ) const; - glm::vec3 point( int x, int y ) const; - glm::vec3 point_normal( int x, int y ) const; - - float height( const float x, const float y ) const; + float bilerp_height( const float x, const float y ) const; void render() const; }; @@ -36,4 +32,11 @@ struct OffsetHeightmap { float x_offset, y_offset; }; +void heightmap_init( Heightmap * const hm, + u8 * const pixels, const u32 width, const u32 height, + const float ox, const float oy, // TODO: take rendering out of Heightmap + const GLint at_pos, const GLint at_normal, const GLint at_lit ); + +void heightmap_destroy( Heightmap * const hm ); + #endif // _HEIGHTMAP_H_ diff --git a/terrain_manager.cc b/terrain_manager.cc @@ -17,6 +17,8 @@ #include "intrinsics.h" #include "heightmap.h" #include "terrain_manager.h" +#include "work_queue.h" +#include "stb_image.h" static const GLchar * const vert_src = GLSL( in vec3 position; @@ -75,8 +77,21 @@ static void terrain_load( Heightmap * const hm = &tm->tiles[ tx ][ ty ]; - if( hm->vbo_verts != 0 ) hm->unload(); - hm->load( path, tx * TILE_SIZE, ty * TILE_SIZE, tm->at_pos, tm->at_normal, tm->at_lit ); + if( hm->vbo_verts != 0 ) heightmap_destroy( hm ); + + size_t len; + u8 * contents = file_get_contents( path, &len ); + assert( contents ); + + int width, height; + u8 * pixels = stbi_load_from_memory( contents, len, &width, &height, nullptr, 1 ); + free( contents ); + + if( !pixels ) err( 1, "stbi_load failed (%s)", stbi_failure_reason() ); + + heightmap_init( hm, pixels, width, height, + tx * TILE_SIZE, ty * TILE_SIZE, + tm->at_pos, tm->at_normal, tm->at_lit ); } void terrain_init( TerrainManager * const tm, const char * const tiles_dir ) { @@ -112,7 +127,7 @@ void terrain_teleport( TerrainManager * const tm, const glm::vec3 position ) { if( !tm->first_teleport ) { for( u32 ty = 0; ty < VIEW_SIZE; ty++ ) { for( u32 tx = 0; tx < VIEW_SIZE; tx++ ) { - tm->tiles[ tm->last_tx + tx - VIEW_HALF ][ tm->last_ty + ty - VIEW_HALF ].unload(); + heightmap_destroy( &tm->tiles[ tm->last_tx + tx - VIEW_HALF ][ tm->last_ty + ty - VIEW_HALF ] ); } } } @@ -197,5 +212,5 @@ float terrain_height( const TerrainManager * const tm, const float x, const floa const Heightmap * const hm = &tm->tiles[ tx ][ ty ]; - return hm->height( x - tx * TILE_SIZE, y - ty * TILE_SIZE ); + return hm->bilerp_height( x - tx * TILE_SIZE, y - ty * TILE_SIZE ); }