step closer to opening a window, shouldn't be this hard but reasoning on

how to do this in a way that encourages cross-platform development.
This commit is contained in:
Tijani Lawal 2024-08-24 09:45:46 -05:00
parent 404ec22e57
commit d3d8421110
19 changed files with 305 additions and 45 deletions

View File

@ -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 - `base` (no namespace): Universal, codebase-wide constructs. It contains
strings, math, memory allocators, threading, and logging. strings, math, memory allocators, threading, and logging.
It depends on no other codebase layers. 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 - `ef/core` (`EF_`): The scanner engine's non-graphical frontend. It implements
`es/core` to provide graphical features such as windows, panels, and all interfacing with the scanner over usb, colour space settings, and all intricate
interfaces needed for using the scanner. It is the main user of `os/gfx`. details that have to do with the software working with the scanner.
- `os/core` (`OS_`): An abstraction layer that provides core, non-graphical - `ef/gfx` (`EF_`): The scanner engine`s graphical frontend. It provides all
functionality from the operating sytem under a general use abstraction API. graphical features, including windows, panels, and all other various interfaces
This is implemented per supported operating system. needed by the engine to function.
- `os/gfx` (`OS_`): This layer builds on top of `os/core`, it provides
graphical operating functionalities under a general use abstraction API. - `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 - `ui` (`UI_`): For building graphical user interfaces. Provides a core
immediate mode hierarchical user interface data structure building API, and immediate mode hierarchical user interface data structure building API, and
has helper layers for building higher level widgets. has helper layers for building higher level widgets.

View File

@ -44,6 +44,10 @@
#define BUILD_DEBUG 1 #define BUILD_DEBUG 1
#endif #endif
#if !defined(BUILD_ENTRY_DEFINING_UNIT)
#define BUILD_ENTRY_DEFINING_UNIT 1
#endif
#if !defined(BUILD_VERSION_MAJOR) #if !defined(BUILD_VERSION_MAJOR)
#define BUILD_VERSION_MAJOR 0 #define BUILD_VERSION_MAJOR 0
#endif #endif

6
src/base/base_core.c Normal file
View File

@ -0,0 +1,6 @@
// Safe Casts
internal u16 safe_cast_u16(u32 x) {
// Assert
u16 result = (u16)x;
return result;
}

View File

@ -134,6 +134,9 @@ global const u32 bit30 = (1 << 29);
global const u32 bit31 = (1 << 30); global const u32 bit31 = (1 << 30);
global const u32 bit32 = (1 << 31); global const u32 bit32 = (1 << 31);
// Safe Casts
internal u16 safe_cast_u16(u32 x);
// Misc helpers // Misc helpers
// NOTE(tijani): Divides total size of array by size of one element in the array gives // NOTE(tijani): Divides total size of array by size of one element in the array gives
// the number of elements in the array. // the number of elements in the array.

View File

@ -1,7 +1,12 @@
internal void main_thread_entry_point(void) { internal void main_thread_base_entry_point(void) {
ThreadNameF("[main thread]"); ThreadNameF("[main thread]");
#if defined(OS_GFX_H) #if defined(OS_GFX_H)
os_gfx_init(); os_gfx_init();
#endif #endif
#if defined(GFX_H)
gfx_init(update_and_render);
#endif
entry_point();
} }

View File

@ -1,6 +1,6 @@
#ifndef BASE_ENTRY_POINT_H #ifndef BASE_ENTRY_POINT_H
#define 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 #endif // BASE_ENTRY_POINT_H

View File

@ -1,7 +1,10 @@
// clang-format off // clang-format off
#include "base_core.c"
#include "base_arena.c" #include "base_arena.c"
#include "base_strings.c" #include "base_strings.c"
#include "base_markup.c" #include "base_markup.c"
#include "base_threading_context.c" #include "base_threading_context.c"
#include "base_entry_point.c"
// clang-format on // clang-format on

View File

