Day 22 complete

This commit is contained in:
2023-09-27 01:16:41 -04:00
parent 9220550dd4
commit 9bb8026762
25 changed files with 532 additions and 205 deletions

View File

@ -110,7 +110,7 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset )
u8 red = 0;
#endif
*pixel++ = u32(red << 16) | u32(green << 8) | blue;
*pixel++ = u32(red << 16) | u32(green/2 << 16) | blue/2 << 0;
}
wildcard += 0.5375f;
row += buffer->Pitch;

View File

@ -50,7 +50,6 @@ struct AudioBuffer
u32 RunningSampleIndex;
s32 SamplesPerSecond;
s32 NumSamples;
char _PAD_[4];
};
struct DigitalBtn
@ -190,7 +189,6 @@ struct InputMode
{
InputBindCallback* Binds;
s32 NumBinds;
char _PAD_[4];
};
void input_mode_pop( InputMode* mode );

View File

@ -0,0 +1,3 @@
/*
This represents the API only accessible to the engine to fullfill for the game module.
*/

View File

@ -1,11 +0,0 @@
#include "platform/win32.hpp"
#include "engine.hpp"
b32 WINAPI DllMain(
HINSTANCE instance,
DWORD reason_for_call,
LPVOID reserved
)
{
return true;
}

View File

@ -27,7 +27,6 @@ struct Actionable
char const* Name;
engine::InputBindCallback* Binds;
s32 NumBinds;
char _PAD_[4];
};
struct ActionableMode

View File

@ -13,7 +13,4 @@
#if Build_Unity
# include "engine/engine.cpp"
# if SYSTEM_WINDOWS
# include "engine/win32_engine.cpp"
# endif
#endif

View File

@ -16,6 +16,8 @@
#pragma warning( disable: 4514 ) // Support for unused inline functions
#pragma warning( disable: 4505 ) // Support for unused static functions
#pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
#pragma warning( disable: 5264 ) // Support for 'const' variables unused
#pragma warning( disable: 4820 ) // Support auto-adding padding to structs
// TODO(Ed) : REMOVE THESE WHEN HE GETS TO THEM
#include <math.h> // TODO : Implement math ourselves
@ -26,6 +28,7 @@
#include "generics.hpp"
#include "math_constants.hpp"
#include "types.hpp"
#include "strings.hpp"
#define NS_PLATFORM_BEGIN namespace platform {
#define NS_PLATFORM_END }
@ -45,7 +48,12 @@ struct Debug_FileContent
{
void* Data;
u32 Size;
char _PAD_[4];
Byte _PAD_[4];
};
struct BinaryModule
{
void* OpaqueHandle;
};
using DebugFileFreeContentFn = void ( Debug_FileContent* file_content );
@ -53,9 +61,54 @@ using DebugFileReadContentFn = Debug_FileContent ( char const* file_path );
using DebugFileWriteContentFn = b32 ( char const* file_path, u32 content_size, void* content_memory );
using DebugSetPauseRenderingFn = void (b32 value);
// TODO(Ed): This also assumes the symbol name is always within size of the provided buffer, needs to fail if not.
// Note: This is a temporary solution until there is more infrastructure for the engine to use.
void get_symbol_from_module_table( Debug_FileContent symbol_table, u32 symbol_ID, char* symbol_name )
{
struct Token
{
char const* Ptr;
u32 Len;
char _PAD_[4];
};
Token tokens[256] = {};
s32 idx = 0;
char const* scanner = rcast( char const*, symbol_table.Data );
u32 left = symbol_table.Size;
while ( left )
{
if ( *scanner == '\n' || *scanner == '\r' )
{
++ scanner;
-- left;
}
else
{
tokens[idx].Ptr = scanner;
while ( left && *scanner != '\r' && *scanner != '\n' )
{
-- left;
++ scanner;
++ tokens[idx].Len;
}
++ idx;
}
}
Token& token = tokens[symbol_ID];
while ( token.Len -- )
{
*symbol_name = *token.Ptr;
++ symbol_name;
++ token.Ptr;
}
*symbol_name = '\0';
}
#endif
// TODO(Ed) : Implement this later when settings UI is setup.
#pragma region Settings Exposure
// Exposing specific properties for user configuration in settings
@ -68,6 +121,13 @@ using SetMonitorRefreshRateFn = void ( u32 rate_in_hz );
using GetEngineFrameTargetFn = u32 ();
using SetEngineFrameTargetFn = void ( u32 rate_in_hz );
// This module api will be used to manage the editor and game modules from the engine side,
// without the platform layer needing to know about it.
using LoadBinaryModuleFn = BinaryModule ( char const* module_path );
using UnloadBinaryModuleFn = void ( BinaryModule* module );
using GetModuleProcedureFn = void* ( BinaryModule module, char const* symbol );
struct ModuleAPI
{
#if Build_Development
@ -83,6 +143,10 @@ struct ModuleAPI
GetEngineFrameTargetFn* get_engine_frame_target;
SetEngineFrameTargetFn* set_engine_frame_target;
LoadBinaryModuleFn* load_binary_module;
UnloadBinaryModuleFn* unload_binary_module;
GetModuleProcedureFn* get_module_procedure;
};
#pragma endregion Settings Exposure

