Extracted commonalities from platform specific app backends

This commit is contained in:
martinfouilleul 2022-12-23 20:46:42 +01:00
parent 30bd704af2
commit 72338b1a25
10 changed files with 1301 additions and 342 deletions

View File

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

View File

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

349
src/mp_app.c Normal file
View File

@ -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<MP_APP_MAX_WINDOWS; i++)
{
__mpApp.windowPool[i].generation = 1;
ListAppend(&__mpApp.windowFreeList, &__mpApp.windowPool[i].freeListElt);
}
}
bool mp_window_handle_is_null(mp_window window)
{
return(window.h == 0);
}
mp_window mp_window_null_handle()
{
return((mp_window){.h = 0});
}
mp_window_data* mp_window_alloc()
{
return(ListPopEntry(&__mpApp.windowFreeList, mp_window_data, freeListElt));
}
mp_window_data* mp_window_ptr_from_handle(mp_window handle)
{
u32 index = handle.h>>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

View File

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

149
src/mp_app_internal.h Normal file
View File

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

View File

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

View File

@ -7,118 +7,240 @@
*
*****************************************************************/
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#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<MP_APP_MAX_WINDOWS; i++)
memset(__mpApp.nativeKeys, 0, sizeof(int)*MP_KEY_COUNT);
for(int nativeKey=0; nativeKey<256; nativeKey++)
{
__mpAppData.windowPool[i].generation = 1;
ListAppend(&__mpAppData.windowFreeList, &__mpAppData.windowPool[i].freeListElt);
mp_key_code mpKey = __mpApp.keyCodes[nativeKey];
if(mpKey)
{
__mpApp.nativeKeys[mpKey] = nativeKey;
}
}
}
mp_window_data* mp_window_alloc()
{
return(ListPopEntry(&__mpAppData.windowFreeList, mp_window_data, freeListElt));
}
mp_window_data* mp_window_ptr_from_handle(mp_window handle)
{
u32 index = handle.h>>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<<button);
}
else if(action == MP_KEY_RELEASE)
{
__mpApp.win32.mouseCaptureMask &= ~(1<<button);
if(!__mpApp.win32.mouseCaptureMask)
{
ReleaseCapture();
}
}
mp_update_key_state(&__mpApp.inputState.mouse.buttons[button], action == MP_KEY_PRESS);
//TODO click/double click
mp_event event = {0};
event.window = mp_window_handle_from_ptr(window);
event.type = MP_EVENT_MOUSE_BUTTON;
event.key.action = MP_KEY_PRESS;
event.key.code = MP_MOUSE_LEFT;
event.key.mods = mp_get_mod_keys();
mp_queue_event(&event);
}
static void process_wheel_event(mp_window_data* window, f32 x, f32 y)
{
mp_event event = {0};
event.window = mp_window_handle_from_ptr(window);
event.type = MP_EVENT_MOUSE_WHEEL;
event.move.deltaX = -x/30.0f;
event.move.deltaY = y/30.0f;
event.move.mods = mp_get_mod_keys();
mp_queue_event(&event);
}
LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
@ -133,9 +255,208 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam)
mp_event event = {0};
event.window = mp_window_handle_from_ptr(mpWindow);
event.type = MP_EVENT_WINDOW_CLOSE;
mp_queue_event(&event);
} break;
//TODO: enter/exit size & move
case WM_SIZING:
{
RECT* rect = (RECT*)lParam;
mp_event event = {0};
event.window = mp_window_handle_from_ptr(mpWindow);
event.type = MP_EVENT_WINDOW_RESIZE;
event.frame.rect = (mp_rect){rect->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

View File

@ -10,17 +10,27 @@
#ifndef __WIN32_APP_H_
#define __WIN32_APP_H_
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#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_

View File

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

View File

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