diff --git a/README.md b/README.md index dfbf107..72c5ceb 100644 --- a/README.md +++ b/README.md @@ -129,15 +129,23 @@ A list of layers in the codebase and their associated namespaces are below: - `base` (no namespace): Universal, codebase-wide constructs. It contains strings, math, memory allocators, threading, and logging. It depends on no other codebase layers. -- `es/core` (`ES_`): Short for Engine Subsystem. Implements the -- `es/gfx` (`ES_`): Engine Subsystem graphical frontend. Builds on top of - `es/core` to provide graphical features such as windows, panels, and all - interfaces needed for using the scanner. It is the main user of `os/gfx`. -- `os/core` (`OS_`): An abstraction layer that provides core, non-graphical - functionality from the operating sytem under a general use abstraction API. - This is implemented per supported operating system. -- `os/gfx` (`OS_`): This layer builds on top of `os/core`, it provides - graphical operating functionalities under a general use abstraction API. + +- `ef/core` (`EF_`): The scanner engine's non-graphical frontend. It implements + interfacing with the scanner over usb, colour space settings, and all intricate + details that have to do with the software working with the scanner. +- `ef/gfx` (`EF_`): The scanner engine`s graphical frontend. It provides all + graphical features, including windows, panels, and all other various interfaces + needed by the engine to function. + +- `render` (`R_`): An abstraction layer providing an abstract API for rendering using + various GPU APIs under a common interface. This layer does not implement a high level + API for drawing, it is strictly for minimal abstractions on a needed basis. Higher + level drawing features are implemented in the `draw` layer + +- `draw` (`D_`): Implements a high level graphics drawing API for the scanning engine. + It uses the underlying `render` abstraction API. It provides a high-level API for various + draw commands, but takes care to bath them together. + - `ui` (`UI_`): For building graphical user interfaces. Provides a core immediate mode hierarchical user interface data structure building API, and has helper layers for building higher level widgets. \ No newline at end of file diff --git a/src/base/base_context_switching.h b/src/base/base_context_switching.h index 92c998e..ca9f147 100644 --- a/src/base/base_context_switching.h +++ b/src/base/base_context_switching.h @@ -44,6 +44,10 @@ #define BUILD_DEBUG 1 #endif +#if !defined(BUILD_ENTRY_DEFINING_UNIT) + #define BUILD_ENTRY_DEFINING_UNIT 1 +#endif + #if !defined(BUILD_VERSION_MAJOR) #define BUILD_VERSION_MAJOR 0 #endif diff --git a/src/base/base_core.c b/src/base/base_core.c new file mode 100644 index 0000000..7e657c1 --- /dev/null +++ b/src/base/base_core.c @@ -0,0 +1,6 @@ +// Safe Casts +internal u16 safe_cast_u16(u32 x) { + // Assert + u16 result = (u16)x; + return result; +} diff --git a/src/base/base_core.h b/src/base/base_core.h index 411ff6f..719e8dc 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -134,6 +134,9 @@ global const u32 bit30 = (1 << 29); global const u32 bit31 = (1 << 30); global const u32 bit32 = (1 << 31); +// Safe Casts +internal u16 safe_cast_u16(u32 x); + // Misc helpers // NOTE(tijani): Divides total size of array by size of one element in the array gives // the number of elements in the array. @@ -168,7 +171,7 @@ global const u32 bit32 = (1 << 31); // Helpers // ??(tijani): the calculation of how this works breaks my brain, need to bust out the pen and paper to figure it out. -#define AlignPow2(x, b) (((x) + (b)-1) & (~((b)-1))) +#define AlignPow2(x, b) (((x) + (b) - 1) & (~((b) - 1))) // Linkedlist building macros diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 84bb0a7..b6006a4 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -1,7 +1,12 @@ -internal void main_thread_entry_point(void) { +internal void main_thread_base_entry_point(void) { ThreadNameF("[main thread]"); #if defined(OS_GFX_H) os_gfx_init(); #endif + +#if defined(GFX_H) + gfx_init(update_and_render); +#endif + entry_point(); } diff --git a/src/base/base_entry_point.h b/src/base/base_entry_point.h index 2324531..bed74cb 100644 --- a/src/base/base_entry_point.h +++ b/src/base/base_entry_point.h @@ -1,6 +1,6 @@ #ifndef BASE_ENTRY_POINT_H #define BASE_ENTRY_POINT_H -internal void main_thread_entry_point(void); +internal void main_thread_base_entry_point(void); #endif // BASE_ENTRY_POINT_H diff --git a/src/base/base_inc.c b/src/base/base_inc.c index baebe29..18afaaf 100644 --- a/src/base/base_inc.c +++ b/src/base/base_inc.c @@ -1,7 +1,10 @@ // clang-format off +#include "base_core.c" #include "base_arena.c" #include "base_strings.c" #include "base_markup.c" #include "base_threading_context.c" +#include "base_entry_point.c" + // clang-format on diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 9e776a0..8ca0ad0 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -10,6 +10,8 @@ #include "base_strings.h" #include "base_markup.h" #include "base_threading_context.h" +#include "base_entry_point.h" + // clang-format on #endif // BASE_INC_H diff --git a/src/ef/gfx/ef_gfx.c b/src/ef/gfx/ef_gfx.c new file mode 100644 index 0000000..0069ce8 --- /dev/null +++ b/src/ef/gfx/ef_gfx.c @@ -0,0 +1,46 @@ + +// Window State functions +internal EF_Window *ef_window_open(Vec2F32 size, OS_Handle preferred_monitor) { + EF_Window *window = ef_gfx_state->free_window; + if (window != 0) { + SLLStackPop(ef_gfx_state->free_window); + u64 gen = window->gen; + MemoryZeroStruct(window); + window->gen = gen; + } else { + window = push_array(ef_gfx_state->arena, EF_Window, 1); + } + window->gen += 1; + window->arena = arena_alloc(); + + { + String8 title = str8_lit_comp(BUILD_TITLE_STRING_LITERAL); + window->os = os_window_open(size, OS_WindowFlag_CustomBorder, title); + } + window->last_dpi = os_dpi_fram_window(window->os); + + // NOTE(tijani): Setting preferred monitor, not important + // OS_Handle zero_monitor = {0}; + // if(!os_handle_match(zero_monitor, preferred_window)){ + // os_set_window + // } + + os_window_equip_repaint(window->os, ef_gfx_state->repaint_hook, window); + DLLPushBack(ef_gfx_state->first_winow, ef_gfx_state->last_window, window); + return window; +} +internal EF_Window *ef_window_from_os_handle(OS_Handle os) {} +internal void df_window_update_and_render(Arena *arena, EF_Window *window_state) {} + +// Main layer top level calls +internal void ef_gfx_init(OS_WindowRepaintFunctionType *window_repaint_entry_point) { + // Begin profiling + Arena *arena = arena_alloc(); + ef_gfx_state = push_array(arena, EF_GfxState, 1); + ef_gfx_state->arena = arena; + ef_gfx_state->num_frame_requested = 2; + ef_gfx_state->repaint_hook = window_repaint_entry_point; +} + +internal void ef_gfx_begin_frame(Arena *arena) {} +internal void ef_gfx_end_frame(void) {} diff --git a/src/ef/gfx/ef_gfx.h b/src/ef/gfx/ef_gfx.h new file mode 100644 index 0000000..b7b0901 --- /dev/null +++ b/src/ef/gfx/ef_gfx.h @@ -0,0 +1,84 @@ +#ifndef EF_GFX_H +#define EF_GFX_H + +// Per-Window State +typedef struct EF_Window EF_Window; +struct EF_Window { + // Links and metadata + EF_Window *next; + EF_Window *previous; + u64 gen; + u64 frames_alive; + // EF_ConfigSource config_source; + + // Top level info & handles + Arena *arena; + OS_Handle os; + // R_handle render; // not needed for now, will revisit + // UI_State *ui_state; // not needed for now, will revisit + f32 last_dpi; + + // config / settings + + // view state delta histor + + // menu bar state + + // tab context menu state + + // error state + + // panel state + + // per-frame drawing state +}; + +// Graphical state +typedef struct EF_GfxState EF_GfxState; +struct EF_GfxState { + Arena *arena; + + // frame request state + u64 num_frames_requested; + + // history cache + + // key map table NOTE(tijani): ?? + + // confirmation popup state + + // windows + OS_WindowRepaintFunctionType *repaint_hook; + EF_Window *first_window; + EF_Window *last_window; + EF_Window *free_window; + u64 window_count; + b32 last_window_queued_save; + + // view state + + // drag/drop satte machine + + // rich hove info + + // running theme state + + // global setting + + // icon texture +}; + +// Globals +global EF_GfxState *ef_gfx_satet = 0; + +// Window State functions +internal EF_Window *ef_window_open(Vec2F32 size, OS_Handle preferred_monitor); +internal EF_Window *ef_window_from_os_handle(OS_Handle os); +internal void df_window_update_and_render(Arena *arena, EF_Window *window_state); + +// Main layer top level calls +internal void ef_gfx_init(OS_WindowRepaintFunctionType *window_repaint_entry_point); +internal void ef_gfx_begin_frame(Arena *arena); +internal void ef_gfx_end_frame(void); + +#endif // EF_GFX_H diff --git a/src/goff/goff.c b/src/goff/goff.c index f0c5e37..e2fea26 100644 --- a/src/goff/goff.c +++ b/src/goff/goff.c @@ -1,20 +1,28 @@ internal void update_and_render(OS_Handle repaint_window_handle) { + // Profiling start Temp scratch = scratch_begin(0, 0); - // pick target hz - f32 target_hz = os_get_gfx_info()->default_referesh_rate; - - // Target HZ -> delta time - f32 dt = 1.f / target_hz; - // Get events from OS OS_EventList events = {0}; if (os_handle_match(repaint_window_handle, os_handle_zero())) { - events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0); + events = os_get_events(scratch.arena, gfx_state->num_frames_requested == 0); } // begin frames - { - df_core_begin(scratch.arena, - } + { gfx_begin_frame(scratch.arena); } + + // Update and render + {} + + // End frondend frame + { gfx_end_frame(); } + + // Submit rendering to all windows + {} + + // Show windows after first frame + {} + + scratch_end(scratch); + // Profiling end } diff --git a/src/goff/goff.h b/src/goff/goff.h index a905b21..f97581e 100644 --- a/src/goff/goff.h +++ b/src/goff/goff.h @@ -1,6 +1,8 @@ #ifndef GOFF_H #define GOFF_H +// Frontend entry point + internal void update_and_render(OS_HANDLE repaint_window); #endif // GOFF_H diff --git a/src/goff/goff_main.c b/src/goff/goff_main.c index b29decf..fcfedf1 100644 --- a/src/goff/goff_main.c +++ b/src/goff/goff_main.c @@ -10,28 +10,36 @@ // clang-format on +// Build Options +// #define BUILD_VERSION_MAJOR 0 +// #define BUILD_VERSION_MINOR 1 +// #define BUILD_VERSION_PATCH 0 +// #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +// #define BUILD_TITLE "Goff Film Scanner" +// #define OS_GRAPHICAL 1 + // Entry Point internal void entry_point() { Temp scratch = scratch_begin(0, 0); // Setup layers - // { - // df_core_init(); - // df_gfx_init(); - // } + { gfx_init(); } -// Main application loop -{ - for (;;) { + // Main application loop + { + for (;;) { - // Update and render frame here - OS_Handle repaint_window = {0}; - update_and_render(repaint_window); + // Update and render frame here + OS_Handle repaint_window = {0}; + update_and_render(repaint_window); - // Quit + // Quit + // if (gfx_state->first_window == 0) { + // break; + // } + } } -} -scratch_end(scratch); + scratch_end(scratch); } diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c new file mode 100644 index 0000000..e69de29 diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index dbc22b6..3569a91 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -51,4 +51,14 @@ internal void os_set_thread_name(String8 name); // %os_hooks(implemented per-os) Aborting internal void os_abort(s32 exit_code); + +// %os_hooks(implemented per-os) Entry Points +// os_core defines a low level entry point if BUILD_ENTRY_DEFINING_UNIT is +// defined to 1. This will call into the standard cocdebase program entry point +// called "entry_point" + +#if BUILD_ENTRY_DEFINING_UNIT +internal void entry_point(void); +#endif + #endif // OS_CORE_H diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 40a49e5..86a23ac 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -2,8 +2,8 @@ // compatibility with older versions of windows where the modern WIN32 // SetThreadDescription function is not available and use old ways. // This way it can be done dynamically at runtime without any hiccups. -typedef HRESULT W32_SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription); -global W32_SetThreadDescription *w32_SetThreadDescription_func = 0; +typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription); +global W32_SetThreadDescription_Type *w32_SetThreadDescription_func = 0; // %os_hooks(implemented per-os) System and process info internal OS_SystemInfo *os_get_system_info(void) { return &os_w32_state.system_info; } @@ -46,7 +46,7 @@ internal b32 os_commit_large(void *ptr, u64 size) { return -1; } // %os_hooks(implemented per-os) Threads internal u32 os_thread_id(void) { - u32 id = GetCurrentThreadID(); + u32 id = GetCurrentThreadId(); return (id); } @@ -90,3 +90,41 @@ internal void os_set_thread_name(String8 name) { // %os_hooks(implemented per-os) Aborting internal void os_abort(s32 exit_code) { ExitProcess(exit_code); } + +internal void w32_entry_point_caller() { + // OS layer initialization + { + // dynamically load windows functions, not guaranteed on all SDKs + { + HMODULE module = LoadLibraryA("kernel32.dll"); + w32_SetThreadDescription_func = (W32_SetThreadDescription_Type *)GetProcAddress(module, "SetThreadDescription"); + FreeLibrary(module); + } + + // enable large pages if possible + { + HANDLE token; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { + LUID luid; + if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) { + TOKEN_PRIVILEGES priv; + priv.PrivilegeCount = 1; + priv.Privileges[0].Luid = luid; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0); + } + CloseHandle(token); + } + } + + // Get system info + } + + // call into the actual entry point + main_thread_base_entry_point(); +} + +int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) { + w32_entry_point_caller(); + return 0; +} diff --git a/src/os/core/win32/os_core_win32.h b/src/os/core/win32/os_core_win32.h index 76de155..b5846e4 100644 --- a/src/os/core/win32/os_core_win32.h +++ b/src/os/core/win32/os_core_win32.h @@ -4,8 +4,12 @@ // clang-format off #define WIN32_LEAN_AND_MEAN #include +#include #include +#pragma comment(lib, "user32") +#pragma comment(lib, "advapi32") + // clang-format on // Application State diff --git a/src/os/os_inc.c b/src/os/os_inc.c index 7f33e0d..048ec39 100644 --- a/src/os/os_inc.c +++ b/src/os/os_inc.c @@ -1,5 +1,18 @@ -// clang-format off +#include "os/core/os_core.c" +#if OS_GRAPHICAL + #include "os/gfx/os_gfx.c" +#endif -#include "core/win32/os_core_win32.c" +#if OS_WINDOWS + #include "os/core/win32/os_core_win32.c" +#else + #error OS core layer not implemented for this operating system. +#endif -// clang-format on +#if OS_GRAPHICAL + #if OS_WINDOWS + #include "os/gfx/win32/os_gfx_win32.c" + #else + #error OS graphical layer not implemented for this operating system. + #endif +#endif diff --git a/src/os/os_inc.h b/src/os/os_inc.h index 48469cd..437c2ef 100644 --- a/src/os/os_inc.h +++ b/src/os/os_inc.h @@ -1,11 +1,27 @@ #ifndef OS_INC_H #define OS_INC_H -// clang-format off +#if !defined(OS_GRAPHICAL) + #define OS_GRAPHICAL 0 +#endif -#include "core/os_core.h" -#include "core/win32/os_core_win32.h" +#include "os/core/os_core.h" +#if OS_GRAHICAL + #include "os/gfx/os_gfx.h" +#endif -// clang-format on +#if OS_WINDOWS + #include "os/core/win32/os_core_win32.h" +#else + #error OS core layer not implemented for this operating system. +#endif + +#if OS_GRAPHICAL + #if OS_WINDOWS + #include "os/gfx/win32/os_gfx_win32.h" + #else + #error OS graphical layer not implemented for this operating system. + #endif +#endif #endif // OS_INC_H