Day 36 complete

This commit is contained in:
Edward R. Gonzalez 2023-10-19 14:16:50 -04:00
parent b81e439038
commit ffba625a24
12 changed files with 216 additions and 44 deletions

View File

@ -33,7 +33,7 @@ Module build order:
## Milestone ## Milestone
Day 35 : Basic Sparse Tilemap Storage Day 36 : Loading BMPs
Features Done so far: Features Done so far:
@ -62,6 +62,7 @@ Features Done so far:
## Gallery ## 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-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_23-39-57.gif)
![img](docs/imgs/handmade_win32_2023-10-11_00-47-19.gif) ![img](docs/imgs/handmade_win32_2023-10-11_00-47-19.gif)

BIN
data/content/MOJITO.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

5
docs/Day 036.md Normal file
View File

@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

View File

@ -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 inline
void draw_debug_point(OffscreenBuffer* back_buffer, World* world, TileMapPosition pos, f32 red, f32 green, f32 blue) 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); 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 Engine_API
void on_module_reload( Memory* memory, platform::ModuleAPI* platfom_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_x = 128;
tile_map->tile_chunks_num_y = 128; tile_map->tile_chunks_num_y = 128;
tile_map->tile_chunks_num_z = 2; 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; 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 ); 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_x = 17;
u32 tiles_per_screen_y = 9; u32 tiles_per_screen_y = 9;
u32 screen_x = 0; u32 screen_x = 0;
u32 screen_y = 0; u32 screen_y = 0;
u32 rng_index = 0; u32 rng_index = 0;
b32 door_left = false; b32 door_left = false;
b32 door_right = false; b32 door_right = false;
b32 door_top = false; b32 door_top = false;
b32 door_bottom = false; b32 door_bottom = false;
b32 door_up = false; b32 door_up = false;
b32 door_down = false; b32 door_down = false;
u32 abs_tile_z = 0; u32 abs_tile_z = 0;
for ( u32 screen_index = 0; screen_index < 100; ++ screen_index ) for ( u32 screen_index = 0; screen_index < 100; ++ screen_index )
{ {
// TODO(Ed) : We need a proper RNG. // 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; random_choice = RNG_Table[ rng_index ] % 3;
} }
++ rng_index; ++ rng_index;
b32 created_z_door = false;
if ( random_choice == 2 ) if ( random_choice == 2 )
{ {
created_z_door = true;
if ( abs_tile_z == 0 ) if ( abs_tile_z == 0 )
{ {
door_up = true; 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 abs_tile_y = screen_y * tiles_per_screen_y + tile_y;
u32 tile_value = 1; u32 tile_value = 1;
bool in_middle_x = tile_x == (tiles_per_screen_x / 2); bool in_middle_x = tile_x == (tiles_per_screen_x / 2);
bool in_middle_y = tile_y == (tiles_per_screen_y / 2); bool in_middle_y = tile_y == (tiles_per_screen_y / 2);
bool on_right = tile_x == (tiles_per_screen_x - 1); bool on_right = tile_x == (tiles_per_screen_x - 1);
bool on_left = tile_x == 0; bool on_left = tile_x == 0;
bool on_bottom = tile_y == 0; bool on_bottom = tile_y == 0;
bool on_top = tile_y == (tiles_per_screen_y - 1); bool on_top = tile_y == (tiles_per_screen_y - 1);
if ( on_left && (! in_middle_y || ! door_left )) if ( on_left && (! in_middle_y || ! door_left ))
{ {
tile_value = 2; tile_value = 2;
@ -408,7 +473,7 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI*
{ {
tile_value = 2; tile_value = 2;
} }
if ( on_bottom && (! in_middle_x || ! door_bottom )) if ( on_bottom && (! in_middle_x || ! door_bottom ))
{ {
tile_value = 2; tile_value = 2;
@ -417,7 +482,7 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI*
{ {
tile_value = 2; tile_value = 2;
} }
if ( tile_x == 6 && tile_y == 6 ) if ( tile_x == 6 && tile_y == 6 )
{ {
if ( door_up ) if ( door_up )
@ -429,31 +494,26 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI*
tile_value = 4; tile_value = 4;
} }
} }
// u32 tile_value = tile_x == tile_y && tile_y % 2 ? 1 : 0; // 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 ); 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_left = door_right;
door_bottom = door_top; door_bottom = door_top;
if ( door_up ) if ( created_z_door )
{ {
door_down = true; door_down = ! door_down;
door_up = false; door_up = ! door_up;
}
else if ( door_down )
{
door_up = true;
door_down = false;
} }
else else
{ {
door_up = false; door_up = false;
door_down = false; door_down = false;
} }
door_right = false; door_right = false;
door_top = 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 ); hh::GameState* game_state = rcast( hh::GameState*, state->game_memory.persistent );
assert( sizeof(hh::GameState) <= state->game_memory.persistent_size ); 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; hh::PlayerState* player = & game_state->player_state;
player->position.tile_x = 4; player->position.tile_x = 4;
player->position.tile_y = 4; player->position.tile_y = 4;
@ -680,7 +748,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back
{ {
TileMapPosition test_pos = { TileMapPosition test_pos = {
new_player_pos_x, new_player_pos_y, 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 ); 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 { TileMapPosition test_pos_nw {
new_player_pos_x - player_half_width, new_player_pos_y + player_quarter_height, 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 ); test_pos_nw = recannonicalize_position( tile_map, test_pos_nw );
valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_nw ); valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_nw );
TileMapPosition test_pos_ne { TileMapPosition test_pos_ne {
new_player_pos_x + player_half_width, new_player_pos_y + player_quarter_height, 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 ); test_pos_ne = recannonicalize_position( tile_map, test_pos_ne );
valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_ne ); valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_ne );
TileMapPosition test_pos_sw { TileMapPosition test_pos_sw {
new_player_pos_x - player_half_width, new_player_pos_y, 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 ); test_pos_sw = recannonicalize_position( tile_map, test_pos_sw );
valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_sw ); valid_new_pos &= TileMap_is_point_empty( tile_map, test_pos_sw );
TileMapPosition test_pos_se { TileMapPosition test_pos_se {
new_player_pos_x + player_half_width, new_player_pos_y, 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 ); test_pos_se = recannonicalize_position( tile_map, test_pos_se );
valid_new_pos &= TileMap_is_point_empty( 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 ) if ( valid_new_pos )
{ {
TileMapPosition new_pos = { TileMapPosition new_pos = {
new_player_pos_x, new_player_pos_y, 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 ) 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 col = player->position.tile_x + relative_col;
u32 row = player->position.tile_y + relative_row; u32 row = player->position.tile_y + relative_row;
u32 tile_id = TileMap_get_tile_value( tile_map, col, row, player->position.tile_z ); u32 tile_id = TileMap_get_tile_value( tile_map, col, row, player->position.tile_z );
f32 color[3] = { 0.15f, 0.15f, 0.15f }; f32 color[3] = { 0.15f, 0.15f, 0.15f };
if ( tile_id > 0 ) if ( tile_id > 0 )
{ {
if ( tile_id == 2 ) if ( tile_id == 2 )
@ -781,7 +867,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back
color[1] = 0.52f; color[1] = 0.52f;
color[2] = 0.52f; color[2] = 0.52f;
} }
if ( row == player->position.tile_y && col == player->position.tile_x ) if ( row == player->position.tile_y && col == player->position.tile_x )
{ {
color[0] = 0.44f; 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 // Player
f32 player_red = 0.7f; f32 player_red = 0.7f;
f32 player_green = 0.7f; f32 player_green = 0.7f;

View File

@ -94,9 +94,9 @@ struct Memory
//ReplayData replay; //ReplayData replay;
#endif #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 static constexpr
ssize game_memory_factor = 4; ssize game_memory_factor = 2;
ssize engine_persistent_size() ssize engine_persistent_size()
{ {
@ -181,4 +181,29 @@ struct World
TileMap* tile_map; 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 NS_ENGINE_END

View File

@ -4,6 +4,7 @@
NS_ENGINE_BEGIN NS_ENGINE_BEGIN
// TODO(Ed) : Consider moving (Casey wants to)
inline inline
void cannonicalize_coord( TileMap* tile_map, u32* tile_coord, f32* pos_coord ) 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; (* pos_coord) = new_pos_coord;
} }
// TODO(Ed) : Consider moving (Casey wants to)
inline inline
TileMapPosition recannonicalize_position( TileMap* tile_map, TileMapPosition pos ) 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; return chunk_pos;
} }
inline
u32 TileMap_get_tile_value( TileMap* tile_map, u32 tile_x, u32 tile_y, u32 tile_z ) u32 TileMap_get_tile_value( TileMap* tile_map, u32 tile_x, u32 tile_y, u32 tile_z )
{ {
assert( tile_map != nullptr ); 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; 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 internal
b32 TileMap_is_point_empty( TileMap* tile_map, TileMapPosition position ) b32 TileMap_is_point_empty( TileMap* tile_map, TileMapPosition position )
{ {
assert( tile_map != nullptr ); assert( tile_map != nullptr );
u32 chunk_value = TileMap_get_tile_value( tile_map, position.tile_x, position.tile_y, position.tile_z ); 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; 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 ); 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 NS_ENGINE_END

View File

@ -50,8 +50,7 @@ struct TileMap
struct TileMapPosition struct TileMapPosition
{ {
// TODO(Ed) : Should this be from the center of the tile? // Note(Ed) : Relative position from tile center.
f32 x; f32 x;
f32 y; f32 y;

View File

@ -94,6 +94,9 @@ struct PlayerActions
struct GameState struct GameState
{ {
PlayerState player_state; PlayerState player_state;
engine::Bitmap test_bg;
engine::Bitmap mojito;
}; };
NS_HANDMADE_END NS_HANDMADE_END

View File

@ -35,8 +35,8 @@ using DebugSetPauseRenderingFn = void (b32 value);
struct File struct File
{ {
void* opaque_handle;
Str path; Str path;
void* opaque_handle;
void* data; void* data;
u32 size; u32 size;
}; };
@ -87,6 +87,7 @@ struct ModuleAPI
{ {
Str path_root; Str path_root;
Str path_binaries; Str path_binaries;
Str path_content;
Str path_scratch; Str path_scratch;
#if Build_Development #if Build_Development

View File

@ -58,6 +58,7 @@ global PlatformContext Platform_Context;
global StrPath Path_Root; global StrPath Path_Root;
global StrPath Path_Binaries; global StrPath Path_Binaries;
global StrPath Path_Content;
global StrPath Path_Scratch; global StrPath Path_Scratch;
// TODO(Ed) : This is a global for now. // 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.concat( Path_Root, str_ascii("scratch") );
Path_Scratch.ptr[ Path_Scratch.len ] = '\\'; Path_Scratch.ptr[ Path_Scratch.len ] = '\\';
++ Path_Scratch.len; ++ Path_Scratch.len;
CreateDirectoryA( Path_Scratch, 0 ); CreateDirectoryA( Path_Scratch, 0 );
Path_Content.concat( Path_Root, str_ascii("content") );
Path_Content.ptr[ Path_Content.len ] = '\\';
++ Path_Content.len;
} }
// Memory // Memory
@ -647,7 +652,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
} }
// WinDimensions dimensions = get_window_dimensions( window_handle ); // 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 // Setup monitor refresh and associated timers
HDC refresh_dc = GetDC( window_handle ); 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_root = Path_Root;
platform_api.path_binaries = Path_Binaries; platform_api.path_binaries = Path_Binaries;
platform_api.path_content = Path_Content;
platform_api.path_scratch = Path_Scratch; platform_api.path_scratch = Path_Scratch;
#if Build_Development #if Build_Development