aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2021-12-09 16:46:37 +0100
committerDrew DeVault <sir@cmpwn.com>2021-12-09 16:46:37 +0100
commit81bac10cd7c26cf1ca1c0fcb9ee3dcccd7710f22 (patch)
tree649b0c5e3977041def1245d61ada75036410f809
parenttimer: correct naming convention (diff)
downloadhare-chip8-81bac10cd7c26cf1ca1c0fcb9ee3dcccd7710f22.tar.gz
Initial gamecontroller support
Diffstat (limited to '')
-rw-r--r--cmd/demo/main.ha189
-rw-r--r--sdl2/events.ha2
-rw-r--r--sdl2/gamecontroller.ha43
-rw-r--r--sdl2/joystick.ha13
4 files changed, 184 insertions, 63 deletions
diff --git a/cmd/demo/main.ha b/cmd/demo/main.ha
index 43aea33..77a24a9 100644
--- a/cmd/demo/main.ha
+++ b/cmd/demo/main.ha
@@ -1,6 +1,11 @@
use fmt;
use os;
-use sdl2::{event_type, window_flags, renderer_flags};
+use sdl2::{
+ controller_axis,
+ event_type,
+ renderer_flags,
+ window_flags,
+};
use sdl2;
use sdl2::image;
use strings;
@@ -12,6 +17,7 @@ type texture = struct {
};
type state = struct {
+ quit: bool,
window: *sdl2::window,
render: *sdl2::renderer,
hare: texture,
@@ -22,10 +28,112 @@ type state = struct {
hare_dy: int,
cat_x: int,
cat_y: int,
+ cat_dx: int,
+ cat_dy: int,
+};
+
+fn update(state: *state) void = {
+ let ev = sdl2::event { ... };
+ for (sdl2::poll_event(&ev) == 1) switch (ev.event_type) {
+ case event_type::QUIT =>
+ state.quit = true;
+ return;
+ case event_type::CONTROLLERAXISMOTION =>
+ let delta = ev.caxis.value: int * 10 / sdl2::JOYSTICK_AXIS_MAX;
+ if (axis_x(ev.caxis.axis)) {
+ state.cat_dx = delta;
+ };
+ if (axis_y(ev.caxis.axis)) {
+ state.cat_dy = delta;
+ };
+ case => void;
+ };
+
+ let width = 0, height = 0;
+ sdl2::get_window_size(state.window, &width, &height);
+
+ state.hare_x += state.hare_dx;
+ state.hare_y += state.hare_dy;
+ if (state.hare_x <= 0 || state.hare_x + state.hare.w >= width) {
+ state.hare_dx = -state.hare_dx;
+ };
+ if (state.hare_y <= 0 || state.hare_y + state.hare.h >= height) {
+ state.hare_dy = -state.hare_dy;
+ };
+
+ state.cat_x += state.cat_dx;
+ state.cat_y += state.cat_dy;
+ if (state.cat_x <= 0) {
+ state.cat_x = 0;
+ };
+ if (state.cat_x > width - state.cat.w) {
+ state.cat_x = width - state.cat.w;
+ };
+ if (state.cat_y <= 0) {
+ state.cat_y = 0;
+ };
+ if (state.cat_y > height - state.cat.h) {
+ state.cat_y = height - state.cat.h;
+ };
+};
+
+fn draw(state: *state) void = {
+ sdl2::set_render_draw_color(state.render, 50, 50, 50, 255);
+ sdl2::render_clear(state.render);
+ draw_tex(state, &state.hare, state.hare_x, state.hare_y);
+ draw_tex(state, &state.cat, state.cat_x, state.cat_y);
+ sdl2::render_present(state.render);
+};
+
+fn draw_tex(state: *state, tex: *texture, x: int, y: int) void = {
+ sdl2::render_copy(state.render, tex.tex, null, &sdl2::rect {
+ x = x,
+ y = y,
+ w = tex.w,
+ h = tex.h,
+ });
+};
+
+fn axis_x(axis: controller_axis) bool = {
+ switch (axis) {
+ case controller_axis::LEFTX, controller_axis::RIGHTX =>
+ return true;
+ case =>
+ return false;
+ };
+};
+
+fn axis_y(axis: controller_axis) bool = {
+ switch (axis) {
+ case controller_axis::LEFTY, controller_axis::RIGHTY =>
+ return true;
+ case =>
+ return false;
+ };
+};
+
+fn load_texture(render: *sdl2::renderer, path: str) texture = {
+ const path = strings::to_c(path);
+ defer free(path);
+
+ const tex = match (image::load_texture(render, path)) {
+ case let tex: *sdl2::texture =>
+ yield tex;
+ case null =>
+ fmt::fatal("sdl2::image::load_texture failed for cat.png");
+ };
+
+ let w = 0, h = 0;
+ sdl2::query_texture(tex, null, null, &w, &h);
+ return texture {
+ tex = tex,
+ w = w,
+ h = h,
+ };
};
export fn main() void = {
- sdl2::init(sdl2::init_flags::VIDEO);
+ sdl2::init(sdl2::init_flags::VIDEO | sdl2::init_flags::GAMECONTROLLER);
defer sdl2::quit();
let flags = image::init(image::init_flags::PNG | image::init_flags::JPG);
defer image::quit();
@@ -50,6 +158,22 @@ export fn main() void = {
};
defer sdl2::destroy_renderer(render);
+ let controller: nullable *sdl2::gamecontroller = null;
+ for (let i = 0; i < sdl2::numjoysticks(); i += 1) {
+ if (!sdl2::is_game_controller(i)) {
+ continue;
+ };
+ controller = sdl2::game_controller_open(i);
+ if (controller != null) {
+ break;
+ };
+ };
+ defer match (controller) {
+ case null => void;
+ case let c: *sdl2::gamecontroller =>
+ sdl2::game_controller_close(c);
+ };
+
let state = state {
window = win,
render = render,
@@ -64,70 +188,11 @@ export fn main() void = {
defer sdl2::destroy_texture(state.hare.tex);
defer sdl2::destroy_texture(state.cat.tex);
- let ev = sdl2::event { ... };
- for (true) {
- if (sdl2::poll_event(&ev) == 1) switch (ev.event_type) {
- case event_type::QUIT =>
- break;
- case => void;
- };
-
+ for (!state.quit) {
update(&state);
draw(&state);
-
sdl2::delay(1000 / 60);
};
os::exit(0); // https://todo.sr.ht/~sircmpwn/hare/525
};
-
-fn load_texture(render: *sdl2::renderer, path: str) texture = {
- const path = strings::to_c(path);
- defer free(path);
-
- const tex = match (image::load_texture(render, path)) {
- case let tex: *sdl2::texture =>
- yield tex;
- case null =>
- fmt::fatal("sdl2::image::load_texture failed for cat.png");
- };
-
- let w = 0, h = 0;
- sdl2::query_texture(tex, null, null, &w, &h);
- return texture {
- tex = tex,
- w = w,
- h = h,
- };
-};
-
-fn update(state: *state) void = {
- let width = 0, height = 0;
- sdl2::get_window_size(state.window, &width, &height);
-
- state.hare_x += state.hare_dx;
- state.hare_y += state.hare_dy;
- if (state.hare_x <= 0 || state.hare_x + state.hare.w >= width) {
- state.hare_dx = -state.hare_dx;
- };
- if (state.hare_y <= 0 || state.hare_y + state.hare.h >= height) {
- state.hare_dy = -state.hare_dy;
- };
-};
-
-fn draw(state: *state) void = {
- sdl2::set_render_draw_color(state.render, 50, 50, 50, 255);
- sdl2::render_clear(state.render);
- draw_tex(state, &state.hare, state.hare_x, state.hare_y);
- draw_tex(state, &state.cat, state.cat_x, state.cat_y);
- sdl2::render_present(state.render);
-};
-
-fn draw_tex(state: *state, tex: *texture, x: int, y: int) void = {
- sdl2::render_copy(state.render, tex.tex, null, &sdl2::rect {
- x = x,
- y = y,
- w = tex.w,
- h = tex.h,
- });
-};
diff --git a/sdl2/events.ha b/sdl2/events.ha
index 60ac771..e26333a 100644
--- a/sdl2/events.ha
+++ b/sdl2/events.ha
@@ -220,7 +220,7 @@ export type joy_device_event = struct {
export type controller_axis_event = struct {
common_event,
which: i32, // TODO
- axis: u8,
+ axis: controller_axis,
padding1: u8,
padding2: u8,
padding3: u8,
diff --git a/sdl2/gamecontroller.ha b/sdl2/gamecontroller.ha
new file mode 100644
index 0000000..3b752e1
--- /dev/null
+++ b/sdl2/gamecontroller.ha
@@ -0,0 +1,43 @@
+// TODO: Flesh me out
+
+// The gamecontroller structure used to identify an SDL game controller.
+// (Opaque)
+export type gamecontroller = void;
+
+// The list of axes available from a controller
+//
+// Thumbstick axis values range from [[JOYSTICK_AXIS_MIN]] to
+// [[JOYSTICK_AXIS_MAX]], and are centered within ~8000 of zero, though advanced
+// UI will allow users to set or autodetect the dead zone, which varies between
+// controllers.
+//
+// Trigger axis values range from 0 to [[JOYSTICK_AXIS_MAX]].
+export type controller_axis = enum u8 {
+ LEFTX,
+ LEFTY,
+ RIGHTX,
+ RIGHTY,
+ TRIGGERLEFT,
+ TRIGGERRIGHT,
+ INVALID = 255,
+};
+
+// Check if the given joystick is supported by the game controller interface.
+//
+// 'joystick_index' is the same as the 'device_index' passed to
+// [[joystick_open]].
+//
+// Returns SDL_TRUE if the given joystick is supported by the game controller
+// interface, SDL_FALSE if it isn't or it's an invalid index.
+export @symbol("SDL_IsGameController") fn is_game_controller(
+ joystick_index: int) bool;
+
+// Get the SDL_GameController associated with an instance id.
+//
+// Returns a [[controller]] on success or NULL on failure.
+export @symbol("SDL_GameControllerOpen") fn game_controller_open(
+ joystick_index: int) *gamecontroller;
+
+// Close a game controller previously opened with [[game_controller_open]].
+export @symbol("SDL_GameControllerClose") fn game_controller_close(
+ gamecontroller: *gamecontroller) void;
diff --git a/sdl2/joystick.ha b/sdl2/joystick.ha
new file mode 100644
index 0000000..c4f4c96
--- /dev/null
+++ b/sdl2/joystick.ha
@@ -0,0 +1,13 @@
+// TODO: Flesh me out
+
+// Minimum value for a joystick axis.
+export def JOYSTICK_AXIS_MIN: i16 = -32768;
+
+// Minimum value for a joystick axis.
+export def JOYSTICK_AXIS_MAX: i16 = 32767;
+
+// Count the number of joysticks attached to the system.
+//
+// Returns the number of attached joysticks on success or a negative error code
+// on failure.
+export @symbol("SDL_NumJoysticks") fn numjoysticks() int;