aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2021-12-09 13:06:45 +0100
committerDrew DeVault <sir@cmpwn.com>2021-12-09 13:07:36 +0100
commit01bb53f01d5d8b732bd80a84f25b661e1452faeb (patch)
tree822f1c568ce60ca68dd8a1f65b1828a60fb554e4
parentInitial commit (diff)
downloadhare-chip8-01bb53f01d5d8b732bd80a84f25b661e1452faeb.tar.gz
Rig up events, partially rig up video
-rw-r--r--Makefile4
-rw-r--r--cmd/demo/main.ha29
-rw-r--r--sdl2/events.ha448
-rw-r--r--sdl2/sdl2.ha (renamed from sdl2/prototypes.ha)0
-rw-r--r--sdl2/video.ha73
5 files changed, 550 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index dd2d9dd..fa692a8 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
demo:
hare build -lSDL2 -lc -T+libc cmd/demo
-run: demo
- ./demo
+run:
+ hare run -lSDL2 -lc -T+libc cmd/demo
.PHONY: demo run
diff --git a/cmd/demo/main.ha b/cmd/demo/main.ha
index 1a8e362..1c780fd 100644
--- a/cmd/demo/main.ha
+++ b/cmd/demo/main.ha
@@ -1,8 +1,33 @@
-use sdl2;
+use fmt;
use os;
+use sdl2::{event_type, window_flags};
+use sdl2;
+use strings;
export fn main() void = {
sdl2::init(sdl2::init_flags::VIDEO);
defer sdl2::quit();
- os::exit(0);
+
+ const title = strings::to_c("Hare SDL2 demo");
+ defer free(title);
+ const win = match (sdl2::create_window(title,
+ sdl2::WINDOWPOS_UNDEFINED, sdl2::WINDOWPOS_UNDEFINED,
+ 640, 480, window_flags::NONE)) {
+ case let win: *sdl2::window =>
+ yield win;
+ case null =>
+ fmt::fatal("sdl2::create_window failed");
+ };
+ defer sdl2::destroy_window(win);
+
+ let ev = sdl2::event { ... };
+ for (sdl2::wait_event(&ev) == 1) {
+ switch (ev.event_type) {
+ case event_type::QUIT =>
+ break;
+ case => void;
+ };
+ };
+
+ os::exit(0); // https://todo.sr.ht/~sircmpwn/hare/525
};
diff --git a/sdl2/events.ha b/sdl2/events.ha
new file mode 100644
index 0000000..60ac771
--- /dev/null
+++ b/sdl2/events.ha
@@ -0,0 +1,448 @@
+export type event_type = enum u32 {
+ FIRSTEVENT = 0,
+
+ QUIT = 0x100,
+
+ APP_TERMINATING,
+ APP_LOWMEMORY,
+ APP_WILLENTERBACKGROUND,
+ APP_DIDENTERBACKGROUND,
+ APP_WILLENTERFOREGROUND,
+ APP_DIDENTERFOREGROUND,
+
+ DISPLAYEVENT = 0x150,
+
+ WINDOWEVENT = 0x200,
+ SYSWMEVENT,
+
+ KEYDOWN = 0x300,
+ KEYUP,
+ TEXTEDITING,
+ TEXTINPUT,
+ KEYMAPCHANGED,
+
+ MOUSEMOTION = 0x400,
+ MOUSEBUTTONDOWN,
+ MOUSEBUTTONUP,
+ MOUSEWHEEL,
+
+ JOYAXISMOTION = 0x600,
+ JOYBALLMOTION,
+ JOYHATMOTION,
+ JOYBUTTONDOWN,
+ JOYBUTTONUP,
+ JOYDEVICEADDED,
+ JOYDEVICEREMOVED,
+
+ CONTROLLERAXISMOTION = 0x650,
+ CONTROLLERBUTTONDOWN,
+ CONTROLLERBUTTONUP,
+ CONTROLLERDEVICEADDED,
+ CONTROLLERDEVICEREMOVED,
+ CONTROLLERDEVICEREMAPPED,
+
+ FINGERDOWN = 0x700,
+ FINGERUP,
+ FINGERMOTION,
+
+ DOLLARGESTURE = 0x800,
+ DOLLARRECORD,
+ MULTIGESTURE,
+
+ CLIPBOARDUPDATE = 0x900,
+
+ DROPFILE = 0x1000,
+ DROPTEXT,
+ DROPBEGIN,
+ DROPCOMPLETE,
+
+ AUDIODEVICEADDED = 0x1100,
+ AUDIODEVICEREMOVED,
+
+ SENSORUPDATE = 0x1200,
+
+ RENDER_TARGETS_RESET = 0x2000,
+ RENDER_DEVICE_RESET,
+
+ USEREVENT = 0x8000,
+
+ LASTEVENT = 0xFFFF
+};
+
+// Fields shared by every event
+export type common_event = struct {
+ event_type: event_type,
+ timestamp: u32,
+};
+
+// Display state change event data (event.display.*)
+export type display_event = struct {
+ common_event,
+ display: u32,
+ event: u8,
+ padding1: u8,
+ padding2: u8,
+ padding3: u8,
+ data1: i32,
+};
+
+// Window state change event data (event.window.*)
+export type window_event = struct {
+ common_event,
+ window_id: u32,
+ event: u8,
+ padding1: u8,
+ padding2: u8,
+ padding3: u8,
+ data1: i32,
+ data2: i32,
+};
+
+// Keyboard button event structure (event.key.*)
+export type keyboard_event = struct {
+ common_event,
+ window_id: u32,
+ state: u8,
+ repeat: u8,
+ padding2: u8,
+ padding3: u8,
+ keysym: uint, // TODO: Rig me up with the keysym type
+};
+
+// Size of the [[text_editing_event]] 'text' field.
+export def TEXTEDITINGEVENT_TEXT_SIZE: size = 32;
+
+// Keyboard text editing event structure (event.edit.*)
+export type text_editing_event = struct {
+ common_event,
+ window_id: u32,
+ text: [TEXTEDITINGEVENT_TEXT_SIZE]char,
+ start: i32,
+ length: i32,
+};
+
+// Size of the [[text_input_event]] 'text' field.
+export def TEXTINPUTEVENT_TEXT_SIZE: size = 32;
+
+// Keyboard text input event structure (event.text.*)
+export type text_input_event = struct {
+ common_event,
+ window_id: u32,
+ text: [TEXTINPUTEVENT_TEXT_SIZE]char,
+};
+
+// Mouse motion event structure (event.motion.*)
+export type mouse_motion_event = struct {
+ common_event,
+ window_id: u32,
+ which: u32,
+ state: u32,
+ x: i32,
+ y: i32,
+ xrel: i32,
+ yrel: i32,
+};
+
+// Mouse button event structure (event.button.*)
+export type mouse_button_event = struct {
+ common_event,
+ window_id: u32,
+ which: u32,
+ button: u8,
+ state: u8,
+ clicks: u8,
+ padding1: u8,
+ x: i32,
+ y: i32,
+};
+
+// Mouse wheel event structure (event.wheel.*)
+export type mouse_wheel_event = struct {
+ common_event,
+ window_id: u32,
+ which: u32,
+ x: i32,
+ y: i32,
+ direction: u32,
+};
+
+// Joystick axis motion event structure (event.jaxis.*)
+export type joy_axis_event = struct {
+ common_event,
+ which: i32, // TODO: Rig me up with the JoystickID type
+ axis: u8,
+ padding1: u8,
+ padding2: u8,
+ padding3: u8,
+ value: i16,
+ padding4: u16,
+};
+
+// Joystick trackball motion event structure (event.jball.*)
+export type joy_ball_event = struct {
+ common_event,
+ which: i32, // TODO: Rig me up with the JoystickID type
+ ball: u8,
+ padding1: u8,
+ padding2: u8,
+ padding3: u8,
+ xrel: i16,
+ yrel: i16,
+};
+
+// Joystick hat position change event structure (event.jhat.*)
+export type joy_hat_event = struct {
+ common_event,
+ which: i32, // TODO: Rig me up with the JoystickID type
+ hat: u8,
+ value: u8, // TODO: Rig me up with HAT_UP et al
+ padding1: u8,
+ padding2: u8,
+};
+
+// Joystick button event structure (event.jbutton.*)
+export type joy_button_event = struct {
+ common_event,
+ which: i32, // TODO: Rig me up with the JoystickID type
+ button: u8,
+ state: u8,
+ padding1: u8,
+ padding2: u8,
+};
+
+// Joystick device event structure (event.jdevice.*)
+export type joy_device_event = struct {
+ common_event,
+ which: i32,
+};
+
+// Game controller axis motion event structure (event.caxis.*)
+export type controller_axis_event = struct {
+ common_event,
+ which: i32, // TODO
+ axis: u8,
+ padding1: u8,
+ padding2: u8,
+ padding3: u8,
+ value: i16,
+ padding4: u16,
+};
+
+// Game controller button event structure (event.cbutton.*)
+export type controller_button_event = struct {
+ common_event,
+ which: i32,
+ button: u8,
+ state: u8,
+ padding1: u8,
+ padding2: u8,
+};
+
+// Controller device event structure (event.cdevice.*)
+export type controller_device_event = struct {
+ common_event,
+ which: i32,
+};
+
+// Audio device event structure (event.adevice.*)
+export type audio_device_event = struct {
+ common_event,
+ which: u32,
+ iscapture: u8,
+ padding1: u8,
+ padding2: u8,
+ padding3: u8,
+};
+
+// Touch finger event structure (event.tfinger.*)
+export type touch_finger_event = struct {
+ common_event,
+ touch_id: i64, // TODO
+ finger_id: i64, // TODO
+ x: f32,
+ y: f32,
+ dx: f32,
+ dy: f32,
+ pressure: f32,
+};
+
+// Multiple Finger Gesture Event (event.mgesture.*)
+export type multi_gesture_event = struct {
+ common_event,
+ touch_id: i64, // TODO
+ dtheta: f32,
+ ddist: f32,
+ x: f32,
+ y: f32,
+ num_fingers: u16,
+ padding: u16,
+};
+
+// Dollar Gesture Event (event.dgesture.*)
+export type dollar_gesture_event = struct {
+ common_event,
+ touch_id: i64, // TODO
+ gesture_id: i64, // TODO
+ num_fingers: u32,
+ error: f32,
+ x: f32,
+ y: f32,
+};
+
+// An event used to request a file open by the system (event.drop.*)
+// This event is enabled by default, you can disable it with [[eventstate]].
+// If this event is enabled, you must free the filename in the event.
+export type drop_event = struct {
+ common_event,
+ file: *char,
+ window_id: u32,
+};
+
+// Sensor event structure (event.sensor.*)
+export type sensor_event = struct {
+ common_event,
+ which: i32,
+ data: [6]f32,
+};
+
+// The "quit requested" event
+export type quit_event = struct {
+ common_event,
+};
+
+// OS Specific event
+export type os_event = struct {
+ common_event,
+};
+
+// A user-defined event type (event.user.*)
+export type user_event = struct {
+ common_event,
+ window_id: u32,
+ code: i32,
+ data1: *void,
+ data2: *void,
+};
+
+// A video driver dependent system event (event.syswm.*)
+// This event is disabled by default, you can enable it with [[eventstate]].
+export type syswm_event = struct {
+ common_event,
+ msg: *void, // TODO
+};
+
+// General event structure
+export type event = union {
+ event_type: event_type,
+ common: common_event,
+ display: display_event,
+ window: window_event,
+ key: keyboard_event,
+ edit: text_editing_event,
+ text: text_input_event,
+ motion: mouse_motion_event,
+ button: mouse_button_event,
+ wheel: mouse_wheel_event,
+ jaxis: joy_axis_event,
+ jball: joy_ball_event,
+ jhat: joy_hat_event,
+ jbutton: joy_button_event,
+ jdevice: joy_device_event,
+ caxis: controller_axis_event,
+ cbutton: controller_button_event,
+ cdevice: controller_device_event,
+ adevice: audio_device_event,
+ sensor: sensor_event,
+ quit: quit_event,
+ user: user_event,
+ syswm: syswm_event,
+ tfinger: touch_finger_event,
+ mgesture: multi_gesture_event,
+ dgestures: dollar_gesture_event,
+ drop: drop_event,
+
+ padding: [56]u8,
+};
+
+// Pumps the event loop, gathering events from the input devices.
+//
+// This function updates the event queue and internal input device state.
+//
+// This should only be run in the thread that sets the video mode.
+export @symbol("SDL_PumpEvents") fn pump_events() void;
+
+export type eventaction = enum {
+ ADDEVENT,
+ PEEKEVENT,
+ GETEVENT,
+};
+
+// Checks the event queue for messages and optionally returns them.
+//
+// If 'action' is ADDEVENT, up to 'numevents' events will be added to the back
+// of the event queue.
+//
+// If 'action' is PEEKEVENT, up to 'numevents' events at the front of the event
+// queue, within the specified minimum and maximum type, will be returned and
+// will not be removed from the queue.
+//
+// If 'action' is GETEVENT, up to 'numevents' events at the front of the event
+// queue, within the specified minimum and maximum type, will be returned and
+// will be removed from the queue.
+//
+// Returns the number of events actually stored, or -1 if there was an error.
+//
+// This function is thread-safe.
+export @symbol("SDL_PeepEvents") fn peep_events(events: *event, numevents: int,
+ action: eventaction, mintype: event_type, maxtype: event_type) int;
+
+// Checks to see if certain event types are in the event queue.
+export @symbol("SDL_HasEvent") fn has_event(event_type: event_type) bool;
+
+// Checks to see if certain event types are in the event queue.
+export @symbol("SDL_HasEvents") fn has_events(mintype: event_type, maxtype: event_type) bool;
+
+// This function clears events from the event queue
+// This function only affects currently queued events. If you want to make
+// sure that all pending OS events are flushed, you can call SDL_PumpEvents()
+// on the main thread immediately before the flush call.
+export @symbol("SDL_FlushEvent") fn flush_event(event_type: event_type) void;
+
+// This function clears events from the event queue
+// This function only affects currently queued events. If you want to make
+// sure that all pending OS events are flushed, you can call SDL_PumpEvents()
+// on the main thread immediately before the flush call.
+export @symbol("SDL_FlushEvents") fn flush_events(mintype: event_type, maxtype: event_type) void;
+
+// Polls for currently pending events.
+//
+// Returns 1 if there are any pending events, or 0 if there are none available.
+//
+// If 'event' is not null, the next event is removed from the queue and stored
+// in that area.
+export @symbol("SDL_PollEvent") fn poll_event(event: nullable *event) int;
+
+// Waits indefinitely for the next available event.
+//
+// Returns 1, or 0 if there was an error while waiting for events.
+//
+// If 'event' is not null, the next event is removed from the queue and stored
+// in that area.
+export @symbol("SDL_WaitEvent") fn wait_event(event: nullable *event) int;
+
+// Waits until the specified timeout (in milliseconds) for the next available event.
+//
+// Returns 1, or 0 if there was an error while waiting for events.
+//
+// If 'event' is not null, the next event is removed from the queue and stored
+// in that area. The 'timeout' is the time (in milliseconds) to wait for next
+// event.
+export @symbol("SDL_WaitEventTimeout") fn wait_event_timeout(event: nullable *event, timeout: int) int;
+
+// Add an event to the event queue.
+//
+// Returns 1 on success, 0 if the event was filtered, or -1 if the event queue
+// was full or there was some other error.
+export @symbol("SDL_PushEvent") fn push_event(event: *event) int;
+
+// TODO: Finish rigging up other SDL_events.h bits
diff --git a/sdl2/prototypes.ha b/sdl2/sdl2.ha
index b71c890..b71c890 100644
--- a/sdl2/prototypes.ha
+++ b/sdl2/sdl2.ha
diff --git a/sdl2/video.ha b/sdl2/video.ha
new file mode 100644
index 0000000..e12ca12
--- /dev/null
+++ b/sdl2/video.ha
@@ -0,0 +1,73 @@
+// TODO: Flesh me out
+
+// The type used to identify a window. (Opaque)
+export type window = void;
+
+// The flags on a window
+export type window_flags = enum u32 {
+ NONE = 0,
+ FULLSCREEN = 0x00000001,
+ OPENGL = 0x00000002,
+ SHOWN = 0x00000004,
+ HIDDEN = 0x00000008,
+ BORDERLESS = 0x00000010,
+ RESIZABLE = 0x00000020,
+ MINIMIZED = 0x00000040,
+ MAXIMIZED = 0x00000080,
+ INPUT_GRABBED = 0x00000100,
+ INPUT_FOCUS = 0x00000200,
+ MOUSE_FOCUS = 0x00000400,
+ FULLSCREEN_DESKTOP = 0x00001001,
+ FOREIGN = 0x00000800,
+ ALLOW_HIGHDPI = 0x00002000,
+ MOUSE_CAPTURE = 0x00004000,
+ ALWAYS_ON_TOP = 0x00008000,
+ SKIP_TASKBAR = 0x00010000,
+ UTILITY = 0x00020000,
+ TOOLTIP = 0x00040000,
+ POPUP_MENU = 0x00080000,
+ VULKAN = 0x10000000
+};
+
+export def WINDOWPOS_UNDEFINED: int = 0x1FFF0000;
+export def WINDOWPOS_CENTERED: int = 0x2FFF0000;
+
+// Create a window with the specified position, dimensions, and flags.
+//
+// 'title' is the title of the window, in UTF-8 encoding. See [[strings::to_c]]
+// to prepare a suitable string.
+//
+// 'x' and 'y' set the position of the window, or use [[WINDOWPOS_CENTERED]] or
+// [[WINDOWPOS_UNDEFINED]].
+//
+// 'w' and 'h' set the width and height of the window, in screen coordinates.
+//
+// 'flags' configure additional window parameters.
+//
+// Returns the created window, or null if window creation failed.
+//
+// If the window is created with the SDL_WINDOW_ALLOW_HIGHDPI flag, its size
+// in pixels may differ from its size in screen coordinates on platforms with
+// high-DPI support (e.g. iOS and Mac OS X). Use SDL_GetWindowSize() to query
+// the client area's size in screen coordinates, and SDL_GL_GetDrawableSize(),
+// SDL_Vulkan_GetDrawableSize(), or SDL_GetRendererOutputSize() to query the
+// drawable size in pixels.
+//
+// If the window is created with any of the SDL_WINDOW_OPENGL or
+// SDL_WINDOW_VULKAN flags, then the corresponding LoadLibrary function
+// (SDL_GL_LoadLibrary or SDL_Vulkan_LoadLibrary) is called and the
+// corresponding UnloadLibrary function is called by SDL_DestroyWindow().
+//
+// If SDL_WINDOW_VULKAN is specified and there isn't a working Vulkan driver,
+// SDL_CreateWindow() will fail because SDL_Vulkan_LoadLibrary() will fail.
+//
+// Note: On non-Apple devices, SDL requires you to either not link to the
+// Vulkan loader or link to a dynamic library version. This limitation may be
+// removed in a future version of SDL.
+//
+// See also: [[destroy_window]] [[gl_loadlibrary]], [[vulkan_loadlibrary]].
+export @symbol("SDL_CreateWindow") fn create_window(title: const *char,
+ x: int, y: int, w: int, h: int, flags: window_flags) nullable *window;
+
+// Destroy a window.
+export @symbol("SDL_DestroyWindow") fn destroy_window(window: *window) void;