diff --git a/.vscode/bookmarks.json b/.vscode/bookmarks.json index ebe0a41..ee7830c 100644 --- a/.vscode/bookmarks.json +++ b/.vscode/bookmarks.json @@ -14,7 +14,7 @@ "label": "Static Data" }, { - "line": 1002, + "line": 1001, "column": 0, "label": "Main Loop : End" } diff --git a/README.md b/README.md index 5c06ce6..94b71f5 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,11 @@ Features Done so far: * Allows for engine or game state to be restored even if a crash occurs to exact memory state it was before. * Basic input abstraction into hard-coded actions (``EngineActions` & `PlayerActions`) * Record & replay input. - * (WIP) : 2D Tile Map setup + * (WIP) : 2D Tile Map (Virtualized into chunks) ## Gallery +![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-10_13-13-14.gif) ![img](docs/imgs/handmade_win32_2023-10-06_12-43-47.gif) diff --git a/docs/Day 034.md b/docs/Day 034.md new file mode 100644 index 0000000..11315a8 --- /dev/null +++ b/docs/Day 034.md @@ -0,0 +1,6 @@ +# Day 34 + +Casey decided to start offloading tile map definitions to separate files so I took the time to also cleanup some of the organization of the code. +I'm still keeping some cpp files directly included within engine.cpp and win32_platform.cpp for now (instead of their translation unit files). I'll problably wait till much later to offload them. + +Making that first baby step for procedural gen, and proper tile_chunk memory felt pretty good after many vods of stumbling. diff --git a/docs/imgs/handmade_win32_2023-10-11_23-39-57.gif b/docs/imgs/handmade_win32_2023-10-11_23-39-57.gif new file mode 100644 index 0000000..3a3fb96 Binary files /dev/null and b/docs/imgs/handmade_win32_2023-10-11_23-39-57.gif differ diff --git a/project/codegen/engine_postbuild_gen.cpp b/project/codegen/engine_postbuild_gen.cpp index 6834652..ab7407e 100644 --- a/project/codegen/engine_postbuild_gen.cpp +++ b/project/codegen/engine_postbuild_gen.cpp @@ -15,12 +15,16 @@ #undef do_once_end using namespace gen; +#include "platform/platform_module.hpp" #include "platform/grime.hpp" #include "platform/macros.hpp" #include "platform/types.hpp" #include "platform/strings.hpp" #include "platform/platform.hpp" +#include "engine/engine_module.hpp" +#include "engine/input.hpp" +#include "engine/tile_map.hpp" #include "engine/engine.hpp" #include "engine/engine_to_platform_api.hpp" diff --git a/project/engine/engine.cpp b/project/engine/engine.cpp index e31fa78..31e06f4 100644 --- a/project/engine/engine.cpp +++ b/project/engine/engine.cpp @@ -1,7 +1,12 @@ #if INTELLISENSE_DIRECTIVES #include "engine.hpp" +#include "input.hpp" #include "engine_to_platform_api.hpp" + +// TODO(Ed) : This needs to be moved out eventually #include "handmade.hpp" + +#include "tile_map.cpp" #endif NS_ENGINE_BEGIN @@ -43,6 +48,11 @@ struct EngineActions struct EngineState { + hh::Memory game_memory; + + MemoryArena world_arena; + World* world; + f32 auto_snapshot_interval; f32 auto_snapshot_timer; @@ -55,15 +65,15 @@ struct EngineState f32 sample_wave_sine_time; b32 sample_wave_switch; - - hh::Memory game_memory; }; NS_ENGINE_END +// TODO(Ed) : does this need to be here or can it be moved to handmade_engine.cpp? #include "test_samples.cpp" #if Build_Development +// TODO(Ed) : Do a proper header/src pair for this #include "state_and_replay.cpp" // Build_Development #endif @@ -121,7 +131,8 @@ void input_poll_player_actions( InputState* input, hh::PlayerActions* actions ) { DualsensePadState* pad = controller->ds_pad; - actions->jump |= pressed( pad->cross ); + actions->sprint |= pressed( pad->circle ); + actions->jump |= pressed( pad->cross ); actions->player_x_move_analog += pad->stick.left.X.end; actions->player_y_move_analog += pad->stick.left.Y.end; @@ -130,7 +141,8 @@ void input_poll_player_actions( InputState* input, hh::PlayerActions* actions ) { XInputPadState* pad = controller->xpad; - actions->jump |= pressed( pad->A ); + actions->sprint |= pressed( pad->B ); + actions->jump |= pressed( pad->A ); actions->player_x_move_analog += pad->stick.left.X.end; actions->player_y_move_analog += pad->stick.left.Y.end; @@ -139,7 +151,8 @@ void input_poll_player_actions( InputState* input, hh::PlayerActions* actions ) if ( controller->keyboard ) { KeyboardState* keyboard = controller->keyboard; - actions->jump |= pressed( keyboard->space ); + actions->jump |= pressed( keyboard->space ); + actions->sprint |= keyboard->left_shift.ended_down; actions->player_x_move_digital += keyboard->D.ended_down - keyboard->A.ended_down; actions->player_y_move_digital += keyboard->W.ended_down - keyboard->S.ended_down; @@ -151,8 +164,8 @@ void input_poll_player_actions( InputState* input, hh::PlayerActions* actions ) } } -internal void -output_sound( EngineState* state, AudioBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value ) +internal +void output_sound( EngineState* state, AudioBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value ) { s16* sample_out = sound_buffer->samples; for ( s32 sample_index = 0; sample_index < sound_buffer->num_samples; ++ sample_index ) @@ -223,122 +236,55 @@ void draw_rectangle( OffscreenBuffer* buffer } inline -void cannonicalize_coord( World* world, u32* tile_coord, f32* pos_coord ) +void draw_debug_point(OffscreenBuffer* back_buffer, World* world, TileMapPosition pos, f32 red, f32 green, f32 blue) { - f32 tile_size = scast(f32, world->tile_size_in_meters); + TileMap* tile_map = world->tile_map; - // Note(Ed) : World is assumed to be a "torodial topology" - s32 offset = floor( (* pos_coord) / tile_size ); - u32 new_tile_coord = (* tile_coord) + offset; - f32 new_pos_coord = (* pos_coord) - scast(f32, offset) * tile_size; - - assert( new_pos_coord >= 0 ); - assert( new_pos_coord <= tile_size ); - - (* tile_coord) = new_tile_coord; - (* pos_coord) = new_pos_coord; + draw_rectangle(back_buffer, + pos.x * tile_map->tile_meters_to_pixels + world->tile_lower_left_x + scast(f32, pos.tile_x * tile_map->tile_size_in_pixels), + pos.y * tile_map->tile_meters_to_pixels + world->tile_lower_left_y + scast(f32, pos.tile_y * tile_map->tile_size_in_pixels), + (pos.x + 0.1f) * tile_map->tile_meters_to_pixels + world->tile_lower_left_x + scast(f32, pos.tile_x * tile_map->tile_size_in_pixels), + (pos.y + 0.1f) * tile_map->tile_meters_to_pixels + world->tile_lower_left_y + scast(f32, pos.tile_y * tile_map->tile_size_in_pixels), + red, green, blue); } -inline -WorldPosition recannonicalize_position( World* world, WorldPosition pos ) + +internal +void MemoryArena_init( MemoryArena* arena, ssize size, Byte* storage ) { - WorldPosition result = pos; - cannonicalize_coord( world, & result.tile_x, & result.x ); - cannonicalize_coord( world, & result.tile_y, & result.y ); + arena->storage = storage; + arena->size = size; + arena->used = 0; +} + +#define MemoryArena_push_struct( arena, type ) MemoryArena__push_struct( arena ) +template< typename Type > inline +Type* MemoryArena__push_struct( MemoryArena* arena ) +{ + assert( arena != nullptr ); + + ssize type_size = sizeof( Type ); + assert( arena->used + type_size <= arena->size ); + + Type* result = rcast(Type*, arena->storage + arena->used); + arena->used += type_size; + return result; } -inline - u32 TileChunk_tile_value( TileChunk* tile_chunk, World* world, u32 x, u32 y ) +#define MemoryArena_push_array( arena, type, num ) MemoryArena__push_array( arena, num ) +template< typename Type> inline +Type* MemoryArena__push_array( MemoryArena* arena, ssize num ) { - assert( world != nullptr ); - assert( tile_chunk != nullptr ); - assert( x < world->chunk_dimension ); - assert( y < world->chunk_dimension ); - - u32 value = tile_chunk->tiles[ (y * world->chunk_dimension) + x ]; - return value; -} - -// TODO(Ed) : Review if this is needed anymore? -#if 0 -inline -b32 TileChunk_is_tile_empty( TileChunk* tile_chunk, World* world, u32 tile_x, u32 tile_y ) -{ - //assert( tile_chunk != nullptr ); - assert( world != nullptr ); - - // Assume space is occupied if there is bad data - if ( tile_chunk == nullptr ) - return false; - - b32 is_empty = false; - u32 tile_value = TileChunk_tile_value( tile_chunk, world, tile_x, tile_y ); - is_empty = tile_value == 0; - return is_empty; -} -#endif - -inline -TileChunk* World_get_tile_chunk( World* world, s32 tile_chunk_x, s32 tile_chunk_y ) -{ - TileChunk* chunk = nullptr; - - if ( tile_chunk_x >= 0 && tile_chunk_x < scast(s32, world->tile_chunks_num_x) - && tile_chunk_y >= 0 && tile_chunk_y < scast(s32, world->tile_chunks_num_y) ) - { - chunk = & world->tile_chunks[ tile_chunk_y * world->tile_chunks_num_x + tile_chunk_x ]; - } - - return chunk; -} - -inline -TileChunkPosition get_tile_chunk_position_for( World* world, u32 abs_tile_x, u32 abs_tile_y ) -{ - TileChunkPosition chunk_pos {}; - chunk_pos.tile_chunk_x = abs_tile_x >> world->chunk_shift; - chunk_pos.tile_chunk_y = abs_tile_y >> world->chunk_shift; - chunk_pos.tile_x = abs_tile_x & world->chunk_mask; - chunk_pos.tile_y = abs_tile_y & world->chunk_mask; - - return chunk_pos; -} - -internal // TODO(Ed) : Review if he keeps this crap. -u32 piggy_get_tile_value( World* world, u32 tile_x, u32 tile_y ) -{ - assert( world != nullptr ); - - u32 value = 0; - - TileChunkPosition chunk_pos = get_tile_chunk_position_for( world, tile_x, tile_y ); - TileChunk* chunk = World_get_tile_chunk( world, chunk_pos.tile_chunk_x, chunk_pos.tile_chunk_y ); - - if ( chunk ) - value = TileChunk_tile_value( chunk, world, chunk_pos.tile_x, chunk_pos.tile_y ); - return value; -} - -internal -b32 world_is_point_empty( World* world, WorldPosition position ) -{ - assert( world != nullptr ); - - u32 chunk_value = piggy_get_tile_value( world, position.tile_x, position.tile_y ); - b32 is_empty = chunk_value == 0; - return is_empty; -} - -inline -void draw_debug_point(OffscreenBuffer* back_buffer, World* world, WorldPosition pos, f32 red, f32 green, f32 blue) -{ - draw_rectangle(back_buffer, - pos.x * world->tile_meters_to_pixels + world->tile_lower_left_x + scast(f32, pos.tile_x * world->tile_size_in_pixels), - pos.y * world->tile_meters_to_pixels + world->tile_lower_left_y + scast(f32, pos.tile_y * world->tile_size_in_pixels), - (pos.x + 0.1f) * world->tile_meters_to_pixels + world->tile_lower_left_x + scast(f32, pos.tile_x * world->tile_size_in_pixels), - (pos.y + 0.1f) * world->tile_meters_to_pixels + world->tile_lower_left_y + scast(f32, pos.tile_y * world->tile_size_in_pixels), - red, green, blue); + assert( arena != nullptr ); + + ssize mem_amount = sizeof( Type ) * num; + assert( arena->used + mem_amount <= arena->size ); + + Type* result = rcast(Type*, arena->storage + arena->used); + arena->used += mem_amount; + + return result; } Engine_API @@ -348,7 +294,7 @@ void on_module_reload( Memory* memory, platform::ModuleAPI* platfom_api ) } Engine_API -void startup( Memory* memory, platform::ModuleAPI* platform_api ) +void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api ) { #if Build_Development memory->active_snapshot_slot = 1; @@ -380,22 +326,88 @@ void startup( Memory* memory, platform::ModuleAPI* platform_api ) state->sample_wave_sine_time = 0.f; state->renderer_paused = false; - state->game_memory.persistent_size = memory->persistent_size / 2; + state->game_memory.persistent_size = memory->persistent_size / Memory::game_memory_factor; state->game_memory.persistent = rcast(Byte*, memory->persistent) + state->game_memory.persistent_size; - state->game_memory.transient_size = memory->transient_size / 2; + state->game_memory.transient_size = memory->transient_size / Memory::game_memory_factor; state->game_memory.transient = rcast(Byte*, memory->transient) + state->game_memory.transient_size; + + // World setup + { + ssize world_arena_size = memory->engine_persistent_size() - sizeof(EngineState); + Byte* world_arena_storage = memory->persistent + sizeof(EngineState); + MemoryArena_init( & state->world_arena, world_arena_size, world_arena_storage ); + + state->world = MemoryArena_push_struct( & state->world_arena, World); + World* world = state->world; + + TileMap* tile_map = MemoryArena_push_struct( & state->world_arena, TileMap); + world->tile_map = tile_map; + tile_map->chunk_shift = 4; + tile_map->chunk_mask = (1 << tile_map->chunk_shift) - 1; + tile_map->chunk_dimension = (1 << tile_map->chunk_shift); + + tile_map->tile_chunks_num_x = 128; + tile_map->tile_chunks_num_y = 128; + + tile_map->chunks = MemoryArena_push_array( & state->world_arena, TileChunk, tile_map->tile_chunks_num_x * tile_map->tile_chunks_num_y ); + + for ( s32 y = 0; y < tile_map->tile_chunks_num_y; ++ y ) + { + for ( s32 x = 0; x < tile_map->tile_chunks_num_x; ++ x ) + { + ssize num_tiles = tile_map->chunk_dimension * tile_map->chunk_dimension; + tile_map->chunks[ (y * tile_map->tile_chunks_num_x) + x ].tiles = MemoryArena_push_array( & state->world_arena, u32, num_tiles ); + } + } + + //TileChunk temp_chunk; + //temp_chunk.tiles = rcast( u32*, & temp_tiles ); + //tile_map->chunks = & temp_chunk; + + tile_map->tile_size_in_meters = 1.4f; + tile_map->tile_size_in_pixels = 85; + tile_map->tile_meters_to_pixels = scast(f32, tile_map->tile_size_in_pixels) / tile_map->tile_size_in_meters; + + f32 tile_size_in_pixels = scast(f32, tile_map->tile_size_in_pixels); + + world->tile_lower_left_x = -( tile_size_in_pixels * 0.5f); + world->tile_lower_left_y = +( tile_size_in_pixels * 0.25f) + scast(f32, back_buffer->height); + + u32 tiles_per_screen_x = 17; + u32 tiles_per_screen_y = 9; + for ( u32 screen_y = 0; screen_y < 32; ++ screen_y ) + { + for ( u32 screen_x = 0; screen_x < 32; ++ screen_x ) + { + for (u32 tile_y = 0; tile_y < tiles_per_screen_y; ++ tile_y ) + { + for ( u32 tile_x = 0; tile_x < tiles_per_screen_x; ++ tile_x ) + { + u32 abs_tile_x = screen_x * tiles_per_screen_x + tile_x; + u32 abs_tile_y = screen_y * tiles_per_screen_y + tile_y; + 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, tile_value ); + } + } + } + } + } + hh::GameState* game_state = rcast( hh::GameState*, state->game_memory.persistent ); assert( sizeof(hh::GameState) <= state->game_memory.persistent_size ); hh::PlayerState* player = & game_state->player_state; - player->position.tile_x = 3; - player->position.tile_y = 3; + player->position.tile_x = 4; + player->position.tile_y = 4; player->position.x = 0.f; player->position.y = 0.f; player->mid_jump = false; player->jump_time = 0.f; + + player->height = 1.4f; + player->width = player->height * 0.7f; } Engine_API @@ -549,63 +561,21 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back f32 x_offset_f = scast(f32, state->x_offset); f32 y_offset_f = scast(f32, state->y_offset); - constexpr s32 tile_map_num_x = 256; - constexpr s32 tile_map_num_y = 256; - - // tiles_XY - u32 temp_tiles [tile_map_num_y][tile_map_num_x] = { - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - }; - - World world; - world.chunk_shift = 8; - world.chunk_mask = (1 << world.chunk_shift) - 1; - world.chunk_dimension = 256; - - world.tile_chunks_num_x = 1; - world.tile_chunks_num_y = 1; - - TileChunk temp_chunk; - temp_chunk.tiles = rcast( u32*, & temp_tiles ); - world.tile_chunks = & temp_chunk; - - world.tile_size_in_meters = 1.4f; - world.tile_size_in_pixels = 85; - world.tile_meters_to_pixels = scast(f32, world.tile_size_in_pixels) / world.tile_size_in_meters; - - f32 tile_size_in_pixels = scast(f32, world.tile_size_in_pixels); - - f32 scale = 85; - - world.tile_lower_left_x = -( tile_size_in_pixels * 0.5f); - world.tile_lower_left_y = +( tile_size_in_pixels * 0.25f) + scast(f32, back_buffer->height); - - player->height = 1.4f; - player->width = player->height * 0.7f; - + World* world = state->world; + TileMap* tile_map = world->tile_map; + + f32 tile_size_in_pixels = scast(f32, tile_map->tile_size_in_pixels); f32 player_half_width = player->width / 2.f; f32 player_quarter_height = player->height / 4.f; input_poll_player_actions( input, & player_actions ); { - f32 move_speed = 4.f; + f32 move_speed = 2.f; + + if ( player_actions.sprint ) + { + move_speed = 6.f; + } f32 new_player_pos_x = player->position.x; f32 new_player_pos_y = player->position.y; @@ -623,53 +593,52 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back b32 valid_new_pos = true; { - WorldPosition test_pos = { + TileMapPosition test_pos = { new_player_pos_x, new_player_pos_y, player->position.tile_x, player->position.tile_y }; - test_pos = recannonicalize_position( & world, test_pos ); + test_pos = recannonicalize_position( tile_map, test_pos ); // TODO(Ed) : Need a delta-function that auto-reconnonicalizes. - WorldPosition test_pos_nw { - new_player_pos_x - player_half_width, new_player_pos_y - player_quarter_height, + 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 }; - test_pos_nw = recannonicalize_position( & world, test_pos_nw ); - valid_new_pos &= world_is_point_empty( & world, 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 ); - WorldPosition test_pos_ne { - new_player_pos_x + player_half_width, new_player_pos_y - player_quarter_height, + 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 }; - test_pos_ne = recannonicalize_position( & world, test_pos_ne ); - valid_new_pos &= world_is_point_empty( & world, 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 ); - WorldPosition test_pos_sw { + TileMapPosition test_pos_sw { new_player_pos_x - player_half_width, new_player_pos_y, player->position.tile_x, player->position.tile_y }; - test_pos_sw = recannonicalize_position( & world, test_pos_sw ); - valid_new_pos &= world_is_point_empty( & world, 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 ); - WorldPosition test_pos_se { + TileMapPosition test_pos_se { new_player_pos_x + player_half_width, new_player_pos_y, player->position.tile_x, player->position.tile_y }; - test_pos_se = recannonicalize_position( & world, test_pos_se ); - valid_new_pos &= world_is_point_empty( & world, 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 ); } if ( valid_new_pos ) { - WorldPosition new_pos = { + TileMapPosition new_pos = { new_player_pos_x, new_player_pos_y, player->position.tile_x, player->position.tile_y }; - player->position = recannonicalize_position( & world, new_pos ); + player->position = recannonicalize_position( tile_map, new_pos ); } - if ( player->jump_time > 0.f ) { player->jump_time -= delta_time; @@ -693,10 +662,9 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back , 1.f, 0.24f, 0.24f ); -// Scrolling shitshow -#if 1 - f32 center_x = 0.5f * scast(f32, back_buffer->width); - f32 center_y = 0.5f * scast(f32, back_buffer->height); +// Scrolling + f32 screen_center_x = 0.5f * scast(f32, back_buffer->width); + f32 screen_center_y = 0.5f * scast(f32, back_buffer->height); for ( s32 relative_row = -10; relative_row < +10; ++ relative_row ) { @@ -705,7 +673,7 @@ 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 tileID = piggy_get_tile_value( & world, col, row ); + u32 tileID = TileMap_get_tile_value( tile_map, col, row ); f32 color[3] = { 0.15f, 0.15f, 0.15f }; if ( tileID == 1 ) @@ -722,14 +690,17 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back color[2] = 0.3f; } - f32 min_x = center_x + scast(f32, relative_col) * tile_size_in_pixels; - f32 min_y = center_y - scast(f32, relative_row) * tile_size_in_pixels; - f32 max_x = min_x + tile_size_in_pixels; - f32 max_y = min_y - tile_size_in_pixels; + f32 center_x = screen_center_x + scast(f32, relative_col) * tile_size_in_pixels - player->position.x * tile_map->tile_meters_to_pixels; + f32 center_y = screen_center_y - scast(f32, relative_row) * tile_size_in_pixels + player->position.y * tile_map->tile_meters_to_pixels; + + f32 min_x = center_x - tile_size_in_pixels * 0.5f; + f32 min_y = center_y - tile_size_in_pixels * 0.5f; + f32 max_x = center_x + tile_size_in_pixels * 0.5f; + f32 max_y = center_y + tile_size_in_pixels * 0.5f; draw_rectangle( back_buffer - , min_x, max_y - , max_x, min_y + , min_x, min_y + , max_x, max_y , color[0], color[1], color[2] ); } } @@ -739,88 +710,18 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back f32 player_green = 0.7f; f32 player_blue = 0.3f; - f32 player_tile_x_offset = center_x + scast(f32, player->position.tile_x) * world.tile_meters_to_pixels; - f32 player_tile_y_offset = center_y - scast(f32, player->position.tile_y) * world.tile_meters_to_pixels; + f32 player_tile_x_offset = screen_center_x + scast(f32, player->position.tile_x) * tile_map->tile_meters_to_pixels + player->position.x * tile_map->tile_meters_to_pixels; + f32 player_tile_y_offset = screen_center_y - scast(f32, player->position.tile_y) * tile_map->tile_meters_to_pixels + player->position.y * tile_map->tile_meters_to_pixels; - f32 player_screen_pos_x = center_x + player->position.x * world.tile_meters_to_pixels; - f32 player_screen_pos_y = center_y - player->position.y * world.tile_meters_to_pixels; + f32 player_screen_pos_x = screen_center_x; + f32 player_screen_pos_y = screen_center_y; // player_min_x = player_tile_x_offset - player_half_width * world; draw_rectangle( back_buffer - , player_screen_pos_x - player_half_width * world.tile_meters_to_pixels, player_screen_pos_y - player->height * world.tile_meters_to_pixels - , player_screen_pos_x + player_half_width * world.tile_meters_to_pixels, player_screen_pos_y + , player_screen_pos_x - player_half_width * tile_map->tile_meters_to_pixels, player_screen_pos_y - player->height * tile_map->tile_meters_to_pixels + , player_screen_pos_x + player_half_width * tile_map->tile_meters_to_pixels, player_screen_pos_y , player_red, player_green, player_blue ); -#endif - -// Non-scrolling screen -#if 0 - // Draw TileChunk - for ( u32 row = 0; row < 9; ++ row ) - { - for ( u32 col = 0; col < 16; ++ col ) - { - u32 tileID = piggy_get_tile_value( & world, col, row ); - f32 color[3] = { 0.15f, 0.15f, 0.15f }; - - if ( tileID == 1 ) - { - color[0] = 0.22f; - color[1] = 0.22f; - color[2] = 0.22f; - } - - if ( row == player->position.tile_y && col == player->position.tile_x ) - { - color[0] = 0.44f; - color[1] = 0.3f; - color[2] = 0.3f; - } - - #if 0 - // Was able to flip Y properly but not get the center alignemnt with the world.tile_lower_left that I wanted.. - f32 min_x = world.tile_lower_left_x + scast(f32, col) * tile_size_in_pixels; - f32 min_y = scast(f32, row) * tile_size_in_pixels; - f32 max_x = min_x + tile_size_in_pixels; - f32 max_y = min_y + tile_size_in_pixels; - - draw_rectangle( back_buffer - , min_x, min_y - , max_x, max_y - //, min_x, max_y - //, max_x, min_y - , color[0], color[1], color[2] ); - #else - f32 min_x = world.tile_lower_left_x + scast(f32, col) * tile_size_in_pixels; - f32 min_y = world.tile_lower_left_y - scast(f32, row) * tile_size_in_pixels; - f32 max_x = min_x + tile_size_in_pixels; - f32 max_y = min_y - tile_size_in_pixels; - - draw_rectangle( back_buffer - , min_x, max_y - , max_x, min_y - , color[0], color[1], color[2] ); - #endif - } - } - - // Player - f32 player_red = 0.7f; - f32 player_green = 0.7f; - f32 player_blue = 0.3f; - - f32 player_tile_x_offset = scast(f32, player->position.tile_x * world.tile_size_in_pixels); - f32 player_tile_y_offset = -scast(f32, player->position.tile_y * world.tile_size_in_pixels); - - f32 player_screen_pos_x = world.tile_lower_left_x + player_tile_x_offset + player->position.x * world.tile_meters_to_pixels; - f32 player_screen_pos_y = world.tile_lower_left_y + player_tile_y_offset - player->position.y * world.tile_meters_to_pixels; - - draw_rectangle( back_buffer - , player_screen_pos_x - player_half_width * world.tile_meters_to_pixels, player_screen_pos_y - player->height * world.tile_meters_to_pixels - , player_screen_pos_x + player_half_width * world.tile_meters_to_pixels, player_screen_pos_y - , player_red, player_green, player_blue ); -#endif - // Auto-Snapshot percent bar if (1) diff --git a/project/engine/engine.hpp b/project/engine/engine.hpp index 0ad6644..d0bc42d 100644 --- a/project/engine/engine.hpp +++ b/project/engine/engine.hpp @@ -6,25 +6,12 @@ #if INTELLISENSE_DIRECTIVES #include "platform/platform.hpp" -#endif - -#define NS_ENGINE_BEGIN namespace engine { -#define NS_ENGINE_END } - -#ifndef Engine_API -// The build system is reponsible for defining this API macro for exporting symbols. -# define Engine_API +#include "engine_module.hpp" +#include "tile_map.hpp" #endif NS_ENGINE_BEGIN -enum ReplayMode : s32 -{ - ReplayMode_Off, - ReplayMode_Record, - ReplayMode_Playback -}; - struct Clocks { // TODO(Ed) : Clock values... @@ -45,23 +32,49 @@ struct MemorySnapshot u64 age; }; + +enum ReplayMode : s32 +{ + ReplayMode_Off, + ReplayMode_Record, + ReplayMode_Playback +}; + +struct ReplayData +{ + static constexpr + s32 Num_Snapshot_Slots = 3; + // Abuse RAM to store snapshots of the Engine or Game state. + MemorySnapshot snapshots[ Num_Snapshot_Slots ]; + s32 active_snapshot_slot; + + // Recording and playback info is the same for either engine or game. + + ReplayMode replay_mode; + platform::File active_input_replay_file; + + // Engine-wide recording & playback loop. + s32 engine_loop_active; + s32 game_loop_active; +}; + struct Memory { // All memory for the engine is required to be zero initialized. // Wiped on shutdown - void* persistent; - u64 persistent_size; + Byte* persistent; + ssize persistent_size; // Wiped on a per-frame basis // void* Frame; // u64 FrameSize; // Wiped whenever the engine wants to? - void* transient; - u64 transient_size; + Byte* transient; + ssize transient_size; - // TODO(Ed) : Move this crap to state & replay archive definitions? + // TODO(Ed) : Move this to state & replay archive definitions? #if Build_Development static constexpr s32 Num_Snapshot_Slots = 3; @@ -77,14 +90,32 @@ struct Memory // Engine-wide recording & playback loop. s32 engine_loop_active; s32 game_loop_active; + + //ReplayData replay; #endif - - u64 total_size() + + // The game will have 1/4 of persistent's memory available ot it. + static constexpr + ssize game_memory_factor = 4; + + ssize engine_persistent_size() + { + return persistent_size - persistent_size / game_memory_factor; + } + + ssize total_size() { return persistent_size + transient_size; } }; +struct MemoryArena +{ + Byte* storage; + ssize size; + ssize used; +}; + struct OffscreenBuffer { void* memory; // Lets use directly mess with the "pixel's memory buffer" @@ -103,238 +134,13 @@ struct AudioBuffer s32 num_samples; }; -struct DigitalBtn -{ - s32 half_transitions; - b32 ended_down; -}; - -struct AnalogAxis -{ - f32 start; - f32 end; - f32 min; - f32 max; - - // Platform doesn't provide this, we process in the engine layer. - f32 average; -}; - -struct AnalogStick -{ - AnalogAxis X; - AnalogAxis Y; -}; - -union KeyboardState -{ - DigitalBtn keys[12]; - struct { - DigitalBtn _1; - DigitalBtn _2; - DigitalBtn _3; - DigitalBtn _4; - - DigitalBtn Q; - DigitalBtn E; - DigitalBtn W; - DigitalBtn A; - DigitalBtn S; - DigitalBtn D; - DigitalBtn K; - DigitalBtn L; - DigitalBtn escape; - DigitalBtn backspace; - DigitalBtn up; - DigitalBtn down; - DigitalBtn left; - DigitalBtn right; - DigitalBtn space; - DigitalBtn pause; - DigitalBtn left_alt; - DigitalBtn right_alt; - DigitalBtn right_shift; - DigitalBtn left_shift; - }; -}; - -struct MousesState -{ - DigitalBtn left; - DigitalBtn middle; - DigitalBtn right; - - AnalogAxis X; - AnalogAxis Y; - AnalogAxis vertical_wheel; - AnalogAxis horizontal_wheel; -}; - -struct XInputPadState -{ - struct - { - AnalogStick left; - AnalogStick right; - } stick; - - AnalogAxis left_trigger; - AnalogAxis right_trigger; - - union { - DigitalBtn btns[14]; - struct { - struct { - DigitalBtn up; - DigitalBtn down; - DigitalBtn left; - DigitalBtn right; - } dpad; - DigitalBtn A; - DigitalBtn B; - DigitalBtn X; - DigitalBtn Y; - DigitalBtn back; - DigitalBtn start; - DigitalBtn left_shoulder; - DigitalBtn right_shoulder; - }; - }; -}; - -struct DualsensePadState -{ - struct - { - AnalogStick left; - AnalogStick right; - } stick; - - AnalogAxis L2; - AnalogAxis R2; - - union { - DigitalBtn btns[14]; - struct { - struct { - DigitalBtn up; - DigitalBtn down; - DigitalBtn left; - DigitalBtn right; - } dpad; - DigitalBtn cross; - DigitalBtn circle; - DigitalBtn square; - DigitalBtn triangle; - DigitalBtn share; - DigitalBtn options; - DigitalBtn L1; - DigitalBtn R1; - }; - }; -}; - -struct ControllerState -{ - KeyboardState* keyboard; - MousesState* mouse; - XInputPadState* xpad; - DualsensePadState* ds_pad; -}; - -struct ControllerStateSnapshot -{ - KeyboardState keyboard; - MousesState mouse; - XInputPadState xpad; - DualsensePadState ds_pad; -}; - -struct InputState -{ - ControllerState controllers[4]; -}; - -struct InputStateSnapshot -{ - ControllerStateSnapshot controllers[4]; -}; - -using InputBindCallback = void( void* ); -using InputBindCallback_DigitalBtn = void( engine::DigitalBtn* button ); -using InputBindCallback_AnalogAxis = void( engine::AnalogAxis* axis ); -using InputBindCallback_AnalogStick = void( engine::AnalogStick* stick ); - -struct InputMode -{ - InputBindCallback* binds; - s32 num_binds; -}; - -void input_mode_pop( InputMode* mode ); -void input_mode_pop( InputMode* mode ); - -#if 0 -struct RecordedInput -{ - s32 num; - InputState* stream; -}; -#endif - -struct TileChunk -{ - u32* tiles; -}; - struct World { // TODO(Ed) : Remove f32 tile_lower_left_x; f32 tile_lower_left_y; - - u32 chunk_shift; - u32 chunk_mask; - - f32 tile_size_in_meters; - s32 tile_size_in_pixels; - f32 tile_meters_to_pixels; - - u32 chunk_dimension; - - // TODO(Ed) : Beginner's sparseness - s32 tile_chunks_num_x; - s32 tile_chunks_num_y; - - TileChunk* tile_chunks; -}; - -/* - This is a "backend" transient datatype for handling lookup of tile data from "chunks" of tiles. -*/ -struct TileChunkPosition -{ - u32 tile_chunk_x; - u32 tile_chunk_y; - - // "Chunk-relative (x, y) - - u32 tile_x; - u32 tile_y; -}; - -struct WorldPosition -{ - // TODO(Ed) : Should this be from the center of the tile? - - f32 x; - f32 y; - - // "World-relative (x, y), AKA: Absolute Position, etc - - u32 tile_x; - u32 tile_y; + TileMap* tile_map; }; NS_ENGINE_END diff --git a/project/engine/engine_game_api.hpp b/project/engine/engine_game_api.hpp deleted file mode 100644 index a08c78e..0000000 --- a/project/engine/engine_game_api.hpp +++ /dev/null @@ -1,3 +0,0 @@ -/* - This represents the API only accessible to the engine to fullfill for the game module. -*/ diff --git a/project/engine/engine_module.hpp b/project/engine/engine_module.hpp new file mode 100644 index 0000000..6f655c6 --- /dev/null +++ b/project/engine/engine_module.hpp @@ -0,0 +1,14 @@ +/* +This header exists for base shared definitions across engine files. + +For now what every file needs is at least the namespace macros. +*/ +#pragma once + +#define NS_ENGINE_BEGIN namespace engine { +#define NS_ENGINE_END } + +#ifndef Engine_API +// The build system is reponsible for defining this API macro for exporting symbols. +# define Engine_API +#endif diff --git a/project/engine/engine_to_platform_api.hpp b/project/engine/engine_to_platform_api.hpp index 3c0f52b..b7f665a 100644 --- a/project/engine/engine_to_platform_api.hpp +++ b/project/engine/engine_to_platform_api.hpp @@ -2,11 +2,14 @@ This represents the API only accessible to the platform layer to fullfill for the engine layer. */ #pragma once +#if INTELLISENSE_DIRECTIVES +#include "engine_module.hpp" +#endif NS_ENGINE_BEGIN using OnModuleRelaodFn = void( Memory* memory, platform::ModuleAPI* platform_api ); -using StartupFn = void( Memory* memory, platform::ModuleAPI* platform_api ); +using StartupFn = void( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* platform_api ); using ShutdownFn = void( Memory* memory, platform::ModuleAPI* platform_api ); // Needs a contextual reference to four things: diff --git a/project/engine/input.cpp b/project/engine/input.cpp new file mode 100644 index 0000000..e69de29 diff --git a/project/engine/input.hpp b/project/engine/input.hpp new file mode 100644 index 0000000..87395a7 --- /dev/null +++ b/project/engine/input.hpp @@ -0,0 +1,178 @@ +#pragma once + +#if INTELLISENSE_DIRECTIVES +#include "platform/platform.hpp" +#include "engine_module.hpp" +#endif + +NS_ENGINE_BEGIN + +struct DigitalBtn +{ + s32 half_transitions; + b32 ended_down; +}; + +struct AnalogAxis +{ + f32 start; + f32 end; + f32 min; + f32 max; + + // Platform doesn't provide this, we process in the engine layer. + f32 average; +}; + +struct AnalogStick +{ + AnalogAxis X; + AnalogAxis Y; +}; + +union KeyboardState +{ + DigitalBtn keys[12]; + struct { + DigitalBtn _1; + DigitalBtn _2; + DigitalBtn _3; + DigitalBtn _4; + + DigitalBtn Q; + DigitalBtn E; + DigitalBtn W; + DigitalBtn A; + DigitalBtn S; + DigitalBtn D; + DigitalBtn K; + DigitalBtn L; + DigitalBtn escape; + DigitalBtn backspace; + DigitalBtn up; + DigitalBtn down; + DigitalBtn left; + DigitalBtn right; + DigitalBtn space; + DigitalBtn pause; + DigitalBtn left_alt; + DigitalBtn right_alt; + DigitalBtn right_shift; + DigitalBtn left_shift; + }; +}; + +struct MousesState +{ + DigitalBtn left; + DigitalBtn middle; + DigitalBtn right; + + AnalogAxis X; + AnalogAxis Y; + AnalogAxis vertical_wheel; + AnalogAxis horizontal_wheel; +}; + +struct XInputPadState +{ + struct + { + AnalogStick left; + AnalogStick right; + } stick; + + AnalogAxis left_trigger; + AnalogAxis right_trigger; + + union { + DigitalBtn btns[14]; + struct { + struct { + DigitalBtn up; + DigitalBtn down; + DigitalBtn left; + DigitalBtn right; + } dpad; + DigitalBtn A; + DigitalBtn B; + DigitalBtn X; + DigitalBtn Y; + DigitalBtn back; + DigitalBtn start; + DigitalBtn left_shoulder; + DigitalBtn right_shoulder; + }; + }; +}; + +struct DualsensePadState +{ + struct + { + AnalogStick left; + AnalogStick right; + } stick; + + AnalogAxis L2; + AnalogAxis R2; + + union { + DigitalBtn btns[14]; + struct { + struct { + DigitalBtn up; + DigitalBtn down; + DigitalBtn left; + DigitalBtn right; + } dpad; + DigitalBtn cross; + DigitalBtn circle; + DigitalBtn square; + DigitalBtn triangle; + DigitalBtn share; + DigitalBtn options; + DigitalBtn L1; + DigitalBtn R1; + }; + }; +}; + +struct ControllerState +{ + KeyboardState* keyboard; + MousesState* mouse; + XInputPadState* xpad; + DualsensePadState* ds_pad; +}; + +struct ControllerStateSnapshot +{ + KeyboardState keyboard; + MousesState mouse; + XInputPadState xpad; + DualsensePadState ds_pad; +}; + +struct InputState +{ + ControllerState controllers[4]; +}; + +struct InputStateSnapshot +{ + ControllerStateSnapshot controllers[4]; +}; + +using InputBindCallback = void( void* ); +using InputBindCallback_DigitalBtn = void( engine::DigitalBtn* button ); +using InputBindCallback_AnalogAxis = void( engine::AnalogAxis* axis ); +using InputBindCallback_AnalogStick = void( engine::AnalogStick* stick ); + +struct InputMode +{ + InputBindCallback* binds; + s32 num_binds; +}; + +NS_ENGINE_END diff --git a/project/engine/tile_map.cpp b/project/engine/tile_map.cpp new file mode 100644 index 0000000..395da9e --- /dev/null +++ b/project/engine/tile_map.cpp @@ -0,0 +1,131 @@ +#if INTELLISENSE_DIRECTIVES +#include "tile_map.hpp" +#endif + +NS_ENGINE_BEGIN + +inline +void cannonicalize_coord( TileMap* tile_map, u32* tile_coord, f32* pos_coord ) +{ + assert( tile_map != nullptr ); + assert( tile_coord != nullptr ); + + f32 tile_size = scast(f32, tile_map->tile_size_in_meters); + + // Note(Ed) : World is assumed to be a "torodial topology" + s32 offset = round( (* pos_coord) / tile_size ); + u32 new_tile_coord = (* tile_coord) + offset; + f32 new_pos_coord = (* pos_coord) - scast(f32, offset) * tile_size; + + assert( new_pos_coord >= -tile_size * 0.5f ); + assert( new_pos_coord <= tile_size * 0.5f ); + + (* tile_coord) = new_tile_coord; + (* pos_coord) = new_pos_coord; +} + +inline +TileMapPosition recannonicalize_position( TileMap* tile_map, TileMapPosition pos ) +{ + assert( tile_map != nullptr ); + + TileMapPosition result = pos; + cannonicalize_coord( tile_map, & result.tile_x, & result.x ); + cannonicalize_coord( tile_map, & result.tile_y, & result.y ); + return result; +} + +inline +u32 TileChunk_get_tile_value( TileChunk* tile_chunk, TileMap* tile_map, u32 x, u32 y ) +{ + assert( tile_map != nullptr ); + assert( tile_chunk != nullptr ); + assert( x < tile_map->chunk_dimension ); + assert( y < tile_map->chunk_dimension ); + + u32 value = tile_chunk->tiles[ (y * tile_map->chunk_dimension) + x ]; + return value; +} + +inline +void TileChunk_set_tile_value( TileChunk* tile_chunk, TileMap* tile_map, u32 x, u32 y , u32 value) +{ + assert( tile_map != nullptr ); + assert( tile_chunk != nullptr ); + assert( x < tile_map->chunk_dimension ); + assert( y < tile_map->chunk_dimension ); + + tile_chunk->tiles[ (y * tile_map->chunk_dimension) + x ] = value; +} + +inline +TileChunk* TileMap_get_chunk( TileMap* tile_map, s32 tile_chunk_x, s32 tile_chunk_y ) +{ + TileChunk* chunk = nullptr; + + if ( tile_chunk_x >= 0 && tile_chunk_x < scast(s32, tile_map->tile_chunks_num_x) + && tile_chunk_y >= 0 && tile_chunk_y < scast(s32, tile_map->tile_chunks_num_y) ) + { + chunk = & tile_map->chunks[ tile_chunk_y * tile_map->tile_chunks_num_x + tile_chunk_x ]; + } + + return chunk; +} + +inline +TileChunkPosition get_tile_chunk_position_for( TileMap* tile_map, u32 abs_tile_x, u32 abs_tile_y ) +{ + assert( tile_map != nullptr ); + + TileChunkPosition chunk_pos {}; + chunk_pos.tile_chunk_x = abs_tile_x >> tile_map->chunk_shift; + chunk_pos.tile_chunk_y = abs_tile_y >> tile_map->chunk_shift; + chunk_pos.tile_x = abs_tile_x & tile_map->chunk_mask; + chunk_pos.tile_y = abs_tile_y & tile_map->chunk_mask; + + return chunk_pos; +} + +u32 TileMap_get_tile_value( TileMap* tile_map, u32 tile_x, u32 tile_y ) +{ + assert( tile_map != nullptr ); + + u32 value = 0; + + TileChunkPosition chunk_pos = get_tile_chunk_position_for( tile_map, tile_x, tile_y ); + TileChunk* chunk = TileMap_get_chunk( tile_map, chunk_pos.tile_chunk_x, chunk_pos.tile_chunk_y ); + + if ( chunk ) + value = TileChunk_get_tile_value( chunk, tile_map, chunk_pos.tile_x, chunk_pos.tile_y ); + 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 ); + b32 is_empty = chunk_value == 0; + return is_empty; +} + +internal +void TileMap_set_tile_value( MemoryArena* arena, TileMap* tile_map, u32 abs_tile_x, u32 abs_tile_y, u32 value ) +{ + TileChunkPosition chunk_pos = get_tile_chunk_position_for( tile_map, abs_tile_x, abs_tile_y ); + TileChunk* chunk = TileMap_get_chunk( tile_map, chunk_pos.tile_chunk_x, chunk_pos.tile_chunk_y ); + +#if 0 + if ( chunk == nullptr ) + { + + } +#else + assert( chunk != nullptr ); +#endif + + TileChunk_set_tile_value( chunk, tile_map, chunk_pos.tile_x, chunk_pos.tile_y, value ); +} + +NS_ENGINE_END diff --git a/project/engine/tile_map.hpp b/project/engine/tile_map.hpp new file mode 100644 index 0000000..ecf1544 --- /dev/null +++ b/project/engine/tile_map.hpp @@ -0,0 +1,65 @@ +/* + + +*/ +#pragma once + +#if INTELLISENSE_DIRECTIVES +#include "platform/platform.hpp" +#include "engine_module.hpp" +#endif + +NS_ENGINE_BEGIN + +struct TileChunk +{ + u32* tiles; +}; + +/* + This is a "backend" transient datatype for handling lookup of tile data from "chunks" of tiles. +*/ +struct TileChunkPosition +{ + u32 tile_chunk_x; + u32 tile_chunk_y; + + // "Chunk-relative (x, y) + + u32 tile_x; + u32 tile_y; +}; + +struct TileMap +{ + // TODO(Ed) : Beginner's sparseness + s32 tile_chunks_num_x; + s32 tile_chunks_num_y; + + s32 tile_size_in_pixels; + f32 tile_size_in_meters; + f32 tile_meters_to_pixels; + + u32 chunk_shift; + u32 chunk_mask; + u32 chunk_dimension; + + TileChunk* chunks; +}; + +struct TileMapPosition +{ + // TODO(Ed) : Should this be from the center of the tile? + + f32 x; + f32 y; + + // "World-relative (x, y), AKA: Absolute Position + // Fixed point tile locations. + // High bits are the tile-chunk index, and the low bits are the tile index in the chunk. + + u32 tile_x; + u32 tile_y; +}; + +NS_ENGINE_END diff --git a/project/gen/engine_symbol_table.hpp b/project/gen/engine_symbol_table.hpp index f22d898..9c406a6 100644 --- a/project/gen/engine_symbol_table.hpp +++ b/project/gen/engine_symbol_table.hpp @@ -6,7 +6,7 @@ NS_ENGINE_BEGIN constexpr Str const symbol_on_module_load = str_ascii("?on_module_reload@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z"); constexpr -Str const symbol_startup = str_ascii("?startup@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z"); +Str const symbol_startup = str_ascii("?startup@engine@@YAXPEAUOffscreenBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@@Z"); constexpr Str const symbol_shutdown = str_ascii("?shutdown@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z"); constexpr diff --git a/project/handmade.hpp b/project/handmade.hpp index 65ccebe..f058284 100644 --- a/project/handmade.hpp +++ b/project/handmade.hpp @@ -13,15 +13,15 @@ struct Memory // Subscection of engine memory for the game to use. void* persistent; - u64 persistent_size; + ssize persistent_size; // void* Frame; // u64 FrameSize; void* transient; - u64 transient_size; + ssize transient_size; - u64 total_size() + ssize total_size() { return persistent_size + transient_size; } @@ -74,12 +74,8 @@ struct PlayerState f32 width; f32 height; - // TODO(Ed) : Should this be canonical position now? - //f32 pos_x; - //f32 pos_y; - - engine::WorldPosition position; - + engine::TileMapPosition position; + b32 mid_jump; f32 jump_time; }; @@ -91,7 +87,8 @@ struct PlayerActions f32 player_x_move_analog; f32 player_y_move_analog; - b32 jump = false; + b32 sprint; + b32 jump; }; struct GameState diff --git a/project/handmade_engine.cpp b/project/handmade_engine.cpp index 7f0a77b..72d03b0 100644 --- a/project/handmade_engine.cpp +++ b/project/handmade_engine.cpp @@ -7,6 +7,7 @@ Handmade Engine Translation Unit #include // TEMP #include // TEMP +#include "platform/platform_module.hpp" #include "platform/grime.hpp" #include "platform/macros.hpp" #include "platform/generics.hpp" @@ -17,10 +18,14 @@ Handmade Engine Translation Unit #include "platform/context.hpp" #include "platform/platform.hpp" +#include "engine_module.hpp" +#include "input.hpp" +#include "tile_map.hpp" #include "engine.hpp" #include "engine_to_platform_api.hpp" // Game layer headers #include "handmade.hpp" +#include "tile_map.cpp" #include "engine.cpp" diff --git a/project/handmade_win32.cpp b/project/handmade_win32.cpp index 69dc710..54facb1 100644 --- a/project/handmade_win32.cpp +++ b/project/handmade_win32.cpp @@ -7,6 +7,7 @@ Handmade Win32 Platform Translation Unit #include // TEMP #include // TEMP +#include "platform_module.hpp" #include "grime.hpp" #include "macros.hpp" #include "generics.hpp" @@ -18,6 +19,9 @@ Handmade Win32 Platform Translation Unit #include "platform.hpp" // Engine layer headers +#include "engine/engine_module.hpp" +#include "engine/input.hpp" +#include "engine/tile_map.hpp" #include "engine/engine.hpp" #include "engine/engine_to_platform_api.hpp" #include "gen/engine_symbol_table.hpp" diff --git a/project/platform/intrinsics.hpp b/project/platform/intrinsics.hpp index 98003a7..3ab532b 100644 --- a/project/platform/intrinsics.hpp +++ b/project/platform/intrinsics.hpp @@ -22,7 +22,7 @@ s32 floor( f32 value ) inline s32 round( f32 value ) { - s32 result = scast(s32, value + 0.5f); + s32 result = scast(s32, roundf( value )); return result; } diff --git a/project/platform/macros.hpp b/project/platform/macros.hpp index 005c593..6587951 100644 --- a/project/platform/macros.hpp +++ b/project/platform/macros.hpp @@ -15,16 +15,7 @@ #define rcast( type, value ) reinterpret_cast< type >( value ) #define scast( type, value ) static_cast< type >( value ) -#define do_once() \ - do \ - { \ - local_persist \ - bool done = false; \ - if ( done ) \ - return; \ - done = true; \ - } \ - while(0) +#define do_once() for ( local_persist b32 once = true; once; once = false ) #define do_once_start \ do \ diff --git a/project/platform/platform.hpp b/project/platform/platform.hpp index 2253e15..439b140 100644 --- a/project/platform/platform.hpp +++ b/project/platform/platform.hpp @@ -10,9 +10,9 @@ #if INTELLISENSE_DIRECTIVES // TODO(Ed) : REMOVE THESE WHEN CASEY GETS TO THEM -#include // TODO : Implement math ourselves #include // TODO : Implement output logging ourselves +#include "platform_module.hpp" #include "grime.hpp" #include "macros.hpp" #include "generics.hpp" @@ -23,9 +23,6 @@ #include "context.hpp" #endif -#define NS_PLATFORM_BEGIN namespace platform { -#define NS_PLATFORM_END } - NS_PLATFORM_BEGIN // On-Demand platform interface. @@ -121,6 +118,8 @@ struct ModuleAPI }; #if Build_Development +// TODO(Ed): This can't be done this way, we need a separate interface for other modules to use this. +// (At least, we need to hookup the symbols statically or at runtime somehow, and right now the only thing that does is the module api passthrough via the Engine API) void impl_congrats( char const* message ); bool impl_ensure( bool condition, char const* message ); void impl_fatal( char const* message ); diff --git a/project/platform/platform_module.hpp b/project/platform/platform_module.hpp new file mode 100644 index 0000000..cf59511 --- /dev/null +++ b/project/platform/platform_module.hpp @@ -0,0 +1,4 @@ +#pragma once + +#define NS_PLATFORM_BEGIN namespace platform { +#define NS_PLATFORM_END } diff --git a/project/platform/types.hpp b/project/platform/types.hpp index 4bbcdbf..ed5116a 100644 --- a/project/platform/types.hpp +++ b/project/platform/types.hpp @@ -79,10 +79,10 @@ static_assert( sizeof( u16 ) == 2, "sizeof(u16) != 2" ); static_assert( sizeof( u32 ) == 4, "sizeof(u32) != 4" ); static_assert( sizeof( u64 ) == 8, "sizeof(u64) != 8" ); -typedef size_t uw; -typedef ptrdiff_t sw; +typedef size_t usize; +typedef ptrdiff_t ssize; -static_assert( sizeof( uw ) == sizeof( sw ), "sizeof(uw) != sizeof(sw)" ); +static_assert( sizeof( usize ) == sizeof( ssize ), "sizeof(usize) != sizeof(ssize)" ); #if defined( _WIN64 ) typedef signed __int64 sptr; diff --git a/project/platform/win32/win32_platform.cpp b/project/platform/win32/win32_platform.cpp index b1495dd..75659aa 100644 --- a/project/platform/win32/win32_platform.cpp +++ b/project/platform/win32/win32_platform.cpp @@ -135,7 +135,6 @@ timing_get_wall_clock() return clock; } #pragma endregion Timing - NS_PLATFORM_END #include "win32_audio.cpp" @@ -540,8 +539,8 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho void* base_address = 0; #endif - engine_memory.persistent = VirtualAlloc( base_address, total_size , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); - engine_memory.transient = rcast( u8*, engine_memory.persistent ) + engine_memory.persistent_size; + engine_memory.persistent = rcast( Byte*, VirtualAlloc( base_address, total_size , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write )); + engine_memory.transient = rcast( Byte*, engine_memory.persistent ) + engine_memory.persistent_size; #if Build_Development // First slot is for restore @@ -794,7 +793,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho } } - engine_api.startup( & engine_memory, & platform_api ); + engine_api.startup( rcast(engine::OffscreenBuffer*, & Surface_Back_Buffer.memory), & engine_memory, & platform_api ); u64 last_frame_clock = timing_get_wall_clock(); u64 last_frame_cycle = __rdtsc(); diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 0a03fad..46aad6e 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -152,6 +152,7 @@ else { $should_format_gen = $false +# TODO(Ed) : Support detecting codegen changes separate from the module's runtime builds (so that it can be rebuild only when necessary as well) function build-engine { $should_build = check-ModuleForChanges $path_engine