#pragma once #if !(defined(STELA_API_NULL) || defined(STELA_API_OPENGL) || \ defined(STELA_API_VULKAN) || defined(STELA_API_DX11)) #error "No graphics API defined." #endif #if defined(STELA_API_NULL) + defined(STELA_API_OPENGL) + \ defined(STELA_API_VULKAN) + defined(STELA_API_DX11) != 1 #error "Conflicting graphics APIs." #endif #if !(defined(STELA_POLL_FD) || defined(STELA_POLL_INLINE)) #error "No poll method defined." #endif #include #include #include #ifdef STELA_EVENT_BUFFER #include #endif #if defined STELA_API_VULKAN #if defined STELA_WINDOW_WIN32 #define VK_USE_PLATFORM_WIN32_KHR #elif defined STELA_WINDOW_WAYLAND #define VK_USE_PLATFORM_WAYLAND_KHR #elif defined STELA_WINDOW_X11 #define VK_USE_PLATFORM_XLIB_KHR #endif #include #elif defined STELA_API_DX11 #include #elif defined STELA_API_OPENGL && defined STELA_USE_EGL #include "egl_common.h" #endif #ifndef STELA_MIN_WIDTH #define STELA_MIN_WIDTH 16u #endif #ifndef STELA_MIN_HEIGHT #define STELA_MIN_HEIGHT 16u #endif #ifdef STELA_WINDOW_WAYLAND #define STELA_ICON_AT_RUNTIME #endif // Drag window by clicking anywhere with MOUSE2. #define STELA_MOUSE2_DRAG enum { STELA_WINDOW_VSYNC = 1, STELA_WINDOW_WALLPAPER = 1 << 1 }; enum { STELA_CURSOR_NORMAL = 0, STELA_CURSOR_MOVE, STELA_CURSOR_CROSSHAIR, STELA_CURSOR_HIDDEN }; #define STELA_MAX_MONITOR_NAME 255u struct stl_monitor { u32 width; u32 height; u32 scale; bool vertical; char name[STELA_MAX_MONITOR_NAME]; }; #define STELA_EVENT_SIZE 24u #ifndef STELA_EVENTS_SIZE #define STELA_EVENTS_SIZE (STELA_EVENT_SIZE * 64u) #endif struct stl_window { u32 width; u32 height; u32 scale; bool fullscreen; u32 flags; // Methods. bool (*create_window)(struct stl_window *, u32, u32, u32, const char *, const char *, const char *); void (*resize_internal)(struct stl_window *, u32, u32); void (*resize)(struct stl_window *, u32, u32); void (*toggle_fullscreen)(struct stl_window *); void (*set_cursor)(struct stl_window *window, u8); void (*set_decorations)(struct stl_window *, bool); #ifdef STELA_POLL_INLINE bool (*poll)(struct stl_window *, bool); #ifdef STELA_PAUSE void (*wake)(struct stl_window *); #endif #endif void (*process_events)(struct stl_window *); #ifdef STELA_PAUSE bool (*should_refresh)(struct stl_window *); #endif void (*close)(struct stl_window *window); void (*free)(struct stl_window **); // Context specific. #if defined STELA_API_VULKAN VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *); VkResult (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *); VkResult (*vk_destroy_surface)(VkInstance, VkSurfaceKHR); const char *const *(*vk_get_extensions)(u32 *); #elif defined STELA_API_DX11 HWND win32_window; #elif defined STELA_API_OPENGL #ifdef STELA_USE_EGL EGLDisplay egl_display; EGLContext egl_context; #endif void (*(*get_gl_proc_address)(const char *))(void); bool (*gl_loader_load)(void *); bool (*gl_make_current)(void *); void (*gl_release_current)(void *); void (*gl_swap_buffers)(void *); #endif // Callbacks. void (*output_discovered_callback)(void *, struct stl_monitor *); void (*render_callback)(void *); void (*resize_callback)(void *, u32, u32); bool (*pointer_pos_callback)(void *, f64, f64); bool (*touch_callback)(void *, s32, u8, f64, f64); bool (*scroll_callback)(void *, f64); bool (*mouse_button_callback)(void *, u8, u8); bool (*key_callback)(void *, u8, u16); // Immediate: // - Always runs on the thread that received the event. // - Return value decides if the event should "pass through" or not. // True = Consume, False = Passthrough. bool (*key_immediate_callback)(void *, u8, u16); void (*should_close_callback)(void *); void *userdata; bool closed; u32 held_mouse_buttons; u32 held_modifiers; #ifdef STELA_PAUSE bool pending_refresh; #endif #ifdef STELA_EVENT_BUFFER bool pending_resize; // Render thread events. struct al_ring_buffer events; u8 data[STELA_EVENTS_SIZE]; #endif }; enum { STELA_EVENT_RESIZE = 0, STELA_EVENT_POINTER_POS, STELA_EVENT_TOUCH, STELA_EVENT_SCROLL, STELA_EVENT_MOUSE_BUTTON, STELA_EVENT_KEY, STELA_EVENT_SHOULD_CLOSE, STELA_EVENT_NONE = 255 }; enum { STELA_BUTTON_PRESSED = 0, STELA_BUTTON_RELEASED }; enum { STELA_MOUSE1 = 1, STELA_MOUSE2 = 1 << 1, STELA_MOUSE3 = 1 << 2 }; AL_IGNORE_WARNING("-Wunused-variable") static u8 stl_all_mouse_buttons[] = { STELA_MOUSE1, STELA_MOUSE2, STELA_MOUSE3 }; AL_IGNORE_WARNING_END enum { STELA_TOUCH_HOVER = 0, STELA_TOUCH_BEGAN, STELA_TOUCH_MOVED, STELA_TOUCH_ENDED, STELA_TOUCH_CANCELLED }; extern s32 stl_platform_main(u32 argc, str *argv); f64 stl_scale_scroll(f64 v, f64 factor); void stl_set_output_discovered_callback(void (*output_discovered)(void *, struct stl_monitor *), void *userdata); #ifdef STELA_ICON_AT_RUNTIME void stl_set_icon_data(u8 *data, u32 size); #endif bool stl_global_init(bool skip_graphics); s32 stl_global_get_poll_fd(void); void stl_global_process_events(void); s32 stl_swallow_main(u32 argc, str *argv, s32 (*main)(u32, str *, void *), void *extra); void stl_global_close(void); struct stl_window *stl_window_create(void); void stl_window_send_render_event(struct stl_window *window); void stl_window_send_resize_event(struct stl_window *window, u32 width, u32 height); void stl_window_send_pointer_pos_event(struct stl_window *window, f64 x, f64 y); void stl_window_send_touch_event(struct stl_window *window, s32 index, u8 phase, f64 x, f64 y); void stl_window_send_scroll_event(struct stl_window *window, f64 y); void stl_window_send_mouse_button_event(struct stl_window *window, u8 state, u8 button); void stl_window_drop_mouse_buttons(struct stl_window *window); void stl_window_send_key_event(struct stl_window *window, u8 state, u16 button); bool stl_window_send_key_immediate_event(struct stl_window *window, u8 state, u16 button); void stl_window_drop_modifiers(struct stl_window *window); void stl_window_send_should_close_event(struct stl_window *window); #ifdef STELA_EVENT_BUFFER bool stl_window_read_events(struct stl_window *window); #endif