View File

@ -42,7 +42,6 @@ struct ModuleAPI
UpdateAudioFn* update_audio;
b32 IsValid;
char _PAD_[4];
};
NS_ENGINE_END

View File

@ -1,3 +0,0 @@
/*
This represents the API only accessible to the platform layer to fullfill for the game layer.
*/

View File

@ -0,0 +1,190 @@
#include "macros.hpp"
#include "types.hpp"
void str_append( u32 dest_len, char* dest, u32 src_len, char const* src );
void str_concat( u32 dest_size, char* dest
, u32 str_a_len, char const* str_a
, u32 str_b_len, char const* str_b );
u32 str_length( char const* str );
#define str_ascii( str ) { sizeof( str ) - 1, str }
// Length tracked raw strings.
struct Str
{
u32 Len;
char* Data;
void append( u32 src_len, char const* src ) {
str_append( Len, Data, src_len, src );
}
void append( Str const src ) {
str_append( Len, Data, src.Len, src.Data );
}
static
void concast( u32 dest_size, Str* dest, Str const str_a, Str const str_b )
{
str_concat( dest_size, dest->Data
, str_a.Len, str_a.Data
, str_b.Len, str_b.Data );
dest->Len = str_a.Len + str_b.Len;
}
operator char*() const {
return Data;
}
char& operator []( u32 idx ) {
return Data[idx];
}
char const& operator []( u32 idx ) const {
return Data[idx];
}
};
template< u32 capacity >
// Fixed length raw strings.
struct StrFixed
{
constexpr static u32 Capacity = capacity;
u32 Len;
char Data[capacity];
void append( u32 src_len, char const* src ) {
str_append( Len, Data, src_len, src );
}
void append( Str const src ) {
str_append( Len, Data, src.Len, src.Data );
}
void concat( Str const str_a, Str const str_b )
{
str_concat( Capacity, Data
, str_a.Len, str_a.Data
, str_b.Len, str_b.Data );
Len = str_a.Len + str_b.Len;
}
operator char*() { return Data;}
operator char const*() { return Data; }
operator Str() { return { Len, Data }; }
operator Str const() const { return { Len, Data }; }
char& operator []( u32 idx ) {
assert( idx < Capacity );
return Data[idx];
}
char const& operator []( u32 idx ) const {
assert( idx < Capacity );
return Data[idx];
}
};
inline
void str_append( u32 dest_len, char* dest, u32 src_len, char const* src )
{
assert( dest_len > 0 );
assert( dest != nullptr );
assert( src_len > 0 );
assert( src != nullptr );
assert( dest_len >= src_len );
char* dest_end = dest + dest_len;
assert( *dest_end == '\0' );
u32 left = src_len;
while ( left-- )
{
*dest = *src;
++ dest;
++ src;
}
}
void str_concat( u32 dest_size, char* dest
, u32 str_a_len, char const* str_a
, u32 str_b_len, char const* str_b )
{
assert( dest_size > 0 );
assert( dest != nullptr );
assert( *dest == '\0' );
assert( str_a_len > 0 );
assert( str_a != nullptr );
assert( str_b_len > 0 );
assert( str_b != nullptr );
assert( str_a_len + str_b_len < dest_size );
char* dest_a = dest;
char* dest_b = dest + str_a_len;
if ( str_a_len > str_b_len )
{
u32 left = str_a_len;
while ( left-- )
{
*dest_a = *str_a;
*dest_b = *str_b;
++ dest_a;
++ dest_b;
++ str_a;
++ str_b;
}
left = str_a_len - str_b_len;
while ( left-- )
{
*dest_b = *str_b;
++ dest_b;
++ str_b;
}
}
else if ( str_a_len < str_b_len )
{
u32 left = str_b_len;
while ( left-- )
{
*dest_a = *str_a;
*dest_b = *str_b;
++ dest_a;
++ dest_b;
++ str_a;
++ str_b;
}
left = str_b_len - str_a_len;
while ( left-- )
{
*dest_a = *str_a;
++ dest_a;
++ str_a;
}
}
else
{
u32 left = str_a_len;
while ( left-- )
{
*dest_a = *str_a;
*dest_b = *str_b;
++ dest_a;
++ str_a;
++ dest_b;
++ str_b;
}
}
}
inline
u32 str_length( char const* str )
{
assert( str != nullptr );
u32 result = 0;
while ( *str != '\0' )
{
++ result;
++ str;
}
return result;
}

