diff --git a/build.c b/build.c index 6c305bc..afdc585 100644 --- a/build.c +++ b/build.c @@ -3,6 +3,8 @@ /// // Build config stuff +#define RUN_TESTS 1 + #define INITIAL_PROGRAM_MEMORY_SIZE MB(5) // You might want to increase this if you get a log warning saying the temporary storage was overflown. @@ -37,10 +39,10 @@ typedef struct Context_Extra { // #include "oogabooga/examples/text_rendering.c" // #include "oogabooga/examples/custom_logger.c" -// #include "oogabooga/examples/renderer_stress_test.c" +#include "oogabooga/examples/renderer_stress_test.c" // #include "oogabooga/examples/tile_game.c" // #include "oogabooga/examples/audio_test.c" -#include "oogabooga/examples/custom_shader.c" +// #include "oogabooga/examples/custom_shader.c" // This is where you swap in your own project! // #include "entry_yourepicgamename.c" diff --git a/build_engine.c b/build_engine.c new file mode 100644 index 0000000..c88a6ce --- /dev/null +++ b/build_engine.c @@ -0,0 +1,79 @@ + +/// +// Build config stuff + +#define OOGABOOGA_BUILD_SHARED_LIBRARY 1 + +#include "oogabooga/oogabooga.c" + +/// +/// +// This is the "engine" part of your game, which will call into your game.dll + + +typedef void (*Game_Update_Proc)(f64); +Game_Update_Proc game_update; + +Dynamic_Library_Handle dll = 0; + +void load_game_dll(char **argv) { + + // Here we load all the game symbols + + if (dll) { + os_unload_dynamic_library(dll); + } + + string exe_path = STR(argv[0]); + string exe_dir = get_directory_of(exe_path); + + // We need to copy the original and open the copy, so we can recompile the original and then close & replace + // the copy. + string dll_path = string_concat(exe_dir, STR("/game.dll"), get_temporary_allocator()); + string used_dll_path = string_concat(exe_dir, STR("/game-in-use.dll"), get_temporary_allocator()); + + bool ok = os_file_copy(dll_path, used_dll_path, true); + assert(ok, "Could not copy %s to %s", dll_path, used_dll_path); + + dll = os_load_dynamic_library(used_dll_path); + assert(dll, "Failed loading game dll"); + + game_update = os_dynamic_library_load_symbol(dll, STR("game_update")); + assert(game_update, "game is missing game_update()"); + + log("Loaded game procedures"); +} + +int entry(int argc, char **argv) { + + load_game_dll(argv); + + window.title = STR("Minimal Game Example"); + window.scaled_width = 1280; // We need to set the scaled size if we want to handle system scaling (DPI) + window.scaled_height = 720; + window.x = 200; + window.y = 90; + window.clear_color = hex_to_rgba(0x6495EDff); + + float64 last_time = os_get_current_time_in_seconds(); + while (!window.should_close) { + float64 now = os_get_current_time_in_seconds(); + float64 delta = now-last_time; + if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(delta), (delta)*1000); + last_time = now; + + reset_temporary_storage(); + + game_update(delta); + + if (is_key_just_pressed('R')) { + load_game_dll(argv); + play_one_audio_clip(STR("oogabooga/examples/bruh.wav")); + } + + os_update(); + gfx_update(); + } + + return 0; +} \ No newline at end of file diff --git a/build_game.c b/build_game.c new file mode 100644 index 0000000..266b911 --- /dev/null +++ b/build_game.c @@ -0,0 +1,30 @@ + + +// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c + +#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1 +#include "oogabooga/oogabooga.c" + +/// +/// +// This is the game module which is what can be recompiled in the engine runtime + +// For the engine to be able to detect a symbol, it needs to be marked with SHARED_EXPORT +void SHARED_EXPORT +game_update(f64 delta_time) { + + float64 now = os_get_current_time_in_seconds(); + + Matrix4 rect_xform = m4_scalar(1.0); + rect_xform = m4_rotate_z(rect_xform, (f32)now); + rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0)); + draw_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN); + + draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED); + + float aspect = (f32)window.width/(f32)window.height; + float mx = (input_frame.mouse_x/(f32)window.width * 2.0 - 1.0)*aspect; + float my = input_frame.mouse_y/(f32)window.height * 2.0 - 1.0; + + draw_line(v2(-.75, -.75), v2(mx, my), 0.005, COLOR_WHITE); +} \ No newline at end of file diff --git a/build_launcher.c b/build_launcher.c new file mode 100644 index 0000000..a09639a --- /dev/null +++ b/build_launcher.c @@ -0,0 +1,36 @@ + + +// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c + +#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1 +#include "oogabooga/oogabooga.c" + + +// All we do with the launcher is to launch the engine +// We need to be careful to use oogabooga things because it has not yet been initialized. +// We can use get_temporary_allocator() because that actually gives us the initialization allocator. +// We cannot use log() but we can use print() +int main(int argc, char **argv) { + string exe_path = STR(argv[0]); + string exe_dir = get_directory_of(exe_path); + + Allocator a = get_initialization_allocator(); + string dll_path = string_concat(exe_dir, STR("/engine.dll"), a); + + Dynamic_Library_Handle dll = os_load_dynamic_library(dll_path); + if (!dll) { + os_write_string_to_stdout(STR("Failed loading engine dll from ")); + os_write_string_to_stdout(dll_path); + os_write_string_to_stdout(STR("\n")); + return -1; + } + + int (*engine_main)(int, char**) = os_dynamic_library_load_symbol(dll, STR("main")); + if (!engine_main) { + os_write_string_to_stdout(STR("Failed loading engine main\n")); + return -1; + } + + print("Launcher found engine main(), running...\n"); + return engine_main(argc, argv); +} \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 96a428d..c9e255c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,6 @@ + +## v0.01.002 - + ## v0.01.001 - Spacial audio, custom shading, scissor boxing - Audio - Implemented spacial audio playback diff --git a/hotload_build_all.bat b/hotload_build_all.bat new file mode 100644 index 0000000..5c6b13a --- /dev/null +++ b/hotload_build_all.bat @@ -0,0 +1,16 @@ +@echo on +if exist build ( + rmdir /s /q build +) +mkdir build + +pushd build + +clang ../build_engine.c -g -shared -o engine.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -fuse-ld=lld -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -ldbghelp -femit-all-decls -Xlinker /IMPLIB:engine.lib -Xlinker /MACHINE:X64 -Xlinker /SUBSYSTEM:CONSOLE + +clang ../build_launcher.c -g -o launcher.exe -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE + +clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE + + +popd \ No newline at end of file diff --git a/hotload_build_game.bat b/hotload_build_game.bat new file mode 100644 index 0000000..ec99931 --- /dev/null +++ b/hotload_build_game.bat @@ -0,0 +1,8 @@ +@echo on + +pushd build + +clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE + + +popd \ No newline at end of file diff --git a/oogabooga/base.c b/oogabooga/base.c index a34e7e4..c03e837 100644 --- a/oogabooga/base.c +++ b/oogabooga/base.c @@ -1,5 +1,5 @@ -#define thread_local _Thread_local + #define local_persist static @@ -9,10 +9,10 @@ #define null 0 -ogb_instance void +void printf(const char* fmt, ...); -ogb_instance void +void dump_stack_trace(); #define ASSERT_STR_HELPER(x) #x @@ -81,7 +81,7 @@ typedef struct Allocator { void *data; } Allocator; -ogb_instance Allocator +Allocator get_heap_allocator(); ogb_instance Allocator @@ -95,15 +95,15 @@ typedef struct Context { CONTEXT_EXTRA extra; } Context; -forward_global thread_local Allocator temp; - #define CONTEXT_STACK_MAX 512 // -// -thread_local ogb_instance Context context; -thread_local ogb_instance Context context_stack[CONTEXT_STACK_MAX]; -thread_local ogb_instance u64 num_contexts; +// #Global +//thread_local ogb_instance Context context; +//thread_local ogb_instance Context context_stack[CONTEXT_STACK_MAX]; +//thread_local ogb_instance u64 num_contexts; +ogb_instance +Context get_context(); ogb_instance void* alloc(Allocator allocator, u64 size); @@ -166,7 +166,10 @@ pop_context() { context = context_stack[num_contexts]; } - +ogb_instance +Context get_context() { + return context; +} #endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE diff --git a/oogabooga/bucket_array.c b/oogabooga/bucket_array.c deleted file mode 100644 index e8b84a9..0000000 --- a/oogabooga/bucket_array.c +++ /dev/null @@ -1,27 +0,0 @@ - - - -typedef struct Bucket_Array { - - - - u64 _block_size; - u64 _bucket_count; -} Bucket_Array; - -typedef struct Bucket_Array_Free_Node { - struct Bucket_Array_Free_Node *next; -} Bucket_Array_Free_Node; -typedef struct Bucket_Array_Bucket { - Bucket_Array_Free_Node *first_free; - void *data; - Bucket *next; -} Bucket_Array_Bucket; - - -Bucket_Array make_bucket_array(u64 block_size, u64 bucket_count) { - Bucket_Array ba; - - ba._block_size = block_size; - ba._bucket_count = bucket_count; -} \ No newline at end of file diff --git a/oogabooga/concurrency.c b/oogabooga/concurrency.c index 8b5d760..4f2c3ea 100644 --- a/oogabooga/concurrency.c +++ b/oogabooga/concurrency.c @@ -14,31 +14,71 @@ inline bool compare_and_swap_bool(bool *a, bool b, bool old); // Spinlock "primitive" // Like a mutex but it eats up the entire core while waiting. // Beneficial if contention is low or sync speed is important -void spinlock_init(Spinlock *l); -void spinlock_acquire_or_wait(Spinlock* l); +typedef struct Spinlock { + bool locked; +} Spinlock; + +void ogb_instance +spinlock_init(Spinlock *l); + +void ogb_instance +spinlock_acquire_or_wait(Spinlock* l); + // This returns true if successfully acquired or false if timeout reached. -bool spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds); -void spinlock_release(Spinlock* l); +bool ogb_instance +spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds); + +void ogb_instance +spinlock_release(Spinlock* l); + /// // High-level mutex primitive (short spinlock then OS mutex lock) // Just spins for a few (configurable) microseconds with a spinlock, // and if acquiring fails it falls back to a OS mutex. -void mutex_init(Mutex *m); -void mutex_destroy(Mutex *m); -void mutex_acquire_or_wait(Mutex *m); -void mutex_release(Mutex *m); +#define MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS 100 +typedef struct Mutex { + Spinlock spinlock; + f64 spin_time_microseconds; + Mutex_Handle os_handle; + volatile bool spinlock_acquired; + volatile u64 acquiring_thread; +} Mutex; + +void ogb_instance +mutex_init(Mutex *m); + +void ogb_instance +mutex_destroy(Mutex *m); + +void ogb_instance +mutex_acquire_or_wait(Mutex *m); + +void ogb_instance +mutex_release(Mutex *m); + /// // Binary semaphore -void binary_semaphore_init(Binary_Semaphore *sem, bool initial_state); -void binary_semaphore_destroy(Binary_Semaphore *sem); -void binary_semaphore_wait(Binary_Semaphore *sem); -void binary_semaphore_signal(Binary_Semaphore *sem); +typedef struct Binary_Semaphore { + bool signaled; + Mutex mutex; +} Binary_Semaphore; -typedef struct Spinlock { - bool locked; -} Spinlock; +void ogb_instance +binary_semaphore_init(Binary_Semaphore *sem, bool initial_state); + +void ogb_instance +binary_semaphore_destroy(Binary_Semaphore *sem); + +void ogb_instance +binary_semaphore_wait(Binary_Semaphore *sem); + +void ogb_instance +binary_semaphore_signal(Binary_Semaphore *sem); + + +#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE void spinlock_init(Spinlock *l) { memset(l, 0, sizeof(*l)); @@ -87,14 +127,7 @@ void spinlock_release(Spinlock* l) { /// // High-level mutex primitive (short spinlock then OS mutex lock) -#define MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS 100 -typedef struct Mutex { - Spinlock spinlock; - f64 spin_time_microseconds; - Mutex_Handle os_handle; - volatile bool spinlock_acquired; - volatile u64 acquiring_thread; -} Mutex; + void mutex_init(Mutex *m) { spinlock_init(&m->spinlock); m->spin_time_microseconds = MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS; @@ -134,10 +167,7 @@ void mutex_release(Mutex *m) { MEMORY_BARRIER; } -typedef struct Binary_Semaphore { - bool signaled; - Mutex mutex; -} Binary_Semaphore; + void binary_semaphore_init(Binary_Semaphore *sem, bool initial_state) { sem->signaled = initial_state; @@ -163,4 +193,6 @@ void binary_semaphore_signal(Binary_Semaphore *sem) { mutex_acquire_or_wait(&sem->mutex); sem->signaled = true; mutex_release(&sem->mutex); -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/oogabooga/cpu.c b/oogabooga/cpu.c index f156aa0..fc1ad99 100644 --- a/oogabooga/cpu.c +++ b/oogabooga/cpu.c @@ -106,6 +106,8 @@ typedef struct Cpu_Capabilities { #define MEMORY_BARRIER _ReadWriteBarrier() + #define thread_local __declspec(thread) + #define SHARED_EXPORT __declspec(dllexport) #define SHARED_IMPORT __declspec(dllimport) @@ -223,8 +225,15 @@ typedef struct Cpu_Capabilities { #define MEMORY_BARRIER __asm__ __volatile__("" ::: "memory") + #define thread_local __thread + +#if TARGET_OS == WINDOWS + #define SHARED_EXPORT __attribute__((visibility("default"))) __declspec(dllexport) + #define SHARED_IMPORT __declspec(dllimport) +#else #define SHARED_EXPORT __attribute__((visibility("default"))) #define SHARED_IMPORT +#endif #else #define inline inline diff --git a/oogabooga/examples/hotload/README.md b/oogabooga/examples/hotload/README.md new file mode 100644 index 0000000..6879290 --- /dev/null +++ b/oogabooga/examples/hotload/README.md @@ -0,0 +1,12 @@ +# !!! THIS VERY EXPERIMENTAL !!! + + +This is an example how how we can set up a oogabooga project where some code can be recompiled while the engine is still running. + +To try this: +1. Copy the files in this directory into the root project directory +2. Compile with `hotload_build_all.bat` +3. Run `build/launcher.exe` +4. Modify `build_game.c` +5. Recompile the game code only with `hotload_build_game.bat` +6. Go back to the application and press 'R' \ No newline at end of file diff --git a/oogabooga/examples/hotload/build_engine.c b/oogabooga/examples/hotload/build_engine.c new file mode 100644 index 0000000..c88a6ce --- /dev/null +++ b/oogabooga/examples/hotload/build_engine.c @@ -0,0 +1,79 @@ + +/// +// Build config stuff + +#define OOGABOOGA_BUILD_SHARED_LIBRARY 1 + +#include "oogabooga/oogabooga.c" + +/// +/// +// This is the "engine" part of your game, which will call into your game.dll + + +typedef void (*Game_Update_Proc)(f64); +Game_Update_Proc game_update; + +Dynamic_Library_Handle dll = 0; + +void load_game_dll(char **argv) { + + // Here we load all the game symbols + + if (dll) { + os_unload_dynamic_library(dll); + } + + string exe_path = STR(argv[0]); + string exe_dir = get_directory_of(exe_path); + + // We need to copy the original and open the copy, so we can recompile the original and then close & replace + // the copy. + string dll_path = string_concat(exe_dir, STR("/game.dll"), get_temporary_allocator()); + string used_dll_path = string_concat(exe_dir, STR("/game-in-use.dll"), get_temporary_allocator()); + + bool ok = os_file_copy(dll_path, used_dll_path, true); + assert(ok, "Could not copy %s to %s", dll_path, used_dll_path); + + dll = os_load_dynamic_library(used_dll_path); + assert(dll, "Failed loading game dll"); + + game_update = os_dynamic_library_load_symbol(dll, STR("game_update")); + assert(game_update, "game is missing game_update()"); + + log("Loaded game procedures"); +} + +int entry(int argc, char **argv) { + + load_game_dll(argv); + + window.title = STR("Minimal Game Example"); + window.scaled_width = 1280; // We need to set the scaled size if we want to handle system scaling (DPI) + window.scaled_height = 720; + window.x = 200; + window.y = 90; + window.clear_color = hex_to_rgba(0x6495EDff); + + float64 last_time = os_get_current_time_in_seconds(); + while (!window.should_close) { + float64 now = os_get_current_time_in_seconds(); + float64 delta = now-last_time; + if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(delta), (delta)*1000); + last_time = now; + + reset_temporary_storage(); + + game_update(delta); + + if (is_key_just_pressed('R')) { + load_game_dll(argv); + play_one_audio_clip(STR("oogabooga/examples/bruh.wav")); + } + + os_update(); + gfx_update(); + } + + return 0; +} \ No newline at end of file diff --git a/oogabooga/examples/hotload/build_game.c b/oogabooga/examples/hotload/build_game.c new file mode 100644 index 0000000..266b911 --- /dev/null +++ b/oogabooga/examples/hotload/build_game.c @@ -0,0 +1,30 @@ + + +// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c + +#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1 +#include "oogabooga/oogabooga.c" + +/// +/// +// This is the game module which is what can be recompiled in the engine runtime + +// For the engine to be able to detect a symbol, it needs to be marked with SHARED_EXPORT +void SHARED_EXPORT +game_update(f64 delta_time) { + + float64 now = os_get_current_time_in_seconds(); + + Matrix4 rect_xform = m4_scalar(1.0); + rect_xform = m4_rotate_z(rect_xform, (f32)now); + rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0)); + draw_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN); + + draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED); + + float aspect = (f32)window.width/(f32)window.height; + float mx = (input_frame.mouse_x/(f32)window.width * 2.0 - 1.0)*aspect; + float my = input_frame.mouse_y/(f32)window.height * 2.0 - 1.0; + + draw_line(v2(-.75, -.75), v2(mx, my), 0.005, COLOR_WHITE); +} \ No newline at end of file diff --git a/oogabooga/examples/hotload/build_launcher.c b/oogabooga/examples/hotload/build_launcher.c new file mode 100644 index 0000000..a09639a --- /dev/null +++ b/oogabooga/examples/hotload/build_launcher.c @@ -0,0 +1,36 @@ + + +// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c + +#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1 +#include "oogabooga/oogabooga.c" + + +// All we do with the launcher is to launch the engine +// We need to be careful to use oogabooga things because it has not yet been initialized. +// We can use get_temporary_allocator() because that actually gives us the initialization allocator. +// We cannot use log() but we can use print() +int main(int argc, char **argv) { + string exe_path = STR(argv[0]); + string exe_dir = get_directory_of(exe_path); + + Allocator a = get_initialization_allocator(); + string dll_path = string_concat(exe_dir, STR("/engine.dll"), a); + + Dynamic_Library_Handle dll = os_load_dynamic_library(dll_path); + if (!dll) { + os_write_string_to_stdout(STR("Failed loading engine dll from ")); + os_write_string_to_stdout(dll_path); + os_write_string_to_stdout(STR("\n")); + return -1; + } + + int (*engine_main)(int, char**) = os_dynamic_library_load_symbol(dll, STR("main")); + if (!engine_main) { + os_write_string_to_stdout(STR("Failed loading engine main\n")); + return -1; + } + + print("Launcher found engine main(), running...\n"); + return engine_main(argc, argv); +} \ No newline at end of file diff --git a/oogabooga/examples/hotload/hotload_build_all.bat b/oogabooga/examples/hotload/hotload_build_all.bat new file mode 100644 index 0000000..5c6b13a --- /dev/null +++ b/oogabooga/examples/hotload/hotload_build_all.bat @@ -0,0 +1,16 @@ +@echo on +if exist build ( + rmdir /s /q build +) +mkdir build + +pushd build + +clang ../build_engine.c -g -shared -o engine.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -fuse-ld=lld -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -ldbghelp -femit-all-decls -Xlinker /IMPLIB:engine.lib -Xlinker /MACHINE:X64 -Xlinker /SUBSYSTEM:CONSOLE + +clang ../build_launcher.c -g -o launcher.exe -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE + +clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE + + +popd \ No newline at end of file diff --git a/oogabooga/examples/hotload/hotload_build_game.bat b/oogabooga/examples/hotload/hotload_build_game.bat new file mode 100644 index 0000000..ec99931 --- /dev/null +++ b/oogabooga/examples/hotload/hotload_build_game.bat @@ -0,0 +1,8 @@ +@echo on + +pushd build + +clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE + + +popd \ No newline at end of file diff --git a/oogabooga/gfx_impl_d3d11.c b/oogabooga/gfx_impl_d3d11.c index 342615c..e81c9cd 100644 --- a/oogabooga/gfx_impl_d3d11.c +++ b/oogabooga/gfx_impl_d3d11.c @@ -231,8 +231,8 @@ void d3d11_update_swapchain() { bool d3d11_compile_shader(string source) { - source = string_replace_all(source, STR("$INJECT_PIXEL_POST_PROCESS"), STR("float4 pixel_shader_extension(PS_INPUT input, float4 color) { return color; }"), temp); - source = string_replace_all(source, STR("$VERTEX_2D_USER_DATA_COUNT"), tprint("%d", VERTEX_2D_USER_DATA_COUNT), temp); + source = string_replace_all(source, STR("$INJECT_PIXEL_POST_PROCESS"), STR("float4 pixel_shader_extension(PS_INPUT input, float4 color) { return color; }"), get_temporary_allocator()); + source = string_replace_all(source, STR("$VERTEX_2D_USER_DATA_COUNT"), tprint("%d", VERTEX_2D_USER_DATA_COUNT), get_temporary_allocator()); // #Leak on recompile @@ -921,7 +921,7 @@ bool shader_recompile_with_extension(string ext_source, u64 cbuffer_size) { - string source = string_replace_all(STR(d3d11_image_shader_source), STR("$INJECT_PIXEL_POST_PROCESS"), ext_source, temp); + string source = string_replace_all(STR(d3d11_image_shader_source), STR("$INJECT_PIXEL_POST_PROCESS"), ext_source, get_temporary_allocator()); if (!d3d11_compile_shader(source)) return false; diff --git a/oogabooga/gfx_interface.c b/oogabooga/gfx_interface.c index df80de0..8da5904 100644 --- a/oogabooga/gfx_interface.c +++ b/oogabooga/gfx_interface.c @@ -37,11 +37,11 @@ typedef struct Gfx_Image { Allocator allocator; } Gfx_Image; -ogb_instance Gfx_Image * +Gfx_Image * make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator); -ogb_instance Gfx_Image * +Gfx_Image * load_image_from_disk(string path, Allocator allocator); -ogb_instance void +void delete_image(Gfx_Image *image); // Implemented per renderer @@ -61,7 +61,7 @@ ogb_instance bool shader_recompile_with_extension(string ext_source, u64 cbuffer_size); // initial_data can be null to leave image data uninitialized -ogb_instance Gfx_Image * +Gfx_Image * make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator) { Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image) + width*height*channels); @@ -78,7 +78,7 @@ make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator al return image; } -ogb_instance Gfx_Image * +Gfx_Image * load_image_from_disk(string path, Allocator allocator) { string png; bool ok = os_read_entire_file(path, &png, allocator); @@ -115,7 +115,7 @@ load_image_from_disk(string path, Allocator allocator) { return image; } -ogb_instance void +void delete_image(Gfx_Image *image) { // Free the image data allocated by stb_image image->width = 0; diff --git a/oogabooga/memory.c b/oogabooga/memory.c index e9c1d72..4869504 100644 --- a/oogabooga/memory.c +++ b/oogabooga/memory.c @@ -536,28 +536,41 @@ Allocator get_heap_allocator() { #define TEMPORARY_STORAGE_SIZE (1024ULL*1024ULL*2ULL) // 2mb #endif -void* talloc(u64); -void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void*); +ogb_instance void* talloc(u64); +ogb_instance void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void*); // #Global -thread_local ogb_instance void * temporary_storage; -thread_local ogb_instance bool temporary_storage_initted; -thread_local ogb_instance void * temporary_storage_pointer; -thread_local ogb_instance bool has_warned_temporary_storage_overflow; -thread_local ogb_instance Allocator temp; +ogb_instance Allocator +get_temporary_allocator(); #if !OOGABOOGA_LINK_EXTERNAL_INSTANCE thread_local void * temporary_storage = 0; thread_local bool temporary_storage_initted = false; thread_local void * temporary_storage_pointer = 0; thread_local bool has_warned_temporary_storage_overflow = false; -thread_local Allocator temp; +thread_local Allocator temp_allocator; + +ogb_instance Allocator +get_temporary_allocator() { + if (!temporary_storage_initted) return get_initialization_allocator(); + return temp_allocator; +} #endif -Allocator get_temporary_allocator() { - return temp; -} +ogb_instance void* +temp_allocator_proc(u64 size, void *p, Allocator_Message message, void* data); +ogb_instance void +temporary_storage_init(); + +ogb_instance void* +talloc(u64 size); + +ogb_instance void +reset_temporary_storage(); + + +#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void* data) { switch (message) { case ALLOCATOR_ALLOCATE: { @@ -581,12 +594,12 @@ void temporary_storage_init() { assert(temporary_storage, "Failed allocating temporary storage"); temporary_storage_pointer = temporary_storage; - temp.proc = temp_allocator_proc; - temp.data = 0; + temp_allocator.proc = temp_allocator_proc; + temp_allocator.data = 0; temporary_storage_initted = true; - temp.proc = temp_allocator_proc; + temp_allocator.proc = temp_allocator_proc; } void* talloc(u64 size) { @@ -617,3 +630,4 @@ void reset_temporary_storage() { has_warned_temporary_storage_overflow = true; } +#endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE \ No newline at end of file diff --git a/oogabooga/oogabooga.c b/oogabooga/oogabooga.c index d268b8c..12a6c33 100644 --- a/oogabooga/oogabooga.c +++ b/oogabooga/oogabooga.c @@ -197,6 +197,10 @@ typedef u8 bool; #define ENABLE_SIMD 1 #endif +#ifndef INITIAL_PROGRAM_MEMORY_SIZE + #define INITIAL_PROGRAM_MEMORY_SIZE MB(5) +#endif + #if ENABLE_SIMD && !defined(SIMD_ENABLE_SSE2) #if COMPILER_CAN_DO_SSE2 #define SIMD_ENABLE_SSE2 1 @@ -246,10 +250,13 @@ typedef u8 bool; #if OOGABOOGA_LINK_EXTERNAL_INSTANCE #define ogb_instance SHARED_IMPORT extern -#else +#elif OOGABOOGA_BUILD_SHARED_LIBRARY #define ogb_instance SHARED_EXPORT +#else + #define ogb_instance #endif + // This needs to be included before dependencies #include "base.c" @@ -367,9 +374,12 @@ void default_logger(Log_Level level, string s) { mutex_release(&_default_logger_mutex); } +ogb_instance void oogabooga_init(u64 program_memory_size); + +#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE void oogabooga_init(u64 program_memory_size) { context.logger = default_logger; - temp = get_initialization_allocator(); + temp_allocator = get_initialization_allocator(); Cpu_Capabilities features = query_cpu_capabilities(); os_init(program_memory_size); heap_init(); @@ -390,10 +400,17 @@ void oogabooga_init(u64 program_memory_size) { log_verbose("CPU has avx2: %cs", features.avx2 ? "true" : "false"); log_verbose("CPU has avx512: %cs", features.avx512 ? "true" : "false"); } +#endif int ENTRY_PROC(int argc, char **argv); +#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE + +#if OOGABOOGA_BUILD_SHARED_LIBRARY +int SHARED_EXPORT main(int argc, char **argv) { +#else int main(int argc, char **argv) { +#endif print("Ooga booga program started\n"); @@ -421,6 +438,8 @@ int main(int argc, char **argv) { return code; } +#endif + diff --git a/oogabooga/os_impl_windows.c b/oogabooga/os_impl_windows.c index 3cedea4..14c023c 100644 --- a/oogabooga/os_impl_windows.c +++ b/oogabooga/os_impl_windows.c @@ -588,8 +588,10 @@ float64 os_get_current_time_in_seconds() { // Dynamic Libraries /// +u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8); + Dynamic_Library_Handle os_load_dynamic_library(string path) { - return LoadLibraryA(temp_convert_to_null_terminated_string(path)); + return LoadLibraryW(temp_win32_fixed_utf8_to_null_terminated_wide(path)); } void *os_dynamic_library_load_symbol(Dynamic_Library_Handle l, string identifier) { return GetProcAddress(l, temp_convert_to_null_terminated_string(identifier)); @@ -635,7 +637,7 @@ u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8, Allocator allocator) return utf16_str; } u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8) { - return win32_fixed_utf8_to_null_terminated_wide(utf8, temp); + return win32_fixed_utf8_to_null_terminated_wide(utf8, get_temporary_allocator()); } string win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16, Allocator allocator) { u64 utf8_length = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)utf16, -1, 0, 0, 0, 0); @@ -663,7 +665,7 @@ string win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16, Allocator allo } string temp_win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16) { - return win32_null_terminated_wide_to_fixed_utf8(utf16, temp); + return win32_null_terminated_wide_to_fixed_utf8(utf16, get_temporary_allocator()); } @@ -694,6 +696,12 @@ bool os_file_delete_s(string path) { return (bool)DeleteFileW(path_wide); } +bool os_file_copy_s(string from, string to, bool replace_if_exists) { + u16 *from_wide = temp_win32_fixed_utf8_to_null_terminated_wide(from); + u16 *to_wide = temp_win32_fixed_utf8_to_null_terminated_wide(to); + return (bool)CopyFileW(from_wide, to_wide, !replace_if_exists); +} + bool os_make_directory_s(string path, bool recursive) { wchar_t *wide_path = temp_win32_fixed_utf8_to_null_terminated_wide(path); @@ -946,11 +954,11 @@ bool os_get_absolute_path(string path, string *result, Allocator allocator) { bool os_get_relative_path(string from, string to, string *result, Allocator allocator) { if (!os_is_path_absolute(from)) { - bool abs_ok = os_get_absolute_path(from, &from, temp); + bool abs_ok = os_get_absolute_path(from, &from, get_temporary_allocator()); if (!abs_ok) return false; } if (!os_is_path_absolute(to)) { - bool abs_ok = os_get_absolute_path(to, &to, temp); + bool abs_ok = os_get_absolute_path(to, &to, get_temporary_allocator()); if (!abs_ok) return false; } diff --git a/oogabooga/os_interface.c b/oogabooga/os_interface.c index deba006..5345fb2 100644 --- a/oogabooga/os_interface.c +++ b/oogabooga/os_interface.c @@ -89,7 +89,8 @@ inline int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args) { -bool os_grow_program_memory(size_t new_size); +bool ogb_instance +os_grow_program_memory(size_t new_size); /// /// @@ -172,6 +173,8 @@ os_get_current_time_in_seconds(); // Dynamic Libraries /// +// #Cleanup this naming is bleh + Dynamic_Library_Handle ogb_instance os_load_dynamic_library(string path); @@ -208,6 +211,9 @@ os_file_close(File f); bool ogb_instance os_file_delete_s(string path); +bool ogb_instance +os_file_copy_s(string from, string to, bool replace_if_exists); + bool ogb_instance os_make_directory_s(string path, bool recursive); @@ -290,6 +296,12 @@ inline bool os_file_delete_f(const char *path) {return os_file_delete_s(STR(path default: os_file_delete_f \ )(__VA_ARGS__) +inline bool os_file_copy_f(const char *from, const char *to, bool replace_if_exists) {return os_file_copy_s(STR(from), STR(to), replace_if_exists);} +#define os_file_copy(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: os_file_copy_s, \ + default: os_file_copy_f \ + )(__VA_ARGS__) + inline bool os_make_directory_f(const char *path, bool recursive) { return os_make_directory_s(STR(path), recursive); } #define os_make_directory(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ string: os_make_directory_s, \ diff --git a/oogabooga/path_utils.c b/oogabooga/path_utils.c index 2745990..12b3eef 100644 --- a/oogabooga/path_utils.c +++ b/oogabooga/path_utils.c @@ -51,4 +51,16 @@ string get_file_name_excluding_extension(string file_path) { } } return file_name; +} + +string get_directory_of(string path) { + if (path.count <= 0) return ZERO(string); + + for (u64 i = path.count; i >= 0; i--) { + if (path.data[i] == '/' || path.data[i] == '\\' || path.data[i] == ':') { + return string_view(path, 0, i); + } + } + + return ZERO(string); } \ No newline at end of file diff --git a/oogabooga/profiling.c b/oogabooga/profiling.c index eaa6373..3a6c859 100644 --- a/oogabooga/profiling.c +++ b/oogabooga/profiling.c @@ -34,7 +34,7 @@ void _profiler_report_time_cycles(string name, u64 count, u64 start) { spinlock_acquire_or_wait(&_profiler_lock); string fmt = STR("{\"cat\":\"function\",\"dur\":%.3f,\"name\":\"%s\",\"ph\":\"X\",\"pid\":0,\"tid\":%zu,\"ts\":%lld},"); - string_builder_print(&_profile_output, fmt, (float64)count*1000, name, context.thread_id, start*1000); + string_builder_print(&_profile_output, fmt, (float64)count*1000, name, get_context().thread_id, start*1000); spinlock_release(&_profiler_lock); } diff --git a/oogabooga/random.c b/oogabooga/random.c index d9c148e..1ee31f3 100644 --- a/oogabooga/random.c +++ b/oogabooga/random.c @@ -10,7 +10,7 @@ ogb_instance u64 seed_for_random; #if !OOGABOOGA_LINK_EXTERNAL_INSTANCE - u64 seed_for_random = 1; +u64 seed_for_random = 1; #endif u64 get_random() { diff --git a/oogabooga/string.c b/oogabooga/string.c index 2bb3b94..8860b59 100644 --- a/oogabooga/string.c +++ b/oogabooga/string.c @@ -5,7 +5,7 @@ */ -void* talloc(u64); +ogb_instance void* talloc(u64); typedef struct string { u64 count; @@ -41,7 +41,7 @@ dealloc_string(Allocator allocator, string s) { } string talloc_string(u64 count) { - string s = alloc_string(temp, count); + string s = alloc_string(get_temporary_allocator(), count); return s; } @@ -69,7 +69,7 @@ convert_to_null_terminated_string(const string s, Allocator allocator) { char * temp_convert_to_null_terminated_string(const string s) { - char *c = convert_to_null_terminated_string(s, temp); + char *c = convert_to_null_terminated_string(s, get_temporary_allocator()); return c; } bool diff --git a/oogabooga/string_format.c b/oogabooga/string_format.c index 2696345..7f9ab46 100644 --- a/oogabooga/string_format.c +++ b/oogabooga/string_format.c @@ -1,5 +1,5 @@ -void os_write_string_to_stdout(string s); +ogb_instance void os_write_string_to_stdout(string s); inline int crt_sprintf(char *str, const char *format, ...); int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args); bool is_pointer_valid(void *p); @@ -135,7 +135,7 @@ string sprints(Allocator allocator, const string fmt, ...) { string tprints(const string fmt, ...) { va_list args = 0; va_start(args, fmt); - string s = sprint_va_list(temp, fmt, args); + string s = sprint_va_list(get_temporary_allocator(), fmt, args); va_end(args); return s; } @@ -161,7 +161,7 @@ string tprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); - string s = sprint_va_list(temp, sfmt, args); + string s = sprint_va_list(get_temporary_allocator(), sfmt, args); va_end(args); return s; @@ -220,7 +220,7 @@ void printf(const char* fmt, ...) { typedef void(*Logger_Proc)(Log_Level level, string s); -#define LOG_BASE(level, ...) if (context.logger) ((Logger_Proc)context.logger)(level, tprint(__VA_ARGS__)) +#define LOG_BASE(level, ...) if (get_context().logger) ((Logger_Proc)get_context().logger)(level, tprint(__VA_ARGS__)) #define log_verbose(...) LOG_BASE(LOG_VERBOSE, __VA_ARGS__) diff --git a/oogabooga/tests.c b/oogabooga/tests.c index 677bb47..31dc736 100644 --- a/oogabooga/tests.c +++ b/oogabooga/tests.c @@ -122,11 +122,11 @@ void test_allocator(bool do_log_heap) { reset_temporary_storage(); - int* foo = (int*)alloc(temp, 72); + int* foo = (int*)alloc(get_temporary_allocator(), 72); *foo = 1337; - void* bar = alloc(temp, 69); + void* bar = alloc(get_temporary_allocator(), 69); (void)bar; - void* baz = alloc(temp, 420); + void* baz = alloc(get_temporary_allocator(), 420); (void)baz; assert(*foo == 1337, "Temp memory corruptada"); @@ -135,7 +135,7 @@ void test_allocator(bool do_log_heap) { reset_temporary_storage(); - foo = (int*)alloc(temp, 72); + foo = (int*)alloc(get_temporary_allocator(), 72); assert(old_foo == foo, "Temp allocator goof");