@ -10,6 +10,8 @@
#include "base_strings.h" #include "base_strings.h"
#include "base_markup.h" #include "base_markup.h"
#include "base_threading_context.h" #include "base_threading_context.h"
#include "base_entry_point.h"
// clang-format on // clang-format on
#endif // BASE_INC_H #endif // BASE_INC_H

46
src/ef/gfx/ef_gfx.c Normal file
View File

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

84
src/ef/gfx/ef_gfx.h Normal file
View File

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

View File

@ -1,20 +1,28 @@
internal void update_and_render(OS_Handle repaint_window_handle) { internal void update_and_render(OS_Handle repaint_window_handle) {
// Profiling start
Temp scratch = scratch_begin(0, 0); 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 // Get events from OS
OS_EventList events = {0}; OS_EventList events = {0};
if (os_handle_match(repaint_window_handle, os_handle_zero())) { 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 // begin frames
{ { gfx_begin_frame(scratch.arena); }
df_core_begin(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
} }

View File

@ -1,6 +1,8 @@
#ifndef GOFF_H #ifndef GOFF_H
#define GOFF_H #define GOFF_H
// Frontend entry point
internal void update_and_render(OS_HANDLE repaint_window); internal void update_and_render(OS_HANDLE repaint_window);
#endif // GOFF_H #endif // GOFF_H

View File

@ -10,16 +10,21 @@
// clang-format on // 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 // Entry Point
internal void entry_point() { internal void entry_point() {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
// Setup layers // Setup layers
// { { gfx_init(); }
// df_core_init();
// df_gfx_init();
// }
// Main application loop // Main application loop
{ {
@ -30,6 +35,9 @@ internal void entry_point() {
update_and_render(repaint_window); update_and_render(repaint_window);
// Quit // Quit
// if (gfx_state->first_window == 0) {
// break;
// }
} }
} }

0
src/os/core/os_core.c Normal file
View File

View File

@ -51,4 +51,14 @@ internal void os_set_thread_name(String8 name);
// %os_hooks(implemented per-os) Aborting // %os_hooks(implemented per-os) Aborting
internal void os_abort(s32 exit_code); 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 #endif // OS_CORE_H

View File

@ -2,8 +2,8 @@
// compatibility with older versions of windows where the modern WIN32 // compatibility with older versions of windows where the modern WIN32
// SetThreadDescription function is not available and use old ways. // SetThreadDescription function is not available and use old ways.
// This way it can be done dynamically at runtime without any hiccups. // This way it can be done dynamically at runtime without any hiccups.
typedef HRESULT W32_SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription); typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription);
global W32_SetThreadDescription *w32_SetThreadDescription_func = 0; global W32_SetThreadDescription_Type *w32_SetThreadDescription_func = 0;
// %os_hooks(implemented per-os) System and process info // %os_hooks(implemented per-os) System and process info
internal OS_SystemInfo *os_get_system_info(void) { return &os_w32_state.system_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 // %os_hooks(implemented per-os) Threads
internal u32 os_thread_id(void) { internal u32 os_thread_id(void) {
u32 id = GetCurrentThreadID(); u32 id = GetCurrentThreadId();
return (id); return (id);
} }
@ -90,3 +90,41 @@ internal void os_set_thread_name(String8 name) {
// %os_hooks(implemented per-os) Aborting // %os_hooks(implemented per-os) Aborting
internal void os_abort(s32 exit_code) { ExitProcess(exit_code); } 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;
}

View File

@ -4,8 +4,12 @@
// clang-format off // clang-format off
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <windowsx.h>
#include <processthreadsapi.h> #include <processthreadsapi.h>
#pragma comment(lib, "user32")
#pragma comment(lib, "advapi32")
// clang-format on // clang-format on
// Application State // Application State

View File

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

View File

@ -1,11 +1,27 @@
#ifndef OS_INC_H #ifndef OS_INC_H
#define 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 "os/core/os_core.h"
#include "core/win32/os_core_win32.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 #endif // OS_INC_H