diff --git a/build.bat b/build.bat index 4a864cb..6dd6a8f 100644 --- a/build.bat +++ b/build.bat @@ -2,5 +2,5 @@ if not exist bin mkdir bin set INCLUDES=/I src /I src/util /I src/platform /I ext -cl /Zi /Zc:preprocessor /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c +cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c lib bin/milepost.obj /OUT:bin/milepost.lib diff --git a/examples/simpleWindow/main.c b/examples/simpleWindow/main.c index 9ab6995..07fca9c 100644 --- a/examples/simpleWindow/main.c +++ b/examples/simpleWindow/main.c @@ -107,7 +107,8 @@ int main() glUseProgram(program); - mp_window_bring_to_front_and_focus(window); + mp_window_bring_to_front(window); +// mp_window_focus(window); while(!mp_should_quit()) { @@ -117,18 +118,72 @@ int main() { switch(event.type) { - case MP_EVENT_KEYBOARD_CHAR: - { - printf("entered char %s\n", event.character.sequence); - } break; - case MP_EVENT_WINDOW_CLOSE: { - mp_do_quit(); + mp_request_quit(); } break; case MP_EVENT_WINDOW_RESIZE: { + printf("resized, rect = {%f, %f, %f, %f}\n", + event.frame.rect.x, + event.frame.rect.y, + event.frame.rect.w, + event.frame.rect.h); + } break; + + case MP_EVENT_WINDOW_MOVE: + { + printf("moved, rect = {%f, %f, %f, %f}\n", + event.frame.rect.x, + event.frame.rect.y, + event.frame.rect.w, + event.frame.rect.h); + } break; + + case MP_EVENT_MOUSE_MOVE: + { + printf("mouse moved, pos = {%f, %f}, delta = {%f, %f}\n", + event.move.x, + event.move.y, + event.move.deltaX, + event.move.deltaY); + } break; + + case MP_EVENT_MOUSE_WHEEL: + { + printf("mouse wheel, delta = {%f, %f}\n", + event.move.deltaX, + event.move.deltaY); + } break; + + case MP_EVENT_MOUSE_ENTER: + { + printf("mouse enter\n"); + } break; + + case MP_EVENT_MOUSE_LEAVE: + { + printf("mouse leave\n"); + } break; + + case MP_EVENT_MOUSE_BUTTON: + { + printf("mouse button %i: %i\n", + event.key.code, + event.key.action == MP_KEY_PRESS ? 1 : 0); + } break; + + case MP_EVENT_KEYBOARD_KEY: + { + printf("key %i: %s\n", + event.key.code, + event.key.action == MP_KEY_PRESS ? "press" : (event.key.action == MP_KEY_RELEASE ? "release" : "repeat")); + } break; + + case MP_EVENT_KEYBOARD_CHAR: + { + printf("entered char %s\n", event.character.sequence); } break; default: diff --git a/src/mp_app.c b/src/mp_app.c new file mode 100644 index 0000000..ab116b3 --- /dev/null +++ b/src/mp_app.c @@ -0,0 +1,349 @@ +/************************************************************//** +* +* @file: mp_app_internal.c +* @author: Martin Fouilleul +* @date: 23/12/2022 +* @revision: +* +*****************************************************************/ + +#include"mp_app_internal.h" + +#define LOG_SUBSYSTEM "Application" + +mp_app __mpApp = {0}; + +//--------------------------------------------------------------- +// Window handles +//--------------------------------------------------------------- + +void mp_init_window_handles() +{ + ListInit(&__mpApp.windowFreeList); + for(int i=0; i>32; + u32 generation = handle.h & 0xffffffff; + if(index >= MP_APP_MAX_WINDOWS) + { + return(0); + } + mp_window_data* window = &__mpApp.windowPool[index]; + if(window->generation != generation) + { + return(0); + } + else + { + return(window); + } +} + +mp_window mp_window_handle_from_ptr(mp_window_data* window) +{ + DEBUG_ASSERT( (window - __mpApp.windowPool) >= 0 + && (window - __mpApp.windowPool) < MP_APP_MAX_WINDOWS); + + u64 h = ((u64)(window - __mpApp.windowPool))<<32 + | ((u64)window->generation); + + return((mp_window){h}); +} + +void mp_window_recycle_ptr(mp_window_data* window) +{ + window->generation++; + ListPush(&__mpApp.windowFreeList, &window->freeListElt); +} + +//--------------------------------------------------------------- +// Init +//--------------------------------------------------------------- + +static void mp_init_common() +{ + mp_init_window_handles(); + ringbuffer_init(&__mpApp.eventQueue, 16); +} + +static void mp_terminate_common() +{ + ringbuffer_cleanup(&__mpApp.eventQueue); +} + +//--------------------------------------------------------------- +// Event handling +//--------------------------------------------------------------- + +void mp_queue_event(mp_event* event) +{ + if(ringbuffer_write_available(&__mpApp.eventQueue) < sizeof(mp_event)) + { + LOG_ERROR("event queue full\n"); + } + else + { + u32 written = ringbuffer_write(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event); + DEBUG_ASSERT(written == sizeof(mp_event)); + } +} + +bool mp_next_event(mp_event* event) +{ + //NOTE pop and return event from queue + if(ringbuffer_read_available(&__mpApp.eventQueue) >= sizeof(mp_event)) + { + u64 read = ringbuffer_read(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event); + DEBUG_ASSERT(read == sizeof(mp_event)); + return(true); + } + else + { + return(false); + } +} + +//--------------------------------------------------------------- +// Input state updating +//--------------------------------------------------------------- + +static void mp_update_key_state(mp_key_state* key, bool down) +{ + u64 frameCounter = __mpApp.inputState.frameCounter; + if(key->lastUpdate != frameCounter) + { + key->transitionCounter = 0; + key->clicked = false; + key->doubleClicked = false; + key->lastUpdate = frameCounter; + } + if(key->down == down) + { + key->transitionCounter++; + } + key->down = down; +} + +static void mp_update_mouse_move(f32 x, f32 y, f32 deltaX, f32 deltaY) +{ + u64 frameCounter = __mpApp.inputState.frameCounter; + mp_mouse_state* mouse = &__mpApp.inputState.mouse; + if(mouse->lastUpdate != frameCounter) + { + mouse->delta = (vec2){0, 0}; + mouse->wheel = (vec2){0, 0}; + mouse->lastUpdate = frameCounter; + } + mouse->pos = (vec2){x, y}; + mouse->delta.x += deltaX; + mouse->delta.y += deltaY; +} + +static void mp_update_mouse_wheel(f32 deltaX, f32 deltaY) +{ + u64 frameCounter = __mpApp.inputState.frameCounter; + mp_mouse_state* mouse = &__mpApp.inputState.mouse; + if(mouse->lastUpdate != frameCounter) + { + mouse->delta = (vec2){0, 0}; + mouse->wheel = (vec2){0, 0}; + mouse->lastUpdate = frameCounter; + } + mouse->wheel.x += deltaX; + mouse->wheel.y += deltaY; +} + +static void mp_update_text(utf32 codepoint) +{ + u64 frameCounter = __mpApp.inputState.frameCounter; + mp_text_state* text = &__mpApp.inputState.text; + + if(text->lastUpdate != frameCounter) + { + text->codePoints.len = 0; + text->lastUpdate = frameCounter; + } + + text->codePoints.ptr = text->backing; + if(text->codePoints.len < MP_INPUT_TEXT_BACKING_SIZE) + { + text->codePoints.ptr[text->codePoints.len] = codepoint; + text->codePoints.len++; + } + else + { + LOG_WARNING("too many input codepoints per frame, dropping input"); + } +} + +//-------------------------------------------------------------------- +// Input state polling +//-------------------------------------------------------------------- + +mp_key_state mp_input_get_key_state(mp_key_code key) +{ + if(key <= MP_KEY_COUNT) + { + return(__mpApp.inputState.keyboard.keys[key]); + } + else + { + return((mp_key_state){0}); + } +} +mp_key_state mp_input_get_mouse_button_state(mp_mouse_button button) +{ + if(button <= MP_MOUSE_BUTTON_COUNT) + { + return(__mpApp.inputState.mouse.buttons[button]); + } + else + { + return((mp_key_state){0}); + } +} + +bool mp_input_check_key_transition(mp_key_state* key, bool pressed) +{ + bool res = ( (key->lastUpdate == __mpApp.inputState.frameCounter) + && key->transitionCounter + &&(key->down == pressed || key->transitionCounter > 1)); + return(res); +} + +bool mp_input_key_down(mp_key_code key) +{ + mp_key_state state = mp_input_get_key_state(key); + return(state.down); +} +bool mp_input_key_pressed(mp_key_code key) +{ + mp_key_state state = mp_input_get_key_state(key); + bool res = mp_input_check_key_transition(&state, true); + return(res); +} + +bool mp_input_key_released(mp_key_code key) +{ + mp_key_state state = mp_input_get_key_state(key); + bool res = mp_input_check_key_transition(&state, false); + return(res); +} + +bool mp_input_mouse_down(mp_mouse_button button) +{ + mp_key_state state = mp_input_get_mouse_button_state(button); + return(state.down); +} + +bool mp_input_mouse_pressed(mp_mouse_button button) +{ + mp_key_state state = mp_input_get_mouse_button_state(button); + bool res = mp_input_check_key_transition(&state, true); + return(res); +} + +bool mp_input_mouse_released(mp_mouse_button button) +{ + mp_key_state state = mp_input_get_mouse_button_state(button); + bool res = mp_input_check_key_transition(&state, false); + return(res); +} + +bool mp_input_mouse_clicked(mp_mouse_button button) +{ + mp_key_state state = mp_input_get_mouse_button_state(button); + return(state.clicked); +} + +bool mp_input_mouse_double_clicked(mp_mouse_button button) +{ + mp_key_state state = mp_input_get_mouse_button_state(button); + if(state.lastUpdate == __mpApp.inputState.frameCounter) + { + return(state.doubleClicked); + } + else + { + return(false); + } +} + +mp_key_mods mp_input_key_mods() +{ + return(__mpApp.inputState.keyboard.mods); +} + +vec2 mp_input_mouse_position() +{ + return(__mpApp.inputState.mouse.pos); +} + +vec2 mp_input_mouse_delta() +{ + if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter) + { + return(__mpApp.inputState.mouse.delta); + } + else + { + return((vec2){0, 0}); + } +} + +vec2 mp_input_mouse_wheel() +{ + if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter) + { + return(__mpApp.inputState.mouse.wheel); + } + else + { + return((vec2){0, 0}); + } +} + +str32 mp_input_text_utf32(mem_arena* arena) +{ + str32 res = {0}; + if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter) + { + res = str32_push_copy(arena, __mpApp.inputState.text.codePoints); + } + return(res); +} + +str8 mp_input_text_utf8(mem_arena* arena) +{ + str8 res = {0}; + if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter) + { + res = utf8_push_from_codepoints(arena, __mpApp.inputState.text.codePoints); + } + return(res); +} + + +#undef LOG_SUBSYSTEM diff --git a/src/mp_app.h b/src/mp_app.h index d743eb2..ea4d818 100644 --- a/src/mp_app.h +++ b/src/mp_app.h @@ -42,7 +42,7 @@ static const mp_window_style MP_WINDOW_STYLE_NO_TITLE = 0x01<<0, MP_WINDOW_STYLE_NO_BUTTONS = 0x01<<7; typedef enum { MP_EVENT_NONE, - MP_EVENT_KEYBOARD_MODS, + MP_EVENT_KEYBOARD_MODS, //TODO: remove, keep only key? MP_EVENT_KEYBOARD_KEY, MP_EVENT_KEYBOARD_CHAR, MP_EVENT_MOUSE_BUTTON, @@ -54,10 +54,9 @@ typedef enum { MP_EVENT_NONE, MP_EVENT_WINDOW_MOVE, MP_EVENT_WINDOW_FOCUS, MP_EVENT_WINDOW_UNFOCUS, - MP_EVENT_WINDOW_HIDE, - MP_EVENT_WINDOW_SHOW, + MP_EVENT_WINDOW_HIDE, // rename to minimize? + MP_EVENT_WINDOW_SHOW, // rename to restore? MP_EVENT_WINDOW_CLOSE, - MP_EVENT_CLIPBOARD, MP_EVENT_PATHDROP, MP_EVENT_FRAME, MP_EVENT_QUIT } mp_event_type; @@ -67,7 +66,10 @@ typedef enum { MP_KEY_NO_ACTION, MP_KEY_RELEASE, MP_KEY_REPEAT } mp_key_action; -typedef enum { MP_KEY_UNKNOWN = -1, +typedef enum { MP_KEY_UNKNOWN = 0, + MP_KEY_SPACE = 32, + MP_KEY_APOSTROPHE = 39, /* ' */ + MP_KEY_COMMA = 44, /* , */ MP_KEY_MINUS = 45, // - MP_KEY_PERIOD = 46, // . MP_KEY_SLASH = 47, // / @@ -185,24 +187,22 @@ typedef enum { MP_KEY_UNKNOWN = -1, MP_KEY_RIGHT_ALT = 346, MP_KEY_RIGHT_SUPER = 347, MP_KEY_MENU = 348, - MP_KEY_MAX } mp_key_code; + MP_KEY_COUNT } mp_key_code; -typedef u8 mp_key_mods; -static const mp_key_mods MP_KEYMOD_NONE = 0x00, - MP_KEYMOD_ALT = 0x01, - MP_KEYMOD_SHIFT = 0x02, - MP_KEYMOD_CTRL = 0x04, - MP_KEYMOD_CMD = 0x08; +typedef enum { + MP_KEYMOD_NONE = 0x00, + MP_KEYMOD_ALT = 0x01, + MP_KEYMOD_SHIFT = 0x02, + MP_KEYMOD_CTRL = 0x04, + MP_KEYMOD_CMD = 0x08 } mp_key_mods; -typedef i32 mp_mouse_button; -static const mp_mouse_button MP_MOUSE_LEFT = 0x00, - MP_MOUSE_RIGHT = 0x01, - MP_MOUSE_MIDDLE = 0x02, - MP_MOUSE_EXT1 = 0x03, - MP_MOUSE_EXT2 = 0x04; - -static const u32 MP_KEY_COUNT = MP_KEY_MAX+1, - MP_MOUSE_BUTTON_COUNT = 5; +typedef enum { + MP_MOUSE_LEFT = 0x00, + MP_MOUSE_RIGHT = 0x01, + MP_MOUSE_MIDDLE = 0x02, + MP_MOUSE_EXT1 = 0x03, + MP_MOUSE_EXT2 = 0x04, + MP_MOUSE_BUTTON_COUNT } mp_mouse_button; typedef struct mp_key_event // keyboard and mouse buttons input { @@ -263,54 +263,63 @@ void mp_init(); void mp_terminate(); bool mp_should_quit(); -void mp_do_quit(); -void mp_request_quit(); void mp_cancel_quit(); +void mp_request_quit(); void mp_set_cursor(mp_mouse_cursor cursor); //-------------------------------------------------------------------- -// window management +// Main loop and events handling //-------------------------------------------------------------------- -//#include"graphics.h" +void mp_pump_events(f64 timeout); +bool mp_next_event(mp_event* event); + +typedef void(*mp_live_resize_callback)(mp_event event, void* data); +void mp_set_live_resize_callback(mp_live_resize_callback callback, void* data); + +//-------------------------------------------------------------------- +// window management +//-------------------------------------------------------------------- bool mp_window_handle_is_null(mp_window window); mp_window mp_window_null_handle(); mp_window mp_window_create(mp_rect contentRect, const char* title, mp_window_style style); void mp_window_destroy(mp_window window); +void* mp_window_native_pointer(mp_window window); bool mp_window_should_close(mp_window window); void mp_window_request_close(mp_window window); void mp_window_cancel_close(mp_window window); -void* mp_window_native_pointer(mp_window window); - -void mp_window_center(mp_window window); - bool mp_window_is_hidden(mp_window window); -bool mp_window_is_focused(mp_window window); - void mp_window_hide(mp_window window); +void mp_window_show(mp_window window); + +bool mp_window_is_minimized(mp_window window); +bool mp_window_is_maximized(mp_window window); +void mp_window_minimize(mp_window window); +void mp_window_maximize(mp_window window); +void mp_window_restore(mp_window window); + +bool mp_window_has_focus(mp_window window); void mp_window_focus(mp_window window); +void mp_window_unfocus(mp_window window); + void mp_window_send_to_back(mp_window window); void mp_window_bring_to_front(mp_window window); -void mp_window_bring_to_front_and_focus(mp_window window); +mp_rect mp_window_get_content_rect(mp_window window); +mp_rect mp_window_get_frame_rect(mp_window window); +void mp_window_set_content_rect(mp_window window, mp_rect contentRect); +void mp_window_set_frame_rect(mp_window window, mp_rect frameRect); + +void mp_window_center(mp_window window); mp_rect mp_window_content_rect_for_frame_rect(mp_rect frameRect, mp_window_style style); mp_rect mp_window_frame_rect_for_content_rect(mp_rect contentRect, mp_window_style style); -mp_rect mp_window_get_content_rect(mp_window window); -mp_rect mp_window_get_absolute_content_rect(mp_window window); -mp_rect mp_window_get_frame_rect(mp_window window); - -void mp_window_set_content_rect(mp_window window, mp_rect contentRect); -void mp_window_set_frame_rect(mp_window window, mp_rect frameRect); -void mp_window_set_frame_size(mp_window window, int width, int height); -void mp_window_set_content_size(mp_window window, int width, int height); - //-------------------------------------------------------------------- // View management //-------------------------------------------------------------------- @@ -321,26 +330,6 @@ mp_view mp_view_create(mp_window window, mp_rect frame); void mp_view_destroy(mp_view view); void mp_view_set_frame(mp_view view, mp_rect frame); -/*TODO -mp_view mp_view_bring_to_front(mp_view view); -mp_view mp_view_send_to_back(mp_view view); -*/ -//-------------------------------------------------------------------- -// Main loop and events handling -//-------------------------------------------------------------------- - -typedef void(*mp_event_callback)(mp_event event, void* data); -void mp_set_event_callback(mp_event_callback callback, void* data); -void mp_set_target_fps(u32 fps); -void mp_run_loop(); -void mp_end_input_frame(); - -void mp_pump_events(f64 timeout); -bool mp_next_event(mp_event* event); - -typedef void(*mp_live_resize_callback)(mp_event event, void* data); -void mp_set_live_resize_callback(mp_live_resize_callback callback, void* data); - //-------------------------------------------------------------------- // Input state polling //-------------------------------------------------------------------- @@ -364,11 +353,6 @@ vec2 mp_input_mouse_wheel(); str32 mp_input_text_utf32(mem_arena* arena); str8 mp_input_text_utf8(mem_arena* arena); -//-------------------------------------------------------------------- -// app resources -//-------------------------------------------------------------------- -str8 mp_app_get_resource_path(mem_arena* arena, const char* name); -str8 mp_app_get_executable_path(mem_arena* arena); //-------------------------------------------------------------------- // Clipboard @@ -414,6 +398,10 @@ int mp_file_remove(str8 path); int mp_directory_create(str8 path); +str8 mp_app_get_resource_path(mem_arena* arena, const char* name); +str8 mp_app_get_executable_path(mem_arena* arena); + + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/mp_app_internal.h b/src/mp_app_internal.h new file mode 100644 index 0000000..2c73f71 --- /dev/null +++ b/src/mp_app_internal.h @@ -0,0 +1,149 @@ +/************************************************************//** +* +* @file: mp_app_internal.h +* @author: Martin Fouilleul +* @date: 23/12/2022 +* @revision: +* +*****************************************************************/ +#ifndef __MP_APP_INTERNAL_H_ +#define __MP_APP_INTERNAL_H_ + +#include"platform.h" +#include"ringbuffer.h" + +#if defined(OS_WIN64) || defined(OS_WIN32) + #include"win32_app.h" +#elif defined(OS_MACOS) + #include"osx_app.h" +#else + #error "platform not supported yet" +#endif + +//--------------------------------------------------------------- +// Input State +//--------------------------------------------------------------- + +typedef struct mp_key_utf8 +{ + u8 labelLen; + char label[8]; +} mp_key_utf8; + +typedef struct mp_key_state +{ + u64 lastUpdate; + u32 transitionCounter; + bool down; + bool clicked; + bool doubleClicked; + +} mp_key_state; + +typedef struct mp_keyboard_state +{ + mp_key_state keys[MP_KEY_COUNT]; + mp_key_mods mods; +} mp_keyboard_state; + +typedef struct mp_mouse_state +{ + u64 lastUpdate; + bool posValid; + vec2 pos; + vec2 delta; + vec2 wheel; + + union + { + mp_key_state buttons[MP_MOUSE_BUTTON_COUNT]; + struct + { + mp_key_state left; + mp_key_state right; + mp_key_state middle; + mp_key_state ext1; + mp_key_state ext2; + }; + }; +} mp_mouse_state; + +enum { MP_INPUT_TEXT_BACKING_SIZE = 64 }; + +typedef struct mp_text_state +{ + u64 lastUpdate; + utf32 backing[MP_INPUT_TEXT_BACKING_SIZE]; + str32 codePoints; +} mp_text_state; + +typedef struct mp_input_state +{ + u64 frameCounter; + mp_keyboard_state keyboard; + mp_mouse_state mouse; + mp_text_state text; +} mp_input_state; + +//--------------------------------------------------------------- +// Window structure +//--------------------------------------------------------------- + +typedef struct mp_frame_stats +{ + f64 start; + f64 workTime; + f64 remainingTime; + f64 targetFramePeriod; +} mp_frame_stats; + +typedef struct mp_window_data +{ + list_elt freeListElt; + u32 generation; + + mp_rect contentRect; + mp_rect frameRect; + mp_window_style style; + + bool shouldClose; //TODO could be in status flags + bool hidden; + bool minimized; + + MP_PLATFORM_WINDOW_DATA +} mp_window_data; + + +//--------------------------------------------------------------- +// Global App State +//--------------------------------------------------------------- + +enum { MP_APP_MAX_WINDOWS = 128 }; + +typedef struct mp_app +{ + bool init; + bool shouldQuit; + bool minimized; + + str8 pendingPathDrop; + mem_arena eventArena; + + ringbuffer eventQueue; + + mp_frame_stats frameStats; + + mp_window_data windowPool[MP_APP_MAX_WINDOWS]; + list_info windowFreeList; + + mp_input_state inputState; + + mp_key_utf8 keyLabels[256]; + int keyCodes[256]; + int nativeKeys[MP_KEY_COUNT]; + + MP_PLATFORM_APP_DATA +} mp_app; + + +#endif // __MP_APP_INTERNAL_H_ diff --git a/src/osx_app.m b/src/osx_app.m index 2e8e066..0587338 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -2283,153 +2283,6 @@ void mp_end_input_frame() mem_arena_clear(&__mpAppData.eventArena); } -//-------------------------------------------------------------------- -// Input state polling -//-------------------------------------------------------------------- - -mp_key_state mp_input_get_key_state(mp_key_code key) -{ - if(key <= MP_KEY_COUNT) - { - return(__mpAppData.inputState.keyboard.keys[key]); - } - else - { - return((mp_key_state){0}); - } -} -mp_key_state mp_input_get_mouse_button_state(mp_mouse_button button) -{ - if(button <= MP_MOUSE_BUTTON_COUNT) - { - return(__mpAppData.inputState.mouse.buttons[button]); - } - else - { - return((mp_key_state){0}); - } -} - -bool mp_input_check_key_transition(mp_key_state* key, bool pressed) -{ - bool res = ( (key->lastUpdate == __mpAppData.inputState.frameCounter) - && key->transitionCounter - &&(key->down == pressed || key->transitionCounter > 1)); - return(res); -} - -bool mp_input_key_down(mp_key_code key) -{ - mp_key_state state = mp_input_get_key_state(key); - return(state.down); -} -bool mp_input_key_pressed(mp_key_code key) -{ - mp_key_state state = mp_input_get_key_state(key); - bool res = mp_input_check_key_transition(&state, true); - return(res); -} - -bool mp_input_key_released(mp_key_code key) -{ - mp_key_state state = mp_input_get_key_state(key); - bool res = mp_input_check_key_transition(&state, false); - return(res); -} - -bool mp_input_mouse_down(mp_mouse_button button) -{ - mp_key_state state = mp_input_get_mouse_button_state(button); - return(state.down); -} - -bool mp_input_mouse_pressed(mp_mouse_button button) -{ - mp_key_state state = mp_input_get_mouse_button_state(button); - bool res = mp_input_check_key_transition(&state, true); - return(res); -} - -bool mp_input_mouse_released(mp_mouse_button button) -{ - mp_key_state state = mp_input_get_mouse_button_state(button); - bool res = mp_input_check_key_transition(&state, false); - return(res); -} - -bool mp_input_mouse_clicked(mp_mouse_button button) -{ - mp_key_state state = mp_input_get_mouse_button_state(button); - return(state.clicked); -} - -bool mp_input_mouse_double_clicked(mp_mouse_button button) -{ - mp_key_state state = mp_input_get_mouse_button_state(button); - if(state.lastUpdate == __mpAppData.inputState.frameCounter) - { - return(state.doubleClicked); - } - else - { - return(false); - } -} - -mp_key_mods mp_input_key_mods() -{ - return(__mpAppData.inputState.keyboard.mods); -} - -vec2 mp_input_mouse_position() -{ - return(__mpAppData.inputState.mouse.pos); -} - -vec2 mp_input_mouse_delta() -{ - if(__mpAppData.inputState.mouse.lastUpdate == __mpAppData.inputState.frameCounter) - { - return(__mpAppData.inputState.mouse.delta); - } - else - { - return((vec2){0, 0}); - } -} - -vec2 mp_input_mouse_wheel() -{ - if(__mpAppData.inputState.mouse.lastUpdate == __mpAppData.inputState.frameCounter) - { - return(__mpAppData.inputState.mouse.wheel); - } - else - { - return((vec2){0, 0}); - } -} - -str32 mp_input_text_utf32(mem_arena* arena) -{ - str32 res = {0}; - if(__mpAppData.inputState.text.lastUpdate == __mpAppData.inputState.frameCounter) - { - res = str32_push_copy(arena, __mpAppData.inputState.text.codePoints); - } - return(res); -} - -str8 mp_input_text_utf8(mem_arena* arena) -{ - str8 res = {0}; - if(__mpAppData.inputState.text.lastUpdate == __mpAppData.inputState.frameCounter) - { - res = utf8_push_from_codepoints(arena, __mpAppData.inputState.text.codePoints); - } - return(res); -} - //-------------------------------------------------------------------- // app resources //-------------------------------------------------------------------- diff --git a/src/win32_app.c b/src/win32_app.c index e31c215..5ae08ab 100644 --- a/src/win32_app.c +++ b/src/win32_app.c @@ -7,118 +7,240 @@ * *****************************************************************/ -#define WIN32_LEAN_AND_MEAN -#include - -#include"win32_app.h" -#include"ringbuffer.h" +#include"mp_app.c" #define LOG_SUBSYSTEM "Application" - -enum { MP_APP_MAX_WINDOWS = 128 }; - -typedef struct mp_app_data +void mp_init_keys() { - bool init; - bool shouldQuit; + memset(__mpApp.keyCodes, MP_KEY_UNKNOWN, 256*sizeof(int)); - mp_window_data windowPool[MP_APP_MAX_WINDOWS]; - list_info windowFreeList; + __mpApp.keyCodes[0x00B] = MP_KEY_0; + __mpApp.keyCodes[0x002] = MP_KEY_1; + __mpApp.keyCodes[0x003] = MP_KEY_2; + __mpApp.keyCodes[0x004] = MP_KEY_3; + __mpApp.keyCodes[0x005] = MP_KEY_4; + __mpApp.keyCodes[0x006] = MP_KEY_5; + __mpApp.keyCodes[0x007] = MP_KEY_6; + __mpApp.keyCodes[0x008] = MP_KEY_7; + __mpApp.keyCodes[0x009] = MP_KEY_8; + __mpApp.keyCodes[0x00A] = MP_KEY_9; + __mpApp.keyCodes[0x01E] = MP_KEY_A; + __mpApp.keyCodes[0x030] = MP_KEY_B; + __mpApp.keyCodes[0x02E] = MP_KEY_C; + __mpApp.keyCodes[0x020] = MP_KEY_D; + __mpApp.keyCodes[0x012] = MP_KEY_E; + __mpApp.keyCodes[0x021] = MP_KEY_F; + __mpApp.keyCodes[0x022] = MP_KEY_G; + __mpApp.keyCodes[0x023] = MP_KEY_H; + __mpApp.keyCodes[0x017] = MP_KEY_I; + __mpApp.keyCodes[0x024] = MP_KEY_J; + __mpApp.keyCodes[0x025] = MP_KEY_K; + __mpApp.keyCodes[0x026] = MP_KEY_L; + __mpApp.keyCodes[0x032] = MP_KEY_M; + __mpApp.keyCodes[0x031] = MP_KEY_N; + __mpApp.keyCodes[0x018] = MP_KEY_O; + __mpApp.keyCodes[0x019] = MP_KEY_P; + __mpApp.keyCodes[0x010] = MP_KEY_Q; + __mpApp.keyCodes[0x013] = MP_KEY_R; + __mpApp.keyCodes[0x01F] = MP_KEY_S; + __mpApp.keyCodes[0x014] = MP_KEY_T; + __mpApp.keyCodes[0x016] = MP_KEY_U; + __mpApp.keyCodes[0x02F] = MP_KEY_V; + __mpApp.keyCodes[0x011] = MP_KEY_W; + __mpApp.keyCodes[0x02D] = MP_KEY_X; + __mpApp.keyCodes[0x015] = MP_KEY_Y; + __mpApp.keyCodes[0x02C] = MP_KEY_Z; + __mpApp.keyCodes[0x028] = MP_KEY_APOSTROPHE; + __mpApp.keyCodes[0x02B] = MP_KEY_BACKSLASH; + __mpApp.keyCodes[0x033] = MP_KEY_COMMA; + __mpApp.keyCodes[0x00D] = MP_KEY_EQUAL; + __mpApp.keyCodes[0x029] = MP_KEY_GRAVE_ACCENT; + __mpApp.keyCodes[0x01A] = MP_KEY_LEFT_BRACKET; + __mpApp.keyCodes[0x00C] = MP_KEY_MINUS; + __mpApp.keyCodes[0x034] = MP_KEY_PERIOD; + __mpApp.keyCodes[0x01B] = MP_KEY_RIGHT_BRACKET; + __mpApp.keyCodes[0x027] = MP_KEY_SEMICOLON; + __mpApp.keyCodes[0x035] = MP_KEY_SLASH; + __mpApp.keyCodes[0x056] = MP_KEY_WORLD_2; + __mpApp.keyCodes[0x00E] = MP_KEY_BACKSPACE; + __mpApp.keyCodes[0x153] = MP_KEY_DELETE; + __mpApp.keyCodes[0x14F] = MP_KEY_END; + __mpApp.keyCodes[0x01C] = MP_KEY_ENTER; + __mpApp.keyCodes[0x001] = MP_KEY_ESCAPE; + __mpApp.keyCodes[0x147] = MP_KEY_HOME; + __mpApp.keyCodes[0x152] = MP_KEY_INSERT; + __mpApp.keyCodes[0x15D] = MP_KEY_MENU; + __mpApp.keyCodes[0x151] = MP_KEY_PAGE_DOWN; + __mpApp.keyCodes[0x149] = MP_KEY_PAGE_UP; + __mpApp.keyCodes[0x045] = MP_KEY_PAUSE; + __mpApp.keyCodes[0x146] = MP_KEY_PAUSE; + __mpApp.keyCodes[0x039] = MP_KEY_SPACE; + __mpApp.keyCodes[0x00F] = MP_KEY_TAB; + __mpApp.keyCodes[0x03A] = MP_KEY_CAPS_LOCK; + __mpApp.keyCodes[0x145] = MP_KEY_NUM_LOCK; + __mpApp.keyCodes[0x046] = MP_KEY_SCROLL_LOCK; + __mpApp.keyCodes[0x03B] = MP_KEY_F1; + __mpApp.keyCodes[0x03C] = MP_KEY_F2; + __mpApp.keyCodes[0x03D] = MP_KEY_F3; + __mpApp.keyCodes[0x03E] = MP_KEY_F4; + __mpApp.keyCodes[0x03F] = MP_KEY_F5; + __mpApp.keyCodes[0x040] = MP_KEY_F6; + __mpApp.keyCodes[0x041] = MP_KEY_F7; + __mpApp.keyCodes[0x042] = MP_KEY_F8; + __mpApp.keyCodes[0x043] = MP_KEY_F9; + __mpApp.keyCodes[0x044] = MP_KEY_F10; + __mpApp.keyCodes[0x057] = MP_KEY_F11; + __mpApp.keyCodes[0x058] = MP_KEY_F12; + __mpApp.keyCodes[0x064] = MP_KEY_F13; + __mpApp.keyCodes[0x065] = MP_KEY_F14; + __mpApp.keyCodes[0x066] = MP_KEY_F15; + __mpApp.keyCodes[0x067] = MP_KEY_F16; + __mpApp.keyCodes[0x068] = MP_KEY_F17; + __mpApp.keyCodes[0x069] = MP_KEY_F18; + __mpApp.keyCodes[0x06A] = MP_KEY_F19; + __mpApp.keyCodes[0x06B] = MP_KEY_F20; + __mpApp.keyCodes[0x06C] = MP_KEY_F21; + __mpApp.keyCodes[0x06D] = MP_KEY_F22; + __mpApp.keyCodes[0x06E] = MP_KEY_F23; + __mpApp.keyCodes[0x076] = MP_KEY_F24; + __mpApp.keyCodes[0x038] = MP_KEY_LEFT_ALT; + __mpApp.keyCodes[0x01D] = MP_KEY_LEFT_CONTROL; + __mpApp.keyCodes[0x02A] = MP_KEY_LEFT_SHIFT; + __mpApp.keyCodes[0x15B] = MP_KEY_LEFT_SUPER; + __mpApp.keyCodes[0x137] = MP_KEY_PRINT_SCREEN; + __mpApp.keyCodes[0x138] = MP_KEY_RIGHT_ALT; + __mpApp.keyCodes[0x11D] = MP_KEY_RIGHT_CONTROL; + __mpApp.keyCodes[0x036] = MP_KEY_RIGHT_SHIFT; + __mpApp.keyCodes[0x15C] = MP_KEY_RIGHT_SUPER; + __mpApp.keyCodes[0x150] = MP_KEY_DOWN; + __mpApp.keyCodes[0x14B] = MP_KEY_LEFT; + __mpApp.keyCodes[0x14D] = MP_KEY_RIGHT; + __mpApp.keyCodes[0x148] = MP_KEY_UP; + __mpApp.keyCodes[0x052] = MP_KEY_KP_0; + __mpApp.keyCodes[0x04F] = MP_KEY_KP_1; + __mpApp.keyCodes[0x050] = MP_KEY_KP_2; + __mpApp.keyCodes[0x051] = MP_KEY_KP_3; + __mpApp.keyCodes[0x04B] = MP_KEY_KP_4; + __mpApp.keyCodes[0x04C] = MP_KEY_KP_5; + __mpApp.keyCodes[0x04D] = MP_KEY_KP_6; + __mpApp.keyCodes[0x047] = MP_KEY_KP_7; + __mpApp.keyCodes[0x048] = MP_KEY_KP_8; + __mpApp.keyCodes[0x049] = MP_KEY_KP_9; + __mpApp.keyCodes[0x04E] = MP_KEY_KP_ADD; + __mpApp.keyCodes[0x053] = MP_KEY_KP_DECIMAL; + __mpApp.keyCodes[0x135] = MP_KEY_KP_DIVIDE; + __mpApp.keyCodes[0x11C] = MP_KEY_KP_ENTER; + __mpApp.keyCodes[0x037] = MP_KEY_KP_MULTIPLY; + __mpApp.keyCodes[0x04A] = MP_KEY_KP_SUBTRACT; - ringbuffer eventQueue; - -} mp_app_data; - -mp_app_data __mpAppData = {0}; - -void mp_init_window_handles() -{ - ListInit(&__mpAppData.windowFreeList); - for(int i=0; i>32; - u32 generation = handle.h & 0xffffffff; - if(index >= MP_APP_MAX_WINDOWS) - { - return(0); - } - mp_window_data* window = &__mpAppData.windowPool[index]; - if(window->generation != generation) - { - return(0); - } - else - { - return(window); - } -} - -mp_window mp_window_handle_from_ptr(mp_window_data* window) -{ - DEBUG_ASSERT( (window - __mpAppData.windowPool) >= 0 - && (window - __mpAppData.windowPool) < MP_APP_MAX_WINDOWS); - - u64 h = ((u64)(window - __mpAppData.windowPool))<<32 - | ((u64)window->generation); - - return((mp_window){h}); -} - -void mp_window_recycle_ptr(mp_window_data* window) -{ - window->generation++; - ListPush(&__mpAppData.windowFreeList, &window->freeListElt); -} - -////////////////////// - -void mp_queue_event(mp_event* event) -{ - if(ringbuffer_write_available(&__mpAppData.eventQueue) < sizeof(mp_event)) - { - LOG_ERROR("event queue full\n"); - } - else - { - u32 written = ringbuffer_write(&__mpAppData.eventQueue, sizeof(mp_event), (u8*)event); - DEBUG_ASSERT(written == sizeof(mp_event)); - } -} - -////////////////////// - void mp_init() { - if(!__mpAppData.init) + if(!__mpApp.init) { - memset(&__mpAppData, 0, sizeof(__mpAppData)); - mp_init_window_handles(); + memset(&__mpApp, 0, sizeof(__mpApp)); - ringbuffer_init(&__mpAppData.eventQueue, 16); + mp_init_common(); + mp_init_keys(); + + __mpApp.win32.savedConsoleCodePage = GetConsoleOutputCP(); + SetConsoleOutputCP(CP_UTF8); } } void mp_terminate() { - if(__mpAppData.init) + if(__mpApp.init) { - __mpAppData = (mp_app_data){0}; + SetConsoleOutputCP(__mpApp.win32.savedConsoleCodePage); + + mp_terminate_common(); + __mpApp = (mp_app){0}; } } +static mp_key_code mp_convert_win32_key(int code) +{ + return(__mpApp.keyCodes[code]); +} + +static mp_key_mods mp_get_mod_keys() +{ + mp_key_mods mods = 0; + if(GetKeyState(VK_SHIFT) & 0x8000) + { + mods |= MP_KEYMOD_SHIFT; + } + if(GetKeyState(VK_CONTROL) & 0x8000) + { + mods |= MP_KEYMOD_CTRL; + } + if(GetKeyState(VK_MENU) & 0x8000) + { + mods |= MP_KEYMOD_ALT; + } + if((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) + { + mods |= MP_KEYMOD_CMD; + } + return(mods); +} + +static void process_mouse_event(mp_window_data* window, mp_key_action action, mp_key_code button) +{ + if(action == MP_KEY_PRESS) + { + if(!__mpApp.win32.mouseCaptureMask) + { + SetCapture(window->win32.hWnd); + } + __mpApp.win32.mouseCaptureMask |= (1<bottom, rect->left, rect->top - rect->bottom, rect->right - rect->left}; + mp_queue_event(&event); + } break; + + case WM_MOVING: + { + RECT* rect = (RECT*)lParam; + + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_WINDOW_MOVE; + event.frame.rect = (mp_rect){rect->bottom, rect->left, rect->top - rect->bottom, rect->right - rect->left}; + mp_queue_event(&event); + } break; + + case WM_SETFOCUS: + { + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_WINDOW_FOCUS; + mp_queue_event(&event); + } break; + + case WM_KILLFOCUS: + { + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_WINDOW_UNFOCUS; + mp_queue_event(&event); + } break; + + case WM_SIZE: + { + bool minimized = (wParam == SIZE_MINIMIZED); + if(minimized != mpWindow->minimized) + { + mpWindow->minimized = minimized; + + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + + if(minimized) + { + event.type = MP_EVENT_WINDOW_HIDE; + } + else if(mpWindow->minimized) + { + event.type = MP_EVENT_WINDOW_SHOW; + } + mp_queue_event(&event); + } + } break; + + case WM_LBUTTONDOWN: + { + process_mouse_event(mpWindow, MP_KEY_PRESS, MP_MOUSE_LEFT); + } break; + + case WM_RBUTTONDOWN: + { + process_mouse_event(mpWindow, MP_KEY_PRESS, MP_MOUSE_RIGHT); + } break; + + case WM_MBUTTONDOWN: + { + process_mouse_event(mpWindow, MP_KEY_PRESS, MP_MOUSE_MIDDLE); + } break; + + case WM_LBUTTONUP: + { + process_mouse_event(mpWindow, MP_KEY_RELEASE, MP_MOUSE_LEFT); + } break; + + case WM_RBUTTONUP: + { + process_mouse_event(mpWindow, MP_KEY_RELEASE, MP_MOUSE_RIGHT); + } break; + + case WM_MBUTTONUP: + { + process_mouse_event(mpWindow, MP_KEY_RELEASE, MP_MOUSE_MIDDLE); + } break; + + case WM_MOUSEMOVE: + { + RECT rect; + GetClientRect(mpWindow->win32.hWnd, &rect); + + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_MOUSE_MOVE; + event.move.x = LOWORD(lParam); + event.move.y = rect.bottom - HIWORD(lParam); + + if(__mpApp.inputState.mouse.posValid) + { + event.move.deltaX = event.move.x - __mpApp.inputState.mouse.pos.x; + event.move.deltaY = event.move.y - __mpApp.inputState.mouse.pos.y; + } + else + { + __mpApp.inputState.mouse.posValid = true; + } + + if(!__mpApp.win32.mouseTracked) + { + __mpApp.win32.mouseTracked = true; + + TRACKMOUSEEVENT track; + memset(&track, 0, sizeof(track)); + track.cbSize = sizeof(track); + track.dwFlags = TME_LEAVE; + track.hwndTrack = mpWindow->win32.hWnd; + TrackMouseEvent(&track); + + mp_event enter = {.window = event.window, + .type = MP_EVENT_MOUSE_ENTER, + .move.x = event.move.x, + .move.y = event.move.y}; + mp_queue_event(&enter); + } + __mpApp.inputState.mouse.pos.x = event.move.x; + __mpApp.inputState.mouse.pos.y = event.move.y; mp_queue_event(&event); + } break; + case WM_MOUSELEAVE: + { + __mpApp.win32.mouseTracked = false; + + if(!__mpApp.win32.mouseCaptureMask) + { + __mpApp.inputState.mouse.posValid = false; + } + + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_MOUSE_LEAVE; + mp_queue_event(&event); + } break; + + case WM_MOUSEWHEEL: + { + process_wheel_event(mpWindow, 0, (float)((i16)HIWORD(wParam))); + } break; + + case WM_MOUSEHWHEEL: + { + process_wheel_event(mpWindow, (float)((i16)HIWORD(wParam)), 0); + } break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_KEYBOARD_KEY; + event.key.action = (lParam & 0x40000000) ? MP_KEY_REPEAT : MP_KEY_PRESS; + event.key.code = mp_convert_win32_key(HIWORD(lParam) & 0x1ff); + event.key.mods = mp_get_mod_keys(); + mp_queue_event(&event); + } break; + + case WM_KEYUP: + case WM_SYSKEYUP: + { + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_KEYBOARD_KEY; + event.key.action = MP_KEY_RELEASE; + event.key.code = mp_convert_win32_key(HIWORD(lParam) & 0x1ff); + event.key.mods = mp_get_mod_keys(); + mp_queue_event(&event); + } break; + + case WM_CHAR: + { + mp_event event = {0}; + event.window = mp_window_handle_from_ptr(mpWindow); + event.type = MP_EVENT_KEYBOARD_CHAR; + event.character.codepoint = (utf32)wParam; + str8 seq = utf8_encode(event.character.sequence, event.character.codepoint); + event.character.seqLen = seq.len; + mp_queue_event(&event); + } break; + + case WM_DROPFILES: + { + //TODO } break; default: @@ -147,6 +468,40 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) return(result); } +//-------------------------------------------------------------------- +// app management +//-------------------------------------------------------------------- + +bool mp_should_quit() +{ + return(__mpApp.shouldQuit); +} + +void mp_cancel_quit() +{ + __mpApp.shouldQuit = false; +} + +void mp_request_quit() +{ + __mpApp.shouldQuit = true; +} + +void mp_pump_events(f64 timeout) +{ + MSG message; + while(PeekMessage(&message, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&message); + DispatchMessage(&message); + } + __mpApp.inputState.frameCounter++; +} + +//-------------------------------------------------------------------- +// window management +//-------------------------------------------------------------------- + mp_window mp_window_create(mp_rect rect, const char* title, mp_window_style style) { WNDCLASS windowClass = {.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC, @@ -177,50 +532,44 @@ mp_window mp_window_create(mp_rect rect, const char* title, mp_window_style styl //TODO: return wrapped window quit:; mp_window_data* window = mp_window_alloc(); - window->windowHandle = windowHandle; + window->win32.hWnd = windowHandle; SetPropW(windowHandle, L"MilePost", window); return(mp_window_handle_from_ptr(window)); } -void mp_window_bring_to_front_and_focus(mp_window window) +void mp_window_destroy(mp_window window) { mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - ShowWindow(windowData->windowHandle, 1); + DestroyWindow(windowData->win32.hWnd); + //TODO: check when to unregister class + + mp_window_recycle_ptr(windowData); } } -bool mp_should_quit() +void* mp_window_native_pointer(mp_window window) { - return(__mpAppData.shouldQuit); -} - -void mp_do_quit() -{ - __mpAppData.shouldQuit = true; -} - -void mp_pump_events(f64 timeout) -{ - MSG message; - while(PeekMessage(&message, 0, 0, 0, PM_REMOVE)) + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) { - TranslateMessage(&message); - DispatchMessage(&message); + return(windowData->win32.hWnd); + } + else + { + return(0); } } -bool mp_next_event(mp_event* event) +bool mp_window_should_close(mp_window window) { - //NOTE pop and return event from queue - if(ringbuffer_read_available(&__mpAppData.eventQueue) >= sizeof(mp_event)) + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) { - u64 read = ringbuffer_read(&__mpAppData.eventQueue, sizeof(mp_event), (u8*)event); - DEBUG_ASSERT(read == sizeof(mp_event)); - return(true); + return(windowData->shouldClose); } else { @@ -228,5 +577,148 @@ bool mp_next_event(mp_event* event) } } +void mp_window_request_close(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + windowData->shouldClose = true; + PostMessage(windowData->win32.hWnd, WM_CLOSE, 0, 0); + } +} + +void mp_window_cancel_close(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + windowData->shouldClose = false; + } +} + + +bool mp_window_is_hidden(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + return(IsWindowVisible(windowData->win32.hWnd)); + } + else + { + return(false); + } +} + +void mp_window_hide(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + ShowWindow(windowData->win32.hWnd, SW_HIDE); + } +} + +void mp_window_show(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + ShowWindow(windowData->win32.hWnd, SW_NORMAL); + } +} + +bool mp_window_is_minimized(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + return(windowData->minimized); + } + else + { + return(false); + } +} + +void mp_window_minimize(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + ShowWindow(windowData->win32.hWnd, SW_MINIMIZE); + } +} + +void mp_window_maximize(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + ShowWindow(windowData->win32.hWnd, SW_MAXIMIZE); + } +} + +void mp_window_restore(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + ShowWindow(windowData->win32.hWnd, SW_RESTORE); + } +} + +bool mp_window_has_focus(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + return(GetActiveWindow() == windowData->win32.hWnd); + } + else + { + return(false); + } +} + +void mp_window_focus(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + SetFocus(windowData->win32.hWnd); + } +} + +void mp_window_unfocus(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + SetFocus(0); + } +} + +void mp_window_send_to_back(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + SetWindowPos(windowData->win32.hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } +} + +void mp_window_bring_to_front(mp_window window) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + if(!IsWindowVisible(windowData->win32.hWnd)) + { + ShowWindow(windowData->win32.hWnd, SW_NORMAL); + } + SetWindowPos(windowData->win32.hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } +} #undef LOG_SUBSYSTEM diff --git a/src/win32_app.h b/src/win32_app.h index ec903d7..c9ddb8e 100644 --- a/src/win32_app.h +++ b/src/win32_app.h @@ -10,17 +10,27 @@ #ifndef __WIN32_APP_H_ #define __WIN32_APP_H_ +#define WIN32_LEAN_AND_MEAN +#include #include"mp_app.h" -typedef struct mp_window_data +typedef struct win32_window_data { - list_elt freeListElt; - u32 generation; + HWND hWnd; - HWND windowHandle; -} mp_window_data; +} win32_window_data; -mp_window_data* mp_window_ptr_from_handle(mp_window handle); -//mp_view_data* mp_view_ptr_from_handle(mp_view handle); +#define MP_PLATFORM_WINDOW_DATA win32_window_data win32; + +typedef struct win32_app_data +{ + u32 savedConsoleCodePage; + + int mouseCaptureMask; + bool mouseTracked; + +} win32_app_data; + +#define MP_PLATFORM_APP_DATA win32_app_data win32; #endif __WIN32_APP_H_ diff --git a/src/win32_gl_surface.c b/src/win32_gl_surface.c index c10901b..7b98c7a 100644 --- a/src/win32_gl_surface.c +++ b/src/win32_gl_surface.c @@ -166,7 +166,7 @@ mg_surface mg_gl_surface_create_for_window(mp_window window) WGL_STENCIL_BITS_ARB, 8, 0}; - HDC hDC = GetDC(windowData->windowHandle); + HDC hDC = GetDC(windowData->win32.hWnd); u32 numFormats = 0; wglChoosePixelFormatARB(hDC, pixelFormatAttrs, 0, 1, &pixelFormat, &numFormats); diff --git a/todo.txt b/todo.txt index 81c7ac4..cc8f714 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,67 @@ +Windows port +------------ +[.] Finish events handling + [x] window + [x] mouse move/buttons/enter/leave + [x] mouse wheel + [.] keys + [!] set key label + [x] text input + [/] pathdrop + +[x] Unify app struct and window structs for different platforms? + > define common app and window struct in mp_app_internal.h + > this file conditionally includes platform specific headers, win32_app.h, osx_app.h, etc... + > these define a macro to fill the common app and window structures with platform specific stuff. + > Common app/window proc are defined in mp_app.c + > Platform specific stuff is defined in platform specific files win32_app.c, osx_app.m, etc... + (mp_app.c can 'see' platform specific stuff, so ObjectiveC defs pose a problem, but we can define id as void* + when not in ObjC...) + +[.] Implement input polling + [ ] Simplify input polling API names + [/] Try to simplify input state and polling once we have UI usage code + +[ ] Finish window properties query/setting + +[ ] use isARepeat in macos keyDown event and simplify update key state + +[ ] Implement clipboard +[ ] Implement file dialogs +[ ] Impement resource path... -> maybe in abstracted file handling + + +[ ] Clean backend selection (compile time and runtime) +[ ] Finish OpenGL loader +[ ] Test compute shaders +[ ] Initial version of vector graphics backend +[ ] Check integration of UI. + +[ ] Views (using docked windows?) -- or see if we can use surfaces and restrict their location? + +[ ] test new run loop structure on macos +[ ] Remove unused APIs + + + +Misc +---- +[ ] Clean-up file structure + [ ] Move stb libs to ext/ + +[ ] Renaming/clean-up pass + [ ] Separate Internal/API functions in mp_app.c + [ ] Remove MP_EVENT_KEYBOARD_MODS + [ ] Rename MP_EVENT_HIDE/SHOW to MINMIZE/UNMINIMIZE + [ ] Remove frame + [ ] Remove sequence from char event? + [ ] Replace frame_event with mp_rect + [ ] Document/unify quit/request_quit etc + [ ] Document/unify close/request_close etc + [ ] Cleanup window management + [ ] Remove unused run loop constructs + [ ] Shortlist ---------