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

View File

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

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

View File

@ -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();
}

View File

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

View File

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

View File

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

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

View File

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

View File

@ -10,19 +10,24 @@
// 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
{
// Main application loop
{
for (;;) {
// Update and render frame here
@ -30,8 +35,11 @@ internal void entry_point() {
update_and_render(repaint_window);
// Quit
// if (gfx_state->first_window == 0) {
// break;
// }
}
}
}
scratch_end(scratch);
scratch_end(scratch);
}

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

View File

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

View File

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