Day 43 complete

This commit is contained in:
Edward R. Gonzalez 2023-10-28 17:10:30 -04:00
parent dddf8a1653
commit e1a481f4f6
19 changed files with 745 additions and 210 deletions

View File

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

37
docs/Day 043.md Normal file
View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View File

@ -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 <type> tmpl_zero< <type> >() {
@ -38,6 +40,27 @@ constexpr char const* vec2_ops = stringize(
};
return result;
}
inline
<unit_type> magnitude( <type> v ) {
<unit_type> result = sqrt( v.x * v.x + v.y * v.y );
return result;
}
inline
<type> normalize( <type> v ) {
<unit_type> square_size = v.x * v.x + v.y * v.y;
if ( square_size < scast(<unit_type>, 1e-4) ) {
return Zero( <type> );
}
<unit_type> mag = sqrt( square_size );
<type> result {
v.x / mag,
v.y / mag
};
return result;
}
inline
<type> operator - ( <type> v ) {
@ -75,6 +98,15 @@ constexpr char const* vec2_ops = stringize(
return result;
}
inline
<type> operator * ( <unit_type> s, <type> v ) {
<type> result {
v.x * s,
v.y * s
};
return result;
}
inline
<type> operator / ( <type> v, <unit_type> s ) {
<type> 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 <type>
{
union {
struct {
<unit_type> x;
<unit_type> y;
};
<unit_type> Basis[2];
};
operator <vec_type>() {
return * rcast(<vec_type>*, this);
}
};
template<>
inline
<type> tmpl_cast< <type>, <vec_type> >( <vec_type> vec )
{
return pcast( <type>, 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 <pos_type> {
struct <type>
{
union {
struct {
<unit_type> x;
@ -171,10 +230,35 @@ Code gen__phys2( StrC type )
operator <vec_type>() {
return * rcast(<vec_type>*, this);
}
operator <vel_type>() {
return * rcast(<vel_type>*, this);
}
operator <accel_type>() {
return * rcast(<accel_type>*, this);
}
};
template<>
inline
<type> tmpl_cast< <type>, <vec_type> >( <vec_type> vec )
{
<unit_type> abs_sum = abs( vec.x + vec.y );
if ( is_nearly_zero( abs_sum - 1 ) )
return pcast( <type>, vec );
<vec_type> normalized = normalize(vec);
return pcast( <type>, 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 <dist_type> = <unit_type>;
inline
<dist_type> distance( <pos_type> a, <pos_type> b ) {
<unit_type> x = b.x - a.x;
@ -183,21 +267,23 @@ Code gen__phys2( StrC type )
<dist_type> result = sqrt( x * x + y * y );
return result;
}
struct <vel_type> {
union {
struct {
<unit_type> x;
<unit_type> y;
};
<unit_type> Basis[2];
};
operator <vec_type>() {
return * rcast(<vec_type>*, 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
<vel_type> velocity( <pos_type> a, <pos_type> b ) {
<vec_type> result = b - a;
@ -205,39 +291,72 @@ Code gen__phys2( StrC type )
}
inline
<pos_type>& operator +=(<pos_type>& pos, const <vel_type>& vel) {
pos.x += vel.x;
pos.y += vel.y;
<pos_type>& operator +=(<pos_type>& pos, const <vel_type> vel) {
pos.x += vel.x * engine::get_context()->delta_time;
pos.y += vel.y * engine::get_context()->delta_time;
return pos;
}
inline
<vel_type>& operator *= ( <vel_type>& v, <unit_type> s ) {
v.x *= s;
v.y *= s;
return v;
}
struct <accel_type> {
union {
struct {
<unit_type> x;
<unit_type> y;
};
<unit_type> Basis[2];
};
operator <vec_type>() {
return * rcast(<vec_type>*, this);
}
};
inline
<accel_type> acceleration( <vel_type> a, <vel_type> b ) {
<vec_type> result = b - a;
return pcast(<accel_type>, result);
}
inline
<vel_type>& operator +=(<vel_type>& vel, const <accel_type> accel) {
vel.x += accel.x * engine::get_context()->delta_time;
vel.y += accel.y * engine::get_context()->delta_time;
return vel;
}
inline
<dir_type> direction( <pos_type> pos_a, <pos_type> pos_b )
{
<vec_type> diff = pos_b - pos_a;
<unit_type> mag = magnitude( diff );
<dir_type> result {
diff.x / mag,
diff.y / mag
};
return result;
}
inline
<dir_type> direction( <vel_type> vel )
{
<unit_type> mag = magnitude( vel );
<dir_type> result {
vel.x / mag,
vel.y / mag
};
return result;
}
inline
<dir_type> direction( <accel_type> accel )
{
<unit_type> mag = magnitude( accel );
<dir_type> 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();
}

View File

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

View File

@ -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];

View File

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

View File

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

View File

@ -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 };

View File

@ -0,0 +1,4 @@
#pragma once
#if INTELLISENSE_DIRECTIVES
#endif

View File

@ -75,6 +75,7 @@ struct PlayerState
f32 height;
engine::TileMapPos position;
Vel2 move_velocity;
b32 mid_jump;
f32 jump_time;

View File

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

View File

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

View File

@ -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;
}

View File

@ -12,3 +12,10 @@ void swap( Type& a, Type& b )
#define Zero( type ) tmpl_zero<type>()
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<type, decltype(obj)>( 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." );
}

View File

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

View File

@ -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);

View File

@ -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' )

Binary file not shown.