diff --git a/README.md b/README.md index 532ad5c..9d83721 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Module build order: ## Milestone -Day 35 : Basic Sparse Tilemap Storage +Day 36 : Loading BMPs Features Done so far: @@ -62,6 +62,7 @@ Features Done so far: ## Gallery +![img](docs/imgs/handmade_win32_2023-10-19_14-07-20.png) ![img](docs/imgs/handmade_win32_2023-10-16_23-08-11.png) ![img](docs/imgs/handmade_win32_2023-10-11_23-39-57.gif) ![img](docs/imgs/handmade_win32_2023-10-11_00-47-19.gif) diff --git a/data/content/MOJITO.bmp b/data/content/MOJITO.bmp new file mode 100644 index 0000000..8d31c56 Binary files /dev/null and b/data/content/MOJITO.bmp differ diff --git a/data/content/test_background.bmp b/data/content/test_background.bmp new file mode 100644 index 0000000..4351678 Binary files /dev/null and b/data/content/test_background.bmp differ diff --git a/docs/Day 036.md b/docs/Day 036.md new file mode 100644 index 0000000..5f66c9c --- /dev/null +++ b/docs/Day 036.md @@ -0,0 +1,5 @@ +# Day 36 + +Just dealing with Casey's "methods" for going about the code exploration... + +Loading an image was nice, I got it to render somewhat properly with draw_bitmap but until he does it I kept the bad way hes doing it. diff --git a/docs/imgs/handmade_win32_2023-10-19_14-07-20.png b/docs/imgs/handmade_win32_2023-10-19_14-07-20.png new file mode 100644 index 0000000..0f71a84 Binary files /dev/null and b/docs/imgs/handmade_win32_2023-10-19_14-07-20.png differ diff --git a/project/engine/engine.cpp b/project/engine/engine.cpp index 64f910c..6b02ebb 100644 --- a/project/engine/engine.cpp +++ b/project/engine/engine.cpp @@ -236,6 +236,49 @@ void draw_rectangle( OffscreenBuffer* buffer } } +internal +void draw_bitmap( OffscreenBuffer* buffer + , f32 min_x, f32 min_y + , f32 max_x, f32 max_y + , u32* pixels, u32 size ) +{ + s32 min_x_32 = round( min_x ); + s32 min_y_32 = round( min_y ); + s32 max_x_32 = round( max_x ); + s32 max_y_32 = round( max_y ); + + s32 buffer_width = buffer->width; + s32 buffer_height = buffer->height; + + if ( min_x_32 < 0 ) + min_x_32 = 0; + if ( min_y_32 < 0 ) + min_y_32 = 0; + if ( max_x_32 > buffer_width ) + max_x_32 = buffer_width; + if ( max_y_32 > buffer_height ) + max_y_32 = buffer_height; + + // Start with the pixel on the top left corner of the rectangle + u8* row = rcast(u8*, buffer->memory ) + + min_x_32 * buffer->bytes_per_pixel + + min_y_32 * buffer->pitch; + + for ( s32 y = min_y_32; y < max_y_32; ++ y ) + { + s32* pixel_32 = rcast(s32*, row); + + for ( s32 x = min_x_32; x < max_x_32; ++ x ) + { + u32 color = pixels[ y * max_x_32 + x ]; + + *pixel_32 = color; + pixel_32++; + } + row += buffer->pitch; + } +} + inline void draw_debug_point(OffscreenBuffer* back_buffer, World* world, TileMapPosition pos, f32 red, f32 green, f32 blue) { @@ -249,6 +292,26 @@ void draw_debug_point(OffscreenBuffer* back_buffer, World* world, TileMapPositio red, green, blue); } +internal +Bitmap load_bmp( platform::FileReadContentFn* file_read_content, Str file_path ) +{ + Bitmap result {}; + + platform::File file { + file_path + }; + if ( ! file_read_content( & file ) ) + { + return result; + } + + BitmapHeaderPacked* header = pcast(BitmapHeaderPacked*, file.data); + result.pixels = rcast(u32*, rcast(Byte*, file.data) + header->bitmap_offset); + result.width = header->width; + result.height = header->height; + result.bits_per_pixel = header->bits_per_pixel; + return result; +} Engine_API void on_module_reload( Memory* memory, platform::ModuleAPI* platfom_api ) @@ -314,7 +377,7 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* tile_map->tile_chunks_num_x = 128; tile_map->tile_chunks_num_y = 128; tile_map->tile_chunks_num_z = 2; - + ssize num_chunks = tile_map->tile_chunks_num_x * tile_map->tile_chunks_num_y * tile_map->tile_chunks_num_z; tile_map->chunks = state->world_arena.push_array( TileChunk, num_chunks ); @@ -333,20 +396,20 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* u32 tiles_per_screen_x = 17; u32 tiles_per_screen_y = 9; - + u32 screen_x = 0; u32 screen_y = 0; u32 rng_index = 0; - + b32 door_left = false; b32 door_right = false; b32 door_top = false; b32 door_bottom = false; b32 door_up = false; b32 door_down = false; - + u32 abs_tile_z = 0; - + for ( u32 screen_index = 0; screen_index < 100; ++ screen_index ) { // TODO(Ed) : We need a proper RNG. @@ -361,9 +424,11 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* random_choice = RNG_Table[ rng_index ] % 3; } ++ rng_index; - + + b32 created_z_door = false; if ( random_choice == 2 ) { + created_z_door = true; if ( abs_tile_z == 0 ) { door_up = true; @@ -390,16 +455,16 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* u32 abs_tile_y = screen_y * tiles_per_screen_y + tile_y; u32 tile_value = 1; - + bool in_middle_x = tile_x == (tiles_per_screen_x / 2); bool in_middle_y = tile_y == (tiles_per_screen_y / 2); - + bool on_right = tile_x == (tiles_per_screen_x - 1); bool on_left = tile_x == 0; - + bool on_bottom = tile_y == 0; bool on_top = tile_y == (tiles_per_screen_y - 1); - + if ( on_left && (! in_middle_y || ! door_left )) { tile_value = 2; @@ -408,7 +473,7 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* { tile_value = 2; } - + if ( on_bottom && (! in_middle_x || ! door_bottom )) { tile_value = 2; @@ -417,7 +482,7 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* { tile_value = 2; } - + if ( tile_x == 6 && tile_y == 6 ) { if ( door_up ) @@ -429,31 +494,26 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* tile_value = 4; } } - + // u32 tile_value = tile_x == tile_y && tile_y % 2 ? 1 : 0; TileMap_set_tile_value( & state->world_arena, world->tile_map, abs_tile_x, abs_tile_y, abs_tile_z, tile_value ); } } - + door_left = door_right; door_bottom = door_top; - - if ( door_up ) + + if ( created_z_door ) { - door_down = true; - door_up = false; - } - else if ( door_down ) - { - door_up = true; - door_down = false; + door_down = ! door_down; + door_up = ! door_up; } else { - door_up = false; + door_up = false; door_down = false; } - + door_right = false; door_top = false; @@ -482,6 +542,14 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* hh::GameState* game_state = rcast( hh::GameState*, state->game_memory.persistent ); assert( sizeof(hh::GameState) <= state->game_memory.persistent_size ); + StrPath path_test_bg; + path_test_bg.concat( platform_api->path_content, str_ascii("test_background.bmp") ); + game_state->test_bg = load_bmp( platform_api->file_read_content, path_test_bg ); + + StrPath path_mojito; + path_mojito.concat( platform_api->path_content, str_ascii("mojito.bmp") ); + game_state->mojito = load_bmp( platform_api->file_read_content, path_mojito ); + hh::PlayerState* player = & game_state->player_state; player->position.tile_x = 4; player->position.tile_y = 4; @@ -680,7 +748,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back { TileMapPosition test_pos = { new_player_pos_x, new_player_pos_y, - player->position.tile_x, player->position.tile_y + player->position.tile_x, player->position.tile_y, player->position.tile_z }; test_pos = recannonicalize_position( tile_map, test_pos ); @@ -688,28 +756,28 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back TileMapPosition test_pos_nw { new_player_pos_x - player_half_width, new_player_pos_y + player_quarter_height, - player->position.tile_x, player->position.tile_y + player->position.tile_x, player->position.tile_y, player->position.tile_z }; test_pos_nw = recannonicalize_position( tile_map, test_pos_nw ); valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_nw ); TileMapPosition test_pos_ne { new_player_pos_x + player_half_width, new_player_pos_y + player_quarter_height, - player->position.tile_x, player->position.tile_y + player->position.tile_x, player->position.tile_y, player->position.tile_z }; test_pos_ne = recannonicalize_position( tile_map, test_pos_ne ); valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_ne ); TileMapPosition test_pos_sw { new_player_pos_x - player_half_width, new_player_pos_y, - player->position.tile_x, player->position.tile_y + player->position.tile_x, player->position.tile_y, player->position.tile_z }; test_pos_sw = recannonicalize_position( tile_map, test_pos_sw ); valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_sw ); TileMapPosition test_pos_se { new_player_pos_x + player_half_width, new_player_pos_y, - player->position.tile_x, player->position.tile_y + player->position.tile_x, player->position.tile_y, player->position.tile_z }; test_pos_se = recannonicalize_position( tile_map, test_pos_se ); valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_se ); @@ -717,11 +785,29 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back if ( valid_new_pos ) { + TileMapPosition new_pos = { new_player_pos_x, new_player_pos_y, - player->position.tile_x, player->position.tile_y + player->position.tile_x, player->position.tile_y, player->position.tile_z }; - player->position = recannonicalize_position( tile_map, new_pos ); + new_pos = recannonicalize_position( tile_map, new_pos ); + + bool on_new_tile = TileMap_are_on_same_tile( & new_pos, & player->position ); + if ( ! on_new_tile ) + { + u32 new_tile_value = TileMap_get_tile_value( tile_map, new_pos ); + + if ( new_tile_value == 3 ) + { + ++ new_pos.tile_z; + } + else if ( new_tile_value == 4 ) + { + -- new_pos.tile_z; + } + } + + player->position = new_pos; } if ( player->jump_time > 0.f ) @@ -757,10 +843,10 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back { u32 col = player->position.tile_x + relative_col; u32 row = player->position.tile_y + relative_row; - + u32 tile_id = TileMap_get_tile_value( tile_map, col, row, player->position.tile_z ); f32 color[3] = { 0.15f, 0.15f, 0.15f }; - + if ( tile_id > 0 ) { if ( tile_id == 2 ) @@ -781,7 +867,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back color[1] = 0.52f; color[2] = 0.52f; } - + if ( row == player->position.tile_y && col == player->position.tile_x ) { color[0] = 0.44f; @@ -805,6 +891,27 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back } } +// draw_bitmap( back_buffer +// , 0, 0 +// , scast(f32, game_state->mojito.width), scast(f32, game_state->mojito.height) +// , game_state->mojito.pixels, game_state->mojito.size +// ); + + // Bad bitmap test + { + u32* src = game_state->mojito.pixels; + u32* dst = rcast(u32*, back_buffer->memory); + for ( s32 y = 0; y < game_state->mojito.height; ++ y ) + { + for ( s32 x = 0; x < game_state->mojito.width; ++ x ) + { + *dst = *src; + ++ dst; + ++ src; + } + } + } + // Player f32 player_red = 0.7f; f32 player_green = 0.7f; diff --git a/project/engine/engine.hpp b/project/engine/engine.hpp index c5dbaed..d5315a5 100644 --- a/project/engine/engine.hpp +++ b/project/engine/engine.hpp @@ -94,9 +94,9 @@ struct Memory //ReplayData replay; #endif - // The game will have 1/4 of persistent's memory available ot it. + // The game will have 1/2 of persistent's memory available ot it. static constexpr - ssize game_memory_factor = 4; + ssize game_memory_factor = 2; ssize engine_persistent_size() { @@ -181,4 +181,29 @@ struct World TileMap* tile_map; }; +#pragma pack(push, 1) +struct BitmapHeaderPacked +{ + u16 file_type; + u32 file_size; + u16 _reserved_1_; + u16 _reserved_2_; + u32 bitmap_offset; + u32 size; + s32 width; + s32 height; + u16 planes; + u16 bits_per_pixel; +}; +#pragma pack(pop) + +struct Bitmap +{ + u32* pixels; + s32 width; + s32 height; + u32 bits_per_pixel; + u32 size; +}; + NS_ENGINE_END diff --git a/project/engine/tile_map.cpp b/project/engine/tile_map.cpp index 68872b0..b439c6b 100644 --- a/project/engine/tile_map.cpp +++ b/project/engine/tile_map.cpp @@ -4,6 +4,7 @@ NS_ENGINE_BEGIN +// TODO(Ed) : Consider moving (Casey wants to) inline void cannonicalize_coord( TileMap* tile_map, u32* tile_coord, f32* pos_coord ) { @@ -24,6 +25,7 @@ void cannonicalize_coord( TileMap* tile_map, u32* tile_coord, f32* pos_coord ) (* pos_coord) = new_pos_coord; } +// TODO(Ed) : Consider moving (Casey wants to) inline TileMapPosition recannonicalize_position( TileMap* tile_map, TileMapPosition pos ) { @@ -91,6 +93,7 @@ TileChunkPosition get_tile_chunk_position_for( TileMap* tile_map, u32 abs_tile_x return chunk_pos; } +inline u32 TileMap_get_tile_value( TileMap* tile_map, u32 tile_x, u32 tile_y, u32 tile_z ) { assert( tile_map != nullptr ); @@ -105,13 +108,24 @@ u32 TileMap_get_tile_value( TileMap* tile_map, u32 tile_x, u32 tile_y, u32 tile_ return value; } +inline +u32 TileMap_get_tile_value( TileMap* tile_map, TileMapPosition position ) +{ + u32 value = TileMap_get_tile_value( tile_map, position.tile_x, position.tile_y, position.tile_z ); + return value; +} + internal b32 TileMap_is_point_empty( TileMap* tile_map, TileMapPosition position ) { assert( tile_map != nullptr ); u32 chunk_value = TileMap_get_tile_value( tile_map, position.tile_x, position.tile_y, position.tile_z ); - b32 is_empty = chunk_value == 1; + + b32 + is_empty = chunk_value == 1; + is_empty |= chunk_value == 3; + is_empty |= chunk_value == 4; return is_empty; } @@ -137,4 +151,15 @@ void TileMap_set_tile_value( MemoryArena* arena, TileMap* tile_map, u32 abs_tile TileChunk_set_tile_value( chunk, tile_map, chunk_pos.tile_x, chunk_pos.tile_y, value ); } + +internal +b32 TileMap_are_on_same_tile( TileMapPosition* pos_a, TileMapPosition* pos_b ) +{ + b32 result = + pos_a->tile_x == pos_b->tile_x + && pos_a->tile_y == pos_b->tile_y + && pos_a->tile_z == pos_b->tile_z; + return result; +} + NS_ENGINE_END diff --git a/project/engine/tile_map.hpp b/project/engine/tile_map.hpp index 48b5ce6..ae67761 100644 --- a/project/engine/tile_map.hpp +++ b/project/engine/tile_map.hpp @@ -50,8 +50,7 @@ struct TileMap struct TileMapPosition { - // TODO(Ed) : Should this be from the center of the tile? - + // Note(Ed) : Relative position from tile center. f32 x; f32 y; diff --git a/project/handmade.hpp b/project/handmade.hpp index f058284..4366780 100644 --- a/project/handmade.hpp +++ b/project/handmade.hpp @@ -94,6 +94,9 @@ struct PlayerActions struct GameState { PlayerState player_state; + + engine::Bitmap test_bg; + engine::Bitmap mojito; }; NS_HANDMADE_END diff --git a/project/platform/platform.hpp b/project/platform/platform.hpp index 439b140..a187185 100644 --- a/project/platform/platform.hpp +++ b/project/platform/platform.hpp @@ -35,8 +35,8 @@ using DebugSetPauseRenderingFn = void (b32 value); struct File { - void* opaque_handle; Str path; + void* opaque_handle; void* data; u32 size; }; @@ -87,6 +87,7 @@ struct ModuleAPI { Str path_root; Str path_binaries; + Str path_content; Str path_scratch; #if Build_Development diff --git a/project/platform/win32/win32_platform.cpp b/project/platform/win32/win32_platform.cpp index 75659aa..a73d1d5 100644 --- a/project/platform/win32/win32_platform.cpp +++ b/project/platform/win32/win32_platform.cpp @@ -58,6 +58,7 @@ global PlatformContext Platform_Context; global StrPath Path_Root; global StrPath Path_Binaries; +global StrPath Path_Content; global StrPath Path_Scratch; // TODO(Ed) : This is a global for now. @@ -518,8 +519,12 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho Path_Scratch.concat( Path_Root, str_ascii("scratch") ); Path_Scratch.ptr[ Path_Scratch.len ] = '\\'; ++ Path_Scratch.len; - + CreateDirectoryA( Path_Scratch, 0 ); + + Path_Content.concat( Path_Root, str_ascii("content") ); + Path_Content.ptr[ Path_Content.len ] = '\\'; + ++ Path_Content.len; } // Memory @@ -647,7 +652,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho } // WinDimensions dimensions = get_window_dimensions( window_handle ); - resize_dib_section( &Surface_Back_Buffer, 1280, 720 ); + resize_dib_section( &Surface_Back_Buffer, 1280, 720 ); // Setup monitor refresh and associated timers HDC refresh_dc = GetDC( window_handle ); @@ -667,6 +672,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho { platform_api.path_root = Path_Root; platform_api.path_binaries = Path_Binaries; + platform_api.path_content = Path_Content; platform_api.path_scratch = Path_Scratch; #if Build_Development