win32_app
This commit is contained in:
39
build_file.c
39
build_file.c
@@ -9,16 +9,51 @@
|
|||||||
|
|
||||||
#include "src/app/app.meta.c"
|
#include "src/app/app.meta.c"
|
||||||
|
|
||||||
|
void list_files_recursive(sb8_t *sb, s8_t path) {
|
||||||
|
for (OS_FileIter iter = OS_IterateFiles(&Perm, path); OS_IsValid(iter); OS_Advance(&iter)) {
|
||||||
|
if (iter.is_directory) {
|
||||||
|
list_files_recursive(sb, iter.absolute_path);
|
||||||
|
} else {
|
||||||
|
sb8_append(sb, iter.absolute_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
ma_arena_t *arena = ma_create(ma_default_reserve_size);
|
ma_arena_t *arena = ma_create(ma_default_reserve_size);
|
||||||
meta_app(arena);
|
meta_app(arena);
|
||||||
|
|
||||||
|
bool execute_python_snippets = true; // make sure to not abuse just for quick maths
|
||||||
bool run_server = false;
|
bool run_server = false;
|
||||||
|
|
||||||
bool core_test_target = false;
|
bool core_test_target = false;
|
||||||
bool wasm_target = true;
|
bool wasm_target = false;
|
||||||
bool win32_target = false;
|
bool win32_target = true;
|
||||||
|
|
||||||
|
if (execute_python_snippets) {
|
||||||
|
sb8_t *sb = sb8_serial_begin(arena);
|
||||||
|
list_files_recursive(sb, s8_lit(".."));
|
||||||
|
for (sb8_node_t *it = sb->first; it; it = it->next) {
|
||||||
|
s8_t abs = it->string;
|
||||||
|
|
||||||
|
bool is_c_file = s8_ends_with(abs, s8_lit(".c"), true) || s8_ends_with(abs, s8_lit(".cpp"), true) || s8_ends_with(abs, s8_lit(".h"), true) || s8_ends_with(abs, s8_lit(".hpp"), true);
|
||||||
|
if (!is_c_file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool is_build_file = s8_ends_with(abs, s8_lit("build_file.c"), true);
|
||||||
|
if (is_build_file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s8_t file = OS_ReadFile(&Perm, abs);
|
||||||
|
i64 idx = s8_find(file, s8_lit("/*#"), 0);
|
||||||
|
if (idx != -1) {
|
||||||
|
os_systemf("\"D:\\dev\\apps\\bin\\pyorun.bat\" %s", abs.str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (run_server) {
|
if (run_server) {
|
||||||
os_systemf("start /D ..\\package ..\\package\\run_server.bat");
|
os_systemf("start /D ..\\package ..\\package\\run_server.bat");
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ type_t type__app_event_kind_t = { type_kind_enum, s8_const_lit("app_event_kind_t
|
|||||||
};
|
};
|
||||||
type_t type__app_event_t = { type_kind_struct, s8_const_lit("app_event_t"), sizeof(app_event_t),
|
type_t type__app_event_t = { type_kind_struct, s8_const_lit("app_event_t"), sizeof(app_event_t),
|
||||||
.members = (type_member_t[]){
|
.members = (type_member_t[]){
|
||||||
|
{.name = s8_const_lit("next"), .type = &(type_t){type_kind_pointer, s8_const_lit("app_event_t*"), sizeof(void *), .base = &type__app_event_t}, .offset = offsetof(app_event_t, next)},
|
||||||
{.name = s8_const_lit("kind"), .type = &type__app_event_kind_t, .offset = offsetof(app_event_t, kind)},
|
{.name = s8_const_lit("kind"), .type = &type__app_event_kind_t, .offset = offsetof(app_event_t, kind)},
|
||||||
{.name = s8_const_lit("mouse_button"), .type = &type__app_mouse_button_t, .offset = offsetof(app_event_t, mouse_button)},
|
{.name = s8_const_lit("mouse_button"), .type = &type__app_mouse_button_t, .offset = offsetof(app_event_t, mouse_button)},
|
||||||
{.name = s8_const_lit("key"), .type = &type__app_key_t, .offset = offsetof(app_event_t, key)},
|
{.name = s8_const_lit("key"), .type = &type__app_key_t, .offset = offsetof(app_event_t, key)},
|
||||||
@@ -268,5 +269,13 @@ type_t type__app_event_t = { type_kind_struct, s8_const_lit("app_event_t"), size
|
|||||||
{.name = s8_const_lit("window_size"), .type = &type__v2f64_t, .offset = offsetof(app_event_t, window_size)},
|
{.name = s8_const_lit("window_size"), .type = &type__v2f64_t, .offset = offsetof(app_event_t, window_size)},
|
||||||
{.name = s8_const_lit("mouse_pos"), .type = &type__v2f64_t, .offset = offsetof(app_event_t, mouse_pos)},
|
{.name = s8_const_lit("mouse_pos"), .type = &type__v2f64_t, .offset = offsetof(app_event_t, mouse_pos)},
|
||||||
},
|
},
|
||||||
.count = 12,
|
.count = 13,
|
||||||
|
};
|
||||||
|
type_t type__app_event_list_t = { type_kind_struct, s8_const_lit("app_event_list_t"), sizeof(app_event_list_t),
|
||||||
|
.members = (type_member_t[]){
|
||||||
|
{.name = s8_const_lit("first"), .type = &(type_t){type_kind_pointer, s8_const_lit("app_event_t*"), sizeof(void *), .base = &type__app_event_t}, .offset = offsetof(app_event_list_t, first)},
|
||||||
|
{.name = s8_const_lit("last"), .type = &(type_t){type_kind_pointer, s8_const_lit("app_event_t*"), sizeof(void *), .base = &type__app_event_t}, .offset = offsetof(app_event_list_t, last)},
|
||||||
|
{.name = s8_const_lit("len"), .type = &type__i32, .offset = offsetof(app_event_list_t, len)},
|
||||||
|
},
|
||||||
|
.count = 3,
|
||||||
};
|
};
|
||||||
@@ -93,6 +93,7 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct app_event_t app_event_t;
|
typedef struct app_event_t app_event_t;
|
||||||
struct app_event_t {
|
struct app_event_t {
|
||||||
|
app_event_t* next;
|
||||||
app_event_kind_t kind;
|
app_event_kind_t kind;
|
||||||
app_mouse_button_t mouse_button;
|
app_mouse_button_t mouse_button;
|
||||||
app_key_t key;
|
app_key_t key;
|
||||||
@@ -106,3 +107,10 @@ struct app_event_t {
|
|||||||
v2f64_t window_size;
|
v2f64_t window_size;
|
||||||
v2f64_t mouse_pos;
|
v2f64_t mouse_pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct app_event_list_t app_event_list_t;
|
||||||
|
struct app_event_list_t {
|
||||||
|
app_event_t* first;
|
||||||
|
app_event_t* last;
|
||||||
|
i32 len;
|
||||||
|
};
|
||||||
@@ -159,12 +159,15 @@ void meta_app(ma_arena_t *arena) {
|
|||||||
} app_event_kind_t;
|
} app_event_kind_t;
|
||||||
|
|
||||||
struct app_event_t {
|
struct app_event_t {
|
||||||
|
app_event_t *next;
|
||||||
app_event_kind_t kind;
|
app_event_kind_t kind;
|
||||||
|
|
||||||
// data present only during events
|
// data present only during events
|
||||||
app_mouse_button_t mouse_button; // @mouse_down @mouse_up
|
app_mouse_button_t mouse_button; // @mouse_down @mouse_up
|
||||||
app_key_t key; // @key_down @key_up
|
app_key_t key; // @key_down @key_up
|
||||||
s8_t text; // @text
|
s8_t text; // @text
|
||||||
|
|
||||||
|
// @todo: test why xyz in js????????????
|
||||||
v3f64_t mouse_wheel_delta; // @mouse_wheel
|
v3f64_t mouse_wheel_delta; // @mouse_wheel
|
||||||
|
|
||||||
// always present data
|
// always present data
|
||||||
@@ -177,6 +180,12 @@ void meta_app(ma_arena_t *arena) {
|
|||||||
v2f64_t window_size;
|
v2f64_t window_size;
|
||||||
v2f64_t mouse_pos;
|
v2f64_t mouse_pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct app_event_list_t {
|
||||||
|
app_event_t *first;
|
||||||
|
app_event_t *last;
|
||||||
|
i32 len;
|
||||||
|
};
|
||||||
));
|
));
|
||||||
|
|
||||||
sb8_serial_ast_to_code(h, decls);
|
sb8_serial_ast_to_code(h, decls);
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
.doesn't miss events (always processes all key strokes and buttons etc.)
|
.doesn't miss events (always processes all key strokes and buttons etc.)
|
||||||
.replayable / deterministic (that is you can serialize all the events, replay them back and get the same results)
|
|
||||||
..rendering and update decoupled
|
|
||||||
.sleeps properly when nothing is happening
|
.sleeps properly when nothing is happening
|
||||||
.animations probably then should be in the rendering part
|
.replayable (that is you can serialize all the events, replay them back and get the same results)
|
||||||
|
..rendering and update decoupled
|
||||||
|
..animations probably then should be in the rendering part
|
||||||
|
|
||||||
void app_update(app_event_t *events, i32 event_count) {
|
void app_update(app_event_t *events, i32 event_count) {
|
||||||
loop (events) update(it);
|
update_result_t *state = NULL; // contains event
|
||||||
|
loop (events) {
|
||||||
|
state = update(it);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
app_event_t *ev = events + event_count - 1;
|
app_event_t *ev = state->ev;
|
||||||
|
|
||||||
|
|
||||||
f64 delta_time = app_anim_get_delta_time();
|
f64 delta_time = app_anim_get_delta_time();
|
||||||
f64 time = app_anim_get_time();
|
f64 time = app_anim_get_time();
|
||||||
animate(ev, delta_time, time);
|
animate(state, delta_time, time);
|
||||||
render(ev);
|
render(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,10 +42,10 @@ glb_wasm_export i32 wasm_temp_buff1_len = 127;
|
|||||||
glb_wasm_export char wasm_temp_buff2[128] = {[127] = 0x13};
|
glb_wasm_export char wasm_temp_buff2[128] = {[127] = 0x13};
|
||||||
glb_wasm_export i32 wasm_temp_buff2_len = 127;
|
glb_wasm_export i32 wasm_temp_buff2_len = 127;
|
||||||
|
|
||||||
global f64 wasm_dpr;
|
// @todo: event list
|
||||||
global ma_arena_t *wasm_input_text_arena;
|
global f64 wasm_dpr;
|
||||||
global STACK(app_event_t, 64) wasm_events;
|
global STACK(app_event_t, 256) wasm_events;
|
||||||
global b32 wasm_event_failed_to_queue;
|
global b32 wasm_event_failed_to_queue;
|
||||||
|
|
||||||
global f64 wasm_delta_time;
|
global f64 wasm_delta_time;
|
||||||
global f64 wasm_time;
|
global f64 wasm_time;
|
||||||
@@ -53,7 +58,7 @@ struct wasm_cached_t {
|
|||||||
b8 ctrl, alt, meta, shift;
|
b8 ctrl, alt, meta, shift;
|
||||||
} wasm_cached;
|
} wasm_cached;
|
||||||
|
|
||||||
fn void app_update(app_event_t *events, i32 event_count);
|
fn void app_update(void);
|
||||||
fn void app_init(void);
|
fn void app_init(void);
|
||||||
|
|
||||||
fn void wasm_add_event(app_event_t event) {
|
fn void wasm_add_event(app_event_t event) {
|
||||||
@@ -147,7 +152,7 @@ fn_wasm_export void wasm_key_down(char *key, b32 ctrl, b32 shift, b32 alt, b32 m
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s8_t text = s8_copy(wasm_input_text_arena, key8);
|
s8_t text = s8_copy(tcx.temp, key8);
|
||||||
wasm_add_event((app_event_t){
|
wasm_add_event((app_event_t){
|
||||||
.kind = app_event_kind_text,
|
.kind = app_event_kind_text,
|
||||||
.mouse_pos = wasm_cached.mouse_pos,
|
.mouse_pos = wasm_cached.mouse_pos,
|
||||||
@@ -180,7 +185,7 @@ fn_wasm_export void wasm_key_up(char *key, b32 ctrl, b32 shift, b32 alt, b32 met
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn_wasm_export void wasm_update(f64 width, f64 height, f64 dpr) {
|
fn_wasm_export void wasm_update(f64 width, f64 height, f64 dpr) {
|
||||||
wasm_time = os_get_milliseconds();
|
wasm_time = os_milliseconds_now();
|
||||||
wasm_delta_time = wasm_time - wasm_last_time_milliseconds;
|
wasm_delta_time = wasm_time - wasm_last_time_milliseconds;
|
||||||
|
|
||||||
v2f64_t window_size = (v2f64_t){width / dpr, height / dpr};
|
v2f64_t window_size = (v2f64_t){width / dpr, height / dpr};
|
||||||
@@ -202,18 +207,32 @@ fn_wasm_export void wasm_update(f64 width, f64 height, f64 dpr) {
|
|||||||
wasm_events.data[i].window_size = window_size;
|
wasm_events.data[i].window_size = window_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
app_update(wasm_events.data, wasm_events.len);
|
app_update();
|
||||||
|
|
||||||
wasm_events.len = 0;
|
wasm_events.len = 0;
|
||||||
wasm_last_time_milliseconds = wasm_time;
|
wasm_last_time_milliseconds = wasm_time;
|
||||||
ma_set0(wasm_input_text_arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_wasm_export void wasm_init(void) {
|
fn_wasm_export void wasm_init(void) {
|
||||||
core_init();
|
core_init();
|
||||||
wasm_input_text_arena = ma_push_arena(&tcx.perm, kib(1));
|
|
||||||
app_init();
|
app_init();
|
||||||
wasm_app_init_time_milliseconds = os_get_milliseconds();
|
wasm_app_init_time_milliseconds = os_milliseconds_now();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app_event_t *app_iterate_events(void) {
|
||||||
|
return wasm_events.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b32 app_is_event_valid(app_event_t *event) {
|
||||||
|
return event < (wasm_events.data + wasm_events.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void app_next_event(app_event_t **event) {
|
||||||
|
event[0] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app_event_t *app_get_last_event(void) {
|
||||||
|
return wasm_events.data + wasm_events.len - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f64 app_get_anim_time(void) {
|
fn f64 app_get_anim_time(void) {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#include "core/core.h"
|
#include "core/core_inc.h"
|
||||||
#include "app.gen.h"
|
#include "app.gen.h"
|
||||||
|
|
||||||
#include "core/core.c"
|
#include "core/core_inc.c"
|
||||||
#include "app.gen.c"
|
#include "app.gen.c"
|
||||||
|
#include "app_win32_opengl.c"
|
||||||
|
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
#pragma comment(linker, "/subsystem:windows")
|
#pragma comment(linker, "/subsystem:windows")
|
||||||
#pragma comment(lib, "gdi32.lib")
|
#pragma comment(lib, "gdi32.lib")
|
||||||
@@ -10,120 +13,361 @@
|
|||||||
#pragma comment(lib, "winmm.lib")
|
#pragma comment(lib, "winmm.lib")
|
||||||
|
|
||||||
|
|
||||||
b32 w32_good_scheduling = false;
|
b32 w32_good_scheduling;
|
||||||
WNDCLASSW w32_wc;
|
WNDCLASSW w32_wc;
|
||||||
HWND w32_window_handle;
|
HWND w32_window_handle;
|
||||||
HDC w32_dc;
|
HDC w32_dc;
|
||||||
|
b32 w32_quit_app;
|
||||||
|
|
||||||
LRESULT CALLBACK w32_window_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
app_event_list_t w32_event_list;
|
||||||
|
ma_arena_t *w32_event_arena;
|
||||||
|
|
||||||
|
fn v2f64_t w32_get_window_size(HWND window) {
|
||||||
|
RECT window_rect;
|
||||||
|
GetClientRect(window, &window_rect);
|
||||||
|
f64 x = window_rect.right - window_rect.left;
|
||||||
|
f64 y = window_rect.bottom - window_rect.top;
|
||||||
|
return (v2f64_t){x, y};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn v2f64_t w32_get_mouse_pos(HWND window) {
|
||||||
|
POINT p;
|
||||||
|
GetCursorPos(&p);
|
||||||
|
ScreenToClient(window, &p);
|
||||||
|
return (v2f64_t){p.x, p.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f64 w32_get_dpr(HWND window_handle) {
|
||||||
|
UINT dpi = GetDpiForWindow(window_handle);
|
||||||
|
if (dpi == 0) {
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
f64 result = (f64)dpi / 96.0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void w32_push_event(app_event_t event) {
|
||||||
|
app_event_t *ev = ma_push_type(w32_event_arena, app_event_t);
|
||||||
|
*ev = event;
|
||||||
|
|
||||||
|
if (GetKeyState(VK_CONTROL) & 0x8000) ev->ctrl = true;
|
||||||
|
if (GetKeyState(VK_SHIFT) & 0x8000) ev->shift = true;
|
||||||
|
if (GetKeyState(VK_MENU) & 0x8000) ev->alt = true;
|
||||||
|
ev->window_size = w32_get_window_size(w32_window_handle);
|
||||||
|
ev->mouse_pos = w32_get_mouse_pos(w32_window_handle);
|
||||||
|
ev->dpr = w32_get_dpr(w32_window_handle);
|
||||||
|
|
||||||
|
SLLQ_APPEND(w32_event_list.first, w32_event_list.last, ev);
|
||||||
|
w32_event_list.len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn LRESULT CALLBACK w32_window_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_CLOSE: PostQuitMessage(0); break;
|
case WM_CLOSE: {
|
||||||
case WM_KEYUP: {
|
ExitProcess(0);
|
||||||
app_key_t key = w32_map_wparam_to_app_key(wparam);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case WM_KEYDOWN: {
|
case WM_KEYDOWN: {
|
||||||
app_key_t key = w32_map_wparam_to_app_key(wparam);
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_key_down,
|
||||||
|
.key = w32_map_wparam_to_app_key(wparam)
|
||||||
|
});
|
||||||
} break;
|
} break;
|
||||||
|
case WM_KEYUP: {
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_key_up,
|
||||||
|
.key = w32_map_wparam_to_app_key(wparam)
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
|
|
||||||
|
case WM_LBUTTONDOWN: {
|
||||||
|
SetCapture(wnd);
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_mouse_down,
|
||||||
|
.mouse_button = app_mouse_button_left,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
case WM_LBUTTONUP: {
|
||||||
|
ReleaseCapture();
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_mouse_up,
|
||||||
|
.mouse_button = app_mouse_button_left,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
|
|
||||||
|
case WM_RBUTTONDOWN: {
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_mouse_down,
|
||||||
|
.mouse_button = app_mouse_button_right,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
case WM_RBUTTONUP: {
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_mouse_up,
|
||||||
|
.mouse_button = app_mouse_button_right,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
|
|
||||||
|
case WM_MBUTTONDOWN: {
|
||||||
|
SetCapture(wnd);
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_mouse_down,
|
||||||
|
.mouse_button = app_mouse_button_middle,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
case WM_MBUTTONUP: {
|
||||||
|
ReleaseCapture();
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_mouse_up,
|
||||||
|
.mouse_button = app_mouse_button_middle,
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case WM_MOUSEWHEEL: {
|
||||||
|
int zDelta = GET_WHEEL_DELTA_WPARAM(wparam);
|
||||||
|
w32_push_event((app_event_t){
|
||||||
|
.kind = app_event_kind_mouse_wheel,
|
||||||
|
.mouse_wheel_delta = (v3f64_t){0, zDelta},
|
||||||
|
});
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case WM_CHAR: {
|
||||||
|
//https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names
|
||||||
|
// WM_UNICHAR
|
||||||
|
/*
|
||||||
|
I looked closer to how you process WM_CHAR in example code and I believe it is very wrong. wParam doesn't contain two ushorts joined in one 32-bit value. It is always one UTF-16 value. That means 16-bits. If Windows wants to send you unicode codepoint with value >0xFFFF, then it sends two UTF-16 WM_CHAR messages. Each with one part of UTF-16 surrogate pair. So your first WM_CHAR needs to remember it, and second one construct full unicode codepoint. For example, this is mentioned here: http://www.catch22.net/tuts/unicode-text-editing
|
||||||
|
*/
|
||||||
|
} break
|
||||||
|
|
||||||
|
|
||||||
default: return DefWindowProcW(wnd, msg, wparam, lparam);
|
default: return DefWindowProcW(wnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
|
app_event_list_t w32_get_events(ma_arena_t *arena) {
|
||||||
typedef enum W32_PROCESS_DPI_AWARENESS {
|
w32_event_arena = arena;
|
||||||
W32_PROCESS_DPI_UNAWARE = 0,
|
memory_zero(&w32_event_list, sizeof(w32_event_list));
|
||||||
W32_PROCESS_SYSTEM_DPI_AWARE = 1,
|
|
||||||
W32_PROCESS_PER_MONITOR_DPI_AWARE = 2
|
|
||||||
} W32_PROCESS_DPI_AWARENESS;
|
|
||||||
|
|
||||||
typedef unsigned MU_TimeBeginPeriod(unsigned);
|
MSG msg;
|
||||||
typedef HRESULT MU_SetProcessDpiAwareness(W32_PROCESS_DPI_AWARENESS);
|
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
HMODULE shcore = LoadLibraryA("Shcore.dll");
|
DispatchMessageW(&msg);
|
||||||
if (shcore) {
|
|
||||||
MU_SetProcessDpiAwareness *set_dpi_awr = (MU_SetProcessDpiAwareness *)GetProcAddress(shcore, "SetProcessDpiAwareness");
|
|
||||||
if (set_dpi_awr) {
|
|
||||||
HRESULT hr = set_dpi_awr(W32_PROCESS_PER_MONITOR_DPI_AWARE);
|
|
||||||
assert(SUCCEEDED(hr) && "Failed to set dpi awareness");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HMODULE winmm = LoadLibraryA("winmm.dll");
|
return w32_event_list;
|
||||||
if (winmm) {
|
}
|
||||||
MU_TimeBeginPeriod *timeBeginPeriod = (MU_TimeBeginPeriod *)GetProcAddress(winmm, "timeBeginPeriod");
|
|
||||||
if (timeBeginPeriod) {
|
|
||||||
if (timeBeginPeriod(1) == 0) {
|
|
||||||
w32_good_scheduling = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WNDCLASSW wc = {0};
|
///////////////////////////////
|
||||||
{
|
// canvas functions
|
||||||
wc.lpfnWndProc = w32_window_proc;
|
|
||||||
wc.hInstance = GetModuleHandleW(NULL);
|
|
||||||
wc.lpszClassName = L"HelloClassName";
|
|
||||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
|
||||||
wc.hIcon = NULL; // LoadIcon(wc.hInstance, IDI_APPLICATION);
|
|
||||||
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
|
|
||||||
ATOM result = RegisterClassW(&wc);
|
|
||||||
assert(result != 0);
|
|
||||||
w32_wc = wc;
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT window_rect = {0};
|
typedef struct w32_canvas_t w32_canvas_t;
|
||||||
{
|
struct w32_canvas_t {
|
||||||
window_rect.left = 0;
|
u32 *memory;
|
||||||
window_rect.right = 1280;
|
HWND window_handle;
|
||||||
window_rect.bottom = 732;
|
HBITMAP dib;
|
||||||
window_rect.top = 12;
|
HDC dib_dc;
|
||||||
AdjustWindowRectEx(&window_rect, WS_OVERLAPPEDWINDOW, false, 0);
|
v2f64_t window_size;
|
||||||
}
|
};
|
||||||
w32_window_handle = CreateWindowW(w32_wc.lpszClassName, L"Zzz... Window, hello!", WS_OVERLAPPEDWINDOW, window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, NULL, NULL, hInstance, NULL);
|
|
||||||
assert(w32_window_handle);
|
|
||||||
|
|
||||||
w32_dc = GetDC(w32_window_handle);
|
w32_canvas_t w32_create_canvas(HWND window_handle) {
|
||||||
assert(w32_dc);
|
v2f64_t window_size = w32_get_window_size(window_handle);
|
||||||
ShowWindow(w32_window_handle, SW_SHOW);
|
w32_canvas_t result = {.window_handle = window_handle, .window_size = window_size};
|
||||||
|
HDC window_dc = GetDC(window_handle);
|
||||||
// @todo: rebuild on resize
|
|
||||||
// Create a writable backbuffer bitmap
|
|
||||||
uint32_t *mem = 0;
|
|
||||||
BITMAPINFO bminfo = {0};
|
BITMAPINFO bminfo = {0};
|
||||||
{
|
{
|
||||||
bminfo.bmiHeader.biSize = sizeof(bminfo.bmiHeader);
|
bminfo.bmiHeader.biSize = sizeof(bminfo.bmiHeader);
|
||||||
bminfo.bmiHeader.biWidth = (LONG)1280;
|
bminfo.bmiHeader.biWidth = (LONG)window_size.x;
|
||||||
bminfo.bmiHeader.biHeight = (LONG)720;
|
bminfo.bmiHeader.biHeight = (LONG)window_size.y;
|
||||||
bminfo.bmiHeader.biPlanes = 1;
|
bminfo.bmiHeader.biPlanes = 1;
|
||||||
bminfo.bmiHeader.biBitCount = 32;
|
bminfo.bmiHeader.biBitCount = 32;
|
||||||
bminfo.bmiHeader.biCompression = BI_RGB; // AA RR GG BB
|
bminfo.bmiHeader.biCompression = BI_RGB; // AA RR GG BB
|
||||||
bminfo.bmiHeader.biXPelsPerMeter = 1;
|
bminfo.bmiHeader.biXPelsPerMeter = 1;
|
||||||
bminfo.bmiHeader.biYPelsPerMeter = 1;
|
bminfo.bmiHeader.biYPelsPerMeter = 1;
|
||||||
}
|
}
|
||||||
HBITMAP dib = CreateDIBSection(w32_dc, &bminfo, DIB_RGB_COLORS, (void **)&mem, 0, 0);
|
result.dib = CreateDIBSection(window_dc, &bminfo, DIB_RGB_COLORS, (void **)&result.memory, 0, 0);
|
||||||
HDC dib_dc = CreateCompatibleDC(w32_dc);
|
result.dib_dc = CreateCompatibleDC(window_dc);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void w32_destroy_canvas(w32_canvas_t *canvas) {
|
||||||
|
if (canvas->memory) {
|
||||||
|
DeleteDC(canvas->dib_dc);
|
||||||
|
DeleteObject(canvas->dib);
|
||||||
|
memory_zero(canvas, sizeof(*canvas));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void w32_present_canvas(w32_canvas_t *canvas) {
|
||||||
|
if (canvas->memory) {
|
||||||
|
SelectObject(canvas->dib_dc, canvas->dib);
|
||||||
|
HDC window_dc = GetDC(canvas->window_handle);
|
||||||
|
BitBlt(window_dc, 0, 0, (int)canvas->window_size.x, (int)canvas->window_size.y, canvas->dib_dc, 0, 0, SRCCOPY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void w32_try_resizing_canvas(w32_canvas_t *canvas, HWND window_handle) {
|
||||||
|
v2f64_t window_size = w32_get_window_size(window_handle);
|
||||||
|
if (canvas->window_size.x != window_size.x || canvas->window_size.y != window_size.y) {
|
||||||
|
w32_destroy_canvas(canvas);
|
||||||
|
*canvas = w32_create_canvas(window_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
|
||||||
|
tcx.temp = ma_create(ma_default_reserve_size);
|
||||||
|
|
||||||
|
// Set DPI aware, @todo: verify / new way to do this | @todo: get dpi ratio
|
||||||
|
{
|
||||||
|
typedef enum W32_PROCESS_DPI_AWARENESS {
|
||||||
|
W32_PROCESS_DPI_UNAWARE = 0,
|
||||||
|
W32_PROCESS_SYSTEM_DPI_AWARE = 1,
|
||||||
|
W32_PROCESS_PER_MONITOR_DPI_AWARE = 2
|
||||||
|
} W32_PROCESS_DPI_AWARENESS;
|
||||||
|
typedef HRESULT MU_SetProcessDpiAwareness(W32_PROCESS_DPI_AWARENESS);
|
||||||
|
|
||||||
|
HMODULE shcore = LoadLibraryA("Shcore.dll");
|
||||||
|
if (shcore) {
|
||||||
|
MU_SetProcessDpiAwareness *set_dpi_awr = (MU_SetProcessDpiAwareness *)GetProcAddress(shcore, "SetProcessDpiAwareness");
|
||||||
|
if (set_dpi_awr) {
|
||||||
|
HRESULT hr = set_dpi_awr(W32_PROCESS_PER_MONITOR_DPI_AWARE);
|
||||||
|
assert(SUCCEEDED(hr) && "Failed to set dpi awareness");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup better scheduling, @todo: should we do this?
|
||||||
|
{
|
||||||
|
typedef unsigned MU_TimeBeginPeriod(unsigned);
|
||||||
|
|
||||||
|
HMODULE winmm = LoadLibraryA("winmm.dll");
|
||||||
|
if (winmm) {
|
||||||
|
MU_TimeBeginPeriod *timeBeginPeriod = (MU_TimeBeginPeriod *)GetProcAddress(winmm, "timeBeginPeriod");
|
||||||
|
if (timeBeginPeriod) {
|
||||||
|
if (timeBeginPeriod(1) == 0) {
|
||||||
|
w32_good_scheduling = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create window
|
||||||
|
{
|
||||||
|
WNDCLASSW wc = {0};
|
||||||
|
{
|
||||||
|
wc.lpfnWndProc = w32_window_proc;
|
||||||
|
wc.hInstance = GetModuleHandleW(NULL);
|
||||||
|
wc.lpszClassName = L"HelloClassName";
|
||||||
|
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||||
|
wc.hIcon = NULL; // LoadIcon(wc.hInstance, IDI_APPLICATION);
|
||||||
|
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
|
||||||
|
ATOM result = RegisterClassW(&wc);
|
||||||
|
assert(result != 0);
|
||||||
|
w32_wc = wc;
|
||||||
|
}
|
||||||
|
|
||||||
|
f64 primary_monitor_size_x = (f64)GetSystemMetrics(SM_CXSCREEN);
|
||||||
|
f64 primary_monitor_size_y = (f64)GetSystemMetrics(SM_CYSCREEN);
|
||||||
|
RECT window_rect = {0};
|
||||||
|
{
|
||||||
|
window_rect.left = 0 + 0;
|
||||||
|
window_rect.right = 0 + (int)(primary_monitor_size_x * 0.8);
|
||||||
|
window_rect.bottom = 30 + (int)(primary_monitor_size_y * 0.8);
|
||||||
|
window_rect.top = 30 + 0;
|
||||||
|
AdjustWindowRectEx(&window_rect, WS_OVERLAPPEDWINDOW, false, 0);
|
||||||
|
}
|
||||||
|
w32_window_handle = CreateWindowW(w32_wc.lpszClassName, L"Zzz... Window, hello!", WS_OVERLAPPEDWINDOW, window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, NULL, NULL, hInstance, NULL);
|
||||||
|
assert(w32_window_handle);
|
||||||
|
|
||||||
|
w32_dc = GetDC(w32_window_handle);
|
||||||
|
assert(w32_dc);
|
||||||
|
|
||||||
|
b32 ok = w32_load_wgl_fns();
|
||||||
|
assert(ok);
|
||||||
|
|
||||||
|
ok = w32_create_opengl_context(w32_dc, 4, 5);
|
||||||
|
assert(ok);
|
||||||
|
|
||||||
|
ShowWindow(w32_window_handle, SW_SHOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// w32_canvas_t canvas = w32_create_canvas(w32_window_handle);
|
||||||
|
|
||||||
|
f64 time_frame_start = os_seconds_now();
|
||||||
|
f64 time_delta = 0.01666666666666;
|
||||||
|
f64 time_total = 0.0;
|
||||||
|
f64 time_update = 0.0;
|
||||||
|
|
||||||
|
u64 consecutive_missed_frames = 0;
|
||||||
|
u64 missed_frames = 0;
|
||||||
|
u64 frame = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
MSG msg;
|
app_event_list_t event_list = w32_get_events(tcx.temp);
|
||||||
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
||||||
if (msg.message == WM_QUIT) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessageW(&msg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i32 y = 0; y < 720; y++) {
|
for (app_event_t *ev = event_list.first; ev; ev = ev->next) {
|
||||||
for (i32 x = 0; x < 1280; x++) {
|
if (ev->kind == app_event_kind_key_down && ev->key == app_key_escape) {
|
||||||
mem[x + y * 1280] = 0xFFFF0000;
|
ExitProcess(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectObject(dib_dc, dib);
|
// w32_try_resizing_canvas(&canvas, w32_window_handle);
|
||||||
BitBlt(w32_dc, 0, 0, 1280, 720, dib_dc, 0, 0, SRCCOPY);
|
// debugf("time_update: %f", time_update);
|
||||||
Sleep(10);
|
|
||||||
|
#if 0
|
||||||
|
for (i32 y = 0; y < canvas.window_size.y; y++) {
|
||||||
|
for (i32 x = 0; x < canvas.window_size.x; x++) {
|
||||||
|
canvas.memory[x + y * (int)canvas.window_size.x] = 0xFFFF0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// w32_present_canvas(&canvas);
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// end of frame timings
|
||||||
|
|
||||||
|
ma_set0(tcx.temp);
|
||||||
|
|
||||||
|
f64 time_update_partial = os_seconds_now() - time_frame_start;
|
||||||
|
time_update = time_update_partial;
|
||||||
|
if (time_update < time_delta) {
|
||||||
|
consecutive_missed_frames = 0;
|
||||||
|
|
||||||
|
// @todo: we are currently busy looping when we don't get the good schduling
|
||||||
|
// is that actually a good tactic??
|
||||||
|
if (w32_good_scheduling) {
|
||||||
|
f64 time_to_sleep = time_delta - time_update;
|
||||||
|
f64 time_to_sleep_in_ms = (time_to_sleep * 1000.0) - 1.0;
|
||||||
|
if (time_to_sleep > 0.0) {
|
||||||
|
DWORD ms = (DWORD)time_to_sleep_in_ms;
|
||||||
|
if (ms) {
|
||||||
|
Sleep(ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// busy loop if we dont have good scheduling
|
||||||
|
// or we woke up early
|
||||||
|
time_update = os_seconds_now() - time_frame_start;
|
||||||
|
while (time_update < time_delta) {
|
||||||
|
time_update = os_seconds_now() - time_frame_start;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
missed_frames += 1;
|
||||||
|
consecutive_missed_frames += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame += 1;
|
||||||
|
|
||||||
|
// @todo:
|
||||||
|
// should this be time_delta or time_update ????
|
||||||
|
// probably want the locked frame rate and total should reflect that, so choosing
|
||||||
|
// time_delta seems the correct choice but not really sure what is correct.
|
||||||
|
time_total += time_delta;
|
||||||
|
time_frame_start = os_seconds_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
270
src/app/app_win32_opengl.c
Normal file
270
src/app/app_win32_opengl.c
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
// first load the opengl loading functions
|
||||||
|
fn b32 w32_load_wgl_fns(void);
|
||||||
|
|
||||||
|
// then create opengl context for window
|
||||||
|
fn b32 w32_create_opengl_context(HDC window_handle_dc, i32 opengl_major, i32 opengl_minor);
|
||||||
|
|
||||||
|
// then you can use this to load opengl functions -
|
||||||
|
// either pass this to glad or load them manually
|
||||||
|
fn void *w32_load_opengl_fn(const char *proc);
|
||||||
|
|
||||||
|
// compile time options
|
||||||
|
#define W32_OPENGL_DEBUG 1
|
||||||
|
#define W32_ENABLE_MULTISAMPLING 1
|
||||||
|
|
||||||
|
// Symbols taken from GLFW
|
||||||
|
//
|
||||||
|
// Executables (but not DLLs) exporting this symbol with this value will be
|
||||||
|
// automatically directed to the high-performance GPU on Nvidia Optimus systems
|
||||||
|
// with up-to-date drivers
|
||||||
|
//
|
||||||
|
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
||||||
|
|
||||||
|
// Executables (but not DLLs) exporting this symbol with this value will be
|
||||||
|
// automatically directed to the high-performance GPU on AMD PowerXpress systems
|
||||||
|
// with up-to-date drivers
|
||||||
|
//
|
||||||
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||||
|
|
||||||
|
typedef HGLRC MU_wglCreateContext(HDC unnamedParam1);
|
||||||
|
typedef BOOL MU_wglMakeCurrent(HDC unnamedParam1, HGLRC unnamedParam2);
|
||||||
|
typedef BOOL MU_wglDeleteContext(HGLRC unnamedParam1);
|
||||||
|
typedef void *MU_glGetProcAddress(const char *);
|
||||||
|
typedef const char *MU_wglGetExtensionsStringARB(HDC hdc);
|
||||||
|
typedef BOOL MU_wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const float *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
||||||
|
typedef HGLRC MU_wglCreateContextAttribsARB(HDC hDC, HGLRC hshareContext, const int *attribList);
|
||||||
|
typedef BOOL MU_wglSwapIntervalEXT(int interval);
|
||||||
|
|
||||||
|
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||||
|
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||||
|
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||||
|
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||||
|
#define WGL_TYPE_RGBA_ARB 0x202B
|
||||||
|
#define WGL_COLOR_BITS_ARB 0x2014
|
||||||
|
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||||
|
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||||
|
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||||
|
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||||
|
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||||
|
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||||
|
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||||
|
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||||
|
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
|
||||||
|
#define WGL_SAMPLES_ARB 0x2042
|
||||||
|
|
||||||
|
global MU_wglChoosePixelFormatARB *wglChoosePixelFormatARB;
|
||||||
|
global MU_wglCreateContextAttribsARB *wglCreateContextAttribsARB;
|
||||||
|
global MU_wglSwapIntervalEXT *wglSwapIntervalEXT;
|
||||||
|
|
||||||
|
global MU_glGetProcAddress *wgl_get_proc_address;
|
||||||
|
global void *(*gl_get_proc_address)(const char *str);
|
||||||
|
global HMODULE opengl_hmodule;
|
||||||
|
|
||||||
|
global HGLRC(*mu_wglCreateContext)(HDC unnamedParam1);
|
||||||
|
global BOOL(*mu_wglMakeCurrent)(HDC unnamedParam1, HGLRC unnamedParam2);
|
||||||
|
global BOOL(*mu_wglDeleteContext)(HGLRC unnamedParam1);
|
||||||
|
|
||||||
|
// compares src string with dstlen characters from dst, returns 1 if they are equal, 0 if not
|
||||||
|
fn int w32_are_strings_equal(const char *src, const char *dst, size_t dstlen) {
|
||||||
|
while (*src && dstlen-- && *dst) {
|
||||||
|
if (*src++ != *dst++) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (dstlen && *src == *dst) || (!dstlen && *src == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void *w32_load_opengl_fn(const char *proc) {
|
||||||
|
void *func = wgl_get_proc_address(proc);
|
||||||
|
if (!func) {
|
||||||
|
func = GetProcAddress(opengl_hmodule, proc);
|
||||||
|
}
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b32 w32_load_wgl_fns(void) {
|
||||||
|
HMODULE opengl32 = LoadLibraryA("opengl32");
|
||||||
|
assert(opengl32);
|
||||||
|
if (opengl32) {
|
||||||
|
opengl_hmodule = opengl32;
|
||||||
|
wgl_get_proc_address = (MU_glGetProcAddress *)GetProcAddress(opengl32, "wglGetProcAddress");
|
||||||
|
gl_get_proc_address = w32_load_opengl_fn;
|
||||||
|
mu_wglCreateContext = (MU_wglCreateContext *)GetProcAddress(opengl32, "wglCreateContext");
|
||||||
|
mu_wglMakeCurrent = (MU_wglMakeCurrent *)GetProcAddress(opengl32, "wglMakeCurrent");
|
||||||
|
mu_wglDeleteContext = (MU_wglDeleteContext *)GetProcAddress(opengl32, "wglDeleteContext");
|
||||||
|
}
|
||||||
|
if (opengl32 == NULL || mu_wglCreateContext == NULL || gl_get_proc_address == NULL || mu_wglMakeCurrent == NULL || mu_wglDeleteContext == NULL) {
|
||||||
|
assert(!"Failed to load Opengl wgl functions from opengl32.lib");
|
||||||
|
}
|
||||||
|
|
||||||
|
// to get WGL functions we need valid GL context, so create dummy window for dummy GL contetx
|
||||||
|
HWND dummy = CreateWindowExW(
|
||||||
|
0, L"STATIC", L"DummyWindow", WS_OVERLAPPED,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
assert(dummy && "Failed to create dummy window");
|
||||||
|
|
||||||
|
HDC dc = GetDC(dummy);
|
||||||
|
assert(dc && "Failed to get device context for dummy window");
|
||||||
|
|
||||||
|
PIXELFORMATDESCRIPTOR desc = {0};
|
||||||
|
{
|
||||||
|
desc.nSize = sizeof(desc);
|
||||||
|
desc.nVersion = 1;
|
||||||
|
desc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||||
|
desc.iPixelType = PFD_TYPE_RGBA;
|
||||||
|
desc.cColorBits = 24;
|
||||||
|
};
|
||||||
|
|
||||||
|
int format = ChoosePixelFormat(dc, &desc);
|
||||||
|
if (!format) {
|
||||||
|
assert(!"Cannot choose OpenGL pixel format for dummy window!");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ok = DescribePixelFormat(dc, format, sizeof(desc), &desc);
|
||||||
|
assert(ok && "Failed to describe OpenGL pixel format");
|
||||||
|
|
||||||
|
// reason to create dummy window is that SetPixelFormat can be called only once for the window
|
||||||
|
if (!SetPixelFormat(dc, format, &desc)) {
|
||||||
|
assert(!"Cannot set OpenGL pixel format for dummy window!");
|
||||||
|
}
|
||||||
|
|
||||||
|
HGLRC rc = mu_wglCreateContext(dc);
|
||||||
|
assert(rc && "Failed to create OpenGL context for dummy window");
|
||||||
|
|
||||||
|
ok = mu_wglMakeCurrent(dc, rc);
|
||||||
|
assert(ok && "Failed to make current OpenGL context for dummy window");
|
||||||
|
|
||||||
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_extensions_string.txt
|
||||||
|
MU_wglGetExtensionsStringARB *wglGetExtensionsStringARB = (MU_wglGetExtensionsStringARB *)gl_get_proc_address("wglGetExtensionsStringARB");
|
||||||
|
if (!wglGetExtensionsStringARB) {
|
||||||
|
assert(!"OpenGL does not support WGL_ARB_extensions_string extension!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ext = wglGetExtensionsStringARB(dc);
|
||||||
|
assert(ext && "Failed to get OpenGL WGL extension string");
|
||||||
|
|
||||||
|
const char *start = ext;
|
||||||
|
for (;;) {
|
||||||
|
while (*ext != 0 && *ext != ' ') {
|
||||||
|
ext++;
|
||||||
|
}
|
||||||
|
size_t length = ext - start;
|
||||||
|
if (w32_are_strings_equal("WGL_ARB_pixel_format", start, length)) {
|
||||||
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt
|
||||||
|
wglChoosePixelFormatARB = (MU_wglChoosePixelFormatARB *)gl_get_proc_address("wglChoosePixelFormatARB");
|
||||||
|
}
|
||||||
|
else if (w32_are_strings_equal("WGL_ARB_create_context", start, length)) {
|
||||||
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_create_context.txt
|
||||||
|
wglCreateContextAttribsARB = (MU_wglCreateContextAttribsARB *)gl_get_proc_address("wglCreateContextAttribsARB");
|
||||||
|
}
|
||||||
|
else if (w32_are_strings_equal("WGL_EXT_swap_control", start, length)) {
|
||||||
|
// https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_swap_control.txt
|
||||||
|
wglSwapIntervalEXT = (MU_wglSwapIntervalEXT *)gl_get_proc_address("wglSwapIntervalEXT");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ext == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext++;
|
||||||
|
start = ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wglChoosePixelFormatARB || !wglCreateContextAttribsARB || !wglSwapIntervalEXT) {
|
||||||
|
assert(!"OpenGL does not support required WGL extensions for modern context!");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ok_b = mu_wglMakeCurrent(NULL, NULL);
|
||||||
|
assert(ok_b);
|
||||||
|
|
||||||
|
ok_b = mu_wglDeleteContext(rc);
|
||||||
|
assert(ok_b);
|
||||||
|
|
||||||
|
ok = ReleaseDC(dummy, dc);
|
||||||
|
assert(ok);
|
||||||
|
|
||||||
|
ok_b = DestroyWindow(dummy);
|
||||||
|
assert(ok_b);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b32 w32_create_opengl_context(HDC window_handle_dc, i32 opengl_major, i32 opengl_minor) {
|
||||||
|
// set pixel format for OpenGL context
|
||||||
|
int attrib[] =
|
||||||
|
{
|
||||||
|
WGL_DRAW_TO_WINDOW_ARB,
|
||||||
|
true,
|
||||||
|
WGL_SUPPORT_OPENGL_ARB,
|
||||||
|
true,
|
||||||
|
WGL_DOUBLE_BUFFER_ARB,
|
||||||
|
true,
|
||||||
|
WGL_PIXEL_TYPE_ARB,
|
||||||
|
WGL_TYPE_RGBA_ARB,
|
||||||
|
WGL_COLOR_BITS_ARB,
|
||||||
|
32,
|
||||||
|
WGL_DEPTH_BITS_ARB,
|
||||||
|
24,
|
||||||
|
WGL_STENCIL_BITS_ARB,
|
||||||
|
8,
|
||||||
|
|
||||||
|
// uncomment for sRGB framebuffer, from WGL_ARB_framebuffer_sRGB extension
|
||||||
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_framebuffer_sRGB.txt
|
||||||
|
// WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE,
|
||||||
|
|
||||||
|
// uncomment for multisampeld framebuffer, from WGL_ARB_multisample extension
|
||||||
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_multisample.txt
|
||||||
|
#if W32_ENABLE_MULTISAMPLING
|
||||||
|
WGL_SAMPLE_BUFFERS_ARB,
|
||||||
|
1,
|
||||||
|
WGL_SAMPLES_ARB,
|
||||||
|
4, // 4x MSAA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
int format;
|
||||||
|
UINT formats;
|
||||||
|
if (!wglChoosePixelFormatARB(window_handle_dc, attrib, 0, 1, &format, &formats) || formats == 0) {
|
||||||
|
assert(!"OpenGL does not support required pixel format!");
|
||||||
|
}
|
||||||
|
|
||||||
|
PIXELFORMATDESCRIPTOR desc = {0};
|
||||||
|
desc.nSize = sizeof(desc);
|
||||||
|
int ok = DescribePixelFormat(window_handle_dc, format, sizeof(desc), &desc);
|
||||||
|
assert(ok && "Failed to describe OpenGL pixel format");
|
||||||
|
|
||||||
|
if (!SetPixelFormat(window_handle_dc, format, &desc)) {
|
||||||
|
assert(!"Cannot set OpenGL selected pixel format!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create modern OpenGL context
|
||||||
|
{
|
||||||
|
int attrib[] =
|
||||||
|
{
|
||||||
|
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
||||||
|
opengl_major,
|
||||||
|
WGL_CONTEXT_MINOR_VERSION_ARB,
|
||||||
|
opengl_minor,
|
||||||
|
WGL_CONTEXT_PROFILE_MASK_ARB,
|
||||||
|
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||||
|
|
||||||
|
#if W32_OPENGL_DEBUG
|
||||||
|
WGL_CONTEXT_FLAGS_ARB,
|
||||||
|
WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
HGLRC rc = wglCreateContextAttribsARB(window_handle_dc, 0, attrib);
|
||||||
|
assert(rc && "Cannot create modern OpenGL context! OpenGL version not supported?");
|
||||||
|
|
||||||
|
BOOL ok = mu_wglMakeCurrent(window_handle_dc, rc);
|
||||||
|
assert(ok && "Failed to make current OpenGL context");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -1,8 +1,15 @@
|
|||||||
typedef struct thread_ctx_t thread_ctx_t;
|
typedef struct thread_ctx_t thread_ctx_t;
|
||||||
struct thread_ctx_t {
|
struct thread_ctx_t {
|
||||||
ma_arena_t scratch[3];
|
ma_arena_t scratch[3];
|
||||||
ma_arena_t perm;
|
|
||||||
ma_arena_t *temp; // application specific arena
|
ma_arena_t *temp; // application specific arena
|
||||||
|
|
||||||
|
// I probably want to discourage using it implicitly like: tcx.perm, instead just pass it around
|
||||||
|
// to functions that allocate pernament memory. temp and scratch very nicely create reusable code
|
||||||
|
// perm is basically global state so it would be nice to annotate which functions are reusable
|
||||||
|
// and which functions have state
|
||||||
|
ma_arena_t _perm;
|
||||||
|
|
||||||
|
|
||||||
logger_t log;
|
logger_t log;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ fn void default_log_proc(log_event_t ev);
|
|||||||
|
|
||||||
#define program_version "---"
|
#define program_version "---"
|
||||||
#if PLATFORM_DEBUG_ASSERT
|
#if PLATFORM_DEBUG_ASSERT
|
||||||
#define assert(x) (!(x) && (os_error_box(FILE_AND_LINE ": internal program error! assertion failed, program version: " program_version "\n"), debug_break()))
|
#define assert(x) (!(x) && (os_error_box(FILE_AND_LINE ": internal program error! assertion failed: " #x ", program version: " program_version "\n"), debug_break()))
|
||||||
#else
|
#else
|
||||||
#define assert(x) (void)(x)
|
#define assert(x) (void)(x)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,9 +9,27 @@ struct date_t {
|
|||||||
u16 year;
|
u16 year;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
typedef struct core_funcs_t core_funcs_t;
|
||||||
|
struct core_funcs_t {
|
||||||
|
void (*error_box)(char *str);
|
||||||
|
void (*console_log)(char *str);
|
||||||
|
|
||||||
|
date_t (*date_now)(void);
|
||||||
|
f64 (*milliseconds_now)(void);
|
||||||
|
|
||||||
|
void *(*reserve)(usize size);
|
||||||
|
b32 (*commit)(void *p, usize size);
|
||||||
|
b32 (*release)(void *p);
|
||||||
|
b32 (*decommit)(void *p, usize size);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
fn void os_error_box(char *str);
|
fn void os_error_box(char *str);
|
||||||
fn void os_console_log(char *str);
|
fn void os_console_log(char *str);
|
||||||
fn date_t os_date_now(void);
|
fn date_t os_date_now(void);
|
||||||
|
fn f64 os_milliseconds_now(void);
|
||||||
|
|
||||||
fn void *os_vmem_reserve(usize size);
|
fn void *os_vmem_reserve(usize size);
|
||||||
fn b32 os_vmem_commit(void *p, usize size);
|
fn b32 os_vmem_commit(void *p, usize size);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ fn u64 os_get_microseconds(void) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f64 os_get_milliseconds(void) {
|
fn f64 os_milliseconds_now(void) {
|
||||||
u64 micros = os_get_microseconds();
|
u64 micros = os_get_microseconds();
|
||||||
f64 result = (f64)micros / 1000.0;
|
f64 result = (f64)micros / 1000.0;
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ fn double strtod(const char *str, char **end_unused) {
|
|||||||
return wasm_parse_float((isize)str, str_len((char *)str));
|
return wasm_parse_float((isize)str, str_len((char *)str));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f64 os_get_milliseconds(void) {
|
fn f64 os_milliseconds_now(void) {
|
||||||
return wasm_get_milliseconds();
|
return wasm_get_milliseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,10 +48,10 @@ fn void core_init(void) {
|
|||||||
isize page_count = __builtin_wasm_memory_size(0);
|
isize page_count = __builtin_wasm_memory_size(0);
|
||||||
u8 *memory = (u8 *)&__heap_base;
|
u8 *memory = (u8 *)&__heap_base;
|
||||||
usize memory_size = page_count * (page_size) - (isize)memory;
|
usize memory_size = page_count * (page_size) - (isize)memory;
|
||||||
tcx.perm.data = memory;
|
tcx._perm.data = memory;
|
||||||
tcx.perm.commit = tcx.perm.reserve = memory_size;
|
tcx._perm.commit = tcx._perm.reserve = memory_size;
|
||||||
|
|
||||||
ma_push_arena_ex(&tcx.perm, &tcx.scratch[0], mib(1));
|
ma_push_arena_ex(&tcx._perm, &tcx.scratch[0], mib(1));
|
||||||
ma_push_arena_ex(&tcx.perm, &tcx.scratch[1], kib(256));
|
ma_push_arena_ex(&tcx._perm, &tcx.scratch[1], kib(256));
|
||||||
ma_push_arena_ex(&tcx.perm, &tcx.scratch[2], kib(64));
|
ma_push_arena_ex(&tcx._perm, &tcx.scratch[2], kib(64));
|
||||||
}
|
}
|
||||||
@@ -32,28 +32,23 @@ fn date_t os_date_now(void) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
global LARGE_INTEGER win32__performance_frequency;
|
fn f64 os_seconds_now(void) {
|
||||||
global u64 win32_performance_frequency = 1;
|
static int64_t counts_per_second;
|
||||||
|
if (counts_per_second == 0) {
|
||||||
fn u64 os_get_microseconds(void) {
|
LARGE_INTEGER freq;
|
||||||
if (win32__performance_frequency.QuadPart == 0) {
|
QueryPerformanceFrequency(&freq);
|
||||||
win32__performance_frequency.QuadPart = 1; // don't query more then one time
|
counts_per_second = freq.QuadPart;
|
||||||
if(QueryPerformanceFrequency(&win32__performance_frequency)) {
|
|
||||||
win32_performance_frequency = win32__performance_frequency.QuadPart;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 result = 0;
|
LARGE_INTEGER time;
|
||||||
LARGE_INTEGER n;
|
QueryPerformanceCounter(&time);
|
||||||
if (QueryPerformanceCounter(&n)) {
|
f64 result = (f64)time.QuadPart / (f64)counts_per_second;
|
||||||
result = (n.QuadPart*million(1))/win32_performance_frequency;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f64 os_get_milliseconds(void) {
|
fn f64 os_milliseconds_now(void) {
|
||||||
u64 micros = os_get_microseconds();
|
f64 secs = os_seconds_now();
|
||||||
f64 result = (f64)micros / 1000.0;
|
f64 result = secs * 1000;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,45 +43,45 @@ fn void draw_rect(r2f64_t rect, v4f32_t color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
gfx2d_kind_null,
|
gfx_kind_null,
|
||||||
gfx2d_kind_clear,
|
gfx_kind_clear,
|
||||||
gfx2d_kind_draw_rect,
|
gfx_kind_draw_rect,
|
||||||
gfx2d_kind_draw_text,
|
gfx_kind_draw_text,
|
||||||
gfx2d_kind_set_clip,
|
gfx_kind_set_clip,
|
||||||
} gfx2d_kind_t;
|
} gfx_kind_t;
|
||||||
|
|
||||||
typedef struct gfx2d_cmd_t gfx2d_cmd_t;
|
typedef struct gfx_cmd_t gfx_cmd_t;
|
||||||
struct gfx2d_cmd_t {
|
struct gfx_cmd_t {
|
||||||
gfx2d_cmd_t *next;
|
gfx_cmd_t *next;
|
||||||
gfx2d_kind_t kind;
|
gfx_kind_t kind;
|
||||||
r2f64_t rect;
|
r2f64_t rect;
|
||||||
v4f32_t color;
|
v4f32_t color;
|
||||||
s8_t text;
|
s8_t text;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct gfx2d_t gfx2d_t;
|
typedef struct gfx_t gfx_t;
|
||||||
struct gfx2d_t {
|
struct gfx_t {
|
||||||
gfx2d_cmd_t *first;
|
gfx_cmd_t *first;
|
||||||
gfx2d_cmd_t *last;
|
gfx_cmd_t *last;
|
||||||
app_event_t *ev;
|
app_event_t *ev;
|
||||||
};
|
};
|
||||||
|
|
||||||
void gfx2d_begin(gfx2d_t *gfx, app_event_t *ev) {
|
void gfx_begin(gfx_t *gfx, app_event_t *ev) {
|
||||||
gfx->ev = ev;
|
gfx->ev = ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx2d_end(gfx2d_t *gfx) {
|
void gfx_end(gfx_t *gfx) {
|
||||||
app_event_t *ev = gfx->ev;
|
app_event_t *ev = gfx->ev;
|
||||||
r2f64_t window = (r2f64_t){0, 0, ev->window_size.x, ev->window_size.y};
|
r2f64_t window = (r2f64_t){0, 0, ev->window_size.x, ev->window_size.y};
|
||||||
for (gfx2d_cmd_t *cmd = gfx->first; cmd; cmd = cmd->next) {
|
for (gfx_cmd_t *cmd = gfx->first; cmd; cmd = cmd->next) {
|
||||||
if (cmd->kind == gfx2d_kind_clear) {
|
if (cmd->kind == gfx_kind_clear) {
|
||||||
wasm_clear();
|
wasm_clear();
|
||||||
draw_rect(window, cmd->color);
|
draw_rect(window, cmd->color);
|
||||||
} else if (cmd->kind == gfx2d_kind_draw_rect) {
|
} else if (cmd->kind == gfx_kind_draw_rect) {
|
||||||
draw_rect(cmd->rect, cmd->color);
|
draw_rect(cmd->rect, cmd->color);
|
||||||
} else if (cmd->kind == gfx2d_kind_draw_text) {
|
} else if (cmd->kind == gfx_kind_draw_text) {
|
||||||
draw_text(cmd->rect.min, cmd->color, cmd->text);
|
draw_text(cmd->rect.min, cmd->color, cmd->text);
|
||||||
} else if (cmd->kind == gfx2d_kind_set_clip) {
|
} else if (cmd->kind == gfx_kind_set_clip) {
|
||||||
set_clip(cmd->rect);
|
set_clip(cmd->rect);
|
||||||
} else {
|
} else {
|
||||||
invalid_codepath;
|
invalid_codepath;
|
||||||
@@ -91,46 +91,46 @@ void gfx2d_end(gfx2d_t *gfx) {
|
|||||||
gfx->first = gfx->last = NULL;
|
gfx->first = gfx->last = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx2d_add_cmd(gfx2d_t *gfx, gfx2d_cmd_t cmd) {
|
void gfx_add_cmd(gfx_t *gfx, gfx_cmd_t cmd) {
|
||||||
gfx2d_cmd_t *c = ma_push_type(tcx.temp, gfx2d_cmd_t);
|
gfx_cmd_t *c = ma_push_type(tcx.temp, gfx_cmd_t);
|
||||||
*c = cmd;
|
*c = cmd;
|
||||||
SLLQ_APPEND(gfx->first, gfx->last, c);
|
SLLQ_APPEND(gfx->first, gfx->last, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx2d_clear(gfx2d_t *gfx, v4f32_t color) {
|
void gfx_clear(gfx_t *gfx, v4f32_t color) {
|
||||||
gfx2d_add_cmd(gfx, (gfx2d_cmd_t){
|
gfx_add_cmd(gfx, (gfx_cmd_t){
|
||||||
.kind = gfx2d_kind_clear,
|
.kind = gfx_kind_clear,
|
||||||
.color = color,
|
.color = color,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx2d_rect(gfx2d_t *gfx, r2f64_t rect, v4f32_t color) {
|
void gfx_rect(gfx_t *gfx, r2f64_t rect, v4f32_t color) {
|
||||||
gfx2d_add_cmd(gfx, (gfx2d_cmd_t){
|
gfx_add_cmd(gfx, (gfx_cmd_t){
|
||||||
.kind = gfx2d_kind_draw_rect,
|
.kind = gfx_kind_draw_rect,
|
||||||
.color = color,
|
.color = color,
|
||||||
.rect = rect,
|
.rect = rect,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx2d_set_clip(gfx2d_t *gfx, r2f64_t rect) {
|
void gfx_set_clip(gfx_t *gfx, r2f64_t rect) {
|
||||||
gfx2d_add_cmd(gfx, (gfx2d_cmd_t){
|
gfx_add_cmd(gfx, (gfx_cmd_t){
|
||||||
.kind = gfx2d_kind_set_clip,
|
.kind = gfx_kind_set_clip,
|
||||||
.rect = rect,
|
.rect = rect,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx2d_text(gfx2d_t *gfx, v2f64_t pos, v4f32_t color, s8_t string) {
|
void gfx_text(gfx_t *gfx, v2f64_t pos, v4f32_t color, s8_t string) {
|
||||||
gfx2d_add_cmd(gfx, (gfx2d_cmd_t){
|
gfx_add_cmd(gfx, (gfx_cmd_t){
|
||||||
.kind = gfx2d_kind_draw_text,
|
.kind = gfx_kind_draw_text,
|
||||||
.text = s8_copy(tcx.temp, string),
|
.text = s8_copy(tcx.temp, string),
|
||||||
.color = color,
|
.color = color,
|
||||||
.rect.min = pos,
|
.rect.min = pos,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
void gfx2d_textf(gfx2d_t *gfx, v2f64_t pos, v4f32_t color, char *str, ...) {
|
void gfx_textf(gfx_t *gfx, v2f64_t pos, v4f32_t color, char *str, ...) {
|
||||||
S8_FMT(tcx.temp, str, text);
|
S8_FMT(tcx.temp, str, text);
|
||||||
gfx2d_add_cmd(gfx, (gfx2d_cmd_t){
|
gfx_add_cmd(gfx, (gfx_cmd_t){
|
||||||
.kind = gfx2d_kind_draw_text,
|
.kind = gfx_kind_draw_text,
|
||||||
.text = text,
|
.text = text,
|
||||||
.color = color,
|
.color = color,
|
||||||
.rect.min = pos,
|
.rect.min = pos,
|
||||||
|
|||||||
@@ -5,32 +5,33 @@
|
|||||||
#include "gfx2d/gfx2d.c"
|
#include "gfx2d/gfx2d.c"
|
||||||
// #include "ui.c"
|
// #include "ui.c"
|
||||||
|
|
||||||
gfx2d_t *gfx2d = NULL;
|
gfx_t *gfx = NULL;
|
||||||
|
|
||||||
void app_init(void) {
|
void app_init(void) {
|
||||||
tcx.temp = ma_push_arena(&tcx.perm, mib(1));
|
ma_arena_t *perm = &tcx._perm;
|
||||||
gfx2d = ma_push_type(&tcx.perm, gfx2d_t);
|
tcx.temp = ma_push_arena(perm, mib(1));
|
||||||
|
gfx = ma_push_type(perm, gfx_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_update(app_event_t *events, i32 events_len) {
|
void app_update(void) {
|
||||||
ma_set0(tcx.temp);
|
ma_set0(tcx.temp);
|
||||||
|
|
||||||
for (app_event_t *ev = events; ev < (events + events_len); ev += 1) {
|
for (app_event_t *ev = app_iterate_events(); app_is_event_valid(ev); app_next_event(&ev)) {
|
||||||
// update(ev)
|
// update
|
||||||
}
|
}
|
||||||
|
|
||||||
// These steps should be totally optional!!
|
// These steps should be totally optional!!
|
||||||
{
|
{
|
||||||
app_event_t *ev = events + events_len - 1;
|
app_event_t *ev = app_get_last_event();
|
||||||
f64 delta = app_get_anim_delta_time();
|
f64 delta = app_get_anim_delta_time();
|
||||||
f64 time = app_get_anim_time();
|
f64 time = app_get_anim_time();
|
||||||
|
|
||||||
// animate
|
// animate
|
||||||
// render
|
// render
|
||||||
gfx2d_begin(gfx2d, ev);
|
gfx_begin(gfx, ev);
|
||||||
gfx2d_clear(gfx2d, white_color_global);
|
gfx_clear(gfx, white_color_global);
|
||||||
gfx2d_textf(gfx2d, (v2f64_t){0,0}, black_color_global, "delta: %f, time: %f", delta, time);
|
gfx_textf(gfx, (v2f64_t){0,0}, black_color_global, "delta: %f, time: %f", delta, time);
|
||||||
gfx2d_end(gfx2d);
|
gfx_end(gfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ ui_signal_t ui_interact(app_event_t *ev, r2f64_t rect) {
|
|||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 ui_button(gfx2d_t *gfx, app_event_t *ev, r2f64_t rect, char *title) {
|
b32 ui_button(gfx_t *gfx, app_event_t *ev, r2f64_t rect, char *title) {
|
||||||
v2f64_t text_pos = ui_calc_text_pos(rect, title);
|
v2f64_t text_pos = ui_calc_text_pos(rect, title);
|
||||||
ui_signal_t sig = ui_interact(ev, rect);
|
ui_signal_t sig = ui_interact(ev, rect);
|
||||||
|
|
||||||
@@ -39,15 +39,15 @@ b32 ui_button(gfx2d_t *gfx, app_event_t *ev, r2f64_t rect, char *title) {
|
|||||||
rect_color = primary_color_global;
|
rect_color = primary_color_global;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx2d_set_clip(gfx, rect);
|
gfx_set_clip(gfx, rect);
|
||||||
gfx2d_rect(gfx, rect, rect_color);
|
gfx_rect(gfx, rect, rect_color);
|
||||||
gfx2d_text(gfx, text_pos, text_color, s8_from_char(title));
|
gfx_text(gfx, text_pos, text_color, s8_from_char(title));
|
||||||
gfx2d_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
|
gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
|
||||||
|
|
||||||
return sig.pressed;
|
return sig.pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 ui_checkbox(gfx2d_t *gfx, app_event_t *ev, r2f64_t rect, b32 *value, char *title) {
|
b32 ui_checkbox(gfx_t *gfx, app_event_t *ev, r2f64_t rect, b32 *value, char *title) {
|
||||||
v2f64_t text_pos = ui_calc_text_pos(rect, title);
|
v2f64_t text_pos = ui_calc_text_pos(rect, title);
|
||||||
ui_signal_t sig = ui_interact(ev, rect);
|
ui_signal_t sig = ui_interact(ev, rect);
|
||||||
if (sig.pressed) *value = !*value;
|
if (sig.pressed) *value = !*value;
|
||||||
@@ -61,10 +61,10 @@ b32 ui_checkbox(gfx2d_t *gfx, app_event_t *ev, r2f64_t rect, b32 *value, char *t
|
|||||||
rect_color = v4f32_lerp(rect_color, accent2_color_global, 0.5);
|
rect_color = v4f32_lerp(rect_color, accent2_color_global, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx2d_set_clip(gfx, rect);
|
gfx_set_clip(gfx, rect);
|
||||||
gfx2d_rect(gfx, rect, rect_color);
|
gfx_rect(gfx, rect, rect_color);
|
||||||
gfx2d_text(gfx, text_pos, text_color, s8_from_char(title));
|
gfx_text(gfx, text_pos, text_color, s8_from_char(title));
|
||||||
gfx2d_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
|
gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
|
||||||
|
|
||||||
return *value;
|
return *value;
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ ui_id_t ui_string_to_id(const char *string, i32 len) { // FNV HASH (1a?)
|
|||||||
#define ui_location_id() ui_string_to_id(FILE_AND_LINE, sizeof(FILE_AND_LINE) - 1)
|
#define ui_location_id() ui_string_to_id(FILE_AND_LINE, sizeof(FILE_AND_LINE) - 1)
|
||||||
ui_id_t ui_active_element = {0};
|
ui_id_t ui_active_element = {0};
|
||||||
|
|
||||||
void ui_slider(gfx2d_t *gfx, app_event_t *ev, r2f64_t rect, ui_id_t id, f64 *value, char *title) {
|
void ui_slider(gfx_t *gfx, app_event_t *ev, r2f64_t rect, ui_id_t id, f64 *value, char *title) {
|
||||||
v2f64_t text_pos = ui_calc_text_pos(rect, title);
|
v2f64_t text_pos = ui_calc_text_pos(rect, title);
|
||||||
ui_signal_t sig = ui_interact(ev, rect);
|
ui_signal_t sig = ui_interact(ev, rect);
|
||||||
b32 interacting = false;
|
b32 interacting = false;
|
||||||
@@ -113,24 +113,24 @@ void ui_slider(gfx2d_t *gfx, app_event_t *ev, r2f64_t rect, ui_id_t id, f64 *val
|
|||||||
if (sig.overlapping) slider_color = v4f32_lerp(slider_color, accent2_color_global, 0.2);
|
if (sig.overlapping) slider_color = v4f32_lerp(slider_color, accent2_color_global, 0.2);
|
||||||
v4f32_t text_color = black_color_global;
|
v4f32_t text_color = black_color_global;
|
||||||
|
|
||||||
gfx2d_set_clip(gfx, rect);
|
gfx_set_clip(gfx, rect);
|
||||||
gfx2d_rect(gfx, rect, rect_color);
|
gfx_rect(gfx, rect, rect_color);
|
||||||
gfx2d_rect(gfx, slider_rect, slider_color);
|
gfx_rect(gfx, slider_rect, slider_color);
|
||||||
gfx2d_text(gfx, text_pos, text_color, s8_from_char(title));
|
gfx_text(gfx, text_pos, text_color, s8_from_char(title));
|
||||||
gfx2d_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
|
gfx_set_clip(gfx, r2f64(-1000, -1000, 1000000, 1000000));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_demo(gfx2d_t *gfx, app_event_t *ev) {
|
void ui_demo(gfx_t *gfx, app_event_t *ev) {
|
||||||
if (ev->kind == app_event_kind_mouse_up) {
|
if (ev->kind == app_event_kind_mouse_up) {
|
||||||
ui_active_element = (ui_id_t){0};
|
ui_active_element = (ui_id_t){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
r2f64_t window_rect = (r2f64_t){(v2f64_t){0}, ev->window_size};
|
r2f64_t window_rect = (r2f64_t){(v2f64_t){0}, ev->window_size};
|
||||||
r2f64_t top_bar_rect = r2f64_cut_top(&window_rect, get_font_height() + 20);
|
r2f64_t top_bar_rect = r2f64_cut_top(&window_rect, get_font_height() + 20);
|
||||||
gfx2d_rect(gfx, window_rect, primary_color_global);
|
gfx_rect(gfx, window_rect, primary_color_global);
|
||||||
|
|
||||||
f64 padding = 50;
|
f64 padding = 50;
|
||||||
gfx2d_rect(gfx, top_bar_rect, secondary_color_global);
|
gfx_rect(gfx, top_bar_rect, secondary_color_global);
|
||||||
|
|
||||||
static b32 open_file_panel;
|
static b32 open_file_panel;
|
||||||
f64 open_file_panel_xsize = 0;
|
f64 open_file_panel_xsize = 0;
|
||||||
@@ -143,7 +143,7 @@ void ui_demo(gfx2d_t *gfx, app_event_t *ev) {
|
|||||||
if (ui_checkbox(gfx, ev, rect, &open_file_panel, title)) {
|
if (ui_checkbox(gfx, ev, rect, &open_file_panel, title)) {
|
||||||
}
|
}
|
||||||
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
|
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
|
||||||
gfx2d_rect(gfx, gap_rect, black_color_global);
|
gfx_rect(gfx, gap_rect, black_color_global);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (open_file_panel) {
|
if (open_file_panel) {
|
||||||
@@ -180,7 +180,7 @@ void ui_demo(gfx2d_t *gfx, app_event_t *ev) {
|
|||||||
if (ui_button(gfx, ev, rect, title)) {
|
if (ui_button(gfx, ev, rect, title)) {
|
||||||
}
|
}
|
||||||
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
|
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
|
||||||
gfx2d_rect(gfx, gap_rect, black_color_global);
|
gfx_rect(gfx, gap_rect, black_color_global);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -189,7 +189,7 @@ void ui_demo(gfx2d_t *gfx, app_event_t *ev) {
|
|||||||
if (ui_button(gfx, ev, rect, title)) {
|
if (ui_button(gfx, ev, rect, title)) {
|
||||||
}
|
}
|
||||||
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
|
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
|
||||||
gfx2d_rect(gfx, gap_rect, black_color_global);
|
gfx_rect(gfx, gap_rect, black_color_global);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
17
todo.txt
17
todo.txt
@@ -2,6 +2,8 @@
|
|||||||
[ ] app
|
[ ] app
|
||||||
[ ] ui
|
[ ] ui
|
||||||
[ ] event playback
|
[ ] event playback
|
||||||
|
[ ] update should produce a straight struct result for render
|
||||||
|
[ ] how to fix variable scroll? or do we not care?
|
||||||
[ ] win32
|
[ ] win32
|
||||||
[ ] hot reload / plugins
|
[ ] hot reload / plugins
|
||||||
[ ] tests using yield
|
[ ] tests using yield
|
||||||
@@ -18,6 +20,10 @@
|
|||||||
[ ] change name, hard to type
|
[ ] change name, hard to type
|
||||||
|
|
||||||
[ ] core
|
[ ] core
|
||||||
|
[ ] add time stuff into core? app start time and stuff like that
|
||||||
|
[ ] meta
|
||||||
|
[ ] search for python snippets and execute meta.py script on that file
|
||||||
|
[ ] new simple format with tags
|
||||||
[x] revisit api
|
[x] revisit api
|
||||||
[ ] s8_bin
|
[ ] s8_bin
|
||||||
[ ] bin_write_begin - serialize binary data (sb8_bin_write?)
|
[ ] bin_write_begin - serialize binary data (sb8_bin_write?)
|
||||||
@@ -34,3 +40,14 @@
|
|||||||
bin_read_end
|
bin_read_end
|
||||||
bin_read_...
|
bin_read_...
|
||||||
|
|
||||||
|
|
||||||
|
new format with tags:
|
||||||
|
|
||||||
|
app_event_t: @struct {
|
||||||
|
kind: app_event_kind_t
|
||||||
|
key: app_key_t
|
||||||
|
button: app_mouse_button_t
|
||||||
|
delta_time: f64
|
||||||
|
|
||||||
|
next: *app_event_t @dont_serialize
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user