From e1623995a756de41f30c2b28ab17e934abcaed31 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 1 Oct 2023 20:17:14 -0400 Subject: [PATCH] Day 28 complete! --- .vscode/bookmarks.json | 23 +- .vscode/c_cpp_properties.json | 2 + .vscode/launch.json | 13 +- HandmadeHero.vcxproj | 10 + data/binaries/handmade_engine.exp | Bin 0 -> 2263 bytes data/binaries/handmade_engine.lib | Bin 0 -> 4466 bytes data/binaries/handmade_win32.exp | Bin 0 -> 808 bytes data/binaries/handmade_win32.lib | Bin 0 -> 2012 bytes project/codegen/engine_postbuild_gen.cpp | 2 +- project/codegen/platform_gen.cpp | 63 +- project/dependencies/gen.hpp | 2 + project/engine/engine.cpp | 159 +- project/engine/engine.hpp | 3 +- project/gen/engine_symbol_table.hpp | 17 +- project/handmade.hpp | 4 +- project/handmade_win32.cpp | 2 +- project/platform/context.hpp | 15 + project/platform/gen/context.gen.hpp | 3 + project/platform/macros.hpp | 47 +- project/platform/platform.hpp | 11 + project/platform/win32.hpp | 187 --- project/platform/win32_platform.cpp | 1814 ---------------------- scripts/.clang-format | 171 ++ scripts/build.ps1 | 593 ++----- scripts/handmade.rdbg | Bin 1123 -> 1523 bytes scripts/helpers/configure_toolchain.ps1 | 356 +++++ scripts/helpers/format_cpp.psm1 | 26 + 27 files changed, 985 insertions(+), 2538 deletions(-) create mode 100644 data/binaries/handmade_engine.exp create mode 100644 data/binaries/handmade_engine.lib create mode 100644 data/binaries/handmade_win32.exp create mode 100644 data/binaries/handmade_win32.lib create mode 100644 project/platform/context.hpp create mode 100644 project/platform/gen/context.gen.hpp delete mode 100644 project/platform/win32.hpp delete mode 100644 project/platform/win32_platform.cpp create mode 100644 scripts/.clang-format create mode 100644 scripts/helpers/configure_toolchain.ps1 create mode 100644 scripts/helpers/format_cpp.psm1 diff --git a/.vscode/bookmarks.json b/.vscode/bookmarks.json index a5935bf..30e7b89 100644 --- a/.vscode/bookmarks.json +++ b/.vscode/bookmarks.json @@ -1,35 +1,20 @@ { "files": [ { - "path": "project/platform/win32_platform.cpp", + "path": "project/platform/win32/win32_platform.cpp", "bookmarks": [ { - "line": 59, + "line": 39, "column": 0, "label": "Struct Defs" }, { - "line": 98, + "line": 58, "column": 0, "label": "Static Data" }, { - "line": 661, - "column": 0, - "label": "Timing" - }, - { - "line": 1592, - "column": 4, - "label": "Main Loop : Audio Processing" - }, - { - "line": 1713, - "column": 2, - "label": "Main Loop : Timing Update" - }, - { - "line": 1797, + "line": 980, "column": 0, "label": "Main Loop : End" } diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 71da193..c3b93be 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -12,6 +12,7 @@ "UNICODE", "_UNICODE", "GEN_TIME", + "INTELLISENSE_DIRECTIVES", "Build_Debug", "Build_Development", ], @@ -31,6 +32,7 @@ "UNICODE", "_UNICODE", "GEN_TIME", + "INTELLISENSE_DIRECTIVES", ], "windowsSdkVersion": "10.0.22621.0", "compilerPath": "clang.exe", diff --git a/.vscode/launch.json b/.vscode/launch.json index 1c9f279..85c72b9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,11 +16,20 @@ { "type":"cppvsdbg", "request": "launch", - "name" : "Debug handmade platform gen msvc", + "name" : "Debug handmade engine (post_build) gen msvc", "program": "${workspaceFolder}/build/engine_postbuild_gen.exe", "args": [], "cwd": "${workspaceFolder}/build", - "visualizerFile": "${workspaceFolder}/scripts/handmade.natvis" + "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" + }, + { + "type":"cppvsdbg", + "request": "launch", + "name" : "Debug handmade platform gen msvc", + "program": "${workspaceFolder}/build/platform_gen.exe", + "args": [], + "cwd": "${workspaceFolder}/project/platform", + "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" } ] } diff --git a/HandmadeHero.vcxproj b/HandmadeHero.vcxproj index c35545b..716b78a 100644 --- a/HandmadeHero.vcxproj +++ b/HandmadeHero.vcxproj @@ -28,9 +28,13 @@ + + + + @@ -39,14 +43,20 @@ + + + + + + diff --git a/data/binaries/handmade_engine.exp b/data/binaries/handmade_engine.exp new file mode 100644 index 0000000000000000000000000000000000000000..f83e992bd50c4780927fd4a8ee4fe55700cf6c45 GIT binary patch literal 2263 zcmeHI&2AGh5T0a9%Wr8oaN-c59*U?|`2!VH)J;=RqW(psRHa%ea$|40u)AJ)cWJ0N zSKN6G#DzED%7qILz=kqKIo(168?_*CgiOs^F$;D36oo*3F@&)I|jZ`0?1yhTplaB$HK?U9EHsJoQ&p;Lo z7=v9FaG!C}7D3kygvmV*7G%)&B~LujR>G5vTj``_J*{pvA6B2N3SX+1R?*S}y|UVD zSfR&aM=Ia4tZi6`c9WRPz2JD8W2WLHJl5VM#E&o9crXk<;6fd?vPvO0f-s3&F|O*L zVcl_}juIkROdJO{^iTGuW0I|nT_qT=$siWJ7&p?<2N5LPl}DUci9HcNm+{KSuo-Xz zk@CTSJmR?4rV%H!HiLLYYx9WbwKj`LS!hrm!Ue4r5U*-&3Gt%VDu`2Bt0P|0+8km| zYb%Hp1!WSzcWj?AgR79CX{g<|LnWVyP8`|wexB8Zk~S5Gz2gQ?-ExAGsd- z{bgy>jS}YNTQOaYT`H7HwA2w%gijVb^68Z{4lf zJ#3yEJU7W3EW=!m%Jf8vsfNbz!~R=QEus;6TNa|@7uRdFL03IY@&8t20Y*Y8KaAv* zi_PjtKQvvAIhdh`7z@V{EH(>;DXgfJIsEL?-5YTDfu{>JAlhGJKIX?Zj?y)%8@|8+ zP?-*xbQP8BfZ1DD9H2R5rq>E6MF>Wi61*Q_%J6N3slY6nO)aN(?!dbtgNt=JQ%^#1 j12idABego02(|ATlgVv&mWAku;dK?L>WslM5r%|{bW!zN^5cIM5#o%zlC`0d+)JG>H4 z-gS(+%CGC5a@myJY~XQwZyCcS2LPM}=sX1I8V2ZIMRCt)y)FRSde)8Bn@1U&bBi{P z3xy+d(HJ*5H9rvzMPhSNF3C$mh8ILmlvYxb2pl)NFf&uB2v3h`8hWvN3$xSQWH1(l zfGlwtS3EAXnwp?lFCk{~LjK*H1oAt|e=^D1gF zpUfo^xws;V(zupL;0w%CwcJM6iX|117bav$6(6hkV$qc?$5F6^CZyyFBLwMeGtS%O z-RkF$u>yZ|0>B~OhPwb(y8-r)OpcK@?6;gc!9Y8lhEvc1onQldiPYAZT(^`W zRwGvl?f~A#Aik|L)sg7j0PIAWP9}L=cy?mBD#K0tn&Yxhb%o zfOC8#g&#bA&}%+AkAn}`zOjim>lQd`a!y5ZB9Us*}m7Eq?{pWo|YD3zxRKhg~q4~KfBJBD2`h5fu(wfyuomdTE-M+qAiSOBBZhsT; kwNZR#8PKv?v>~VT`6?oM^UJFrYk11`(o;6M*r|4wzc9eE1^@s6 literal 0 HcmV?d00001 diff --git a/data/binaries/handmade_win32.exp b/data/binaries/handmade_win32.exp new file mode 100644 index 0000000000000000000000000000000000000000..f12565c07b161fa4e11ddde137ed853797a8a746 GIT binary patch literal 808 zcma)4UuzRV5T7J!RYaP19}dYw)pA@eMO3P8EtU8$79%CfLfPK#rQ6=!9=jJ)#Am;N zAIlfNil0D#d&$*^2px9*{g|Ddof-MHO}{`d+eFuCL7|eO5=#f_6fD6%me3Vwh7(G4 zG@JIuOPHRth;D#aiP8Eq@B23z+=n#WV1MglQOI0KbvW0>AP&`;qNl0O)M09D0-4R+ zF)K4s!Ot1{urt};+nKPBcpr%_fje{y@^WnjkiO;)^&r=3YXkCHZEZqctu24=CpboN zj9OiowEKvc)|{xMa(uX~YN)K?zD4{<7s6`g_&)`gbdR>XYslPmjp!!brte>f-sr>{ zXVNOzcy}jw{bKZrzR}|@C3E@T_sI7E#q3)%wIUCmqZ^L@$#kIIOk}~hnn`VV9L2E@ zO_g)n6e8mXyZpT|8Lo_B_P4?TPXFOx;Qzpf##NL1Tl@^1>Eg8RIBn8{uAkGzTF(-b zm!X#UVaw0DLo8LI3ZrNp?OhciXmy9Mf5U>#pZ3lX81-&=?Ws+7Ausm3-xOG}4*&oF literal 0 HcmV?d00001 diff --git a/data/binaries/handmade_win32.lib b/data/binaries/handmade_win32.lib new file mode 100644 index 0000000000000000000000000000000000000000..74d01df99b149bd39c2a4f3fd343a157056658c1 GIT binary patch literal 2012 zcmcIlL2DC16#lY_ZCyk{^`am|2~-az>87z3#BQ{OhNfxQrqFuXtl5nTBuz+D^iWU` zd(j`@kLX_z;<*b&V;Gw>^nQ618Z8ky%cILge-_E@G=6ka@A6TtY<)Ipn zc-!4+uP?oXFsA433#+ICxBw_+Ahb{BAuw+6W15+j{Hjqf7Z%qZ8<~7z)i5j8mR+}O z$9!JhN@_68+>1_g>)f}`Es@9nB_*RM15^%yP`L1R-62~u5YF{ z@{8#W{RvH9tv5}7*kKva5+@9Vh=Q^L?2~awTo~gnB?ut^h5DfHeE*-ZVfH$R-S|Ib z3|52GM^W`2T+DglK#fb;2-u+cQkr(GE_*Ks<<;A-*8{)=@ysn|J5P6>Mc29>utdf? z>4;HB_))BCTWu?<$yZm&_)O0a5eU+#BheAKdm;?RjnR4%$8jBz4jnPB;Uc@3?BD1V zu7v62@yP`MmvIXRyOS%`Qme7uD7PcGjXRNSCbul!dxlHoaX$P|CAn6ZdXf{x`WK^& zN{xDxQa{)Y1dfh+zobvVxhjwh=zyDjMMm7ccGnY_8OG2@IL4$-A{?LMPBfmKGI0BD zr=Up2C~JOL6=|v29u+BgJ^$f%hjQ%Ze!7Zmdf(f6RFsr)RtH^lp2jNTc}JxVKWBY| z)<5$?9l8dS30bs7m22?L`#;~m(F*6WcTNqaBwbv?T!Xz$hc0VyM#dTUMLJ?++^AUg q!*G=H7ye literal 0 HcmV?d00001 diff --git a/project/codegen/engine_postbuild_gen.cpp b/project/codegen/engine_postbuild_gen.cpp index a8d63cf..3b66ebf 100644 --- a/project/codegen/engine_postbuild_gen.cpp +++ b/project/codegen/engine_postbuild_gen.cpp @@ -93,7 +93,7 @@ int gen_main() builder.write(); #pragma pop_macro("str_ascii") - log_fmt("Generaton finished for Handmade Hero: Engine Module\n"); + log_fmt("Generaton finished for Handmade Hero: Engine Module\n\n"); // gen::deinit(); return 0; } diff --git a/project/codegen/platform_gen.cpp b/project/codegen/platform_gen.cpp index 22469db..9b49bf5 100644 --- a/project/codegen/platform_gen.cpp +++ b/project/codegen/platform_gen.cpp @@ -6,11 +6,72 @@ #include "dependencies/gen.hpp" using namespace gen; +#define path_gen "./gen/" + + int gen_main() { gen::init(); log_fmt("Generating code for Handmade Hero: Platform Module\n"); - log_fmt("Generaton finished for Handmade Hero: Platform Module\n"); + + CodeComment generation_notice = def_comment( txt("This was generated by project/codegen/platform_gen.cpp") ); + + Builder builder = Builder::open( path_gen "context.gen.hpp"); + builder.print( generation_notice ); + builder.print( fmt_newline ); + + FileContents h_context = file_read_contents(GlobalAllocator, true, "context.hpp"); + CodeBody code_context = parse_global_body( { h_context.size, rcast( char const*, h_context.data ) } ); + + CodeStruct context_struct = {}; + for ( Code code : code_context ) + { + if ( code->Type == ECode::Struct ) + { + if ( str_compare( code->Name, txt("Context") ) == 0 ) + { + context_struct = code; + break; + } + break; + } + } + + Array context_data_members = Array::init_reserve( GlobalAllocator, kilobytes( 1 ) ); + for ( Code code : context_struct->Body ) + { + if ( code->Type == ECode::Variable ) + { + context_data_members.append( code ); + } + } + + CodeDefine using_context; + { + String using_context_content = String::make_reserve( GlobalAllocator, kilobytes( 1 ) ); + { + String + content = using_context_content; + content.append( "\\\n" ); + + for ( s32 id = 0; id < context_data_members.num() - 1; ++id ) + { + Code code = context_data_members[ id ]; + content.append( code.to_string() ); + + // Default serializer inserts a newline at the end of the string, we need to insert a line continuation + content[ content.length() - 1 ] = '\\'; + content.append( "\n" ); + } + content.append( context_data_members[ context_data_members.num() - 1 ]->to_string() ); + } + using_context = def_define( txt("using_context()"), using_context_content ); + } + + builder.print( using_context ); + builder.write(); + + log_fmt("Generaton finished for Handmade Hero: Platform Module\n\n"); // gen::deinit(); return 0; } diff --git a/project/dependencies/gen.hpp b/project/dependencies/gen.hpp index b31cb04..0171dc4 100644 --- a/project/dependencies/gen.hpp +++ b/project/dependencies/gen.hpp @@ -18050,6 +18050,8 @@ namespace Parser ); return { { nullptr }, 0 }; } + move_forward(); + content.Length++; while ( left && current != '"' && current != '>' ) { diff --git a/project/engine/engine.cpp b/project/engine/engine.cpp index 217bd12..b9e84c5 100644 --- a/project/engine/engine.cpp +++ b/project/engine/engine.cpp @@ -30,15 +30,21 @@ struct EngineActions #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 { + f32 auto_snapshot_interval; + f32 auto_snapshot_timer; + s32 wave_tone_hz; s32 tone_volume; s32 x_offset; @@ -115,6 +121,7 @@ internal void take_engine_snapshot( Memory* memory, platform::ModuleAPI* platform_api ) { platform_api->memory_copy( memory->snapshots[ memory->active_snapshot_slot ].memory, memory->total_size(), memory->persistent ); + memory->snapshots[ memory->active_snapshot_slot ].age = platform_api->get_wall_clock(); } internal @@ -128,6 +135,7 @@ void take_game_snapshot( Memory* memory, platform::ModuleAPI* platform_api ) platform_api->memory_copy( persistent_slot, state->game_memory.persistent_size, state->game_memory.persistent ); platform_api->memory_copy( transient_slot, state->game_memory.transient_size, state->game_memory.transient ); + memory->snapshots[ memory->active_snapshot_slot ].age = platform_api->get_wall_clock(); } internal @@ -300,7 +308,7 @@ void input_poll_engine_actions( InputState* input, EngineActions* actions ) actions->toggle_wave_tone |= pressed( keyboard->Q ); - actions->loop_mode_game |= pressed( keyboard->L ) && ! keyboard->right_shift.ended_down; + actions->loop_mode_game |= pressed( keyboard->L ) && ! keyboard->right_shift.ended_down && ! keyboard->right_alt.ended_down; actions->loop_mode_engine |= pressed( keyboard->L ) && keyboard->right_shift.ended_down; MousesState* mouse = controller->mouse; @@ -311,6 +319,7 @@ void input_poll_engine_actions( InputState* input, EngineActions* actions ) actions->move_up = (mouse->vertical_wheel.end > 0.f) * 10; actions->move_down = (mouse->vertical_wheel.end < 0.f) * 10; + actions->load_auto_snapshot |= pressed( keyboard->L ) && keyboard->right_alt.ended_down; } internal @@ -402,7 +411,14 @@ void draw_rectangle( OffscreenBuffer* buffer if ( max_y_32 > buffer_height ) max_y_32 = buffer_height; - s32 color = (scast(s32, red) << 16) | (scast(s32, green) << 8) | (scast(s32, blue) << 0); + s32 red_32 = round_f32_to_s32( 255.f * red ); + s32 green_32 = round_f32_to_s32( 255.f * green ); + s32 blue_32 = round_f32_to_s32( 255.f * blue ); + + s32 color = + (scast(s32, red_32) << 16) + | (scast(s32, green_32) << 8) + | (scast(s32, blue_32) << 0); // Start with the pixel on the top left corner of the rectangle u8* row = rcast(u8*, buffer->memory ) @@ -439,14 +455,18 @@ void startup( Memory* memory, platform::ModuleAPI* platform_api ) memory->game_loop_active = false; #endif +#if 0 for ( s32 slot = 0; slot < memory->Num_Snapshot_Slots; ++ slot ) { // TODO(Ed) : Specify default file paths for saving slots ? } +#endif EngineState* state = rcast( EngineState*, memory->persistent ); assert( sizeof(EngineState) <= memory->persistent_size ); + state->auto_snapshot_interval = 10.f; + state->tone_volume = 1000; state->x_offset = 0; @@ -465,8 +485,8 @@ void startup( Memory* memory, platform::ModuleAPI* platform_api ) hh::PlayerState* player = rcast( hh::PlayerState*, state->game_memory.persistent ); assert( sizeof(hh::PlayerState) <= state->game_memory.persistent_size ); - player->pos_x = 100; - player->pos_y = 100; + player->pos_x = 920; + player->pos_y = 466; player->mid_jump = false; player->jump_time = 0.f; } @@ -483,6 +503,22 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back EngineState* state = rcast( EngineState*, memory->persistent ); assert( sizeof(EngineState) <= memory->persistent_size ); + // Engine auto_snapshot + { + state->auto_snapshot_timer += delta_time; + if ( state->auto_snapshot_timer >= state->auto_snapshot_interval ) + { + state->auto_snapshot_timer = 0.f; + + s32 current_slot = memory->active_snapshot_slot; + memory->active_snapshot_slot = 0; + + take_engine_snapshot( memory, platform_api ); + memory->active_snapshot_slot = current_slot; + state->auto_snapshot_timer = 0.f; + } + } + ControllerState* controller = & input->controllers[0]; EngineActions engine_actions {}; @@ -490,6 +526,14 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back input_poll_engine_actions( input, & engine_actions ); + if ( engine_actions.load_auto_snapshot ) + { + s32 current_slot = memory->active_snapshot_slot; + memory->active_snapshot_slot = 0; + load_engine_snapshot( memory, platform_api ); + memory->active_snapshot_slot = current_slot; + } + #if Build_Development // Ease of use: Allow user to press L key without shift if engine loop recording is active. engine_actions.loop_mode_engine |= engine_actions.loop_mode_game && memory->engine_loop_active; @@ -571,10 +615,8 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back if ( ! memory->game_loop_active ) { - if ( engine_actions.set_snapshot_slot_1 ) memory->active_snapshot_slot = 0; - if ( engine_actions.set_snapshot_slot_2 ) memory->active_snapshot_slot = 1; - if ( engine_actions.set_snapshot_slot_3 ) memory->active_snapshot_slot = 2; - if ( engine_actions.set_snapshot_slot_4 ) memory->active_snapshot_slot = 3; + if ( engine_actions.set_snapshot_slot_1 ) memory->active_snapshot_slot = 1; + if ( engine_actions.set_snapshot_slot_2 ) memory->active_snapshot_slot = 2; } #endif } @@ -599,14 +641,18 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back input_poll_player_actions( input, & player_actions ); { - player->pos_x += player_actions.player_x_move_digital * 5; - player->pos_y -= player_actions.player_y_move_digital * 5; - player->pos_x += scast(u32, player_actions.player_x_move_analog * 5); - player->pos_y -= scast(u32, player_actions.player_y_move_analog * 5) - scast(u32, sinf( player->jump_time * TAU ) * 10); + f32 move_speed = 200.f; + + player->pos_x += scast(f32, player_actions.player_x_move_digital) * delta_time * move_speed; + player->pos_y -= scast(f32, player_actions.player_y_move_digital) * delta_time * move_speed; + + player->pos_x += scast(f32, player_actions.player_x_move_analog * delta_time * move_speed); + player->pos_y -= scast(f32, player_actions.player_y_move_analog * delta_time * move_speed); + player->pos_y += sinf( player->jump_time * TAU ) * 200.f * delta_time; if ( player->jump_time > 0.f ) { - player->jump_time -= 0.025f; + player->jump_time -= delta_time; } else { @@ -624,21 +670,97 @@ 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); - // render_weird_graident( back_buffer, state->x_offset, state->y_offset ); draw_rectangle( back_buffer , 0.f, 0.f , scast(f32, back_buffer->width), scast(f32, back_buffer->height) - , 0x22, 0x22, 0x22 ); - render_player( back_buffer, player->pos_x, player->pos_y ); + , 1.f, 0.24f, 0.24f ); + + // Draw tilemap + u32 tilemap[9][16] = { + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, + { 1, 1, 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, 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + }; + + f32 upper_left_x = 0; + f32 upper_left_y = 0; + + f32 tile_width = 119; + f32 tile_height = 116; + + for ( s32 row = 0; row < 9; ++ row ) + { + for ( s32 col = 0; col < 16; ++ col ) + { + u32 tileID = tilemap[row][col]; + f32 grey[3] = { 0.15f, 0.15f, 0.15f }; + + if ( tileID == 1 ) + { + grey[0] = 0.22f; + grey[1] = 0.22f; + grey[2] = 0.22f; + } + + f32 min_x = upper_left_x + scast(f32, col) * tile_width; + f32 min_y = upper_left_y + scast(f32, row) * tile_height; + f32 max_x = min_x + tile_width; + f32 max_y = min_y + tile_height; + + draw_rectangle( back_buffer + , min_x, min_y + , max_x, max_y + , grey[0], grey[1], grey[2] ); + } + } + + // Player + f32 player_width = 50.f; + f32 player_height = 100.f; + + f32 player_red = 0.3f; + f32 player_green = 0.3f; + f32 player_blue = 0.3f; + + draw_rectangle( back_buffer + , player->pos_x, player->pos_y + , player->pos_x + player_width, player->pos_y + player_height + , player_red, player_green, player_blue ); + + // Auto-Snapshot percent bar + if (1) + { + f32 snapshot_percent_x = ((state->auto_snapshot_timer / state->auto_snapshot_interval)) * (f32)back_buffer->width / 4.f; + draw_rectangle( back_buffer + , 0.f, 0.f + , snapshot_percent_x, 10.f + , 0x00, 0.15f, 0.35f ); + } #if Build_Development if ( memory->replay_mode == ReplayMode_Record ) - render_player( back_buffer, player->pos_x + 20, player->pos_y - 20 ); + { + draw_rectangle( back_buffer + , scast(f32, player->pos_x) + 50.f, scast(f32, player->pos_y) - 50.f + , scast(f32, player->pos_x) + 10.f, scast(f32, player->pos_y) + 40.f + , 1.f, 1.f, 1.f ); + } #endif - render_player( back_buffer, (s32)input->controllers[0].mouse->X.end, (s32)input->controllers[0].mouse->Y.end ); + // Change above to use draw rectangle + draw_rectangle( back_buffer + , (f32)input->controllers[0].mouse->X.end, (f32)input->controllers[0].mouse->Y.end + , (f32)input->controllers[0].mouse->X.end + 10.f, (f32)input->controllers[0].mouse->Y.end + 10.f + , 1.f, 1.f, 0.f ); // Mouse buttons test + #if 0 { if ( input->controllers[0].mouse->left.ended_down == true ) render_player( back_buffer, 5, 5 ); @@ -650,6 +772,7 @@ void update_and_render( f32 delta_time, InputState* input, OffscreenBuffer* back if ( input->controllers[0].mouse->right.ended_down == true ) render_player( back_buffer, 5, 35 ); } + #endif } Engine_API diff --git a/project/engine/engine.hpp b/project/engine/engine.hpp index 1caf252..b76c281 100644 --- a/project/engine/engine.hpp +++ b/project/engine/engine.hpp @@ -35,6 +35,7 @@ struct MemorySnapshot void* opaque_handle; void* opaque_handle_2; void* memory; + u64 age; }; struct Memory @@ -56,7 +57,7 @@ struct Memory // TODO(Ed) : Move this crap to state & replay archive definitions? #if Build_Development static constexpr - s32 Num_Snapshot_Slots = 2; + 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; diff --git a/project/gen/engine_symbol_table.hpp b/project/gen/engine_symbol_table.hpp index f22d898..37d90be 100644 --- a/project/gen/engine_symbol_table.hpp +++ b/project/gen/engine_symbol_table.hpp @@ -3,15 +3,12 @@ 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"); -constexpr -Str const symbol_shutdown = str_ascii("?shutdown@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z"); -constexpr -Str const symbol_update_and_render = str_ascii("?update_and_render@engine@@YAXMPEAUInputState@1@PEAUOffscreenBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@PEAUThreadContext@1@@Z"); -constexpr -Str const symbol_update_audio = str_ascii("?update_audio@engine@@YAXMPEAUAudioBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@PEAUThreadContext@1@@Z"); +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" ); +constexpr Str const symbol_shutdown = str_ascii( "?shutdown@engine@@YAXPEAUMemory@1@PEAUModuleAPI@platform@@@Z" ); +constexpr Str const symbol_update_and_render = + str_ascii( "?update_and_render@engine@@YAXMPEAUInputState@1@PEAUOffscreenBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@PEAUThreadContext@1@@Z" ); +constexpr Str const symbol_update_audio = + str_ascii( "?update_audio@engine@@YAXMPEAUAudioBuffer@1@PEAUMemory@1@PEAUModuleAPI@platform@@PEAUThreadContext@1@@Z" ); NS_ENGINE_END diff --git a/project/handmade.hpp b/project/handmade.hpp index 8f1fe3c..88ab10f 100644 --- a/project/handmade.hpp +++ b/project/handmade.hpp @@ -70,8 +70,8 @@ struct Player struct PlayerState { - s32 pos_x; - s32 pos_y; + f32 pos_x; + f32 pos_y; b32 mid_jump; f32 jump_time; diff --git a/project/handmade_win32.cpp b/project/handmade_win32.cpp index d7e0e21..efaf60b 100644 --- a/project/handmade_win32.cpp +++ b/project/handmade_win32.cpp @@ -1,5 +1,5 @@ #include "platform/compiler_ignores.hpp" #if Build_Unity -#include "platform/win32_platform.cpp" +#include "platform/win32/win32_platform.cpp" #endif diff --git a/project/platform/context.hpp b/project/platform/context.hpp new file mode 100644 index 0000000..a99ec13 --- /dev/null +++ b/project/platform/context.hpp @@ -0,0 +1,15 @@ +#include "platform.hpp" + + +struct Context +{ + Context* parent; + // AllocatorInfo allocator; + // Logger logger; +}; + + +Context* make_context(); + + +#include "gen/context.gen.hpp" diff --git a/project/platform/gen/context.gen.hpp b/project/platform/gen/context.gen.hpp new file mode 100644 index 0000000..096e975 --- /dev/null +++ b/project/platform/gen/context.gen.hpp @@ -0,0 +1,3 @@ +// This was generated by project/codegen/platform_gen.cpp + +#define using_context() Context* parent; diff --git a/project/platform/macros.hpp b/project/platform/macros.hpp index 6781700..005c593 100644 --- a/project/platform/macros.hpp +++ b/project/platform/macros.hpp @@ -67,47 +67,12 @@ # define compiler_decorated_func_name __FUNCDNAME__ #endif -// TODO(Ed) : Add this sauce later -#if 0 -#define congrats( message ) -#define ensure( condition, expression ) -#define fatal( message ) -#endif - -// Just experimenting with a way to check for global variables being accessed from the wrong place. -// (Could also be done with gencpp technically) -#if 0 -enum class EGlobalVarsAllowFuncs -{ - ProcessPendingWindowMessages, - Num, - Invalid, -}; -EGlobalVarsAllowFuncs to_type( char const* proc_name ) -{ - char const* global_vars_allowed_funcs[] { - "process_pending_window_messages" - }; - - if ( proc_name ) - { - for ( u32 idx = 0; idx < array_count( global_vars_allowed_funcs ); ++idx ) - { - if ( strcmp( proc_name, global_vars_allowed_funcs[idx] ) == 0 ) - { - return scast( EGlobalVarsAllowFuncs, idx ); - } - } - } - - return EGlobalVarsAllowFuncs::Invalid; -} - #if Build_Development -# define checked_global_getter( global_var, procedure ) \ - ( ensure( to_type(procedure) != EGlobalVarsAllowFuncs::Invalid), global_var ) +# define congrats( message ) platform::impl_congrats( message ) +# define ensure( condition, message ) platform::impl_ensure( condition, message ) +# define fatal( message ) platform::impl_fatal( message ) #else -# define checked_global_getter( global_var, procedure ) global_var -#endif - +# define congrats( message ) +# define ensure( condition, message ) +# define fatal( message ) #endif diff --git a/project/platform/platform.hpp b/project/platform/platform.hpp index 98341cc..94da947 100644 --- a/project/platform/platform.hpp +++ b/project/platform/platform.hpp @@ -18,6 +18,7 @@ #include "math_constants.hpp" #include "types.hpp" #include "strings.hpp" +#include "context.hpp" #define NS_PLATFORM_BEGIN namespace platform { #define NS_PLATFORM_END } @@ -80,6 +81,8 @@ using FileRewindFn = void ( File* file ); using MemoryCopyFn = void( void* dest, u64 src_size, void* src ); +using GetWallClockFn = u64(); + struct ModuleAPI { Str path_root; @@ -90,6 +93,8 @@ struct ModuleAPI DebugSetPauseRenderingFn* debug_set_pause_rendering; #endif + GetWallClockFn* get_wall_clock; + GetMonitorRefreshRateFn* get_monitor_refresh_rate; SetMonitorRefreshRateFn* set_monitor_refresh_rate; @@ -112,6 +117,12 @@ struct ModuleAPI MemoryCopyFn* memory_copy; }; +#if Build_Development +void impl_congrats( char const* message ); +bool impl_ensure( bool condition, char const* message ); +void impl_fatal( char const* message ); +#endif + #pragma endregion Settings Exposure NS_PLATFORM_END diff --git a/project/platform/win32.hpp b/project/platform/win32.hpp deleted file mode 100644 index 1182e03..0000000 --- a/project/platform/win32.hpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - Windows dependency header -*/ -#pragma once - -#pragma warning( push ) -#pragma warning( disable: 5105 ) -#pragma warning( disable: 4820 ) -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#pragma warning( pop ) - -// #include "windows/windows_base.h" -// #include "windows/window.h" - -// #include "windows/file.h" -// #include "windows/io.h" - -// #if Build_Debug -// # include "windows/dbghelp.h" -// #endif - -#if Build_DLL -# define WIN_LIB_API extern "C" __declspec(dllexport) -#else -# define WIN_LIB_API extern "C" -#endif - -// #ifndef CONST -// # define CONST const -// #endif - -// SAL BS -#ifndef _In_ -# define _In_ -#endif - -#define NS_WIN32_BEGIN namespace win32 { -#define NS_WIN32_END } - -NS_WIN32_BEGIN - -enum LWA : DWORD -{ - LWA_Alpha = 0x00000002, - LWA_ColorKey = 0x00000001, -}; - -enum BI : DWORD -{ - BI_RGB_Uncompressed = 0L, - BI_RunLength_Encoded_8bpp = 1L, - BI_RunLength_Encoded_4bpp = 2L, -}; - -enum CS : UINT -{ - CS_Own_Device_Context = CS_OWNDC, - CS_Horizontal_Redraw = CS_HREDRAW, - CS_Vertical_Redraw = CS_VREDRAW, -}; - -enum CW : s32 -{ - CW_Use_Default = CW_USEDEFAULT, -}; - -enum DIB : UINT -{ - DIB_ColorTable_RGB = 0, - DIB_ColorTable_Palette = 1 - -}; - -enum MB : UINT -{ - MB_Ok_Btn = MB_OK, - MB_Icon_Information = MB_ICONINFORMATION, -}; - -enum Mem : DWORD -{ - MEM_Commit_Zeroed = MEM_COMMIT, - MEM_Reserve = MEM_RESERVE, - MEM_Release = MEM_RELEASE, - MEM_Use_Large_pages = MEM_LARGE_PAGES, -}; - -enum Page : DWORD -{ - Page_Read_Write = PAGE_READWRITE, -}; - -enum PM : UINT -{ - PM_Remove_Messages_From_Queue = PM_REMOVE, -}; - -enum RasterOps : DWORD -{ - RO_Source_To_Dest = (DWORD)0x00CC0020, - RO_Blackness = (DWORD)0x00000042, - RO_Whiteness = (DWORD)0x00FF0062, -}; - -#define WM_ACTIVATEAPP 0x001C - -enum WS : UINT -{ - WS_Overlapped_Window = WS_OVERLAPPEDWINDOW, - WS_Initially_Visible = WS_VISIBLE, -}; - -enum XI_State : DWORD -{ - XI_PluggedIn = ERROR_SUCCESS, -}; - - -template< typename ProcSignature > -ProcSignature* get_procedure_from_library( HMODULE library_module, char const* symbol ) -{ - void* address = rcast( void*, GetProcAddress( library_module, symbol ) ); - return rcast( ProcSignature*, address ); -} - -#pragma region XInput -WIN_LIB_API DWORD WINAPI XInputGetState -( - DWORD dwUserIndex, // Index of the gamer associated with the device - XINPUT_STATE* pState // Receives the current state -); - -WIN_LIB_API DWORD WINAPI XInputSetState -( - DWORD dwUserIndex, // Index of the gamer associated with the device - XINPUT_VIBRATION* pVibration // The vibration information to send to the controller -); - -DWORD WINAPI xinput_get_state_stub( DWORD dwUserIndex, XINPUT_STATE* pVibration ) { - do_once_start - OutputDebugStringA( "xinput_get_state stubbed!\n"); - do_once_end - return ERROR_DEVICE_NOT_CONNECTED; -} - -DWORD WINAPI xinput_set_state_stub( DWORD dwUserIndex, XINPUT_VIBRATION* pVibration ) { - do_once_start - OutputDebugStringA( "xinput_set_state stubbed!\n"); - do_once_end - return ERROR_DEVICE_NOT_CONNECTED; -} - -using XInputGetStateFn = DWORD WINAPI( DWORD dwUserIndex, XINPUT_STATE* pVibration ); -using XInputSetStateFn = DWORD WINAPI( DWORD dwUserIndex, XINPUT_VIBRATION* pVibration ); - -global XInputGetStateFn* xinput_get_state = xinput_get_state_stub; -global XInputSetStateFn* xinput_set_state = xinput_set_state_stub; - -internal void -xinput_load_library_bindings() -{ - HMODULE xinput_lib = LoadLibraryA( XINPUT_DLL_A ); - - XInputGetStateFn* get_state = get_procedure_from_library< XInputGetStateFn >( xinput_lib, "XInputGetState" ); - XInputSetStateFn* set_state = get_procedure_from_library< XInputSetStateFn >( xinput_lib, "XInputSetState" ); - - if ( get_state ) - xinput_get_state = get_state; - - if ( set_state ) - xinput_set_state = set_state; -} -#pragma endregion XInput - -NS_WIN32_END -#undef _SAL_nop_impl_ -#undef _SAL2_Source_ -#undef _Deref_post2_impl_ -#undef _Outptr_result_bytebuffer_ -#undef _At_ -#undef _When_ -#undef GDI_DIBSIZE diff --git a/project/platform/win32_platform.cpp b/project/platform/win32_platform.cpp deleted file mode 100644 index 08db01e..0000000 --- a/project/platform/win32_platform.cpp +++ /dev/null @@ -1,1814 +0,0 @@ -/* - TODO : This is not a final platform layer - - - Saved game locations - - Getting a handle to our own executable file - - Asset loading path - - Threading (launch a thread) - - Raw Input (support for multiple keyboards) - - Sleep / timeBeginPeriod - - ClipCursor() (for multimonitor support) - - Fullscreen support - - WM_SETCURSOR (control cursor visibility) - - QueryCancelAutoplay - - WM_ACTIVATEAPP (for when not active) - - Blit speed improvemnts (BitBlt) - - Hardware acceleration ( OpenGL or Direct3D or both ) - - GetKeyboardLayout (for French keyboards, international WASD support) -*/ - -// Platform Layer headers -#include "platform.hpp" -#include "jsl.hpp" // Using this to get dualsense controllers -#include "win32.hpp" - -// Engine layer headers -#include "engine/engine.hpp" -#include "engine/engine_to_platform_api.hpp" - -#include "gen/engine_symbol_table.hpp" - -#if 1 -// TODO(Ed): Redo these macros properly later. - -#define congrats( message ) do { \ - JslSetLightColour( 0, (255 << 16) | (215 << 8) ); \ - MessageBoxA( 0, message, "Congratulations!", MB_OK | MB_ICONEXCLAMATION ); \ - JslSetLightColour( 0, (255 << 8 ) ); \ -} while (0) - -#define ensure( condition, message ) ensure_impl( condition, message ) -inline bool -ensure_impl( bool condition, char const* message ) { - if ( ! condition ) { - JslSetLightColour( 0, (255 << 16) ); - MessageBoxA( 0, message, "Ensure Failure", MB_OK | MB_ICONASTERISK ); - JslSetLightColour( 0, ( 255 << 8 ) ); - } - return condition; -} - -#define fatal(message) do { \ - JslSetLightColour( 0, (255 << 16) ); \ - MessageBoxA( 0, message, "Fatal Error", MB_OK | MB_ICONERROR ); \ - JslSetLightColour( 0, (255 << 8 ) ); \ -} while (0) -#endif - -NS_PLATFORM_BEGIN -using namespace win32; - -// This is the "backbuffer" data related to the windowing surface provided by the operating system. -struct OffscreenBuffer -{ - BITMAPINFO info; - char _PAD_[4]; - void* memory; // Lets use directly mess with the "pixel's memory buffer" - s32 width; - s32 height; - s32 pitch; - s32 bytes_per_pixel; -}; - -struct WinDimensions -{ - u32 width; - u32 height; -}; - -// TODO : This will def need to be looked over. -struct DirectSoundBuffer -{ - LPDIRECTSOUNDBUFFER secondary_buffer; - s16* samples; - u32 secondary_buffer_size; - u32 samples_per_second; - u32 bytes_per_sample; - - // TODO(Ed) : Makes math easier... - u32 bytes_per_second; - u32 guard_sample_bytes; - - DWORD is_playing; - u32 running_sample_index; - - // TODO(Ed) : Should this be in bytes? - u32 latency_sample_count; -}; - -#pragma region Static Data -global StrPath Path_Root; -global StrPath Path_Binaries; -global StrPath Path_Scratch; - -// TODO(Ed) : This is a global for now. -global b32 Running = false; -global b32 Pause_Rendering = false; - -global WinDimensions Window_Dimensions; -global OffscreenBuffer Surface_Back_Buffer; - -using DirectSoundCreateFn = HRESULT WINAPI (LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter ); -global DirectSoundCreateFn* direct_sound_create; - -constexpr u64 Tick_To_Millisecond = 1000; -constexpr u64 Tick_To_Microsecond = 1000 * 1000; - -global u64 Performance_Counter_Frequency; - -// As of 2023 the highest refreshrate on the market is 500 hz. I'll just make this higher if something comes out beyond that... -constexpr u32 Monitor_Refresh_Max_Supported = 500; - -// Anything at or below the high performance frame-time is too low latency to sleep against the window's scheduler. -constexpr f32 High_Perf_Frametime_MS = 1000.f / 240.f; - -global u32 Monitor_Refresh_Hz = 60; -global u32 Engine_Refresh_Hz = Monitor_Refresh_Hz; -global f32 Engine_Frame_Target_MS = 1000.f / scast(f32, Engine_Refresh_Hz); -#pragma endregion Static Data - -#pragma region Internal -internal -FILETIME file_get_last_write_time( char const* path ) -{ - WIN32_FILE_ATTRIBUTE_DATA engine_dll_file_attributes = {}; - GetFileAttributesExA( path, GetFileExInfoStandard, & engine_dll_file_attributes ); - - return engine_dll_file_attributes.ftLastWriteTime; -#if 0 - WIN32_FIND_DATAA dll_file_info = {}; - HANDLE dll_file_handle = FindFirstFileA( path, & dll_file_info ); - if ( dll_file_handle == INVALID_HANDLE_VALUE ) - { - FindClose( dll_file_handle ); - } - return dll_file_info.ftLastWriteTime; -#endif -} - -struct AudioTimeMarker -{ - DWORD output_play_cursor; - DWORD output_write_cursor; - DWORD output_location; - DWORD output_byte_count; - - DWORD flip_play_curosr; - DWORD flip_write_cursor; - - DWORD expected_flip_cursor; -}; - -#if Build_Debug -internal void -debug_draw_vertical( s32 x_pos, s32 top, s32 bottom, s32 color ) -{ - if ( top <= 0 ) - { - top = 0; - } - - if ( bottom > Surface_Back_Buffer.height ) - { - bottom = Surface_Back_Buffer.height; - } - - if ( x_pos >= 0 && x_pos < Surface_Back_Buffer.width ) - { - u8* - pixel_byte = rcast(u8*, Surface_Back_Buffer.memory ); - pixel_byte += x_pos * Surface_Back_Buffer.bytes_per_pixel; - pixel_byte += top * Surface_Back_Buffer.pitch; - - for ( s32 y = top; y < bottom; ++ y ) - { - s32* pixel = rcast(s32*, pixel_byte); - *pixel = color; - - pixel_byte += Surface_Back_Buffer.pitch; - } - } -} - -inline void -debug_draw_sound_buffer_marker( DirectSoundBuffer* sound_buffer, f32 ratio - , u32 pad_x, u32 pad_y - , u32 top, u32 bottom - , DWORD value, u32 color ) -{ - // assert( value < sound_buffer->SecondaryBufferSize ); - u32 x = pad_x + scast(u32, ratio * scast(f32, value )); - debug_draw_vertical( x, top, bottom, color ); -} - -internal void -debug_sync_display( DirectSoundBuffer* sound_buffer - , u32 num_markers, AudioTimeMarker* markers - , u32 current_marker - , f32 ms_per_frame ) -{ - u32 pad_x = 32; - u32 pad_y = 16; - f32 buffers_ratio = scast(f32, Surface_Back_Buffer.width) / (scast(f32, sound_buffer->secondary_buffer_size) * 1); - - u32 line_height = 64; - for ( u32 marker_index = 0; marker_index < num_markers; ++ marker_index ) - { - AudioTimeMarker* marker = & markers[marker_index]; - assert( marker->output_play_cursor < sound_buffer->secondary_buffer_size ); - assert( marker->output_write_cursor < sound_buffer->secondary_buffer_size ); - assert( marker->output_location < sound_buffer->secondary_buffer_size ); - assert( marker->output_byte_count < sound_buffer->secondary_buffer_size ); - assert( marker->flip_play_curosr < sound_buffer->secondary_buffer_size ); - assert( marker->flip_write_cursor < sound_buffer->secondary_buffer_size ); - - DWORD play_color = 0x88888888; - DWORD write_color = 0x88800000; - DWORD expected_flip_color = 0xFFFFF000; - DWORD play_window_color = 0xFFFF00FF; - - u32 top = pad_y; - u32 bottom = pad_y + line_height; - if ( marker_index == current_marker ) - { - play_color = 0xFFFFFFFF; - write_color = 0xFFFF0000; - - top += pad_y + line_height; - bottom += pad_y + line_height; - - u32 row_2_top = top; - - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_play_cursor, play_color ); - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_write_cursor, write_color ); - - play_color = 0xFFFFFFFF; - write_color = 0xFFFF0000; - - top += pad_y + line_height; - bottom += pad_y + line_height; - - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_location, play_color ); - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_location + marker->output_byte_count, write_color ); - - play_color = 0xFFFFFFFF; - write_color = 0xFFFF0000; - - top += pad_y + line_height; - bottom += pad_y + line_height; - - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, row_2_top, bottom, marker->expected_flip_cursor, expected_flip_color ); - } - - DWORD play_window = marker->flip_play_curosr + 480 * sound_buffer->bytes_per_sample; - - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->flip_play_curosr, play_color ); - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, play_window, play_window_color ); - debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->flip_write_cursor, write_color ); - } -} -#endif - -#pragma region Direct Sound -internal void -init_sound(HWND window_handle, DirectSoundBuffer* sound_buffer ) -{ - // Load library - HMODULE sound_library = LoadLibraryA( "dsound.dll" ); - if ( ! ensure(sound_library, "Failed to load direct sound library" ) ) - { - // TOOD : Diagnostic - return; - } - - // Get direct sound object - direct_sound_create = get_procedure_from_library< DirectSoundCreateFn >( sound_library, "DirectSoundCreate" ); - if ( ! ensure( direct_sound_create, "Failed to get direct_sound_create_procedure" ) ) - { - // TOOD : Diagnostic - return; - } - - LPDIRECTSOUND direct_sound; - if ( ! SUCCEEDED(direct_sound_create( 0, & direct_sound, 0 )) ) - { - // TODO : Diagnostic - } - if ( ! SUCCEEDED( direct_sound->SetCooperativeLevel(window_handle, DSSCL_PRIORITY) ) ) - { - // TODO : Diagnostic - } - - WAVEFORMATEX - wave_format {}; - wave_format.wFormatTag = WAVE_FORMAT_PCM; /* format type */ - wave_format.nChannels = 2; /* number of channels (i.e. mono, stereo...) */ - wave_format.nSamplesPerSec = scast(u32, sound_buffer->samples_per_second); /* sample rate */ - wave_format.wBitsPerSample = 16; /* number of bits per sample of mono data */ - wave_format.nBlockAlign = wave_format.nChannels * wave_format.wBitsPerSample / 8 ; /* block size of data */ - wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign; /* for buffer estimation */ - wave_format.cbSize = 0; /* the count in bytes of the size of */ - - LPDIRECTSOUNDBUFFER primary_buffer; - { - DSBUFFERDESC - buffer_description { sizeof(buffer_description) }; - buffer_description.dwFlags = DSBCAPS_PRIMARYBUFFER; - buffer_description.dwBufferBytes = 0; - - if ( ! SUCCEEDED( direct_sound->CreateSoundBuffer( & buffer_description, & primary_buffer, 0 ) )) - { - // TODO : Diagnostic - } - if ( ! SUCCEEDED( primary_buffer->SetFormat( & wave_format ) ) ) - { - // TODO : Diagnostic - } - } - - DSBUFFERDESC - buffer_description { sizeof(buffer_description) }; - buffer_description.dwFlags = DSBCAPS_GETCURRENTPOSITION2; - buffer_description.dwBufferBytes = sound_buffer->secondary_buffer_size; - buffer_description.lpwfxFormat = & wave_format; - - if ( ! SUCCEEDED( direct_sound->CreateSoundBuffer( & buffer_description, & sound_buffer->secondary_buffer, 0 ) )) - { - // TODO : Diagnostic - } - if ( ! SUCCEEDED( sound_buffer->secondary_buffer->SetFormat( & wave_format ) ) ) - { - // TODO : Diagnostic - } -} - -internal void -ds_clear_sound_buffer( DirectSoundBuffer* sound_buffer ) -{ - LPVOID region_1; - DWORD region_1_size; - LPVOID region_2; - DWORD region_2_size; - - HRESULT ds_lock_result = sound_buffer->secondary_buffer->Lock( 0, sound_buffer->secondary_buffer_size - , & region_1, & region_1_size - , & region_2, & region_2_size - , 0 ); - if ( ! SUCCEEDED( ds_lock_result ) ) - { - return; - } - - u8* sample_out = rcast( u8*, region_1 ); - for ( DWORD byte_index = 0; byte_index < region_1_size; ++ byte_index ) - { - *sample_out = 0; - ++ sample_out; - } - - sample_out = rcast( u8*, region_2 ); - for ( DWORD byte_index = 0; byte_index < region_2_size; ++ byte_index ) - { - *sample_out = 0; - ++ sample_out; - } - - if ( ! SUCCEEDED( sound_buffer->secondary_buffer->Unlock( region_1, region_1_size, region_2, region_2_size ) )) - { - return; - } -} - -internal void -ds_fill_sound_buffer( DirectSoundBuffer* sound_buffer, DWORD byte_to_lock, DWORD bytes_to_write ) -{ - LPVOID region_1; - DWORD region_1_size; - LPVOID region_2; - DWORD region_2_size; - - HRESULT ds_lock_result = sound_buffer->secondary_buffer->Lock( byte_to_lock, bytes_to_write - , & region_1, & region_1_size - , & region_2, & region_2_size - , 0 ); - if ( ! SUCCEEDED( ds_lock_result ) ) - { - return; - } - - // TODO : Assert that region sizes are valid - - DWORD region_1_sample_count = region_1_size / sound_buffer->bytes_per_sample; - s16* sample_out = rcast( s16*, region_1 ); - s16* sample_in = sound_buffer->samples; - for ( DWORD sample_index = 0; sample_index < region_1_sample_count; ++ sample_index ) - { - *sample_out = *sample_in; - ++ sample_out; - ++ sample_in; - - *sample_out = *sample_in; - ++ sample_out; - ++ sample_in; - - ++ sound_buffer->running_sample_index; - } - - DWORD region_2_sample_count = region_2_size / sound_buffer->bytes_per_sample; - sample_out = rcast( s16*, region_2 ); - for ( DWORD sample_index = 0; sample_index < region_2_sample_count; ++ sample_index ) - { - *sample_out = *sample_in; - ++ sample_out; - ++ sample_in; - - *sample_out = *sample_in; - ++ sample_out; - ++ sample_in; - - ++ sound_buffer->running_sample_index; - } - - if ( ! SUCCEEDED( sound_buffer->secondary_buffer->Unlock( region_1, region_1_size, region_2, region_2_size ) )) - { - return; - } -} -#pragma endregion Direct Sound - -#pragma region Input - -// Max controllers for the platform layer and thus for all other layers is 4. (Sanity and xinput limit) -constexpr u32 Max_Controllers = 4; - -using JSL_DeviceHandle = int; -using EngineXInputPadStates = engine::XInputPadState[ Max_Controllers ]; -using EngineDSPadStates = engine::DualsensePadState[Max_Controllers]; - -internal void -input_process_digital_btn( engine::DigitalBtn* old_state, engine::DigitalBtn* new_state, u32 raw_btns, u32 btn_flag ) -{ -#define had_transition() ( old_state->ended_down != new_state->ended_down ) - new_state->ended_down = (raw_btns & btn_flag) > 0; - if ( had_transition() ) - new_state->half_transitions += 1; - else - new_state->half_transitions = 0; -#undef had_transition -} - -internal f32 -jsl_input_process_axis_value( f32 value, f32 deadzone_threshold ) -{ - f32 result = 0; - if ( value < -deadzone_threshold ) - { - result = (value + deadzone_threshold ) / (1.0f - deadzone_threshold ); - - if (result < -1.0f) - result = -1.0f; // Clamp to ensure it doesn't go below -1 - } - else if ( value > deadzone_threshold ) - { - result = (value - deadzone_threshold ) / (1.0f - deadzone_threshold ); - - if (result > 1.0f) - result = 1.0f; // Clamp to ensure it doesn't exceed 1 - } - return result; -} - -internal f32 -xinput_process_axis_value( s16 value, s16 deadzone_threshold ) -{ - f32 result = 0; - if ( value < -deadzone_threshold ) - { - result = scast(f32, value + deadzone_threshold) / (32768.0f - scast(f32, deadzone_threshold)); - } - else if ( value > deadzone_threshold ) - { - result = scast(f32, value + deadzone_threshold) / (32767.0f - scast(f32, deadzone_threshold)); - } - return result; -} - -internal void -poll_input( HWND window_handle, engine::InputState* input, u32 jsl_num_devices, JSL_DeviceHandle* jsl_device_handles - , engine::KeyboardState* old_keyboard, engine::KeyboardState* new_keyboard - , engine::MousesState* old_mouse, engine::MousesState* new_mouse - , EngineXInputPadStates* old_xpads, EngineXInputPadStates* new_xpads - , EngineDSPadStates* old_ds_pads, EngineDSPadStates* new_ds_pads ) -{ - // Keyboard Polling - // Keyboards are unified for now. - { - constexpr u32 is_down = 0x80000000; - input_process_digital_btn( & old_keyboard->_1, & new_keyboard->_1, GetAsyncKeyState( '1' ), is_down ); - input_process_digital_btn( & old_keyboard->_2, & new_keyboard->_2, GetAsyncKeyState( '2' ), is_down ); - input_process_digital_btn( & old_keyboard->_3, & new_keyboard->_3, GetAsyncKeyState( '3' ), is_down ); - input_process_digital_btn( & old_keyboard->_4, & new_keyboard->_4, GetAsyncKeyState( '4' ), is_down ); - input_process_digital_btn( & old_keyboard->Q, & new_keyboard->Q, GetAsyncKeyState( 'Q' ), is_down ); - input_process_digital_btn( & old_keyboard->E, & new_keyboard->E, GetAsyncKeyState( 'E' ), is_down ); - input_process_digital_btn( & old_keyboard->W, & new_keyboard->W, GetAsyncKeyState( 'W' ), is_down ); - input_process_digital_btn( & old_keyboard->A, & new_keyboard->A, GetAsyncKeyState( 'A' ), is_down ); - input_process_digital_btn( & old_keyboard->S, & new_keyboard->S, GetAsyncKeyState( 'S' ), is_down ); - input_process_digital_btn( & old_keyboard->D, & new_keyboard->D, GetAsyncKeyState( 'D' ), is_down ); - input_process_digital_btn( & old_keyboard->K, & new_keyboard->K, GetAsyncKeyState( 'K' ), is_down ); - input_process_digital_btn( & old_keyboard->L, & new_keyboard->L, GetAsyncKeyState( 'L' ), is_down ); - input_process_digital_btn( & old_keyboard->escape, & new_keyboard->escape, GetAsyncKeyState( VK_ESCAPE ), is_down ); - input_process_digital_btn( & old_keyboard->backspace, & new_keyboard->backspace, GetAsyncKeyState( VK_BACK ), is_down ); - input_process_digital_btn( & old_keyboard->up, & new_keyboard->up, GetAsyncKeyState( VK_UP ), is_down ); - input_process_digital_btn( & old_keyboard->down, & new_keyboard->down, GetAsyncKeyState( VK_DOWN ), is_down ); - input_process_digital_btn( & old_keyboard->left, & new_keyboard->left, GetAsyncKeyState( VK_LEFT ), is_down ); - input_process_digital_btn( & old_keyboard->right, & new_keyboard->right, GetAsyncKeyState( VK_RIGHT ), is_down ); - input_process_digital_btn( & old_keyboard->space, & new_keyboard->space, GetAsyncKeyState( VK_SPACE ), is_down ); - input_process_digital_btn( & old_keyboard->pause, & new_keyboard->pause, GetAsyncKeyState( VK_PAUSE ), is_down ); - input_process_digital_btn( & old_keyboard->left_alt, & new_keyboard->left_alt, GetAsyncKeyState( VK_LMENU ), is_down ); - input_process_digital_btn( & old_keyboard->right_alt, & new_keyboard->right_alt, GetAsyncKeyState( VK_RMENU ), is_down ); - input_process_digital_btn( & old_keyboard->left_shift, & new_keyboard->left_shift, GetAsyncKeyState( VK_LSHIFT ), is_down ); - input_process_digital_btn( & old_keyboard->right_shift, & new_keyboard->right_shift, GetAsyncKeyState( VK_RSHIFT ), is_down ); - - input->controllers[0].keyboard = new_keyboard; - } - - // Mouse polling - { - // input->Controllers[0].Mouse = {}; - - constexpr u32 is_down = 0x80000000; - input_process_digital_btn( & old_mouse->left, & new_mouse->left, GetAsyncKeyState( VK_LBUTTON ), is_down ); - input_process_digital_btn( & old_mouse->middle, & new_mouse->middle, GetAsyncKeyState( VK_MBUTTON ), is_down ); - input_process_digital_btn( & old_mouse->right, & new_mouse->right, GetAsyncKeyState( VK_RBUTTON ), is_down ); - - POINT mouse_pos; - GetCursorPos( & mouse_pos ); - ScreenToClient( window_handle, & mouse_pos ); - - new_mouse->vertical_wheel = {}; - new_mouse->horizontal_wheel = {}; - - new_mouse->X.end = (f32)mouse_pos.x; - new_mouse->Y.end = (f32)mouse_pos.y; - - input->controllers[0].mouse = new_mouse; - } - - // XInput Polling - // TODO(Ed) : Should we poll this more frequently? - for ( DWORD controller_index = 0; controller_index < Max_Controllers; ++ controller_index ) - { - XINPUT_STATE controller_state; - b32 xinput_detected = xinput_get_state( controller_index, & controller_state ) == XI_PluggedIn; - if ( xinput_detected ) - { - XINPUT_GAMEPAD* xpad = & controller_state.Gamepad; - engine::XInputPadState* old_xpad = old_xpads[ controller_index ]; - engine::XInputPadState* new_xpad = new_xpads[ controller_index ]; - input_process_digital_btn( & old_xpad->dpad.up, & new_xpad->dpad.up, xpad->wButtons, XINPUT_GAMEPAD_DPAD_UP ); - input_process_digital_btn( & old_xpad->dpad.down, & new_xpad->dpad.down, xpad->wButtons, XINPUT_GAMEPAD_DPAD_DOWN ); - input_process_digital_btn( & old_xpad->dpad.left, & new_xpad->dpad.left, xpad->wButtons, XINPUT_GAMEPAD_DPAD_LEFT ); - input_process_digital_btn( & old_xpad->dpad.right, & new_xpad->dpad.right, xpad->wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ); - - input_process_digital_btn( & old_xpad->Y, & new_xpad->Y, xpad->wButtons, XINPUT_GAMEPAD_Y ); - input_process_digital_btn( & old_xpad->A, & new_xpad->A, xpad->wButtons, XINPUT_GAMEPAD_A ); - input_process_digital_btn( & old_xpad->B, & new_xpad->B, xpad->wButtons, XINPUT_GAMEPAD_B ); - input_process_digital_btn( & old_xpad->X, & new_xpad->X, xpad->wButtons, XINPUT_GAMEPAD_X ); - - input_process_digital_btn( & old_xpad->back, & new_xpad->back, xpad->wButtons, XINPUT_GAMEPAD_BACK ); - input_process_digital_btn( & old_xpad->start, & new_xpad->start, xpad->wButtons, XINPUT_GAMEPAD_START ); - - input_process_digital_btn( & old_xpad->left_shoulder, & new_xpad->left_shoulder, xpad->wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ); - input_process_digital_btn( & old_xpad->right_shoulder, & new_xpad->right_shoulder, xpad->wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ); - - new_xpad->stick.left.X.start = old_xpad->stick.left.X.end; - new_xpad->stick.left.Y.start = old_xpad->stick.left.Y.end; - - f32 left_x = xinput_process_axis_value( xpad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ); - f32 left_y = xinput_process_axis_value( xpad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ); - - // TODO(Ed) : Min/Max macros!!! - new_xpad->stick.left.X.min = new_xpad->stick.left.X.max = new_xpad->stick.left.X.end = left_x; - new_xpad->stick.left.Y.min = new_xpad->stick.left.Y.max = new_xpad->stick.left.Y.end = left_y; - - // TODO(Ed): Make this actually an average for later - new_xpad->stick.left.X.average = left_x; - new_xpad->stick.left.Y.average = left_y; - - input->controllers[ controller_index ].xpad = new_xpad; - } - else - { - input->controllers[ controller_index ].xpad = nullptr; - } - } - - // JSL Input Polling - for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index ) - { - if ( ! JslStillConnected( jsl_device_handles[ jsl_device_index ] ) ) - { - OutputDebugStringA( "Error: JSLStillConnected returned false\n" ); - continue; - } - - // TODO : Won't support more than 4 for now... (or prob ever) - if ( jsl_device_index > 4 ) - break; - - JOY_SHOCK_STATE state = JslGetSimpleState( jsl_device_handles[ jsl_device_index ] ); - - // For now we're assuming anything that is detected via JSL is a dualsense pad. - // We'll eventually add support possibly for the nintendo pro controller. - engine::DualsensePadState* old_ds_pad = old_ds_pads[ jsl_device_index ]; - engine::DualsensePadState* new_ds_pad = new_ds_pads[ jsl_device_index ]; - - input_process_digital_btn( & old_ds_pad->dpad.up, & new_ds_pad->dpad.up, state.buttons, JSMASK_UP ); - input_process_digital_btn( & old_ds_pad->dpad.down, & new_ds_pad->dpad.down, state.buttons, JSMASK_DOWN ); - input_process_digital_btn( & old_ds_pad->dpad.left, & new_ds_pad->dpad.left, state.buttons, JSMASK_LEFT ); - input_process_digital_btn( & old_ds_pad->dpad.right, & new_ds_pad->dpad.right, state.buttons, JSMASK_RIGHT ); - - input_process_digital_btn( & old_ds_pad->triangle, & new_ds_pad->triangle, state.buttons, JSMASK_N ); - input_process_digital_btn( & old_ds_pad->cross, & new_ds_pad->cross, state.buttons, JSMASK_S ); - input_process_digital_btn( & old_ds_pad->square, & new_ds_pad->square, state.buttons, JSMASK_W ); - input_process_digital_btn( & old_ds_pad->circle, & new_ds_pad->circle, state.buttons, JSMASK_E ); - - input_process_digital_btn( & old_ds_pad->share, & new_ds_pad->share, state.buttons, JSMASK_SHARE ); - input_process_digital_btn( & old_ds_pad->options, & new_ds_pad->options, state.buttons, JSMASK_OPTIONS ); - - input_process_digital_btn( & old_ds_pad->L1, & new_ds_pad->L1, state.buttons, JSMASK_L ); - input_process_digital_btn( & old_ds_pad->R1, & new_ds_pad->R1, state.buttons, JSMASK_R ); - - new_ds_pad->stick.left.X.start = old_ds_pad->stick.left.X.end; - new_ds_pad->stick.left.Y.start = old_ds_pad->stick.left.Y.end; - - // Joyshock abstracts the sticks to a float value already for us of -1.f to 1.f. - // We'll assume a deadzone of 10% for now. - f32 left_x = jsl_input_process_axis_value( state.stickLX, 0.1f ); - f32 left_y = jsl_input_process_axis_value( state.stickLY, 0.1f ); - - new_ds_pad->stick.left.X.min = new_ds_pad->stick.left.X.max = new_ds_pad->stick.left.X.end = left_x; - new_ds_pad->stick.left.Y.min = new_ds_pad->stick.left.Y.max = new_ds_pad->stick.left.Y.end = left_y; - - // TODO(Ed): Make this actually an average for later - new_ds_pad->stick.left.X.average = left_x; - new_ds_pad->stick.left.Y.average = left_y; - - input->controllers[ jsl_device_index ].ds_pad = new_ds_pad; - } -} -#pragma endregion Input - -#pragma region Timing -inline f32 -timing_get_ms_elapsed( u64 start, u64 end ) -{ - u64 delta = (end - start) * Tick_To_Millisecond; - f32 result = scast(f32, delta) / scast(f32, Performance_Counter_Frequency); - return result; -} - -inline f32 -timing_get_seconds_elapsed( u64 start, u64 end ) -{ - u64 delta = end - start; - f32 result = scast(f32, delta) / scast(f32, Performance_Counter_Frequency); - return result; -} - -inline f32 -timing_get_us_elapsed( u64 start, u64 end ) -{ - u64 delta = (end - start) * Tick_To_Microsecond; - f32 result = scast(f32, delta) / scast(f32, Performance_Counter_Frequency); - return result; -} - -inline u64 -timing_get_wall_clock() -{ - u64 clock; - QueryPerformanceCounter( rcast( LARGE_INTEGER*, & clock) ); - return clock; -} -#pragma endregion Timing - -internal WinDimensions -get_window_dimensions( HWND window_handle ) -{ - RECT client_rect; - GetClientRect( window_handle, & client_rect ); - WinDimensions result; - result.width = client_rect.right - client_rect.left; - result.height = client_rect.bottom - client_rect.top; - return result; -} - -internal void -display_buffer_in_window( HDC device_context, u32 window_width, u32 window_height, OffscreenBuffer* buffer - , u32 x, u32 y - , u32 width, u32 height ) -{ - // TODO(Ed) : Aspect ratio correction - StretchDIBits( device_context - #if 0 - , x, y, width, height - , x, y, width, height - #endif - , 0, 0, buffer->width, buffer->height - // , 0, 0, window_width, window_height - , 0, 0, buffer->width, buffer->height - , buffer->memory, & buffer->info - , DIB_ColorTable_RGB, RO_Source_To_Dest ); -} - -internal void -resize_dib_section( OffscreenBuffer* buffer, u32 width, u32 height ) -{ - // TODO(Ed) : Bulletproof memory handling here for the bitmap memory - if ( buffer->memory ) - { - VirtualFree( buffer->memory, 0, MEM_RELEASE ); - } - - buffer->width = width; - buffer->height = height; - buffer->bytes_per_pixel = 4; - buffer->pitch = buffer->width * buffer->bytes_per_pixel; - - // Negative means top-down in the context of the biHeight -# define Top_Down - - BITMAPINFOHEADER& - header = buffer->info.bmiHeader; - header.biSize = sizeof( buffer->info.bmiHeader ); - header.biWidth = buffer->width; - header.biHeight = Top_Down buffer->height; - header.biPlanes = 1; - header.biBitCount = 32; // Need 24, but want 32 ( alignment ) - header.biCompression = BI_RGB_Uncompressed; - // header.biSizeImage = 0; - // header.biXPelsPerMeter = 0; - // header.biYPelsPerMeter = 0; - // header.biClrUsed = 0; - // header.biClrImportant = 0; -# undef Top_Down - - // We want to "touch" a pixel on every 4-byte boundary - u32 BitmapMemorySize = (buffer->width * buffer->height) * buffer->bytes_per_pixel; - buffer->memory = VirtualAlloc( NULL, BitmapMemorySize, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ); - - // TODO(Ed) : Clear to black -} - -internal LRESULT CALLBACK -main_window_callback( HWND handle - , UINT system_messages - , WPARAM w_param - , LPARAM l_param ) -{ - LRESULT result = 0; - - switch ( system_messages ) - { - case WM_ACTIVATEAPP: - { - if ( scast( bool, w_param ) == true ) - { - SetLayeredWindowAttributes( handle, RGB(0, 0, 0), 255, LWA_Alpha ); - } - else - { - SetLayeredWindowAttributes( handle, RGB(0, 0, 0), 100, LWA_Alpha ); - } - } - break; - - case WM_CLOSE: - { - // TODO(Ed) : Handle with a message to the user - Running = false; - } - break; - - case WM_DESTROY: - { - // TODO(Ed) : Handle with as an error and recreate the window - Running = false; - } - break; - - case WM_PAINT: - { - PAINTSTRUCT info; - HDC device_context = BeginPaint( handle, & info ); - u32 x = info.rcPaint.left; - u32 y = info.rcPaint.top; - u32 width = info.rcPaint.right - info.rcPaint.left; - u32 height = info.rcPaint.bottom - info.rcPaint.top; - - WinDimensions dimensions = get_window_dimensions( handle ); - - display_buffer_in_window( device_context, dimensions.width, dimensions.height, &Surface_Back_Buffer - , x, y - , width, height ); - EndPaint( handle, & info ); - } - break; - - case WM_MOUSEMOVE: - { - RECT rect; - POINT pt = { LOWORD(l_param), HIWORD(l_param) }; - - GetClientRect(handle, &rect); - if (PtInRect(&rect, pt)) - { - // Hide the cursor when it's inside the window - while (ShowCursor(FALSE) >= 0); - } - else - { - // Show the cursor when it's outside the window - while (ShowCursor(TRUE) < 0); - } - } - break; - - case WM_SIZE: - { - } - break; - - default: - { - result = DefWindowProc( handle, system_messages, w_param, l_param ); - } - } - - return result; -} - -internal void -process_pending_window_messages( engine::KeyboardState* keyboard, engine::MousesState* mouse ) -{ - MSG window_msg_info; - while ( PeekMessageA( & window_msg_info, 0, 0, 0, PM_Remove_Messages_From_Queue ) ) - { - if ( window_msg_info.message == WM_QUIT ) - { - OutputDebugStringA("WM_QUIT\n"); - Running = false; - } - - // Keyboard input handling - switch (window_msg_info.message) - { - // I rather do this with GetAsyncKeyState... - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - { - WPARAM vk_code = window_msg_info.wParam; - b32 is_down = scast(b32, (window_msg_info.lParam >> 31) == 0 ); - b32 was_down = scast(b32, (window_msg_info.lParam >> 30) ); - b32 alt_down = scast(b32, (window_msg_info.lParam & (1 << 29)) ); - - switch ( vk_code ) - { - case VK_F4: - { - if ( alt_down ) - Running = false; - } - break; - } - } - break; - - case WM_MOUSEWHEEL: - { - // This captures the vertical scroll value - int verticalScroll = GET_WHEEL_DELTA_WPARAM(window_msg_info.wParam); - mouse->vertical_wheel.end += scast(f32, verticalScroll); - } - break; - - case WM_MOUSEHWHEEL: - { - // This captures the horizontal scroll value - int horizontalScroll = GET_WHEEL_DELTA_WPARAM(window_msg_info.wParam); - mouse->horizontal_wheel.end += scast( f32, horizontalScroll); - } - break; - - default: - TranslateMessage( & window_msg_info ); - DispatchMessageW( & window_msg_info ); - } - } -} - -#pragma endregion Internal - -#pragma region Platfom API -#if Build_Development -void debug_set_pause_rendering( b32 value ) -{ - Pause_Rendering = value; -} -#endif - -b32 file_check_exists( Str path ) -{ - HANDLE file_handle = CreateFileA( path - , GENERIC_READ, FILE_SHARE_READ, 0 - , OPEN_EXISTING, 0, 0 - ); - if ( file_handle != INVALID_HANDLE_VALUE ) - { - CloseHandle( file_handle ); - return true; - } - return false; -} - -void file_close( File* file ) -{ - HANDLE handle = pcast(HANDLE, file->opaque_handle); - - if ( handle == INVALID_HANDLE_VALUE ) - return; - - CloseHandle( handle ); - - if ( file->data ) - { - // TODO(Ed): This should use our persistent memory block. - VirtualFree( file->data, 0, MEM_Release); - } - *file = {}; -} - -b32 file_delete( Str path ) -{ - return DeleteFileA( path ); -} - -b32 file_read_stream( File* file, u32 content_size, void* content_memory ) -{ - HANDLE file_handle; - if ( file->opaque_handle == nullptr ) - { - file_handle = CreateFileA( file->path - , GENERIC_READ, FILE_SHARE_READ, 0 - , OPEN_EXISTING, 0, 0 - ); - if ( file_handle == INVALID_HANDLE_VALUE ) - { - // TODO : Logging - return {}; - } - - file->opaque_handle = file_handle; - } - else - { - file_handle = pcast(HANDLE, file->opaque_handle ); - } - - u32 bytes_read; - if ( ReadFile( file_handle, content_memory, content_size, rcast(LPDWORD, &bytes_read), 0 ) == false ) - { - // TODO : Logging - return {}; - } - - if ( bytes_read != content_size ) - { - // TODO : Logging - return {}; - } - return bytes_read; -} - -b32 file_read_content( File* file ) -{ - HANDLE file_handle = CreateFileA( file->path - , GENERIC_READ, FILE_SHARE_READ, 0 - , OPEN_EXISTING, 0, 0 - ); - if ( file_handle == INVALID_HANDLE_VALUE ) - { - // TODO(Ed) : Logging - return {}; - } - - u32 size; - GetFileSizeEx( file_handle, rcast(LARGE_INTEGER*, &size) ); - if ( size == 0 ) - { - // TODO(Ed) : Logging - CloseHandle( file_handle ); - return {}; - } - - // TODO(Ed) : This should use our memory block. - file->data = rcast(HANDLE*, VirtualAlloc( 0, sizeof(HANDLE) + size, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write )); - file->size = size; - file->opaque_handle = file_handle; - - u32 bytes_read; - if ( ReadFile( file_handle, file->data, file->size, rcast(LPDWORD, &bytes_read), 0 ) == false ) - { - // TODO(Ed) : Logging - CloseHandle( file_handle ); - return {}; - } - - if ( bytes_read != file->size ) - { - // TODO : Logging - CloseHandle( file_handle ); - return {}; - } - return bytes_read; -} - -void file_rewind( File* file ) -{ - HANDLE file_handle = pcast(HANDLE, file->opaque_handle ); - if ( file_handle == INVALID_HANDLE_VALUE ) - return; - - SetFilePointer(file_handle, 0, NULL, FILE_BEGIN); -} - -u32 file_write_stream( File* file, u32 content_size, void* content_memory ) -{ - HANDLE file_handle; - if ( file->opaque_handle == nullptr ) - { - file_handle = CreateFileA( file->path - ,GENERIC_WRITE, 0, 0 - , OPEN_ALWAYS, 0, 0 - ); - if ( file_handle == INVALID_HANDLE_VALUE ) - { - // TODO(Ed) : Logging - return {}; - } - - file->opaque_handle = file_handle; - } - else - { - file_handle = pcast(HANDLE, file->opaque_handle ); - } - - DWORD bytes_written; - if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false ) - { - // TODO : Logging - return false; - } - - return bytes_written; -} - -u32 file_write_content( File* file, u32 content_size, void* content_memory ) -{ - HANDLE file_handle = CreateFileA( file->path - , GENERIC_WRITE, 0, 0 - , CREATE_ALWAYS, 0, 0 - ); - if ( file_handle == INVALID_HANDLE_VALUE ) - { - // TODO : Logging - return false; - } - file->opaque_handle = file_handle; - - DWORD bytes_written; - if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false ) - { - // TODO : Logging - return false; - } - return bytes_written; -} - -u32 get_monitor_refresh_rate() -{ - return 0; -} -void set_monitor_refresh_rate( u32 refresh_rate ) -{ -} -u32 get_engine_refresh_rate() -{ - return 0; -} -void set_engine_refresh_rate( u32 refresh_rate ) -{ - -} - -BinaryModule load_binary_module( char const* module_path ) -{ - HMODULE lib = LoadLibraryA( module_path ); - return BinaryModule { scast(void*, lib) }; -} - -void unload_binary_module( BinaryModule* module ) -{ - FreeLibrary( scast(HMODULE, module->opaque_handle) ); - *module = {}; -} - -void* get_binary_module_symbol( BinaryModule module, char const* symbol_name ) -{ - return rcast(void*, GetProcAddress( scast(HMODULE, module.opaque_handle), symbol_name )); -} - -void memory_copy( void* dest, u64 src_size, void* src ) -{ - CopyMemory( dest, src, src_size ); -} -#pragma endregion Platform API - -#pragma region Engine Module API - -constexpr const Str FName_Engine_DLL = str_ascii("handmade_engine.dll"); -constexpr const Str FName_Engine_DLL_InUse = str_ascii("handmade_engine_in_use.dll"); -constexpr const Str FName_Engine_PDB_Lock = str_ascii("handmade_engine.pdb.lock"); - -global HMODULE Lib_Handmade_Engine = nullptr; -global StrFixed< S16_MAX > Path_Engine_DLL; -global StrFixed< S16_MAX > Path_Engine_DLL_InUse; - -internal -engine::ModuleAPI load_engine_module_api() -{ - using ModuleAPI = engine::ModuleAPI; - - CopyFileA( Path_Engine_DLL, Path_Engine_DLL_InUse, FALSE ); - - // Engine - Lib_Handmade_Engine = LoadLibraryA( Path_Engine_DLL_InUse ); - if ( ! Lib_Handmade_Engine ) - { - return {}; - } - - engine::ModuleAPI engine_api {}; - engine_api.on_module_reload = get_procedure_from_library< engine::OnModuleRelaodFn > ( Lib_Handmade_Engine, engine::symbol_on_module_load ); - engine_api.startup = get_procedure_from_library< engine::StartupFn > ( Lib_Handmade_Engine, engine::symbol_startup ); - engine_api.shutdown = get_procedure_from_library< engine::ShutdownFn > ( Lib_Handmade_Engine, engine::symbol_shutdown ); - engine_api.update_and_render = get_procedure_from_library< engine::UpdateAndRenderFn >( Lib_Handmade_Engine, engine::symbol_update_and_render ); - engine_api.update_audio = get_procedure_from_library< engine::UpdateAudioFn > ( Lib_Handmade_Engine, engine::symbol_update_audio ); - - engine_api.IsValid = - engine_api.on_module_reload - && engine_api.startup - && engine_api.shutdown - && engine_api.update_and_render - && engine_api.update_audio; - if ( engine_api.IsValid ) - { - OutputDebugStringA( "Loaded engine module API\n" ); - } - return engine_api; -} - -internal -void unload_engine_module_api( engine::ModuleAPI* engine_api ) -{ - if ( engine_api->IsValid ) - { - FreeLibrary( Lib_Handmade_Engine ); - *engine_api = {}; - OutputDebugStringA( "Unloaded engine module API\n" ); - } -} -#pragma endregion Engine Module API - -NS_PLATFORM_END - -int CALLBACK -WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int show_command ) -{ - using namespace win32; - using namespace platform; - -#pragma region Startup - // Timing -#if Build_Development - u64 launch_clock = timing_get_wall_clock(); - u64 launch_cycle = __rdtsc(); -#endif - - // Sets the windows scheduler granulaity for this process to 1 ms - constexpr u32 desired_scheduler_ms = 1; - b32 sleep_is_granular = ( timeBeginPeriod( desired_scheduler_ms ) == TIMERR_NOERROR ); - - // If its a high-perofmrance frame-time (a refresh rate that produces a target frametime at or below 4.16~ ms, we cannot allow the scheduler to mess things up) - b32 sub_ms_granularity_required = scast(f32, Engine_Refresh_Hz) <= High_Perf_Frametime_MS; - - QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & Performance_Counter_Frequency) ); - - // Setup pathing - StrFixed< S16_MAX > path_pdb_lock {}; - { - // TODO(Ed): This will not support long paths, NEEDS to be changed to support long paths. - - char path_buffer[S16_MAX]; - GetModuleFileNameA( 0, path_buffer, sizeof(path_buffer) ); - - if ( GetCurrentDirectoryA( S16_MAX, Path_Binaries ) == 0 ) - { - fatal( "Failed to get the root directory!" ); - } - Path_Binaries.len = str_length( Path_Binaries ); - Path_Binaries[ Path_Binaries.len ] = '\\'; - ++ Path_Binaries.len; - - if ( SetCurrentDirectoryA( ".." ) == 0 ) - { - fatal( "Failed to set current directory to root!"); - } - - if ( GetCurrentDirectoryA( S16_MAX, Path_Root.ptr ) == 0 ) - { - fatal( "Failed to get the root directory!" ); - } - Path_Root.len = str_length(Path_Root.ptr); - Path_Root.ptr[ Path_Root.len ] = '\\'; - ++ Path_Root.len; - - Path_Engine_DLL. concat( Path_Binaries, FName_Engine_DLL ); - Path_Engine_DLL_InUse.concat( Path_Binaries, FName_Engine_DLL_InUse ); - - path_pdb_lock.concat( Path_Binaries, FName_Engine_PDB_Lock ); - - Path_Scratch.concat( Path_Root, str_ascii("scratch") ); - Path_Scratch.ptr[ Path_Scratch.len ] = '\\'; - ++ Path_Scratch.len; - - CreateDirectoryA( Path_Scratch, 0 ); - } - - // Memory - engine::Memory engine_memory {}; - { - engine_memory.persistent_size = megabytes( 128 ); - // engine_memory.FrameSize = megabytes( 64 ); - engine_memory.transient_size = gigabytes( 2 ); - - u64 total_size = engine_memory.persistent_size - // + engine_memory.FrameSize - + engine_memory.transient_size; - - #if Build_Debug - void* base_address = rcast(void*, terabytes( 1 )); - #else - 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; - - #if Build_Development - for (u32 slot = 0; slot < engine_memory.Num_Snapshot_Slots; ++slot) - { - engine::MemorySnapshot& snapshot = engine_memory.snapshots[ slot ]; - - snapshot.file_path.concat( Path_Scratch, str_ascii("snapshot_") ); - wsprintfA( snapshot.file_path.ptr, "%s%d.hm_snapshot", snapshot.file_path.ptr, slot ); - - HANDLE snapshot_file = CreateFileA( snapshot.file_path - , GENERIC_READ | GENERIC_WRITE, 0, 0 - , CREATE_ALWAYS, 0, 0 ); - - LARGE_INTEGER file_size {}; - file_size.QuadPart = total_size; - - HANDLE snapshot_mapping = CreateFileMappingA( snapshot_file, 0 - , Page_Read_Write - , file_size.HighPart, file_size.LowPart - , 0 ); - - snapshot.memory = MapViewOfFile( snapshot_mapping, FILE_MAP_ALL_ACCESS, 0, 0, total_size ); - snapshot.opaque_handle = snapshot_file; - snapshot.opaque_handle_2 = snapshot_mapping; - } - #endif - - if ( engine_memory.persistent == nullptr - || engine_memory.transient == nullptr ) - { - // TODO : Diagnostic Logging - return -1; - } - } - - WNDCLASSW window_class {}; - HWND window_handle = nullptr; - { - window_class.style = CS_Horizontal_Redraw | CS_Vertical_Redraw; - window_class.lpfnWndProc = main_window_callback; - // window_class.cbClsExtra = ; - // window_class.cbWndExtra = ; - window_class.hInstance = instance; - // window_class.hIcon = ; - // window_class.hCursor = ; - // window_class.hbrBackground = ; - window_class.lpszMenuName = L"Handmade Hero!"; - window_class.lpszClassName = L"HandmadeHeroWindowClass"; - - if ( ! RegisterClassW( & window_class ) ) - { - // TODO : Diagnostic Logging - return 0; - } - - window_handle = CreateWindowExW( - // WS_EX_LAYERED | WS_EX_TOPMOST, - WS_EX_LAYERED, - window_class.lpszClassName, - L"Handmade Hero", - WS_Overlapped_Window | WS_Initially_Visible, - CW_Use_Default, CW_Use_Default, // x, y - 1920, 1080, // width, height - 0, 0, // parent, menu - instance, 0 // instance, param - ); - - if ( ! window_handle ) - { - // TODO : Diagnostic Logging - return 0; - } - - // WinDimensions dimensions = get_window_dimensions( window_handle ); - resize_dib_section( &Surface_Back_Buffer, 1920, 1080 ); - - // Setup monitor refresh and associated timers - HDC refresh_dc = GetDC( window_handle ); - u32 monitor_refresh_hz = GetDeviceCaps( refresh_dc, VREFRESH ); - if ( monitor_refresh_hz > 1 ) - { - Monitor_Refresh_Hz = monitor_refresh_hz; - } - ReleaseDC( window_handle, refresh_dc ); - - Engine_Refresh_Hz = 60; - Engine_Frame_Target_MS = 1000.f / scast(f32, Engine_Refresh_Hz); - } - - // Prepare platform API - ModuleAPI platform_api {}; - { - platform_api.path_root = Path_Root; - platform_api.path_binaries = Path_Binaries; - platform_api.path_scratch = Path_Scratch; - - #if Build_Development - platform_api.debug_set_pause_rendering = & debug_set_pause_rendering; - #endif - // Not implemented yet - platform_api.get_monitor_refresh_rate = nullptr; - platform_api.set_monitor_refresh_rate = nullptr; - platform_api.get_engine_frame_target = nullptr; - platform_api.set_engine_frame_target = nullptr; - - platform_api.load_binary_module = & load_binary_module; - platform_api.unload_binary_module = & unload_binary_module; - platform_api.get_module_procedure = & get_binary_module_symbol; - - platform_api.file_check_exists = & file_check_exists; - platform_api.file_close = & file_close; - platform_api.file_delete = & file_delete; - platform_api.file_read_content = & file_read_content; - platform_api.file_read_stream = & file_read_stream; - platform_api.file_rewind = & file_rewind; - platform_api.file_write_content = & file_write_content; - platform_api.file_write_stream = & file_write_stream; - - platform_api.memory_copy = & memory_copy; - } - - // Load engine module - FILETIME engine_api_load_time = file_get_last_write_time( Path_Engine_DLL ); - engine::ModuleAPI engine_api = load_engine_module_api(); - - b32 sound_is_valid = false; - DWORD ds_cursor_byte_delta = 0; - f32 ds_latency_ms = 0; - DirectSoundBuffer ds_sound_buffer; - u32 audio_marker_index = 0; - AudioTimeMarker audio_time_markers[ Monitor_Refresh_Max_Supported ] {}; - u32 audio_time_markers_size = Engine_Refresh_Hz / 2; - assert( audio_time_markers_size <= Monitor_Refresh_Max_Supported ) - { - ds_sound_buffer.is_playing = 0; - ds_sound_buffer.samples_per_second = 48000; - ds_sound_buffer.bytes_per_sample = sizeof(s16) * 2; - - ds_sound_buffer.secondary_buffer_size = ds_sound_buffer.samples_per_second * ds_sound_buffer.bytes_per_sample; - init_sound( window_handle, & ds_sound_buffer ); - - ds_sound_buffer.samples = rcast( s16*, VirtualAlloc( 0, 48000 * 2 * sizeof(s16) - , MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write )); - - assert( ds_sound_buffer.samples ); - ds_sound_buffer.running_sample_index = 0; - // ds_clear_sound_buffer( & sound_output ); - ds_sound_buffer.secondary_buffer->Play( 0, 0, DSBPLAY_LOOPING ); - - ds_sound_buffer.bytes_per_second = ds_sound_buffer.samples_per_second * ds_sound_buffer.bytes_per_sample; - ds_sound_buffer.guard_sample_bytes = (ds_sound_buffer.bytes_per_second / Engine_Refresh_Hz) / 2; - - // TODO(Ed): When switching to core audio at minimum, this will be 1 ms of lag and guard samples wont really be needed. - u32 min_guard_sample_bytes = 1540; - if ( ds_sound_buffer.guard_sample_bytes < min_guard_sample_bytes ) - { - ds_sound_buffer.guard_sample_bytes = min_guard_sample_bytes; - } - } - - engine::InputState input {}; - - // There can be 4 of any of each input API type : KB & Mouse, XInput, JSL. -#if 0 - using EngineKeyboardStates = engine::KeyboardState[ Max_Controllers ]; - EngineKeyboardStates keyboard_states[2] {}; - EngineKeyboardStates* old_keyboards = & keyboard_states[0]; - EngineKeyboardStates* new_keyboards = & keyboard_states[1]; -#endif - - engine::KeyboardState keyboard_states[2] {}; - engine::KeyboardState* old_keyboard = & keyboard_states[0]; - engine::KeyboardState* new_keyboard = & keyboard_states[1]; - // Important: Assuming keyboard always connected for now, and assigning to first controller. - - engine::MousesState mouse_states[2] {}; - engine::MousesState* old_mouse = & mouse_states[0]; - engine::MousesState* new_mouse = & mouse_states[1]; - - EngineXInputPadStates xpad_states[2] {}; - EngineXInputPadStates* old_xpads = & xpad_states[0]; - EngineXInputPadStates* new_xpads = & xpad_states[1]; - - EngineDSPadStates ds_pad_states[2] {}; - EngineDSPadStates* old_ds_pads = & ds_pad_states[0]; - EngineDSPadStates* new_ds_pads = & ds_pad_states[1]; - - u32 jsl_num_devices = JslConnectDevices(); - JSL_DeviceHandle jsl_device_handles[4] {}; - { - xinput_load_library_bindings(); - - u32 jsl_getconnected_found = JslGetConnectedDeviceHandles( jsl_device_handles, jsl_num_devices ); - { - if ( jsl_getconnected_found != jsl_num_devices ) - { - OutputDebugStringA( "Error: JSLGetConnectedDeviceHandles didn't find as many as were stated with JslConnectDevices\n"); - } - - if ( jsl_num_devices > 0 ) - { - OutputDebugStringA( "JSL Connected Devices:\n" ); - for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index ) - { - JslSetLightColour( jsl_device_handles[ jsl_device_index ], (255 << 8) ); - } - } - } - - if ( jsl_num_devices > 4 ) - { - jsl_num_devices = 4; - MessageBoxA( window_handle, "More than 4 JSL devices found, this engine will only support the first four found." - , "Warning", MB_ICONEXCLAMATION ); - } - } - - engine_api.startup( & engine_memory, & platform_api ); - - u64 last_frame_clock = timing_get_wall_clock(); - u64 last_frame_cycle = __rdtsc(); - u64 flip_wall_clock = last_frame_clock; - -#if Build_Development - u64 startup_cycles = last_frame_cycle - launch_cycle; - f32 startup_ms = timing_get_ms_elapsed( launch_clock, last_frame_clock ); - - char text_buffer[256]; - sprintf_s( text_buffer, sizeof(text_buffer), "Startup MS: %f\n", startup_ms ); - OutputDebugStringA( text_buffer ); -#endif -#pragma endregion Startup - - // Placeholder - engine::ThreadContext thread_context_placeholder {}; - - Running = true; -#if 0 -// This tests the play & write cursor update frequency. - while ( Running ) - { - DWORD play_cursor; - DWORD write_cursor; - - ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & play_cursor, & write_cursor ); - char text_buffer[256]; - sprintf_s( text_buffer, sizeof(text_buffer), "PC:%u WC:%u\n", (u32)play_cursor, (u32)write_cursor ); - OutputDebugStringA( text_buffer ); - } -#endif - while( Running ) - { - // Engine Module Hot-Reload - do { - FILETIME engine_api_current_time = file_get_last_write_time( Path_Engine_DLL ); - if ( CompareFileTime( & engine_api_load_time, & engine_api_current_time ) == 0 ) - break; - - WIN32_FIND_DATAA lock_file_info = {}; - for(;;) - { - HANDLE lock_file = FindFirstFileA( path_pdb_lock, & lock_file_info ); - if ( lock_file != INVALID_HANDLE_VALUE ) - { - FindClose( lock_file ); - Sleep( 1 ); - continue; - } - break; - } - - engine_api_load_time = engine_api_current_time; - unload_engine_module_api( & engine_api ); - engine_api = load_engine_module_api(); - } while (0); - - - // Swapping at the beginning of the input frame instead of the end. - swap( old_keyboard, new_keyboard ); - swap( old_mouse, new_mouse ); - swap( old_xpads, new_xpads ); - swap( old_ds_pads, new_ds_pads ); - - poll_input( window_handle, & input, jsl_num_devices, jsl_device_handles - , old_keyboard, new_keyboard - , old_mouse, new_mouse - , old_xpads, new_xpads - , old_ds_pads, new_ds_pads ); - - process_pending_window_messages( new_keyboard, new_mouse ); - - f32 delta_time = timing_get_seconds_elapsed( last_frame_clock, timing_get_wall_clock() ); - - // Engine's logical iteration and rendering process - engine_api.update_and_render( delta_time, & input, rcast(engine::OffscreenBuffer*, & Surface_Back_Buffer.memory ) - , & engine_memory, & platform_api, & thread_context_placeholder ); - - u64 audio_frame_start = timing_get_wall_clock(); - f32 flip_to_audio_ms = timing_get_ms_elapsed( flip_wall_clock, audio_frame_start ); - - DWORD ds_play_cursor; - DWORD ds_write_cursor; - do { - /* - Audio Processing: - There is a sync boundary value, that is the number of samples that the engine's frame-time may vary by - (ex: approx 2ms of variance between frame-times). - - On wakeup : Check play cursor position and forcast ahead where the cursor will be for the next sync boundary. - Based on that, check the write cursor position, if its (at least) before the synch boundary, the target write position is - the frame boundary plus one frame. (Low latency) - - If its after (sync boundary), we cannot sync audio. - Write a frame's worth of audio plus some number of "guard" samples. (High Latency) - */ - if ( ! SUCCEEDED( ds_sound_buffer.secondary_buffer->GetCurrentPosition( & ds_play_cursor, & ds_write_cursor ) )) - { - sound_is_valid = false; - break; - } - - if ( ! sound_is_valid ) - { - ds_sound_buffer.running_sample_index = ds_write_cursor / ds_sound_buffer.bytes_per_sample; - sound_is_valid = true; - } - - DWORD byte_to_lock = 0; - DWORD target_cursor = 0; - DWORD bytes_to_write = 0; - - byte_to_lock = (ds_sound_buffer.running_sample_index * ds_sound_buffer.bytes_per_sample) % ds_sound_buffer.secondary_buffer_size; - - DWORD bytes_per_second = ds_sound_buffer.bytes_per_sample * ds_sound_buffer.samples_per_second; - - DWORD expected_samplebytes_per_frame = bytes_per_second / Engine_Refresh_Hz; - - f32 left_until_flip_ms = Engine_Frame_Target_MS - flip_to_audio_ms; - DWORD expected_bytes_until_flip = scast(DWORD, (left_until_flip_ms / Engine_Frame_Target_MS) * scast(f32, expected_samplebytes_per_frame)); - - DWORD expected_sync_boundary_byte = ds_play_cursor + expected_bytes_until_flip; - - DWORD sync_write_cursor = ds_write_cursor; - if ( sync_write_cursor < ds_play_cursor ) - { - // unwrap the cursor so its ahead of the play curosr linearly. - sync_write_cursor += ds_sound_buffer.secondary_buffer_size; - } - assert( sync_write_cursor >= ds_play_cursor ); - - sync_write_cursor += ds_sound_buffer.guard_sample_bytes; - - b32 audio_interface_is_low_latency = sync_write_cursor < expected_sync_boundary_byte; - if ( audio_interface_is_low_latency ) - { - target_cursor = ( expected_sync_boundary_byte + expected_samplebytes_per_frame ); - } - else - { - target_cursor = (ds_write_cursor + expected_samplebytes_per_frame + ds_sound_buffer.guard_sample_bytes); - } - target_cursor %= ds_sound_buffer.secondary_buffer_size; - - if ( byte_to_lock > target_cursor) - { - // Infront of play cursor |--play--byte_to_write-->--| - bytes_to_write = ds_sound_buffer.secondary_buffer_size - byte_to_lock; - bytes_to_write += target_cursor; - } - else - { - // Behind play cursor |--byte_to_write-->--play--| - bytes_to_write = target_cursor - byte_to_lock; - } - - // Engine Sound - delta_time = timing_get_seconds_elapsed( last_frame_clock, timing_get_wall_clock() ); - - // s16 samples[ 48000 * 2 ]; - engine::AudioBuffer sound_buffer {}; - sound_buffer.num_samples = bytes_to_write / ds_sound_buffer.bytes_per_sample; - sound_buffer.running_sample_index = ds_sound_buffer.running_sample_index; - sound_buffer.samples_per_second = ds_sound_buffer.samples_per_second; - sound_buffer.samples = ds_sound_buffer.samples; - engine_api.update_audio( delta_time, & sound_buffer, & engine_memory, & platform_api, & thread_context_placeholder ); - - AudioTimeMarker* marker = & audio_time_markers[ audio_marker_index ]; - marker->output_play_cursor = ds_play_cursor; - marker->output_write_cursor = ds_write_cursor; - marker->output_location = byte_to_lock; - marker->output_byte_count = bytes_to_write; - marker->expected_flip_cursor = expected_sync_boundary_byte; - - // Update audio buffer - if ( ! sound_is_valid ) - break; - - #if Build_Development && 0 - #if 0 - DWORD play_cursor; - DWORD write_cursor; - ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & play_cursor, & write_cursor ); - #endif - DWORD unwrapped_write_cursor = ds_write_cursor; - if ( unwrapped_write_cursor < ds_play_cursor ) - { - unwrapped_write_cursor += ds_sound_buffer.SecondaryBufferSize; - } - ds_cursor_byte_delta = unwrapped_write_cursor - ds_play_cursor; - - constexpr f32 to_milliseconds = 1000.f; - f32 sample_delta = scast(f32, ds_cursor_byte_delta) / scast(f32, ds_sound_buffer.BytesPerSample); - f32 ds_latency_s = sample_delta / scast(f32, ds_sound_buffer.SamplesPerSecond); - ds_latency_ms = ds_latency_s * to_milliseconds; - - char text_buffer[256]; - sprintf_s( text_buffer, sizeof(text_buffer), "BTL:%u TC:%u BTW:%u - PC:%u WC:%u DELTA:%u bytes %f ms\n" - , (u32)byte_to_lock, (u32)target_cursor, (u32)bytes_to_write - , (u32)play_cursor, (u32)write_cursor, (u32)ds_cursor_byte_delta, ds_latency_ms ); - OutputDebugStringA( text_buffer ); - #endif - ds_fill_sound_buffer( & ds_sound_buffer, byte_to_lock, bytes_to_write ); - - DWORD ds_status = 0; - if ( SUCCEEDED( ds_sound_buffer.secondary_buffer->GetStatus( & ds_status ) ) ) - { - ds_sound_buffer.is_playing = ds_status & DSBSTATUS_PLAYING; - } - if ( ds_sound_buffer.is_playing ) - break; - - ds_sound_buffer.secondary_buffer->Play( 0, 0, DSBPLAY_LOOPING ); - } while(0); - - // Timing Update - { - u64 work_frame_end_cycle = __rdtsc(); - u64 work_frame_end_clock = timing_get_wall_clock(); - - f32 work_frame_ms = timing_get_ms_elapsed( last_frame_clock, work_frame_end_clock ); // WorkSecondsElapsed - f32 work_cycles = timing_get_ms_elapsed( last_frame_cycle, work_frame_end_cycle ); - - f32 frame_elapsed_ms = work_frame_ms; // SecondsElapsedForFrame - if ( frame_elapsed_ms < Engine_Frame_Target_MS ) - { - s32 sleep_ms = scast(DWORD, (Engine_Frame_Target_MS - frame_elapsed_ms)) - 1; - if ( sleep_ms > 0 && ! sub_ms_granularity_required && sleep_is_granular ) - { - Sleep( scast(DWORD, sleep_ms) ); - } - - u64 frame_clock = timing_get_wall_clock(); - frame_elapsed_ms = timing_get_ms_elapsed( last_frame_clock, frame_clock ); - if ( frame_elapsed_ms < Engine_Frame_Target_MS ) - { - // TODO(Ed) : Log missed sleep here. - } - - while ( frame_elapsed_ms < Engine_Frame_Target_MS ) - { - frame_clock = timing_get_wall_clock(); - frame_elapsed_ms = timing_get_ms_elapsed( last_frame_clock, frame_clock ); - } - } - else - { - // TODO(Ed) : Missed the display sync window! - } - - last_frame_clock = timing_get_wall_clock(); // LastCouner - last_frame_cycle = __rdtsc(); - } - - // Update surface back buffer - if ( ! Pause_Rendering ) - { - WinDimensions dimensions = get_window_dimensions( window_handle ); - HDC device_context = GetDC( window_handle ); - - #if Build_Development && 0 - // Note: debug_marker_index is wrong for the 0th index - debug_sync_display( & ds_sound_buffer - , audio_time_markers_size, audio_time_markers, audio_marker_index - 1 - , Engine_Frame_Target_MS ); - #endif - - display_buffer_in_window( device_context, dimensions.width, dimensions.height, &Surface_Back_Buffer - , 0, 0 - , dimensions.width, dimensions.height ); - ReleaseDC( window_handle, device_context ); - } - - flip_wall_clock = timing_get_wall_clock(); - #if Build_Development - { - // Audio Debug - DWORD play_cursor = 0; - DWORD write_cursor = 0; - if ( SUCCEEDED( ds_sound_buffer.secondary_buffer->GetCurrentPosition( & play_cursor, & write_cursor ) ) ) - { - if ( ! sound_is_valid ) - { - ds_sound_buffer.running_sample_index = write_cursor / ds_sound_buffer.bytes_per_sample; - sound_is_valid = true; - } - - assert( audio_marker_index < audio_time_markers_size ) - AudioTimeMarker* marker = & audio_time_markers[ audio_marker_index ]; - - marker->flip_play_curosr = play_cursor; - marker->flip_write_cursor = write_cursor; - } - } - #endif - - #if Build_Development - audio_marker_index++; - if ( audio_marker_index >= audio_time_markers_size ) - audio_marker_index = 0; - #endif - } - - engine_api.shutdown( & engine_memory, & platform_api ); - - unload_engine_module_api( & engine_api ); - DeleteFileA( Path_Engine_DLL_InUse ); - - if ( jsl_num_devices > 0 ) - { - for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index ) - { - JslSetLightColour( jsl_device_handles[ jsl_device_index ], 0 ); - } - } - - return 0; -} diff --git a/scripts/.clang-format b/scripts/.clang-format new file mode 100644 index 0000000..06805ad --- /dev/null +++ b/scripts/.clang-format @@ -0,0 +1,171 @@ +# Format Style Options - Created with Clang Power Tools +--- +AccessModifierOffset: -4 + +AlignAfterOpenBracket: BlockIndent +AlignArrayOfStructures: Left +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false +AlignEscapedNewlines: Left +AlignOperands: DontAlign + +AlignTrailingComments: true + +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortLambdasOnASingleLine: None +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false + +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes + +BinPackArguments: false +BinPackParameters: false + +BitFieldColonSpacing: Both + +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false + BeforeLambdaBody: false + BeforeWhile: false + +BreakAfterAttributes: Always +BreakArrays: true +# BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: true +BreakInheritanceList: BeforeComma +BreakBeforeConceptDeclarations: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakStringLiterals: true + +ColumnLimit: 160 + +CompactNamespaces: true + +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth : 4 + +ContinuationIndentWidth: 4 + +Cpp11BracedListStyle: false + +DeriveLineEnding: true + +ExperimentalAutoDetectBinPacking: false + +FixNamespaceComments: true + +IncludeBlocks: Preserve + +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequires: true +IndentWidth: 4 +IndentWrappedFunctionNames: true + +# InsertNewlineAtEOF: true +# InsertTrailingCommas: Wrapped + +LambdaBodyIndentation: OuterScope + +Language: Cpp + +MaxEmptyLinesToKeep: 4 + +NamespaceIndentation: All + +PointerAlignment: Left + +QualifierAlignment: Leave + +ReferenceAlignment: Left + +ReflowComments: true + +# RequiresExpressionIndentation: OuterScope + +SeparateDefinitionBlocks: Always + +ShortNamespaceLines: 40 + +SortIncludes: false +SortUsingDeclarations: false + +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: true +SpaceAfterTemplateKeyword: false + +SpaceAroundPointerQualifiers: Default + +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatementsExceptControlMacros +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpacesBeforeTrailingComments: 4 + +SpaceInEmptyBlock: true +SpaceInEmptyParentheses: false +SpacesInAngles: true +SpacesInCStyleCastParentheses: true +SpacesInConditionalStatement: true +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: 20 +SpacesInParentheses: true +SpacesInSquareBrackets: true + +Standard: c++17 + +TabWidth: 4 + +UseTab: ForIndentation +... diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 21979b3..95e9d1b 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -1,11 +1,17 @@ -Clear-Host +if ( $CursorPosition ) { + Clear-Host +} + +$target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1' +$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' +$format_cpp = Join-Path $PSScriptRoot 'helpers/format_cpp.psm1' +$config_toolchain = Join-Path $PSScriptRoot 'helpers/configure_toolchain.ps1' -$target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1' -$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' $path_root = git rev-parse --show-toplevel $path_build = Join-Path $path_root 'build' Import-Module $target_arch +Import-Module $format_cpp Push-Location $path_root @@ -18,6 +24,7 @@ Push-Location $path_root $platform = $null $engine = $null $game = $null + $verbose = $null [array] $vendors = @( "clang", "msvc" ) @@ -33,362 +40,13 @@ if ( $args ) { $args | ForEach-Object { "platform" { $platform = $true } "engine" { $engine = $true } "game" { $game = $true } + "verbose" { $verbose = $true } } }} #endregion Argument -#region Toolchain Configuration -if ($IsWindows) { - # This HandmadeHero implementation is only designed for 64-bit systems - & $devshell -arch amd64 -} - -if ( $vendor -eq $null ) { - write-host "No vendor specified, assuming clang available" - $compiler = "clang" -} - -write-host "Building HandmadeHero with $vendor" - -if ( $dev ) { - if ( $debug -eq $null ) { - $debug = $true - } - - if ( $optimize -eq $null ) { - $optimize = $false - } -} - -function run-compiler -{ - param( $compiler, $unit, $compiler_args ) - - if ( $analysis ) { - $compiler_args += $flag_syntax_only - } - - write-host "`Compiling $unit" - write-host "Compiler config:" - $compiler_args | ForEach-Object { - write-host $_ -ForegroundColor Cyan - } - - $time_taken = Measure-Command { - & $compiler $compiler_args 2>&1 | ForEach-Object { - $color = 'White' - switch ($_){ - { $_ -match "error" } { $color = 'Red' ; break } - { $_ -match "warning" } { $color = 'Yellow'; break } - } - write-host `t $_ -ForegroundColor $color - } - } - - if ( Test-Path($unit) ) { - write-host "$unit compile finished in $($time_taken.TotalMilliseconds) ms" - } - else { - write-host "Compile failed for $unit" -ForegroundColor Red - } -} - -function run-linker -{ - param( $linker, $binary, $linker_args ) - - write-host "`Linking $binary" - write-host "Linker config:" - $linker_args | ForEach-Object { - write-host $_ -ForegroundColor Cyan - } - - $time_taken = Measure-Command { - & $linker $linker_args 2>&1 | ForEach-Object { - $color = 'White' - switch ($_){ - { $_ -match "error" } { $color = 'Red' ; break } - { $_ -match "warning" } { $color = 'Yellow'; break } - } - write-host `t $_ -ForegroundColor $color - } - } - - if ( Test-Path($binary) ) { - write-host "$binary linking finished in $($time_taken.TotalMilliseconds) ms" - } - else { - write-host "Linking failed for $binary" -ForegroundColor Red - } -} - -if ( $vendor -match "clang" ) -{ - # https://clang.llvm.org/docs/ClangCommandLineReference.html - $flag_all_c = '/TC' - $flag_all_cpp = '/TP' - $flag_compile = '-c' - $flag_color_diagnostics = '-fcolor-diagnostics' - $flag_no_color_diagnostics = '-fno-color-diagnostics' - $flag_debug = '-g' - $flag_debug_codeview = '-gcodeview' - $flag_define = '-D' - $flag_exceptions_disabled = '-fno-exceptions' - $flag_preprocess = '-E' - $flag_include = '-I' - $flag_section_data = '-fdata-sections' - $flag_section_functions = '-ffunction-sections' - $flag_library = '-l' - $flag_library_path = '-L' - $flag_linker = '-Wl,' - if ( $IsWindows ) { - $flag_link_dll = '/DLL' - $flag_link_mapfile = '/MAP:' - $flag_link_optimize_references = '/OPT:REF' - } - if ( $IsLinux ) { - $flag_link_mapfile = '--Map=' - $flag_link_optimize_references = '--gc-sections' - } - $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' - $flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' - $flag_link_win_machine_32 = '/MACHINE:X86' - $flag_link_win_machine_64 = '/MACHINE:X64' - $flag_link_win_debug = '/DEBUG' - $flag_link_win_pdb = '/PDB:' - $flag_link_win_path_output = '/OUT:' - $flag_no_optimization = '-O0' - $flag_optimize_fast = '-O2' - $flag_optimize_size = '-O1' - $flag_optimize_intrinsics = '-Oi' - $flag_path_output = '-o' - $flag_preprocess_non_intergrated = '-no-integrated-cpp' - $flag_profiling_debug = '-fdebug-info-for-profiling' - $flag_set_stack_size = '-stack=' - $flag_syntax_only = '-fsyntax-only' - $flag_target_arch = '-target' - $flag_wall = '-Wall' - $flag_warning = '-W' - $flag_warnings_as_errors = '-Werror' - $flag_win_nologo = '/nologo' - - $ignore_warning_ms_include = 'no-microsoft-include' - $ignore_warning_return_type_c_linkage = 'no-return-type-c-linkage' - - $target_arch = Get-TargetArchClang - - $warning_ignores = @( - $ignore_warning_ms_include, - $ignore_warning_return_type_c_linkage - ) - - # https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 - $libraries = @( - 'Kernel32' # For Windows API - # 'msvcrt', # For the C Runtime (Dynamically Linked) - # 'libucrt', - 'libcmt' # For the C Runtime (Static Linkage) - ) - - function build-simple - { - param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) - Write-Host "build-simple: clang" - - $object = $unit -replace '\.cpp', '.obj' - $map = $unit -replace '\.cpp', '.map' - $object = join-path $path_build (split-path $object -Leaf) - $map = join-path $path_build (split-path $map -Leaf) - - # The PDB file has to also be time-stamped so that we can reload the DLL at runtime - $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" - - $compiler_args += @( - $flag_no_color_diagnostics, - $flag_exceptions_disabled, - $flag_target_arch, $target_arch, - $flag_wall, - $flag_preprocess_on_intergrated, - # $flag_section_data, - # $flag_section_functions, - ( $flag_path_output + $object ) - ) - if ( $optimize ) { - $compiler_args += $flag_optimize_fast - } - else { - $compiler_args += $flag_no_optimization - } - if ( $debug ) { - $compiler_args += ( $flag_define + 'Build_Debug=1' ) - $compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug - } - else { - $compiler_args += ( $flag_define + 'Build_Debug=0' ) - } - - $warning_ignores | ForEach-Object { - $compiler_args += $flag_warning + $_ - } - $compiler_args += $includes | ForEach-Object { $flag_include + $_ } - - $compiler_args += $flag_compile, $unit - run-compiler $compiler $unit $compiler_args - - $linker_args += @( - $flag_link_win_machine_64, - $( $flag_link_win_path_output + $binary ) - ) - if ( $debug ) { - $linker_args += $flag_link_win_debug - $linker_args += $flag_link_win_pdb + $pdb - $linker_args += $flag_link_mapfile + $map - } - - $libraries | ForEach-Object { - $linker_args += $_ + '.lib' - } - - $linker_args += $object - run-linker $linker $binary $linker_args - - # $compiler_args += $unit - # $linker_args | ForEach-Object { - # $compiler_args += $flag_linker + $_ - # } - # run-compiler $compiler $unit $compiler_args - } - - $compiler = 'clang++' - $linker = 'lld-link' -} - -if ( $vendor -match "msvc" ) -{ - # https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 - $flag_all_c = '/TC' - $flag_all_cpp = '/TP' - $flag_compile = '/c' - $flag_debug = '/Zi' - $flag_define = '/D' - $flag_exceptions_disabled = '/EHsc-' - $flag_RTTI_disabled = '/GR-' - $flag_include = '/I' - $flag_full_src_path = '/FC' - $flag_nologo = '/nologo' - $flag_dll = '/LD' - $flag_dll_debug = '/LDd' - $flag_linker = '/link' - $flag_link_dll = '/DLL' - $flag_link_no_incremental = '/INCREMENTAL:NO' - $flag_link_mapfile = '/MAP:' - $flag_link_optimize_references = '/OPT:REF' - $flag_link_win_debug = '/DEBUG' - $flag_link_win_pdb = '/PDB:' - $flag_link_win_machine_32 = '/MACHINE:X86' - $flag_link_win_machine_64 = '/MACHINE:X64' - $flag_link_win_path_output = '/OUT:' - $flag_link_win_rt_dll = '/MD' - $flag_link_win_rt_dll_debug = '/MDd' - $flag_link_win_rt_static = '/MT' - $flag_link_win_rt_static_debug = '/MTd' - $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' - $flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' - $flag_no_optimization = '/Od' - $flag_optimize_fast = '/O2' - $flag_optimize_size = '/O1' - $flag_optimize_intrinsics = '/Oi' - $flag_optimized_debug = '/Zo' - $flag_out_name = '/OUT:' - $flag_path_interm = '/Fo' - $flag_path_debug = '/Fd' - $flag_path_output = '/Fe' - $flag_preprocess_conform = '/Zc:preprocessor' - $flag_set_stack_size = '/F' - $flag_syntax_only = '/Zs' - $flag_wall = '/Wall' - $flag_warnings_as_errors = '/WX' - - # This works because this project uses a single unit to build - function build-simple - { - param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) - Write-Host "build-simple: msvc" - - $object = $unit -replace '\.(cpp)$', '.obj' - $map = $unit -replace '\.(cpp)$', '.map' - $object = join-path $path_build (split-path $object -Leaf) - $map = join-path $path_build (split-path $map -Leaf) - - # The PDB file has to also be time-stamped so that we can reload the DLL at runtime - $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" - - $compiler_args += @( - $flag_nologo, - # $flag_all_cpp, - $flag_exceptions_disabled, - ( $flag_define + '_HAS_EXCEPTIONS=0' ), - $flag_RTTI_disabled, - $flag_preprocess_conform, - $flag_full_src_path, - ( $flag_path_interm + $path_build + '\' ), - ( $flag_path_output + $path_build + '\' ) - ) - - if ( $optimize ) { - $compiler_args += $flag_optimize_fast - } - else { - $compiler_args += $flag_no_optimization - } - - if ( $debug ) - { - $compiler_args += $flag_debug - $compiler_args += ( $flag_define + 'Build_Debug=1' ) - $compiler_args += ( $flag_path_debug + $path_build + '\' ) - $compiler_args += $flag_link_win_rt_static_debug - - if ( $optimize ) { - $compiler_args += $flag_optimized_debug - } - } - else { - $compiler_args += ( $flag_define + 'Build_Debug=0' ) - $compiler_args += $flag_link_win_rt_static - } - $compiler_args += $includes | ForEach-Object { $flag_include + $_ } - - $compiler_args += $flag_compile, $unit - run-compiler $compiler $unit $compiler_args - - $linker_args += @( - $flag_nologo, - $flag_link_win_machine_64, - $flag_link_no_incremental, - ( $flag_link_win_path_output + $binary ) - ) - if ( $debug ) { - $linker_args += $flag_link_win_debug - $linker_args += $flag_link_win_pdb + $pdb - $linker_args += $flag_link_mapfile + $map - } - else { - } - - $linker_args += $object - run-linker $linker $binary $linker_args - - # $compiler_args += $unit - # $compiler_args += $flag_linker - # $compiler_args += $linker_args - # run-compiler $compiler $unit $compiler_args - } - - $compiler = 'cl' - $linker = 'link' -} -#endregion Configuration +# Load up toolchain configuraion +. $config_toolchain #region Building $path_project = Join-Path $path_root 'project' @@ -450,31 +108,31 @@ else { $compiler_args += ( $flag_define + 'Build_Development=0' ) } -if ( $engine ) +function build-engine { $path_pdb_lock = Join-Path $path_binaries 'handmade_engine.pdb.lock' - New-Item $path_pdb_lock -ItemType File -Force -Verbose + New-Item $path_pdb_lock -ItemType File -Force # Delete old PDBs [Array]$pdb_files = Get-ChildItem -Path $path_binaries -Filter "handmade_engine_*.pdb" foreach ($file in $pdb_files) { Remove-Item -Path $file.FullName -Force - Write-Host "Deleted $file" -ForegroundColor Green + if ( $verbose ) { Write-Host "Deleted $file" -ForegroundColor Green } } - $engine_compiler_args = $compiler_args - $engine_compiler_args += ($flag_define + 'Build_DLL=1' ) + $local:compiler_args = $script:compiler_args + $compiler_args += ($flag_define + 'Build_DLL=1' ) if ( $vendor -eq 'msvc' ) { - $engine_compiler_args += ($flag_define + 'Engine_API=__declspec(dllexport)') + $compiler_args += ($flag_define + 'Engine_API=__declspec(dllexport)') } if ( $vendor -eq 'clang' ) { - $engine_compiler_args += ($flag_define + 'Engine_API=__attribute__((visibility("default")))') + $compiler_args += ($flag_define + 'Engine_API=__attribute__((visibility("default")))') } - $linker_args = @( + $local:linker_args = @( $flag_link_dll # $flag_link_optimize_references ) @@ -482,124 +140,167 @@ if ( $engine ) $unit = Join-Path $path_project 'handmade_engine.cpp' $dynamic_library = Join-Path $path_binaries 'handmade_engine.dll' - build-simple $includes $engine_compiler_args $linker_args $unit $dynamic_library + build-simple $includes $compiler_args $linker_args $unit $dynamic_library - if ( Test-Path $dynamic_library ) - { - # $data_path = Join-Path $path_data 'handmade_engine.dll' - # move-item $dynamic_library $data_path -Force - $path_lib = $dynamic_library -replace '\.dll', '.lib' - $path_exp = $dynamic_library -replace '\.dll', '.exp' - Remove-Item $path_lib -Force - if ( Test-Path $path_exp ) { Remove-Item $path_exp -Force } + Remove-Item $path_pdb_lock -Force - # We need to generate the symbol table so that we can lookup the symbols we need when loading/reloading the library at runtime. - # This is done by sifting through the emitter.map file from the linker for the base symbol names - # and mapping them to their found decorated name + #region CodeGen Post-Build + if ( -not $handmade_process_active ) { + # Create the symbol table + if ( Test-Path $dynamic_library ) + { + # $data_path = Join-Path $path_data 'handmade_engine.dll' + # move-item $dynamic_library $data_path -Force + $path_lib = $dynamic_library -replace '\.dll', '.lib' + $path_exp = $dynamic_library -replace '\.dll', '.exp' + Remove-Item $path_lib -Force + if ( Test-Path $path_exp ) { Remove-Item $path_exp -Force } - # Initialize the hashtable with the desired order of symbols - $engine_symbols = [ordered]@{ - 'on_module_reload' = $null - 'startup' = $null - 'shutdown' = $null - 'update_and_render' = $null - 'update_audio' = $null - } + # We need to generate the symbol table so that we can lookup the symbols we need when loading/reloading the library at runtime. + # This is done by sifting through the emitter.map file from the linker for the base symbol names + # and mapping them to their found decorated name - $path_engine_obj = Join-Path $path_build 'handmade_engine.obj' - $path_engine_map = Join-Path $path_build 'handmade_engine.map' - $maxNameLength = ($engine_symbols.Keys | Measure-Object -Property Length -Maximum).Maximum - - Get-Content -Path $path_engine_map | ForEach-Object { - # If all symbols are found, exit the loop - if ($engine_symbols.Values -notcontains $null) { - return - } - # Split the line into tokens - $tokens = $_ -split '\s+', 4 - # Extract only the decorated name using regex for both MSVC and Clang conventions - $decoratedName = ($tokens[2] -match '(\?[\w@]+|_Z[\w@]+)') ? $matches[1] : $null - - # Check the origin of the symbol - # If the origin matches 'handmade_engine.obj', then process the symbol - $originParts = $tokens[3] -split '\s+' - $origin = if ($originParts.Count -eq 3) { $originParts[2] } else { $originParts[1] } - - # Diagnostic output - if ( $false -and $decoratedName) { - write-host "Found decorated name: $decoratedName" -ForegroundColor Yellow - write-host "Origin : $origin" -ForegroundColor Yellow + # Initialize the hashtable with the desired order of symbols + $engine_symbols = [ordered]@{ + 'on_module_reload' = $null + 'startup' = $null + 'shutdown' = $null + 'update_and_render' = $null + 'update_audio' = $null } - if ($origin -like 'handmade_engine.obj') { - # Check each regular name against the current line - $engine_symbols.Keys | Where-Object { $engine_symbols[$_] -eq $null } | ForEach-Object { - if ($decoratedName -like "*$_*") { - $engine_symbols[$_] = $decoratedName + $path_engine_obj = Join-Path $path_build 'handmade_engine.obj' + $path_engine_map = Join-Path $path_build 'handmade_engine.map' + $maxNameLength = ($engine_symbols.Keys | Measure-Object -Property Length -Maximum).Maximum + + Get-Content -Path $path_engine_map | ForEach-Object { + # If all symbols are found, exit the loop + if ($engine_symbols.Values -notcontains $null) { + return + } + # Split the line into tokens + $tokens = $_ -split '\s+', 4 + # Extract only the decorated name using regex for both MSVC and Clang conventions + $decoratedName = ($tokens[2] -match '(\?[\w@]+|_Z[\w@]+)') ? $matches[1] : $null + + # Check the origin of the symbol + # If the origin matches 'handmade_engine.obj', then process the symbol + $originParts = $tokens[3] -split '\s+' + $origin = if ($originParts.Count -eq 3) { $originParts[2] } else { $originParts[1] } + + # Diagnostic output + if ( $false -and $decoratedName) { + write-host "Found decorated name: $decoratedName" -ForegroundColor Yellow + write-host "Origin : $origin" -ForegroundColor Yellow + } + + if ($origin -like 'handmade_engine.obj') { + # Check each regular name against the current line + $engine_symbols.Keys | Where-Object { $engine_symbols[$_] -eq $null } | ForEach-Object { + if ($decoratedName -like "*$_*") { + $engine_symbols[$_] = $decoratedName + } } } } + + if ($verbose) { write-host "Engine Symbol Table:" -ForegroundColor Green } + $engine_symbols.GetEnumerator() | ForEach-Object { + $paddedName = $_.Key.PadRight($maxNameLength) + $decoratedName = $_.Value + if ($verbose ) { write-host "`t$paddedName, $decoratedName" -ForegroundColor Green } + } + + # Write the symbol table to a file + $path_engine_symbols = Join-Path $path_build 'handmade_engine.symbols' + $engine_symbols.Values | Out-File -Path $path_engine_symbols } - write-host "Engine Symbol Table:" -ForegroundColor Green - $engine_symbols.GetEnumerator() | ForEach-Object { - $paddedName = $_.Key.PadRight($maxNameLength) - $decoratedName = $_.Value - write-host "`t$paddedName, $decoratedName" -ForegroundColor Green - } - - # Write the symbol table to a file - $path_engine_symbols = Join-Path $path_build 'handmade_engine.symbols' - $engine_symbols.Values | Out-File -Path $path_engine_symbols - } - - Remove-Item $path_pdb_lock -Force -Verbose - - #region CodeGen - if ( $handmade_process_active -eq $null ) { # Delete old PDBs $pdb_files = Get-ChildItem -Path $path_build -Filter "engine_postbuild_gen_*.pdb" foreach ($file in $pdb_files) { Remove-Item -Path $file.FullName -Force - Write-Host "Deleted $file" -ForegroundColor Green + if ($verbose) { Write-Host "Deleted $file" -ForegroundColor Green } } - $engine_codegen_compiler_args = @() - $engine_codegen_compiler_args += ( $flag_define + 'GEN_TIME' ) + $compiler_args = @() + $compiler_args += ( $flag_define + 'GEN_TIME' ) - $engine_codegen_linker_args = @( + $linker_args = @( $flag_link_win_subsystem_console ) $unit = Join-Path $path_codegen 'engine_postbuild_gen.cpp' $executable = Join-Path $path_build 'engine_postbuild_gen.exe' - build-simple $includes $engine_codegen_compiler_args $engine_codegen_linker_args $unit $executable - write-host + build-simple $includes $compiler_args $linker_args $unit $executable Push-Location $path_build - & $executable + $time_taken = Measure-Command { + & $executable 2>&1 | ForEach-Object { + write-host `t $_ -ForegroundColor Green + } + } Pop-Location $path_generated_file = Join-Path $path_build 'engine_symbol_table.hpp' move-item $path_generated_file (join-path $path_gen (split-path $path_generated_file -leaf)) -Force } - #endregion CodeGen +} +if ( $engine ) { + build-engine } -if ( $platform ) +function build-platform { + # CodeGen Pre-Build + if ( $true ) + { + # Delete old PDBs + $pdb_files = Get-ChildItem -Path $path_build -Filter "platform_gen_*.pdb" + foreach ($file in $pdb_files) { + Remove-Item -Path $file.FullName -Force + if ( $verbose ) { Write-Host "Deleted $file" -ForegroundColor Green } + } + + $path_platform_gen = Join-Path $path_platform 'gen' + + if ( -not (Test-Path $path_platform_gen) ) { + New-Item $path_platform_gen -ItemType Directory + } + + $local:compiler_args = @() + $compiler_args += ( $flag_define + 'GEN_TIME' ) + + $local:linker_args = @( + $flag_link_win_subsystem_console + ) + + $unit = Join-Path $path_codegen 'platform_gen.cpp' + $executable = Join-Path $path_build 'platform_gen.exe' + + build-simple $includes $compiler_args $linker_args $unit $executable + + Push-Location $path_platform + $time_taken = Measure-Command { + & $executable 2>&1 | ForEach-Object { + write-host `t $_ -ForegroundColor Green + } + } + Pop-Location + } + # Delete old PDBs $pdb_files = Get-ChildItem -Path $path_binaries -Filter "handmade_win32_*.pdb" foreach ($file in $pdb_files) { Remove-Item -Path $file.FullName -Force - Write-Host "Deleted $file" -ForegroundColor Green + if ( $verbose ) { Write-Host "Deleted $file" -ForegroundColor Green } } - $platform_compiler_args = $compiler_args - $platform_compiler_args += ($flag_define + 'Build_DLL=0' ) + $local:compiler_args = $script:compiler_args + $compiler_args += ($flag_define + 'Build_DLL=0' ) - $linker_args = @( + $local:linker_args = @( $lib_gdi32, # $lib_xinput, $lib_user32, @@ -614,7 +315,7 @@ if ( $platform ) $unit = Join-Path $path_project 'handmade_win32.cpp' $executable = Join-Path $path_binaries 'handmade_win32.exe' - build-simple $includes $platform_compiler_args $linker_args $unit $executable + build-simple $includes $compiler_args $linker_args $unit $executable # if ( Test-Path $executable ) # { @@ -622,6 +323,9 @@ if ( $platform ) # move-item $executable $data_path -Force # } } +if ( $platform ) { + build-platform +} $path_jsl_dll = Join-Path $path_binaries 'JoyShockLibrary.dll' if ( (Test-Path $path_jsl_dll) -eq $false ) @@ -631,5 +335,12 @@ if ( (Test-Path $path_jsl_dll) -eq $false ) } #endregion Handmade Runtime +$include = @( + '*.cpp' + '*.hpp' +) +format-cpp $path_gen $include +format-cpp (Join-Path $path_platform 'gen' ) $include + Pop-Location #endregion Building diff --git a/scripts/handmade.rdbg b/scripts/handmade.rdbg index 7ddac53a51aa913281f1966201b1af7a625b897b..14c6c47df00ce9954797d8292f530c45b104303b 100644 GIT binary patch delta 317 zcmaFN@tJ!b4(BnJ z$&Sntle?HUyMa_I0x`@lR#u)N!SQaP&fcDW?(sp6;ql4&c_pb8B|tSO0Awr(GXeqk dEi%&kvTmoiEO!j3F0|0v=QV9S6 delta 96 zcmey&{g`7y@x=F*j7Aebs7&@}5@fWQ_(4~sJTuSOD83*ku_P_OC|57Jpn!p4a}rY| w&1 | ForEach-Object { + $color = 'White' + switch ($_){ + { $_ -match "error" } { $color = 'Red' ; break } + { $_ -match "warning" } { $color = 'Yellow'; break } + } + write-host `t $_ -ForegroundColor $color + } + } + + if ( Test-Path($unit) ) { + write-host "$unit compile finished in $($time_taken.TotalMilliseconds) ms`n" + } + else { + write-host "Compile failed for $unit`n" -ForegroundColor Red + } +} + +function run-linker +{ + param( $linker, $binary, $linker_args ) + + write-host "`Linking $binary" + if ( $verbose ) { + write-host "Linker config:" + $linker_args | ForEach-Object { + write-host $_ -ForegroundColor Cyan + } + } + + $time_taken = Measure-Command { + & $linker $linker_args 2>&1 | ForEach-Object { + $color = 'White' + switch ($_){ + { $_ -match "error" } { $color = 'Red' ; break } + { $_ -match "warning" } { $color = 'Yellow'; break } + } + write-host `t $_ -ForegroundColor $color + } + } + + if ( Test-Path($binary) ) { + write-host "$binary linking finished in $($time_taken.TotalMilliseconds) ms`n" + } + else { + write-host "Linking failed for $binary`n" -ForegroundColor Red + } +} + +if ( $vendor -match "clang" ) +{ + # https://clang.llvm.org/docs/ClangCommandLineReference.html + $flag_all_c = '/TC' + $flag_all_cpp = '/TP' + $flag_compile = '-c' + $flag_color_diagnostics = '-fcolor-diagnostics' + $flag_no_color_diagnostics = '-fno-color-diagnostics' + $flag_debug = '-g' + $flag_debug_codeview = '-gcodeview' + $flag_define = '-D' + $flag_exceptions_disabled = '-fno-exceptions' + $flag_preprocess = '-E' + $flag_include = '-I' + $flag_section_data = '-fdata-sections' + $flag_section_functions = '-ffunction-sections' + $flag_library = '-l' + $flag_library_path = '-L' + $flag_linker = '-Wl,' + if ( $IsWindows ) { + $flag_link_dll = '/DLL' + $flag_link_mapfile = '/MAP:' + $flag_link_optimize_references = '/OPT:REF' + } + if ( $IsLinux ) { + $flag_link_mapfile = '--Map=' + $flag_link_optimize_references = '--gc-sections' + } + $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' + $flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' + $flag_link_win_machine_32 = '/MACHINE:X86' + $flag_link_win_machine_64 = '/MACHINE:X64' + $flag_link_win_debug = '/DEBUG' + $flag_link_win_pdb = '/PDB:' + $flag_link_win_path_output = '/OUT:' + $flag_no_optimization = '-O0' + $flag_optimize_fast = '-O2' + $flag_optimize_size = '-O1' + $flag_optimize_intrinsics = '-Oi' + $flag_path_output = '-o' + $flag_preprocess_non_intergrated = '-no-integrated-cpp' + $flag_profiling_debug = '-fdebug-info-for-profiling' + $flag_set_stack_size = '-stack=' + $flag_syntax_only = '-fsyntax-only' + $flag_target_arch = '-target' + $flag_wall = '-Wall' + $flag_warning = '-W' + $flag_warnings_as_errors = '-Werror' + $flag_win_nologo = '/nologo' + + $ignore_warning_ms_include = 'no-microsoft-include' + $ignore_warning_return_type_c_linkage = 'no-return-type-c-linkage' + + $target_arch = Get-TargetArchClang + + $warning_ignores = @( + $ignore_warning_ms_include, + $ignore_warning_return_type_c_linkage + ) + + # https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 + $libraries = @( + 'Kernel32' # For Windows API + # 'msvcrt', # For the C Runtime (Dynamically Linked) + # 'libucrt', + 'libcmt' # For the C Runtime (Static Linkage) + ) + + function build-simple + { + param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) + #Write-Host "build-simple: clang" + + $object = $unit -replace '\.cpp', '.obj' + $map = $unit -replace '\.cpp', '.map' + $object = join-path $path_build (split-path $object -Leaf) + $map = join-path $path_build (split-path $map -Leaf) + + # The PDB file has to also be time-stamped so that we can reload the DLL at runtime + $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" + + $compiler_args += @( + $flag_no_color_diagnostics, + $flag_exceptions_disabled, + $flag_target_arch, $target_arch, + $flag_wall, + $flag_preprocess_on_intergrated, + # $flag_section_data, + # $flag_section_functions, + ( $flag_path_output + $object ) + ) + if ( $optimize ) { + $compiler_args += $flag_optimize_fast + } + else { + $compiler_args += $flag_no_optimization + } + if ( $debug ) { + $compiler_args += ( $flag_define + 'Build_Debug=1' ) + $compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug + } + else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) + } + + $warning_ignores | ForEach-Object { + $compiler_args += $flag_warning + $_ + } + $compiler_args += $includes | ForEach-Object { $flag_include + $_ } + + $compiler_args += $flag_compile, $unit + run-compiler $compiler $unit $compiler_args + + $linker_args += @( + $flag_link_win_machine_64, + $( $flag_link_win_path_output + $binary ) + ) + if ( $debug ) { + $linker_args += $flag_link_win_debug + $linker_args += $flag_link_win_pdb + $pdb + $linker_args += $flag_link_mapfile + $map + } + + $libraries | ForEach-Object { + $linker_args += $_ + '.lib' + } + + $linker_args += $object + run-linker $linker $binary $linker_args + + # $compiler_args += $unit + # $linker_args | ForEach-Object { + # $compiler_args += $flag_linker + $_ + # } + # run-compiler $compiler $unit $compiler_args + } + + $compiler = 'clang++' + $linker = 'lld-link' +} + +if ( $vendor -match "msvc" ) +{ + # https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 + $flag_all_c = '/TC' + $flag_all_cpp = '/TP' + $flag_compile = '/c' + $flag_debug = '/Zi' + $flag_define = '/D' + $flag_exceptions_disabled = '/EHsc-' + $flag_RTTI_disabled = '/GR-' + $flag_include = '/I' + $flag_full_src_path = '/FC' + $flag_nologo = '/nologo' + $flag_dll = '/LD' + $flag_dll_debug = '/LDd' + $flag_linker = '/link' + $flag_link_dll = '/DLL' + $flag_link_no_incremental = '/INCREMENTAL:NO' + $flag_link_mapfile = '/MAP:' + $flag_link_optimize_references = '/OPT:REF' + $flag_link_win_debug = '/DEBUG' + $flag_link_win_pdb = '/PDB:' + $flag_link_win_machine_32 = '/MACHINE:X86' + $flag_link_win_machine_64 = '/MACHINE:X64' + $flag_link_win_path_output = '/OUT:' + $flag_link_win_rt_dll = '/MD' + $flag_link_win_rt_dll_debug = '/MDd' + $flag_link_win_rt_static = '/MT' + $flag_link_win_rt_static_debug = '/MTd' + $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' + $flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' + $flag_no_optimization = '/Od' + $flag_optimize_fast = '/O2' + $flag_optimize_size = '/O1' + $flag_optimize_intrinsics = '/Oi' + $flag_optimized_debug = '/Zo' + $flag_out_name = '/OUT:' + $flag_path_interm = '/Fo' + $flag_path_debug = '/Fd' + $flag_path_output = '/Fe' + $flag_preprocess_conform = '/Zc:preprocessor' + $flag_set_stack_size = '/F' + $flag_syntax_only = '/Zs' + $flag_wall = '/Wall' + $flag_warnings_as_errors = '/WX' + + # This works because this project uses a single unit to build + function build-simple + { + param( [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) + #Write-Host "build-simple: msvc" + + $object = $unit -replace '\.(cpp)$', '.obj' + $map = $unit -replace '\.(cpp)$', '.map' + $object = join-path $path_build (split-path $object -Leaf) + $map = join-path $path_build (split-path $map -Leaf) + + # The PDB file has to also be time-stamped so that we can reload the DLL at runtime + $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" + + $compiler_args += @( + $flag_nologo, + # $flag_all_cpp, + $flag_exceptions_disabled, + ( $flag_define + '_HAS_EXCEPTIONS=0' ), + $flag_RTTI_disabled, + $flag_preprocess_conform, + $flag_full_src_path, + ( $flag_path_interm + $path_build + '\' ), + ( $flag_path_output + $path_build + '\' ) + ) + + if ( $optimize ) { + $compiler_args += $flag_optimize_fast + } + else { + $compiler_args += $flag_no_optimization + } + + if ( $debug ) + { + $compiler_args += $flag_debug + $compiler_args += ( $flag_define + 'Build_Debug=1' ) + $compiler_args += ( $flag_path_debug + $path_build + '\' ) + $compiler_args += $flag_link_win_rt_static_debug + + if ( $optimize ) { + $compiler_args += $flag_optimized_debug + } + } + else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) + $compiler_args += $flag_link_win_rt_static + } + $compiler_args += $includes | ForEach-Object { $flag_include + $_ } + + $compiler_args += $flag_compile, $unit + run-compiler $compiler $unit $compiler_args + + $linker_args += @( + $flag_nologo, + $flag_link_win_machine_64, + $flag_link_no_incremental, + ( $flag_link_win_path_output + $binary ) + ) + if ( $debug ) { + $linker_args += $flag_link_win_debug + $linker_args += $flag_link_win_pdb + $pdb + $linker_args += $flag_link_mapfile + $map + } + else { + } + + $linker_args += $object + run-linker $linker $binary $linker_args + + # $compiler_args += $unit + # $compiler_args += $flag_linker + # $compiler_args += $linker_args + # run-compiler $compiler $unit $compiler_args + } + + $compiler = 'cl' + $linker = 'link' +} diff --git a/scripts/helpers/format_cpp.psm1 b/scripts/helpers/format_cpp.psm1 new file mode 100644 index 0000000..fdfc293 --- /dev/null +++ b/scripts/helpers/format_cpp.psm1 @@ -0,0 +1,26 @@ +# format_cpp.psm1 + +function format-cpp +{ + param( $path, $include, $exclude ) + + # Format generated gencpp + Write-Host "Beginning format" + $formatParams = @( + '-i' # In-place + '-style=file:./scripts/.clang-format' + '-verbose' + ) + + $targetFiles = @( + Get-ChildItem -Recurse -Path $path -Include $include -Exclude $exclude + | Select-Object -ExpandProperty FullName + ) + + $time_taken = Measure-Command { + clang-format $formatParams $targetFiles + } + Write-Host "Formatting complete in $($time_taken.TotalMilliseconds) ms`n" +} + +Export-ModuleMember -Function format-cpp