diff --git a/README.md b/README.md index 3d8afb7..2af0ebe 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Module build order: ## Milestone -Day 40 : Cursor Hiding and Fullscreen Support +Day 43 : The Equations of Motion Features Done so far: @@ -68,9 +68,11 @@ Features Done so far: * Basic rendering * Linear alpha blending * Anchored to center position + * Experimental type sytem for physics vectors. ## Gallery +![img](docs/imgs/10x_2023-10-28_16-58-16.gif) ![img](docs/imgs/10x_2023-10-22_01-44-21.gif) ![img](docs/imgs/handmade_win32_2023-10-21_22-18-47.gif) ![img](docs/imgs/handmade_win32_2023-10-21_02-16-43.png) diff --git a/docs/Day 043.md b/docs/Day 043.md new file mode 100644 index 0000000..cf5c914 --- /dev/null +++ b/docs/Day 043.md @@ -0,0 +1,37 @@ +# Day 43 + +My little experiment with making a types of vectors for the physical interpreations +used when doing basic 2D physics actually produced some interesting results. + +I made types for position, distance, direction, velocity, and acceleration so far. +Right now at the level of complexity our "physics" code is operating at they feel more +"in the way" than actually something helping us with intuition or productivity. + +However, when Casey explained that delta-time is essentially applied to intergrate to "lower" frame of time; +I realized that you could technically compress the application of delta time when you apply acceleration to velocity, velocity to position, etc. + +```cpp +inline Pos2_f32& operator+=( Pos2_f32& pos, Vel2_f32 const vel ) +{ + pos.x += vel.x * engine::get_context()->delta_time; + pos.y += vel.y * engine::get_context()->delta_time; + return pos; +} + +inline Vel2_f32& operator+=( Vel2_f32& vel, Accel2_f32 const accel ) +{ + vel.x += accel.x * engine::get_context()->delta_time; + vel.y += accel.y * engine::get_context()->delta_time; + return vel; +} +``` + +The of this encapsulation is that the operators need to have awareness of the delta time from some context. +So in a sense your enforcing that there is an implicit delta universally. +For now I'm making that context just the engine's known delta from the platform's frametime. + +This most likely would get more complex if there are multiple physics threads or substepping is involved. +I'm also not sure how much performance is also sacrificed with this approach since an indirection was introduced with having to grab the context. + +If there is a issue with performance the user can always at worst case downcast to regular vectors and just do the math directly... +For now I'll continue to use this approach and see how it goes. diff --git a/docs/imgs/10x_2023-10-28_16-58-16.gif b/docs/imgs/10x_2023-10-28_16-58-16.gif new file mode 100644 index 0000000..19afb34 Binary files /dev/null and b/docs/imgs/10x_2023-10-28_16-58-16.gif differ diff --git a/project/codegen/engine_gen.cpp b/project/codegen/engine_gen.cpp index 13a2725..d08f001 100644 --- a/project/codegen/engine_gen.cpp +++ b/project/codegen/engine_gen.cpp @@ -24,6 +24,8 @@ using namespace gen; constexpr StrC fname_vec_header = txt("vectors.hpp"); +#pragma push_macro("scast") +#undef scast constexpr char const* vec2_ops = stringize( template<> constexpr tmpl_zero< >() { @@ -38,6 +40,27 @@ constexpr char const* vec2_ops = stringize( }; return result; } + + inline + magnitude( v ) { + result = sqrt( v.x * v.x + v.y * v.y ); + return result; + } + + inline + normalize( v ) { + square_size = v.x * v.x + v.y * v.y; + if ( square_size < scast(, 1e-4) ) { + return Zero( ); + } + + mag = sqrt( square_size ); + result { + v.x / mag, + v.y / mag + }; + return result; + } inline operator - ( v ) { @@ -75,6 +98,15 @@ constexpr char const* vec2_ops = stringize( return result; } + inline + operator * ( s, v ) { + result { + v.x * s, + v.y * s + }; + return result; + } + inline operator / ( v, s ) { result { @@ -111,6 +143,7 @@ constexpr char const* vec2_ops = stringize( return v; } ); +#pragma pop_macro("scast") #define gen_vec2( vec_name, type ) gen__vec2( txt( stringize(vec_name) ), txt( stringize(type) ) ) CodeBody gen__vec2( StrC vec_name, StrC type ) @@ -141,25 +174,51 @@ CodeBody gen__vec2( StrC vec_name, StrC type ) #define gen_phys2( type ) gen__phys2( txt( stringize(type) ) ) Code gen__phys2( StrC type ) { - String t_vec = String::fmt_buf( GlobalAllocator, "Vec2_%s", type.Ptr ); - String t_pos = String::fmt_buf( GlobalAllocator, "Pos2_%s", type.Ptr ); - String t_dist = String::fmt_buf( GlobalAllocator, "Dist2_%s", type.Ptr ); - String t_vel = String::fmt_buf( GlobalAllocator, "Vel2_%s", type.Ptr ); - String t_accel = String::fmt_buf( GlobalAllocator, "Accel2_%s", type.Ptr ); + String sym_vec = String::fmt_buf( GlobalAllocator, "Vec2_%s", type.Ptr ); + String sym_pos = String::fmt_buf( GlobalAllocator, "Pos2_%s", type.Ptr ); + String sym_dir = String::fmt_buf( GlobalAllocator, "Dir2_%s", type.Ptr); + String sym_dist = String::fmt_buf( GlobalAllocator, "Dist2_%s", type.Ptr ); + String sym_vel = String::fmt_buf( GlobalAllocator, "Vel2_%s", type.Ptr ); + String sym_accel = String::fmt_buf( GlobalAllocator, "Accel2_%s", type.Ptr ); #pragma push_macro("pcast") #pragma push_macro("rcast") #undef pcast #undef rcast - Code result = parse_global_body( token_fmt( - "unit_type", (StrC)type, - "vec_type", (StrC)t_vec, - "pos_type", (StrC)t_pos, - "dist_type", (StrC)t_dist, - "vel_type", (StrC)t_vel, - "accel_type", (StrC)t_accel, + constexpr char const* tmpl_struct = stringize( + struct + { + union { + struct { + x; + y; + }; + Basis[2]; + }; + operator () { + return * rcast(*, this); + } + }; + + template<> + inline + tmpl_cast< , >( vec ) + { + return pcast( , vec ); + } + ); + CodeBody pos_struct = parse_global_body( token_fmt( "type", (StrC)sym_pos, "unit_type", type, "vec_type", (StrC)sym_vec, tmpl_struct )); + CodeBody pos_ops = parse_global_body( token_fmt( "type", (StrC)sym_pos, "unit_type", type, vec2_ops )); + + CodeBody dir_struct = parse_global_body( token_fmt( + "type", (StrC)sym_dir, + "unit_type", type, + "vec_type", (StrC)sym_vec, + "vel_type", (StrC)sym_vel, + "accel_type", (StrC)sym_accel, stringize( - struct { + struct + { union { struct { x; @@ -171,10 +230,35 @@ Code gen__phys2( StrC type ) operator () { return * rcast(*, this); } + operator () { + return * rcast(*, this); + } + operator () { + return * rcast(*, this); + } }; + + template<> + inline + tmpl_cast< , >( vec ) + { + abs_sum = abs( vec.x + vec.y ); + if ( is_nearly_zero( abs_sum - 1 ) ) + return pcast( , vec ); + normalized = normalize(vec); + return pcast( , normalized ); + } + ))); + + CodeBody dist_def = parse_global_body( token_fmt( + "type", (StrC)sym_dist, + "unit_type", type, + "dist_type", (StrC)sym_dist, + "pos_type", (StrC)sym_pos, + stringize( using = ; - + inline distance( a, b ) { x = b.x - a.x; @@ -183,21 +267,23 @@ Code gen__phys2( StrC type ) result = sqrt( x * x + y * y ); return result; } - - struct { - union { - struct { - x; - y; - }; - Basis[2]; - }; - - operator () { - return * rcast(*, this); - } - }; - + ))); + + CodeBody vel_struct = parse_global_body( token_fmt( "type", (StrC)sym_vel, "unit_type", type, "vec_type", (StrC)sym_vec, tmpl_struct )); + CodeBody vel_ops = parse_global_body( token_fmt( "type", (StrC)sym_vel, "unit_type", type, vec2_ops )); + + CodeBody accel_struct = parse_global_body( token_fmt( "type", (StrC)sym_accel, "unit_type", type, "vec_type", (StrC)sym_vec, tmpl_struct )); + CodeBody accel_ops = parse_global_body( token_fmt( "type", (StrC)sym_accel, "unit_type", type, vec2_ops )); + + // TODO(Ed): Is there a better name for this? + Code ops = parse_global_body( token_fmt( + "unit_type", (StrC)type, + "vec_type", (StrC)sym_vec, + "pos_type", (StrC)sym_pos, + "dir_type", (StrC)sym_dir, + "vel_type", (StrC)sym_vel, + "accel_type", (StrC)sym_accel, + stringize( inline velocity( a, b ) { result = b - a; @@ -205,39 +291,72 @@ Code gen__phys2( StrC type ) } inline - & operator +=(& pos, const & vel) { - pos.x += vel.x; - pos.y += vel.y; + & operator +=(& pos, const vel) { + pos.x += vel.x * engine::get_context()->delta_time; + pos.y += vel.y * engine::get_context()->delta_time; return pos; } - inline - & operator *= ( & v, s ) { - v.x *= s; - v.y *= s; - return v; - } - - struct { - union { - struct { - x; - y; - }; - Basis[2]; - }; - - operator () { - return * rcast(*, this); - } - }; - inline acceleration( a, b ) { result = b - a; return pcast(, result); } + + inline + & operator +=(& vel, const accel) { + vel.x += accel.x * engine::get_context()->delta_time; + vel.y += accel.y * engine::get_context()->delta_time; + return vel; + } + + inline + direction( pos_a, pos_b ) + { + diff = pos_b - pos_a; + mag = magnitude( diff ); + + result { + diff.x / mag, + diff.y / mag + }; + return result; + } + + inline + direction( vel ) + { + mag = magnitude( vel ); + result { + vel.x / mag, + vel.y / mag + }; + return result; + } + + inline + direction( accel ) + { + mag = magnitude( accel ); + result { + accel.x / mag, + accel.y / mag + }; + return result; + } ))); + + CodeBody result = def_global_body( args( + pos_struct, + pos_ops, + dist_def, + vel_struct, + vel_ops, + accel_struct, + accel_ops, + dir_struct, + ops + )); return result; #pragma pop_macro("rcast") #pragma pop_macro("pcast") @@ -260,6 +379,7 @@ int gen_main() vec_header.print( def_include( txt("platform.hpp") )); vec_header.print( preprocess_endif ); vec_header.print( fmt_newline ); +// vec_header.print_fmt( "NS_ENGINE_BEGIN\n" ); CodeUsing using_vec2 = parse_using( code( using Vec2 = Vec2_f32; )); CodeUsing using_vec2i = parse_using( code( using Vec2i = Vec2_s32; )); @@ -272,6 +392,8 @@ int gen_main() CodeUsing using_vec3i = parse_using( code( using Vec2i = Vec3_f32; )); // vec_header.print( using_vec3 ); + +// vec_header.print_fmt( "NS_ENGINE_END\n" ); vec_header.write(); } @@ -282,24 +404,22 @@ int gen_main() physics_header.print_fmt( "#if INTELLISENSE_DIRECTIVES" ); physics_header.print( fmt_newline ); physics_header.print( def_include( txt("vectors.hpp") )); + physics_header.print( def_include( txt("engine.hpp") )); physics_header.print( preprocess_endif ); physics_header.print( fmt_newline ); +// physics_header.print_fmt( "NS_ENGINE_BEGIN\n" ); physics_header.print( gen_phys2( f32 ) ); - physics_header.print( gen_phys2( s32 ) ); physics_header.print( parse_global_body( code( using Pos2 = Pos2_f32; + using Dir2 = Dir2_f32; using Dist2 = Dist2_f32; using Vel2 = Vel2_f32; using Accel2 = Accel2_f32; - - using Pos2i = Pos2_s32; - using Dist2i = Dist2_s32; - using Vel2i = Vel2_s32; - using Accel2i = Accel2_s32; ))); +// physics_header.print_fmt( "NS_ENGINE_END\n" ); physics_header.write(); } diff --git a/project/dependencies/gen.hpp b/project/dependencies/gen.hpp index 021cc7e..a0e43bc 100644 --- a/project/dependencies/gen.hpp +++ b/project/dependencies/gen.hpp @@ -12703,8 +12703,10 @@ char const* AST::debug_str() case Parameters : result.append_fmt( "\n\tNumEntries: %d", NumEntries ); - result.append_fmt( "\n\tLast : %S", Last->Name ); - result.append_fmt( "\n\tNext : %S", Next->Name ); + if ( Last ) + result.append_fmt( "\n\tLast : %S", Last->Name ); + if ( Next ) + result.append_fmt( "\n\tNext : %S", Next->Name ); result.append_fmt( "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); result.append_fmt( "\n\tValue : %S", Value ? Value->to_string() : "Null" ); break; @@ -15189,7 +15191,10 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy break; case 2 : - if ( ! params_code->ValueType.is_equal( ret_type ) ) + break; + // Its not required by c++ to have this constraint so I'm omitting it. +#if 0 + if ( ! params_code->ValueType.is_equal( ret_type ) && ! params_code->Next.is_equal( ret_type ) ) { log_failure( "gen::def_operator: " @@ -15202,6 +15207,7 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy return OpValidateResult::Fail; } break; +#endif default : log_failure( diff --git a/project/engine/engine.cpp b/project/engine/engine.cpp index 0522ce9..7a9d247 100644 --- a/project/engine/engine.cpp +++ b/project/engine/engine.cpp @@ -3,56 +3,19 @@ #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" #include "random.cpp" + +// TODO(Ed) : This needs to be moved out eventually +#include "handmade.hpp" #endif NS_ENGINE_BEGIN - -#define pressed( btn ) (btn.ended_down && btn.half_transitions > 0) - -// Used to determine if analog input is at move threshold -constexpr f32 analog_move_threshold = 0.5f; - -struct EngineActions -{ - b32 move_up; - b32 move_down; - b32 move_left; - b32 move_right; - - b32 loop_mode_engine; - b32 loop_mode_game; - - b32 raise_volume; - b32 lower_volume; - b32 raise_tone_hz; - b32 lower_tone_hz; - - b32 toggle_wave_tone; - -#if Build_Development - b32 pause_renderer; - - b32 load_auto_snapshot; - b32 set_snapshot_slot_1; - b32 set_snapshot_slot_2; - b32 set_snapshot_slot_3; - b32 set_snapshot_slot_4; - - b32 force_null_access_violation; -#endif -}; - struct EngineState { hh::Memory game_memory; MemoryArena world_arena; - World* world; f32 auto_snapshot_interval; f32 auto_snapshot_timer; @@ -66,8 +29,9 @@ struct EngineState f32 sample_wave_sine_time; b32 sample_wave_switch; -}; + EngineContext context; +}; NS_ENGINE_END // TODO(Ed) : does this need to be here or can it be moved to handmade_engine.cpp? @@ -81,6 +45,15 @@ NS_ENGINE_END NS_ENGINE_BEGIN +global EngineContext* Engine_Context = nullptr; + +EngineContext* get_context() +{ + return Engine_Context; +} + +#define pressed( btn ) (btn.ended_down && btn.half_transitions > 0) + internal void input_poll_engine_actions( InputState* input, EngineActions* actions ) { @@ -391,7 +364,7 @@ Bitmap load_bmp( platform::ModuleAPI* platform_api, Str file_path ) Engine_API void on_module_reload( Memory* memory, platform::ModuleAPI* platfom_api ) { - + Engine_Context = & rcast(EngineState*, memory->persistent)->context; } Engine_API @@ -415,6 +388,8 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* EngineState* state = rcast( EngineState*, memory->persistent ); assert( sizeof(EngineState) <= memory->persistent_size ); + Engine_Context = & state->context; + state->auto_snapshot_interval = 60.f; state->tone_volume = 1000; @@ -432,6 +407,8 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* 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* world; + // World setup { ssize world_arena_size = memory->engine_persistent_size() - sizeof(EngineState); @@ -439,8 +416,8 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* MemoryArena::init( & state->world_arena, world_arena_size, world_arena_storage ); //state->world = MemoryArena_push_struct( & state->world_arena, World); - state->world = state->world_arena.push_struct( World ); - World* world = state->world; + state->context.world = state->world_arena.push_struct( World ); + world = state->context.world; TileMap* tile_map = state->world_arena.push_struct( TileMap ); world->tile_map = tile_map; @@ -702,8 +679,8 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* game_state->hero_direction = HeroBitmaps_Front; } - game_state->camera_pos.tile_x = state->world->tiles_per_screen_x / 2; - game_state->camera_pos.tile_y = state->world->tiles_per_screen_y / 2; + game_state->camera_pos.tile_x = world->tiles_per_screen_x / 2; + game_state->camera_pos.tile_y = world->tiles_per_screen_y / 2; hh::PlayerState* player = & game_state->player_state; player->position.tile_x = 4; @@ -711,6 +688,8 @@ void startup( OffscreenBuffer* back_buffer, Memory* memory, platform::ModuleAPI* player->position.rel_pos.x = 0.f; player->position.rel_pos.y = 0.f; + player->move_velocity = {}; + player->mid_jump = false; player->jump_time = 0.f; @@ -730,6 +709,8 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back EngineState* state = rcast( EngineState*, memory->persistent ); assert( sizeof(EngineState) <= memory->persistent_size ); + state->context.delta_time = delta_time; + // Engine auto_snapshot { state->auto_snapshot_timer += delta_time; @@ -866,7 +847,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back hh::GameState* game_state = rcast( hh::GameState*, state->game_memory.persistent ); hh::PlayerState* player = & game_state->player_state; - World* world = state->world; + World* world = state->context.world; TileMap* tile_map = world->tile_map; f32 tile_size_in_pixels = scast(f32, world->tile_size_in_pixels); @@ -881,37 +862,35 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back input_poll_player_actions( input, & player_actions ); { - f32 move_speed = 6.f; - + f32 move_accel = 36.f; if ( player_actions.sprint ) { - move_speed = 24.f; + move_accel = 94.f; } Pos2_f32 new_player_pos = { player->position.rel_pos.x, player->position.rel_pos.y }; - b32 moved_x = player_actions.player_x_move_analog != 0 || player_actions.player_x_move_digital != 0; - b32 moved_y = player_actions.player_y_move_analog != 0 || player_actions.player_y_move_digital != 0; - - Vel2_f32 player_move_vel = {}; + Vec2 player_move_vec = {}; if ( player_actions.player_x_move_analog || player_actions.player_y_move_analog ) { - player_move_vel.x = scast(f32, player_actions.player_x_move_analog * delta_time * move_speed); - player_move_vel.y = scast(f32, player_actions.player_y_move_analog * delta_time * move_speed); + player_move_vec.x = scast(f32, player_actions.player_x_move_analog ); + player_move_vec.y = scast(f32, player_actions.player_y_move_analog ); } else { - player_move_vel.x = scast(f32, player_actions.player_x_move_digital) * delta_time * move_speed; - player_move_vel.y = scast(f32, player_actions.player_y_move_digital) * delta_time * move_speed; + player_move_vec.x = scast(f32, player_actions.player_x_move_digital ); + player_move_vec.y = scast(f32, player_actions.player_y_move_digital ); } - if ( moved_x && moved_y ) - { - player_move_vel *= (f32)0.707106781187f; - } + Dir2 player_direction = cast( Dir2, player_move_vec ); + Accel2 player_move_accel = scast( Accel2, player_direction ) * move_accel; - new_player_pos += player_move_vel; - new_player_pos.y -= sinf( player->jump_time * TAU ) * 10.f * delta_time; + // TODO(Ed) : ODE! + Accel2 friction = pcast( Accel2, player->move_velocity) * 9.f; + player_move_accel -= friction; + + player->move_velocity += player_move_accel * 0.5f; + new_player_pos += player->move_velocity; b32 valid_new_pos = true; { @@ -1033,7 +1012,6 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back } } - Vec2 screen_center { scast(f32, back_buffer->width) * 0.5f, scast(f32, back_buffer->height) * 0.5f @@ -1088,12 +1066,12 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back } Vec2 tile_pixel_size = { tile_size_in_pixels * 0.5f, tile_size_in_pixels * 0.5f }; - Vec2 center { + Pos2 center { screen_center.x + scast(f32, relative_col) * tile_size_in_pixels - game_state->camera_pos.rel_pos.x * world->tile_meters_to_pixels, screen_center.y - scast(f32, relative_row) * tile_size_in_pixels + game_state->camera_pos.rel_pos.y * world->tile_meters_to_pixels }; - Vec2 min = center - tile_pixel_size; - Vec2 max = center + tile_pixel_size; + Pos2 min = center - cast( Pos2, tile_pixel_size ); + Pos2 max = center + cast( Pos2, tile_pixel_size ); draw_rectangle( back_buffer , min, max @@ -1130,7 +1108,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back player_to_camera.rel_pos.x + scast(f32, player_to_camera.tile_x) * world->tile_map->tile_size_in_meters, -1 * (player_to_camera.rel_pos.y + scast(f32, player_to_camera.tile_y) * world->tile_map->tile_size_in_meters) }; - Vec2 player_ground_pos = screen_center + player_to_screenspace * world->tile_meters_to_pixels; + Pos2 player_ground_pos = cast( Pos2, screen_center + player_to_screenspace * world->tile_meters_to_pixels ); hh::HeroBitmaps* hero_bitmaps = & game_state->hero_bitmaps[game_state->hero_direction]; diff --git a/project/engine/engine.hpp b/project/engine/engine.hpp index be87ebc..44d34ab 100644 --- a/project/engine/engine.hpp +++ b/project/engine/engine.hpp @@ -7,9 +7,9 @@ #if INTELLISENSE_DIRECTIVES #include "platform/platform.hpp" #include "gen/vectors.hpp" -#include "gen/physics.hpp" #include "engine_module.hpp" #include "tile_map.hpp" + #endif NS_ENGINE_BEGIN @@ -220,4 +220,46 @@ struct Bitmap u32 bits_per_pixel; }; +// Used to determine if analog input is at move threshold +constexpr f32 analog_move_threshold = 0.5f; + +struct EngineActions +{ + b32 move_up; + b32 move_down; + b32 move_left; + b32 move_right; + + b32 loop_mode_engine; + b32 loop_mode_game; + + b32 raise_volume; + b32 lower_volume; + b32 raise_tone_hz; + b32 lower_tone_hz; + + b32 toggle_wave_tone; + +#if Build_Development + b32 pause_renderer; + + b32 load_auto_snapshot; + b32 set_snapshot_slot_1; + b32 set_snapshot_slot_2; + b32 set_snapshot_slot_3; + b32 set_snapshot_slot_4; + + b32 force_null_access_violation; +#endif +}; + +// TODO(Ed) : Do this properly? +struct EngineContext +{ + World* world; + float delta_time; +}; + +EngineContext* get_context(); + NS_ENGINE_END diff --git a/project/engine/gen/physics.hpp b/project/engine/gen/physics.hpp index 6de8de1..e07515b 100644 --- a/project/engine/gen/physics.hpp +++ b/project/engine/gen/physics.hpp @@ -2,6 +2,7 @@ #pragma once #if INTELLISENSE_DIRECTIVES #include "vectors.hpp" +#include "engine.hpp" #endif struct Pos2_f32 @@ -23,6 +24,106 @@ struct Pos2_f32 } }; +template<> +inline Pos2_f32 tmpl_cast< Pos2_f32, Vec2_f32 >( Vec2_f32 vec ) +{ + return pcast( Pos2_f32, vec ); +} + +template<> +constexpr Pos2_f32 tmpl_zero< Pos2_f32 >() +{ + return { 0, 0 }; +} + +inline Pos2_f32 abs( Pos2_f32 v ) +{ + Pos2_f32 result { abs( v.x ), abs( v.y ) }; + return result; +} + +inline f32 magnitude( Pos2_f32 v ) +{ + f32 result = sqrt( v.x * v.x + v.y * v.y ); + return result; +} + +inline Pos2_f32 normalize( Pos2_f32 v ) +{ + f32 square_size = v.x * v.x + v.y * v.y; + if ( square_size < scast( f32, 1e-4 ) ) + { + return Zero( Pos2_f32 ); + } + f32 mag = sqrt( square_size ); + Pos2_f32 result { v.x / mag, v.y / mag }; + return result; +} + +inline Pos2_f32 operator-( Pos2_f32 v ) +{ + Pos2_f32 result { -v.x, -v.y }; + return result; +} + +inline Pos2_f32 operator+( Pos2_f32 a, Pos2_f32 b ) +{ + Pos2_f32 result { a.x + b.x, a.y + b.y }; + return result; +} + +inline Pos2_f32 operator-( Pos2_f32 a, Pos2_f32 b ) +{ + Pos2_f32 result { a.x - b.x, a.y - b.y }; + return result; +} + +inline Pos2_f32 operator*( Pos2_f32 v, f32 s ) +{ + Pos2_f32 result { v.x * s, v.y * s }; + return result; +} + +inline Pos2_f32 operator*( f32 s, Pos2_f32 v ) +{ + Pos2_f32 result { v.x * s, v.y * s }; + return result; +} + +inline Pos2_f32 operator/( Pos2_f32 v, f32 s ) +{ + Pos2_f32 result { v.x / s, v.y / s }; + return result; +} + +inline Pos2_f32& operator+=( Pos2_f32& a, Pos2_f32 b ) +{ + a.x += b.x; + a.y += b.y; + return a; +} + +inline Pos2_f32& operator-=( Pos2_f32& a, Pos2_f32 b ) +{ + a.x -= b.x; + a.y -= b.y; + return a; +} + +inline Pos2_f32& operator*=( Pos2_f32& v, f32 s ) +{ + v.x *= s; + v.y *= s; + return v; +} + +inline Pos2_f32& operator/=( Pos2_f32& v, f32 s ) +{ + v.x /= s; + v.y /= s; + return v; +} + using Dist2_f32 = f32; inline Dist2_f32 distance( Pos2_f32 a, Pos2_f32 b ) @@ -52,17 +153,90 @@ struct Vel2_f32 } }; -inline Vel2_f32 velocity( Pos2_f32 a, Pos2_f32 b ) +template<> +inline Vel2_f32 tmpl_cast< Vel2_f32, Vec2_f32 >( Vec2_f32 vec ) { - Vec2_f32 result = b - a; - return pcast( Vel2_f32, result ); + return pcast( Vel2_f32, vec ); } -inline Pos2_f32& operator+=( Pos2_f32& pos, Vel2_f32 const& vel ) +template<> +constexpr Vel2_f32 tmpl_zero< Vel2_f32 >() { - pos.x += vel.x; - pos.y += vel.y; - return pos; + return { 0, 0 }; +} + +inline Vel2_f32 abs( Vel2_f32 v ) +{ + Vel2_f32 result { abs( v.x ), abs( v.y ) }; + return result; +} + +inline f32 magnitude( Vel2_f32 v ) +{ + f32 result = sqrt( v.x * v.x + v.y * v.y ); + return result; +} + +inline Vel2_f32 normalize( Vel2_f32 v ) +{ + f32 square_size = v.x * v.x + v.y * v.y; + if ( square_size < scast( f32, 1e-4 ) ) + { + return Zero( Vel2_f32 ); + } + f32 mag = sqrt( square_size ); + Vel2_f32 result { v.x / mag, v.y / mag }; + return result; +} + +inline Vel2_f32 operator-( Vel2_f32 v ) +{ + Vel2_f32 result { -v.x, -v.y }; + return result; +} + +inline Vel2_f32 operator+( Vel2_f32 a, Vel2_f32 b ) +{ + Vel2_f32 result { a.x + b.x, a.y + b.y }; + return result; +} + +inline Vel2_f32 operator-( Vel2_f32 a, Vel2_f32 b ) +{ + Vel2_f32 result { a.x - b.x, a.y - b.y }; + return result; +} + +inline Vel2_f32 operator*( Vel2_f32 v, f32 s ) +{ + Vel2_f32 result { v.x * s, v.y * s }; + return result; +} + +inline Vel2_f32 operator*( f32 s, Vel2_f32 v ) +{ + Vel2_f32 result { v.x * s, v.y * s }; + return result; +} + +inline Vel2_f32 operator/( Vel2_f32 v, f32 s ) +{ + Vel2_f32 result { v.x / s, v.y / s }; + return result; +} + +inline Vel2_f32& operator+=( Vel2_f32& a, Vel2_f32 b ) +{ + a.x += b.x; + a.y += b.y; + return a; +} + +inline Vel2_f32& operator-=( Vel2_f32& a, Vel2_f32 b ) +{ + a.x -= b.x; + a.y -= b.y; + return a; } inline Vel2_f32& operator*=( Vel2_f32& v, f32 s ) @@ -72,6 +246,13 @@ inline Vel2_f32& operator*=( Vel2_f32& v, f32 s ) return v; } +inline Vel2_f32& operator/=( Vel2_f32& v, f32 s ) +{ + v.x /= s; + v.y /= s; + return v; +} + struct Accel2_f32 { union @@ -91,110 +272,195 @@ struct Accel2_f32 } }; -inline Accel2_f32 acceleration( Vel2_f32 a, Vel2_f32 b ) +template<> +inline Accel2_f32 tmpl_cast< Accel2_f32, Vec2_f32 >( Vec2_f32 vec ) { - Vec2_f32 result = b - a; - return pcast( Accel2_f32, result ); + return pcast( Accel2_f32, vec ); } -struct Pos2_s32 +template<> +constexpr Accel2_f32 tmpl_zero< Accel2_f32 >() { - union - { - struct - { - s32 x; - s32 y; - }; + return { 0, 0 }; +} - s32 Basis[ 2 ]; - }; - - operator Vec2_s32() - { - return *rcast( Vec2_s32*, this ); - } -}; - -using Dist2_s32 = s32; - -inline Dist2_s32 distance( Pos2_s32 a, Pos2_s32 b ) +inline Accel2_f32 abs( Accel2_f32 v ) { - s32 x = b.x - a.x; - s32 y = b.y - a.y; - Dist2_s32 result = sqrt( x * x + y * y ); + Accel2_f32 result { abs( v.x ), abs( v.y ) }; return result; } -struct Vel2_s32 +inline f32 magnitude( Accel2_f32 v ) { - union - { - struct - { - s32 x; - s32 y; - }; + f32 result = sqrt( v.x * v.x + v.y * v.y ); + return result; +} - s32 Basis[ 2 ]; - }; - - operator Vec2_s32() +inline Accel2_f32 normalize( Accel2_f32 v ) +{ + f32 square_size = v.x * v.x + v.y * v.y; + if ( square_size < scast( f32, 1e-4 ) ) { - return *rcast( Vec2_s32*, this ); + return Zero( Accel2_f32 ); } -}; - -inline Vel2_s32 velocity( Pos2_s32 a, Pos2_s32 b ) -{ - Vec2_s32 result = b - a; - return pcast( Vel2_s32, result ); + f32 mag = sqrt( square_size ); + Accel2_f32 result { v.x / mag, v.y / mag }; + return result; } -inline Pos2_s32& operator+=( Pos2_s32& pos, Vel2_s32 const& vel ) +inline Accel2_f32 operator-( Accel2_f32 v ) { - pos.x += vel.x; - pos.y += vel.y; - return pos; + Accel2_f32 result { -v.x, -v.y }; + return result; } -inline Vel2_s32& operator*=( Vel2_s32& v, s32 s ) +inline Accel2_f32 operator+( Accel2_f32 a, Accel2_f32 b ) +{ + Accel2_f32 result { a.x + b.x, a.y + b.y }; + return result; +} + +inline Accel2_f32 operator-( Accel2_f32 a, Accel2_f32 b ) +{ + Accel2_f32 result { a.x - b.x, a.y - b.y }; + return result; +} + +inline Accel2_f32 operator*( Accel2_f32 v, f32 s ) +{ + Accel2_f32 result { v.x * s, v.y * s }; + return result; +} + +inline Accel2_f32 operator*( f32 s, Accel2_f32 v ) +{ + Accel2_f32 result { v.x * s, v.y * s }; + return result; +} + +inline Accel2_f32 operator/( Accel2_f32 v, f32 s ) +{ + Accel2_f32 result { v.x / s, v.y / s }; + return result; +} + +inline Accel2_f32& operator+=( Accel2_f32& a, Accel2_f32 b ) +{ + a.x += b.x; + a.y += b.y; + return a; +} + +inline Accel2_f32& operator-=( Accel2_f32& a, Accel2_f32 b ) +{ + a.x -= b.x; + a.y -= b.y; + return a; +} + +inline Accel2_f32& operator*=( Accel2_f32& v, f32 s ) { v.x *= s; v.y *= s; return v; } -struct Accel2_s32 +inline Accel2_f32& operator/=( Accel2_f32& v, f32 s ) +{ + v.x /= s; + v.y /= s; + return v; +} + +struct Dir2_f32 { union { struct { - s32 x; - s32 y; + f32 x; + f32 y; }; - s32 Basis[ 2 ]; + f32 Basis[ 2 ]; }; - operator Vec2_s32() + operator Vec2_f32() { - return *rcast( Vec2_s32*, this ); + return *rcast( Vec2_f32*, this ); + } + + operator Vel2_f32() + { + return *rcast( Vel2_f32*, this ); + } + + operator Accel2_f32() + { + return *rcast( Accel2_f32*, this ); } }; -inline Accel2_s32 acceleration( Vel2_s32 a, Vel2_s32 b ) +template<> +inline Dir2_f32 tmpl_cast< Dir2_f32, Vec2_f32 >( Vec2_f32 vec ) { - Vec2_s32 result = b - a; - return pcast( Accel2_s32, result ); + f32 abs_sum = abs( vec.x + vec.y ); + if ( is_nearly_zero( abs_sum - 1 ) ) + return pcast( Dir2_f32, vec ); + Vec2_f32 normalized = normalize( vec ); + return pcast( Dir2_f32, normalized ); } -using Pos2 = Pos2_f32; -using Dist2 = Dist2_f32; -using Vel2 = Vel2_f32; -using Accel2 = Accel2_f32; -using Pos2i = Pos2_s32; -using Dist2i = Dist2_s32; -using Vel2i = Vel2_s32; -using Accel2i = Accel2_s32; +inline Vel2_f32 velocity( Pos2_f32 a, Pos2_f32 b ) +{ + Vec2_f32 result = b - a; + return pcast( Vel2_f32, result ); +} + +inline Pos2_f32& operator+=( Pos2_f32& pos, Vel2_f32 const vel ) +{ + pos.x += vel.x * engine::get_context()->delta_time; + pos.y += vel.y * engine::get_context()->delta_time; + return pos; +} + +inline Accel2_f32 acceleration( Vel2_f32 a, Vel2_f32 b ) +{ + Vec2_f32 result = b - a; + return pcast( Accel2_f32, result ); +} + +inline Vel2_f32& operator+=( Vel2_f32& vel, Accel2_f32 const accel ) +{ + vel.x += accel.x * engine::get_context()->delta_time; + vel.y += accel.y * engine::get_context()->delta_time; + return vel; +} + +inline Dir2_f32 direction( Pos2_f32 pos_a, Pos2_f32 pos_b ) +{ + Vec2_f32 diff = pos_b - pos_a; + f32 mag = magnitude( diff ); + Dir2_f32 result { diff.x / mag, diff.y / mag }; + return result; +} + +inline Dir2_f32 direction( Vel2_f32 vel ) +{ + f32 mag = magnitude( vel ); + Dir2_f32 result { vel.x / mag, vel.y / mag }; + return result; +} + +inline Dir2_f32 direction( Accel2_f32 accel ) +{ + f32 mag = magnitude( accel ); + Dir2_f32 result { accel.x / mag, accel.y / mag }; + return result; +} + +using Pos2 = Pos2_f32; +using Dir2 = Dir2_f32; +using Dist2 = Dist2_f32; +using Vel2 = Vel2_f32; +using Accel2 = Accel2_f32; diff --git a/project/engine/gen/vectors.hpp b/project/engine/gen/vectors.hpp index 850e536..0732a4c 100644 --- a/project/engine/gen/vectors.hpp +++ b/project/engine/gen/vectors.hpp @@ -31,6 +31,24 @@ inline Vec2_f32 abs( Vec2_f32 v ) return result; } +inline f32 magnitude( Vec2_f32 v ) +{ + f32 result = sqrt( v.x * v.x + v.y * v.y ); + return result; +} + +inline Vec2_f32 normalize( Vec2_f32 v ) +{ + f32 square_size = v.x * v.x + v.y * v.y; + if ( square_size < scast( f32, 1e-4 ) ) + { + return Zero( Vec2_f32 ); + } + f32 mag = sqrt( square_size ); + Vec2_f32 result { v.x / mag, v.y / mag }; + return result; +} + inline Vec2_f32 operator-( Vec2_f32 v ) { Vec2_f32 result { -v.x, -v.y }; @@ -55,6 +73,12 @@ inline Vec2_f32 operator*( Vec2_f32 v, f32 s ) return result; } +inline Vec2_f32 operator*( f32 s, Vec2_f32 v ) +{ + Vec2_f32 result { v.x * s, v.y * s }; + return result; +} + inline Vec2_f32 operator/( Vec2_f32 v, f32 s ) { Vec2_f32 result { v.x / s, v.y / s }; @@ -115,6 +139,24 @@ inline Vec2_s32 abs( Vec2_s32 v ) return result; } +inline s32 magnitude( Vec2_s32 v ) +{ + s32 result = sqrt( v.x * v.x + v.y * v.y ); + return result; +} + +inline Vec2_s32 normalize( Vec2_s32 v ) +{ + s32 square_size = v.x * v.x + v.y * v.y; + if ( square_size < scast( s32, 1e-4 ) ) + { + return Zero( Vec2_s32 ); + } + s32 mag = sqrt( square_size ); + Vec2_s32 result { v.x / mag, v.y / mag }; + return result; +} + inline Vec2_s32 operator-( Vec2_s32 v ) { Vec2_s32 result { -v.x, -v.y }; @@ -139,6 +181,12 @@ inline Vec2_s32 operator*( Vec2_s32 v, s32 s ) return result; } +inline Vec2_s32 operator*( s32 s, Vec2_s32 v ) +{ + Vec2_s32 result { v.x * s, v.y * s }; + return result; +} + inline Vec2_s32 operator/( Vec2_s32 v, s32 s ) { Vec2_s32 result { v.x / s, v.y / s }; diff --git a/project/engine/state_and_replay.hpp b/project/engine/state_and_replay.hpp new file mode 100644 index 0000000..238cc05 --- /dev/null +++ b/project/engine/state_and_replay.hpp @@ -0,0 +1,4 @@ +#pragma once +#if INTELLISENSE_DIRECTIVES + +#endif \ No newline at end of file diff --git a/project/handmade.hpp b/project/handmade.hpp index 2fa025d..66db865 100644 --- a/project/handmade.hpp +++ b/project/handmade.hpp @@ -75,6 +75,7 @@ struct PlayerState f32 height; engine::TileMapPos position; + Vel2 move_velocity; b32 mid_jump; f32 jump_time; diff --git a/project/handmade_engine.cpp b/project/handmade_engine.cpp index 933ceab..8bdcd00 100644 --- a/project/handmade_engine.cpp +++ b/project/handmade_engine.cpp @@ -14,16 +14,18 @@ Handmade Engine Translation Unit #include "platform/math_constants.hpp" #include "platform/types.hpp" #include "platform/intrinsics.hpp" +#include "platform/float_ops.hpp" #include "platform/strings.hpp" #include "platform/context.hpp" #include "platform/platform.hpp" #include "engine_module.hpp" #include "gen/vectors.hpp" -#include "gen/physics.hpp" #include "input.hpp" #include "tile_map.hpp" #include "engine.hpp" +// Physics Depends on stuff in engine.hpp for now. +#include "gen/physics.hpp" #include "engine_to_platform_api.hpp" // Game layer headers diff --git a/project/handmade_win32.cpp b/project/handmade_win32.cpp index e3b1502..ce791df 100644 --- a/project/handmade_win32.cpp +++ b/project/handmade_win32.cpp @@ -14,6 +14,7 @@ Handmade Win32 Platform Translation Unit #include "math_constants.hpp" #include "types.hpp" #include "intrinsics.hpp" +#include "float_ops.hpp" #include "strings.hpp" #include "context.hpp" #include "platform.hpp" @@ -21,10 +22,10 @@ Handmade Win32 Platform Translation Unit // Engine layer headers #include "engine/engine_module.hpp" #include "engine/gen/vectors.hpp" -#include "engine/gen/physics.hpp" #include "engine/input.hpp" #include "engine/tile_map.hpp" #include "engine/engine.hpp" +#include "engine/gen/physics.hpp" #include "engine/engine_to_platform_api.hpp" #include "engine/gen/engine_symbols.gen.hpp" diff --git a/project/platform/float_ops.hpp b/project/platform/float_ops.hpp new file mode 100644 index 0000000..577ac2d --- /dev/null +++ b/project/platform/float_ops.hpp @@ -0,0 +1,17 @@ +#pragma once +#if INTELLISENSE_DIRECTIVES +#include "types.hpp" +#include "intrinsics.hpp" +#endif + +#define mili_accuracy 0.001 +#define micro_accuracy 0.00001 +#define nano_accuracy 0.000000001 + +b32 is_nearly_zero( f32 value, f32 accuracy = mili_accuracy ) { + return abs(value) < accuracy; +} + +f32 square( f32 value ) { + return value * value; +} diff --git a/project/platform/generics.hpp b/project/platform/generics.hpp index 19b0dde..a814c74 100644 --- a/project/platform/generics.hpp +++ b/project/platform/generics.hpp @@ -12,3 +12,10 @@ void swap( Type& a, Type& b ) #define Zero( type ) tmpl_zero() template< class Type > constexpr Type tmpl_zero(); + +// Custom casting trait for when you cannot define an implicit cast ergonomically. +#define cast( type, obj ) tmpl_cast( obj ) +template< class Type, class OtherType > +constexpr Type tmpl_cast( OtherType obj ) { + static_assert( false, "No overload templated cast defined for type combination. Define this using an overload of tmpl_cast specialization." ); +} diff --git a/project/platform/types.hpp b/project/platform/types.hpp index ed5116a..5d2c136 100644 --- a/project/platform/types.hpp +++ b/project/platform/types.hpp @@ -38,6 +38,9 @@ #define F64_MIN 2.2250738585072014e-308 #define F64_MAX 1.7976931348623157e+308 +#define F32_EPSILON 1.1920929e-7f +#define F64_EPSILON 2.220446049250313e-16 + #if defined( COMPILER_MSVC ) # if _MSC_VER < 1300 typedef unsigned char u8; diff --git a/project/platform/win32/win32_platform.cpp b/project/platform/win32/win32_platform.cpp index 28d3c1f..dadf2bc 100644 --- a/project/platform/win32/win32_platform.cpp +++ b/project/platform/win32/win32_platform.cpp @@ -936,6 +936,7 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho engine_api_load_time = engine_api_current_time; unload_engine_module_api( & engine_api ); engine_api = load_engine_module_api(); + engine_api.on_module_reload( & engine_memory, & platform_api ); } while (0); diff --git a/scripts/build.ps1 b/scripts/build.ps1 index b3b710c..3deeb0a 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -121,7 +121,7 @@ function build-engine $should_build = (check-FileForChanges $unit) -eq $true if ( $should_build ) { - $executable = Join-Path $path_build 'engine_gen.exe' + $executable = Join-Path $path_build 'engine_gen.exe' $compiler_args = @() $compiler_args += ( $flag_define + 'GEN_TIME' ) diff --git a/scripts/handmade.rdbg b/scripts/handmade.rdbg index c50c85f..3ef6510 100644 Binary files a/scripts/handmade.rdbg and b/scripts/handmade.rdbg differ