View File

@ -97,6 +97,9 @@ static_assert( sizeof( uptr ) == sizeof( sptr ), "sizeof(uptr) != sizeof(sptr)"
typedef float f32;
typedef double f64;
struct Byte {};
static_assert( sizeof( Byte ) == 1, "Unit type must be 1 byte in size" );
static_assert( sizeof( f32 ) == 4, "sizeof(f32) != 4" );
static_assert( sizeof( f64 ) == 8, "sizeof(f64) != 8" );

View File

@ -101,6 +101,16 @@ struct DirectSoundBuffer
#pragma region Static Data
global StrFixed< S16_MAX > Path_Root;
global StrFixed< S16_MAX > Path_Binaries;
constexpr Str FName_Engine_DLL = str_ascii("handmade_engine.dll");
constexpr Str FName_Engine_DLL_InUse = str_ascii("handmade_engine_in_use.dll");
global StrFixed< S16_MAX > Path_Engine_DLL;
global StrFixed< S16_MAX > Path_Engine_DLL_InUse;
// TODO(Ed) : This is a global for now.
global b32 Running = false;
global b32 Pause_Rendering = false;
@ -130,7 +140,7 @@ global u32 Engine_Refresh_Hz = Monitor_Refresh_Hz / 2;
global f32 Engine_Frame_Target_MS = 1000.f / scast(f32, Engine_Refresh_Hz);
#pragma endregion Static Data
#pragma region Internal
#if Build_Debug
struct DebugTimeMarker
{
@ -145,82 +155,6 @@ struct DebugTimeMarker
DWORD ExpectedFlipCursor;
};
void debug_file_free_content( Debug_FileContent* content )
{
if ( content->Data)
{
VirtualFree( content->Data, 0, MEM_Release);
*content = {};
}
}
Debug_FileContent debug_file_read_content( char const* file_path )
{
Debug_FileContent result {};
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 result;
}
GetFileSizeEx( file_handle, rcast(LARGE_INTEGER*, &result.Size) );
if ( result.Size == 0 )
{
// TODO(Ed) : Logging
return result;
}
result.Data = VirtualAlloc( 0, result.Size, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write );
u32 bytes_read;
if ( ReadFile( file_handle, result.Data, result.Size, rcast(LPDWORD, &bytes_read), 0 ) == false )
{
// TODO(Ed) : Logging
return {};
}
if ( bytes_read != result.Size )
{
// TODO : Logging
return {};
}
CloseHandle( file_handle );
return result;
}
b32 debug_file_write_content( char const* file_path, 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;
}
DWORD bytes_written;
if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false )
{
// TODO : Logging
return false;
}
CloseHandle( file_handle );
return true;
}
void debug_set_pause_rendering( b32 value )
{
Pause_Rendering = value;
}
internal void
debug_draw_vertical( s32 x_pos, s32 top, s32 bottom, s32 color )
{
@ -748,84 +682,144 @@ process_pending_window_messages( engine::KeyboardState* keyboard )
}
}
}
#pragma endregion Internal
#pragma region Platfom API
u32 get_monitor_refresh_rate();
#pragma endregion Platform API
// TODO(Ed): This also assumes the symbol name is always within size of the provided buffer, needs to fail if not.
void get_symbol_from_module_table( Debug_FileContent symbol_table, u32 symbol_ID, char* symbol_name )
#if Build_Development
void debug_file_free_content( Debug_FileContent* content )
{
struct Token
if ( content->Data)
{
char const* Ptr;
u32 Len;
char _PAD_[4];
};
Token tokens[256] = {};
s32 idx = 0;
char const* scanner = rcast( char const*, symbol_table.Data );
u32 left = symbol_table.Size;
while ( left )
{
if ( *scanner == '\n' || *scanner == '\r' )
{
++ scanner;
-- left;
}
else
{
tokens[idx].Ptr = scanner;
while ( left && *scanner != '\r' && *scanner != '\n' )
{
-- left;
++ scanner;
++ tokens[idx].Len;
}
++ idx;
}
VirtualFree( content->Data, 0, MEM_Release);
*content = {};
}
Token& token = tokens[symbol_ID];
while ( token.Len -- )
{
*symbol_name = *token.Ptr;
++ symbol_name;
++ token.Ptr;
}
*symbol_name = '\0';
}
// Right now they are just the data directory
#define Path_To_Symbol_Tables
Debug_FileContent debug_file_read_content( char const* file_path )
{
Debug_FileContent result {};
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 result;
}
GetFileSizeEx( file_handle, rcast(LARGE_INTEGER*, &result.Size) );
if ( result.Size == 0 )
{
// TODO(Ed) : Logging
return result;
}
result.Data = VirtualAlloc( 0, result.Size, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write );
u32 bytes_read;
if ( ReadFile( file_handle, result.Data, result.Size, rcast(LPDWORD, &bytes_read), 0 ) == false )
{
// TODO(Ed) : Logging
return {};
}
if ( bytes_read != result.Size )
{
// TODO : Logging
return {};
}
CloseHandle( file_handle );
return result;
}
b32 debug_file_write_content( char const* file_path, 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;
}
DWORD bytes_written;
if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false )
{
// TODO : Logging
return false;
}
CloseHandle( file_handle );
return true;
}
void debug_set_pause_rendering( b32 value )
{
Pause_Rendering = value;
}
#endif
u32 get_monitor_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->OpaqueHandle) );
*module = {};
}
void* get_binary_module_symbol( BinaryModule module, char const* symbol_name )
{
return rcast(void*, GetProcAddress( scast(HMODULE, module.OpaqueHandle), symbol_name ));
}
#pragma endregion Platform API
FILETIME file_get_last_write_time( char const* path )
{
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;
}
#pragma region Engine Module API
global HMODULE Lib_Handmade_Engine = nullptr;
engine::ModuleAPI load_engine_module_api()
{
using ModuleAPI = engine::ModuleAPI;
// TODO(Ed) : Need proper paything to the dll (not assume is in the base directory).
CopyFileA( "handmade_engine.dll", "handmade_engine_temp.dll", FALSE );
CopyFileA( Path_Engine_DLL, Path_Engine_DLL_InUse, FALSE );
// Engine
Lib_Handmade_Engine = LoadLibraryA( "handmade_engine_temp.dll" );
Lib_Handmade_Engine = LoadLibraryA( Path_Engine_DLL_InUse );
if ( ! Lib_Handmade_Engine )
{
return {};
}
constexpr char const*
handmade_engine_symbols = Path_To_Symbol_Tables "handmade_engine.symbols";
constexpr Str fname_handmade_engine_symbols = str_ascii("handmade_engine.symbols");
Debug_FileContent symbol_table = debug_file_read_content( handmade_engine_symbols );
StrFixed< S16_MAX > path_handmade_engine_symbols { 0, {} };
path_handmade_engine_symbols.concat( Path_Binaries, fname_handmade_engine_symbols );
Debug_FileContent symbol_table = debug_file_read_content( path_handmade_engine_symbols );
if ( symbol_table.Size == 0 )
{
fatal( "Failed to laod symbol table for handmade engine module!" );
fatal( "Failed to load symbol table for handmade engine module!" );
return {};
}
@ -872,6 +866,7 @@ void unload_engine_module_api( engine::ModuleAPI* engine_api )
OutputDebugStringA( "Unloaded engine module API\n" );
}
}
#pragma endregion Engine Module API
NS_PLATFORM_END
@ -910,6 +905,10 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
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;
}
// Memory
@ -940,9 +939,6 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
}
}
// Load engine module
engine::ModuleAPI engine_api = load_engine_module_api();
WNDCLASSW window_class {};
HWND window_handle = nullptr;
{
@ -983,6 +979,41 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
// WinDimensions dimensions = get_window_dimensions( window_handle );
resize_dib_section( &Surface_Back_Buffer, 1280, 720 );
// Setup pathing
// 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.Data ) == 0 )
{
fatal( "Failed to get the root directory!" );
}
Path_Root.Len = str_length(Path_Root.Data);
Path_Root.Data[ 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 );
}
// 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;
@ -1091,8 +1122,6 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
OutputDebugStringA( text_buffer );
#endif
u64 module_reload_counter = 0;
Running = true;
#if 0
// This tests the play & write cursor update frequency.
@ -1109,13 +1138,13 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
#endif
while( Running )
{
if ( module_reload_counter > 120 )
FILETIME engine_api_current_time = file_get_last_write_time( Path_Engine_DLL );
if ( CompareFileTime( & engine_api_load_time, & engine_api_current_time ) != 0 )
{
engine_api_load_time = engine_api_current_time;
unload_engine_module_api( & engine_api );
engine_api = load_engine_module_api();
module_reload_counter = 0;
}
++ module_reload_counter;
process_pending_window_messages( new_keyboard );
@ -1490,6 +1519,9 @@ WinMain( HINSTANCE instance, HINSTANCE prev_instance, LPSTR commandline, int sho
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 )