Mouse pointers & text rendering bug

This commit is contained in:
Charlie Malmqvist 2024-07-26 21:33:04 +02:00
parent db7159a306
commit 234e3ed440
12 changed files with 329 additions and 45 deletions

15
TODO
View file

@ -12,15 +12,13 @@
- Optimize
- Spam simd
- Concurrent jobs for players?
- Mega buffer for contiguous intermediate buffers
We definitely also want a limit to how much memory we want allocated to intermediate buffers.
- Pool of intermediate buffers (2^)
- Bugs:
- Small fadeout on pause is slightly noisy
- Setting time stamp/progression causes noise (need fade transition like on pause/play)
- End of clip also causes noise if audio clip does not end smoothly
- Setting audio source to a format which differs from audio output format in both channels and bit_width at the same time will produce pure loud noise.
- 24-Bit audio conversion doesn't really work
- Converting 24-bit audio files doesn't really work
- General bugs & issues
- Release freeze in run_tests
@ -30,6 +28,10 @@
- Renderer
- API to pass constant values to shader (codegen #define's)
- Draw_Frame instances
- Or draw to a custom Quad_Buffer, then draw quad buffers ?
- draw_deferred ?
- Draw_Frame Render_Image
- Fonts
- Atlases are way too big, render atlases with size depending on font_height (say, 128 codepoints per atlas)
@ -38,9 +40,16 @@
- Window::bool is_minimized
- don't set window.width & window.height to 0
- Sockets recv, send
- Mouse pointer
- Hide mouse pointer
- Arenas
- Examples/Guides:
- Scaling text for pixel perfect rendering
- Z sorting
- Scissor boxing
- Needs testing:
- Audio format channel conversions

View file

@ -6,6 +6,6 @@ mkdir build
pushd build
clang -g -o cgame.exe ../build.c -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -ldbghelp -femit-all-decls
clang -g -fuse-ld=lld -o cgame.exe ../build.c -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -ldbghelp -femit-all-decls
popd

View file

@ -37,11 +37,11 @@ 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/growing_array_example.c"
// #include "oogabooga/examples/growing_array_example.c"
// This is where you swap in your own project!
// #include "entry_yourepicgamename.c"

View file

@ -1,4 +1,18 @@
## v0.01.003 -
- Os layer
- Implemented setting of mouse pointers, either to system standard pointers or a custom image
- Ignore SETCURSOR events unless window resize
- Store SYSTEM_INFO in init
- os_get_number_of_logical_processors()
- Renderer
- Fix bad uv sampling bug when uneven window dimensions
- Misc
-
## v0.01.002 - Flexible build options, Hotloading, growing array
- Build system
- We can now compile with:

View file

@ -28,9 +28,10 @@ typedef struct Cpu_Capabilities {
#if COMPILER_MVSC
#define inline __forceinline
#define alignat(x) __declspec(align(x))
#define noreturn __declspec(noreturn)
#define COMPILER_HAS_MEMCPY_INTRINSICS 1
inline void
crash() {
crash() noreturn {
__debugbreak();
volatile int *a = 0;
*a = 5;
@ -113,10 +114,11 @@ typedef struct Cpu_Capabilities {
#elif COMPILER_GCC || COMPILER_CLANG
#define inline __attribute__((always_inline)) inline
#define alignat(x) __attribute__((aligned(x)))
#define alignat(x) __attribute__((aligned(x)))
#define noreturn __attribute__((noreturn))
#define COMPILER_HAS_MEMCPY_INTRINSICS 1
inline void __attribute__((noreturn))
inline void noreturn
crash() {
__builtin_trap();
volatile int *a = 0;

View file

@ -14,7 +14,6 @@
Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip);
Draw_Quad *draw_quad(Draw_Quad quad);
Draw_Quad *draw_quad_xform(Draw_Quad quad, Matrix4 xform);
bool draw_text_callback(Gfx_Glyph glyph, Gfx_Font_Atlas *atlas, float glyph_x, float glyph_y, void *ud);
void draw_text_xform(Gfx_Font *font, string text, u32 raster_height, Matrix4 xform, Vector2 scale, Vector4 color);
void draw_text(Gfx_Font *font, string text, u32 raster_height, Vector2 position, Vector2 scale, Vector4 color);
Gfx_Text_Metrics draw_text_and_measure(Gfx_Font *font, string text, u32 raster_height, Vector2 position, Vector2 scale, Vector4 color);

View file

@ -15,6 +15,11 @@ int entry(int argc, char **argv) {
Gfx_Image *hammer_image = load_image_from_disk(STR("oogabooga/examples/hammer.png"), get_heap_allocator());
assert(hammer_image, "Failed loading hammer.png");
Custom_Mouse_Pointer hammer_pointer
= os_make_custom_mouse_pointer_from_file(STR("oogabooga/examples/hammer.png"), 16, 16, get_heap_allocator());
assert(hammer_pointer != 0, "Could not load hammer pointer");
void *my_data = alloc(get_heap_allocator(), 32*32*4);
memset(my_data, 0xffffffff, 32*32*4);
Gfx_Image *my_image = make_image(32, 32, 4, my_data, get_heap_allocator());
@ -54,7 +59,7 @@ int entry(int argc, char **argv) {
if (is_key_just_released(KEY_ESCAPE)) {
window.should_close = true;
}
os_set_mouse_pointer_custom(hammer_pointer);
if (is_key_just_pressed(KEY_ARROW_LEFT)) {
window.x -= 10;
}

View file

@ -244,8 +244,8 @@ void font_atlas_init(Gfx_Font_Atlas *atlas, Gfx_Font_Variation *variation, u32 f
glyph->advance = (float)advance*variation->scale;
//glyph->xoffset += (float)left_side_bearing*variation->scale;
glyph->uv.x1 = (float)cursor_x/(float)FONT_ATLAS_WIDTH;
glyph->uv.y1 = (float)cursor_y/(float)FONT_ATLAS_HEIGHT;
glyph->uv.x1 = ((float)cursor_x)/(float)FONT_ATLAS_WIDTH;
glyph->uv.y1 = ((float)cursor_y)/(float)FONT_ATLAS_HEIGHT;
glyph->uv.x2 = ((float)cursor_x+glyph->width)/(float)FONT_ATLAS_WIDTH;
glyph->uv.y2 = ((float)cursor_y+glyph->height)/(float)FONT_ATLAS_HEIGHT;

View file

@ -674,8 +674,21 @@ void d3d11_process_draw_frame() {
}
if (q->type == QUAD_TYPE_TEXT) {
// This is meant to fix the annoying artifacts that shows up when sampling text from an atlas
// presumably for floating point precision issues or something.
// #Incomplete
// If we want to animate text with small movements then it will look wonky.
// This should be optional probably.
// Also, we might want to do this on non-text if rendering with linear filtering
// from a large texture atlas.
float pixel_width = 2.0/(float)window.width;
float pixel_height = 2.0/(float)window.height;
bool xeven = window.width % 2 == 0;
bool yeven = window.height % 2 == 0;
q->bottom_left.x = round(q->bottom_left.x / pixel_width) * pixel_width;
q->bottom_left.y = round(q->bottom_left.y / pixel_height) * pixel_height;
@ -703,10 +716,50 @@ void d3d11_process_draw_frame() {
TR->position = v4(q->top_right.x, q->top_right.y, 0, 1);
BR->position = v4(q->bottom_right.x, q->bottom_right.y, 0, 1);
BL->uv = v2(q->uv.x1, q->uv.y1);
TL->uv = v2(q->uv.x1, q->uv.y2);
TR->uv = v2(q->uv.x2, q->uv.y2);
BR->uv = v2(q->uv.x2, q->uv.y1);
if (q->image) {
BL->uv = v2(q->uv.x1, q->uv.y1);
TL->uv = v2(q->uv.x1, q->uv.y2);
TR->uv = v2(q->uv.x2, q->uv.y2);
BR->uv = v2(q->uv.x2, q->uv.y1);
// #Hack #Bug #Cleanup
// When a window dimension is uneven it slightly under/oversamples on an axis by a
// seemingly arbitrary amount. The 0.25 is a magic value I got from trial and error.
// (It undersamples by a fourth of the atlas texture?)
// Anything > 0.25 < will slightly over/undersample on my machine.
// I have no idea about #Portability here.
// - Charlie M 26th July 2024
if (window.width % 2 != 0) {
BL->uv.x += (2.0/(float)q->image->width)*0.25;
TL->uv.x += (2.0/(float)q->image->width)*0.25;
TR->uv.x += (2.0/(float)q->image->width)*0.25;
BR->uv.x += (2.0/(float)q->image->width)*0.25;
}
if (window.height % 2 != 0) {
BL->uv.y -= (2.0/(float)q->image->height)*0.25;
TL->uv.y -= (2.0/(float)q->image->height)*0.25;
TR->uv.y -= (2.0/(float)q->image->height)*0.25;
BR->uv.y -= (2.0/(float)q->image->height)*0.25;
}
u8 sampler = -1;
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
sampler = 0;
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
sampler = 1;
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
sampler = 2;
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
sampler = 3;
BL->sampler=TL->sampler=TR->sampler=BR->sampler = (u8)sampler;
}
BL->texture_index=TL->texture_index=TR->texture_index=BR->texture_index = texture_index;
BL->self_uv = v2(0, 0);
TL->self_uv = v2(0, 1);
@ -721,7 +774,6 @@ void d3d11_process_draw_frame() {
BL->color = TL->color = TR->color = BR->color = q->color;
BL->texture_index=TL->texture_index=TR->texture_index=BR->texture_index = texture_index;
BL->type=TL->type=TR->type=BR->type = (u8)q->type;
float t = q->scissor.y1;
@ -734,23 +786,6 @@ void d3d11_process_draw_frame() {
BL->has_scissor=TL->has_scissor=TR->has_scissor=BR->has_scissor = q->has_scissor;
BL->scissor=TL->scissor=TR->scissor=BR->scissor = q->scissor;
u8 sampler = -1;
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
sampler = 0;
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
sampler = 1;
if (q->image_min_filter == GFX_FILTER_MODE_LINEAR
&& q->image_mag_filter == GFX_FILTER_MODE_NEAREST)
sampler = 2;
if (q->image_min_filter == GFX_FILTER_MODE_NEAREST
&& q->image_mag_filter == GFX_FILTER_MODE_LINEAR)
sampler = 3;
BL->type=TL->type=TR->type=BR->type = (u8)q->type;
BL->sampler=TL->sampler=TR->sampler=BR->sampler = (u8)sampler;
*BL2 = *BL;
*TR2 = *TR;

View file

@ -118,7 +118,7 @@
#define OGB_VERSION_MAJOR 0
#define OGB_VERSION_MINOR 1
#define OGB_VERSION_PATCH 2
#define OGB_VERSION_PATCH 3
#define OGB_VERSION (OGB_VERSION_MAJOR*1000000+OGB_VERSION_MINOR*1000+OGB_VERSION_PATCH)
@ -228,6 +228,7 @@ typedef u8 bool;
#ifdef _WIN32
#define COBJMACROS
#undef noreturn
#include <Windows.h>
#if CONFIGURATION == DEBUG
#include <dbghelp.h>

View file

@ -41,6 +41,12 @@ void win32_check_hr_impl(HRESULT hr, u32 line, const char* file_name) {
}
}
// #Global
bool win32_want_override_mouse_pointer = false;
HCURSOR win32_shadowed_mouse_pointer = 0;
bool win32_did_override_user_mouse_pointer = false;
SYSTEM_INFO win32_system_info;
#ifndef OOGABOOGA_HEADLESS
// Persistent
@ -86,6 +92,8 @@ void win32_handle_key_repeat(Input_Key_Code code) {
win32_send_key_event(code, win32_key_states[code]);
}
LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wparam, LPARAM lparam) {
if (window._initialized) {
@ -161,6 +169,32 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar
goto DEFAULT_HANDLE;
}
case WM_SETCURSOR: {
WORD hit_test = LOWORD(lparam);
WORD mouse_message = HIWORD(lparam);
if (hit_test == HTLEFT || hit_test == HTRIGHT || hit_test == HTTOP ||
hit_test == HTBOTTOM || hit_test == HTTOPLEFT || hit_test == HTTOPRIGHT ||
hit_test == HTBOTTOMLEFT || hit_test == HTBOTTOMRIGHT) {
// We are hovering the borders, let windows decide the pointer
win32_want_override_mouse_pointer = true;
goto DEFAULT_HANDLE;
} else {
if (win32_want_override_mouse_pointer) {
win32_want_override_mouse_pointer = false;
if (win32_did_override_user_mouse_pointer) {
win32_did_override_user_mouse_pointer = false;
SetCursor(win32_shadowed_mouse_pointer);
} else {
goto DEFAULT_HANDLE;
}
}
}
break;
}
default:
DEFAULT_HANDLE:
@ -255,10 +289,11 @@ void os_init(u64 program_memory_size) {
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
SYSTEM_INFO si;
GetSystemInfo(&si);
os.granularity = cast(u64)si.dwAllocationGranularity;
os.page_size = cast(u64)si.dwPageSize;
os_set_mouse_pointer_standard(MOUSE_POINTER_DEFAULT);
GetSystemInfo(&win32_system_info);
os.granularity = cast(u64)win32_system_info.dwAllocationGranularity;
os.page_size = cast(u64)win32_system_info.dwPageSize;
os.static_memory_start = 0;
os.static_memory_end = 0;
@ -1031,18 +1066,25 @@ void fprintf(File f, const char* fmt, ...) {
///
///
// Memory
// Queries
///
void* os_get_stack_base() {
void*
os_get_stack_base() {
NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
return tib->StackBase;
}
void* os_get_stack_limit() {
void*
os_get_stack_limit() {
NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
return tib->StackLimit;
}
u64
os_get_number_of_logical_processors() {
return (u64)win32_system_info.dwNumberOfProcessors;
}
///
///
// Debug
@ -1144,8 +1186,140 @@ os_get_stack_trace(u64 *trace_count, Allocator allocator) {
#endif // NOT DEBUG
}
///
///
// Mouse pointer
#ifndef OOGABOOGA_HEADLESS
LPCSTR
win32_mouse_pointer_kind_to_win32(Mouse_Pointer_Kind k) {
switch (k) {
case MOUSE_POINTER_DEFAULT: return IDC_ARROW;
case MOUSE_POINTER_TEXT_SELECT: return IDC_IBEAM;
case MOUSE_POINTER_BUSY: return IDC_WAIT;
case MOUSE_POINTER_BUSY_BACKGROUND: return IDC_APPSTARTING;
case MOUSE_POINTER_CROSS: return IDC_CROSS;
case MOUSE_POINTER_ARROW_N: return IDC_UPARROW;
case MOUSE_POINTER_ARROWS_NW_SE: return IDC_SIZENWSE;
case MOUSE_POINTER_ARROWS_NE_SW: return IDC_SIZENESW;
case MOUSE_POINTER_ARROWS_HORIZONTAL: return IDC_SIZEWE;
case MOUSE_POINTER_ARROWS_VERTICAL: return IDC_SIZENS;
case MOUSE_POINTER_ARROWS_ALL: return IDC_SIZEALL;
case MOUSE_POINTER_NO: return IDC_NO;
case MOUSE_POINTER_POINT: return IDC_HAND;
default: break;
}
panic("Unhandled Mouse_Pointer_Kind");
}
void ogb_instance
os_set_mouse_pointer_standard(Mouse_Pointer_Kind kind) {
thread_local local_persist HCURSOR loaded_pointers[MOUSE_POINTER_MAX] = {0};
if (loaded_pointers[kind] == 0) {
loaded_pointers[kind] = LoadCursor(0, win32_mouse_pointer_kind_to_win32(kind));
}
if (win32_want_override_mouse_pointer) {
win32_shadowed_mouse_pointer = loaded_pointers[kind];
win32_did_override_user_mouse_pointer = true;
} else {
SetCursor(loaded_pointers[kind]);
}
}
void ogb_instance
os_set_mouse_pointer_custom(Custom_Mouse_Pointer p) {
if (win32_want_override_mouse_pointer) {
win32_shadowed_mouse_pointer = (HCURSOR)p;
win32_did_override_user_mouse_pointer = true;
} else {
SetCursor((HCURSOR)p);
}
}
// Expects 32-bit rgba
Custom_Mouse_Pointer ogb_instance
os_make_custom_mouse_pointer(void *image, int width, int height, int hotspot_x, int hotspot_y) {
HICON icon = NULL;
HBITMAP bitmap = NULL;
ICONINFO icon_info = { 0 };
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
BYTE* bits = NULL;
HDC hdc = GetDC(NULL);
bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
ReleaseDC(NULL, hdc);
if (!bitmap) {
assert(false, "Failed to create DIB section");
return NULL;
}
memcpy(bits, image, width * height * 4);
icon_info.fIcon = FALSE; // Cursor, not icon
icon_info.xHotspot = hotspot_x;
icon_info.yHotspot = height-hotspot_y;
icon_info.hbmMask = bitmap;
icon_info.hbmColor = bitmap;
icon = CreateIconIndirect(&icon_info);
if (!icon) {
assert(false, "Failed to create icon from bitmap");
DeleteObject(bitmap);
return NULL;
}
DeleteObject(bitmap);
return icon;
}
Custom_Mouse_Pointer ogb_instance
os_make_custom_mouse_pointer_from_file(string path, int hotspot_x, int hotspot_y, Allocator allocator) {
int width, height, channels;
stbi_set_flip_vertically_on_load(1);
third_party_allocator = allocator;
string png;
bool ok = os_read_entire_file(path, &png, allocator);
if (!ok) return 0;
unsigned char* stb_data = stbi_load_from_memory(
png.data,
png.count,
&width,
&height,
&channels,
STBI_rgb_alpha
);
if (!stb_data) {
dealloc_string(allocator, png);
return 0;
}
Custom_Mouse_Pointer p = os_make_custom_mouse_pointer(stb_data, width, height, hotspot_x, hotspot_y);
dealloc_string(allocator, png);
stbi_image_free(stb_data);
third_party_allocator = ZERO(Allocator);
return p;
}
#ifndef OOGABOOGA_HEADLESS // No audio in headless
// Actually fuck you bill gates
const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}};

View file

@ -200,6 +200,7 @@ typedef enum Os_Io_Open_Flags {
// To append, pass WRITE flag without CREATE flag
} Os_Io_Open_Flags;
// Returns OS_INVALID_FILE on fail
File ogb_instance
os_file_open_s(string path, Os_Io_Open_Flags flags);
@ -376,13 +377,16 @@ void fprint_va_list_buffered(File f, const string fmt, va_list args) {
///
///
// Memory
// Queries
///
ogb_instance void*
os_get_stack_base();
ogb_instance void*
os_get_stack_limit();
ogb_instance u64
os_get_number_of_logical_processors();
///
///
@ -401,6 +405,47 @@ void dump_stack_trace() {
}
}
///
///
// Mouse pointer
typedef enum Mouse_Pointer_Kind {
MOUSE_POINTER_DEFAULT = 0, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_arrow.png
MOUSE_POINTER_TEXT_SELECT = 10, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_ibeam.png
MOUSE_POINTER_BUSY = 20, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_wait.png
MOUSE_POINTER_BUSY_BACKGROUND = 30, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_appstarting.png
MOUSE_POINTER_CROSS = 40, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_cross.png
MOUSE_POINTER_ARROW_N = 50, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_uparrow.png
MOUSE_POINTER_ARROWS_NW_SE = 60, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizenwse.png
MOUSE_POINTER_ARROWS_NE_SW = 70, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizenesw.png
MOUSE_POINTER_ARROWS_HORIZONTAL = 80, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizewe.png
MOUSE_POINTER_ARROWS_VERTICAL = 90, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizens.png
MOUSE_POINTER_ARROWS_ALL = 100, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_sizeall.png
MOUSE_POINTER_NO = 110, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_no.png
MOUSE_POINTER_POINT = 120, // https://learn.microsoft.com/en-us/windows/win32/menurc/images/idc_hand.png
MOUSE_POINTER_MAX,
} Mouse_Pointer_Kind;
typedef void* Custom_Mouse_Pointer;
void ogb_instance
os_set_mouse_pointer_standard(Mouse_Pointer_Kind kind);
void ogb_instance
os_set_mouse_pointer_custom(Custom_Mouse_Pointer p);
// Expects 32-bit rgba
// Returns 0 on fail
Custom_Mouse_Pointer ogb_instance
os_make_custom_mouse_pointer(void *image, int width, int height, int hotspot_x, int hotspot_y);
// Returns 0 on fail
// Will free everything that's allocated, passing temp allocator should be fine as long as the image is small
Custom_Mouse_Pointer ogb_instance
os_make_custom_mouse_pointer_from_file(string path, int hotspot_x, int hotspot_y, Allocator allocator);
///////////////////////////////////////////////
void ogb_instance
os_init(u64 program_memory_size);