diff --git a/GNUmakefile b/GNUmakefile index f61e1a4..9cff818 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -9,7 +9,7 @@ CXXFLAGS ?= -std=c++20 -Wall -Wpedantic -Wextra -g -Og LDFLAGS ?= NAME := suwi -libs := m z portaudio SDL3 +libs := m z SDL3 includes := src/ cflags := $(addprefix -I,${includes}) ${CFLAGS} cxxflags := $(addprefix -I,${includes}) ${CXXFLAGS} diff --git a/assets.mk b/assets.mk index d31341b..6012596 100644 --- a/assets.mk +++ b/assets.mk @@ -9,19 +9,19 @@ pictures := $(patsubst src/%.ase,out/%.picture, $(wildcard src/*.ase)) out/suwi.assets: ${shaders} ${pictures} | out/assetsmk printf '%s\0' $^ | sed -nz 'p;s:.*/::p' | $| -c0f out/suwi.assets -F - -N - -out/%.shader: src/%.glsl utl/vert.awk utl/frag.awk +out/%.shader: src/%.glsl utl/vert.awk utl/frag.awk | out/ awk -f utl/vert.awk $< > $@ printf '\0' >> $@ awk -f utl/frag.awk $< >> $@ printf '\0' >> $@ -out/%.shader: src/%.frag utl/vert.awk utl/frag.awk src/default.glsl +out/%.shader: src/%.frag utl/vert.awk utl/frag.awk src/default.glsl | out/ awk -f utl/vert.awk src/default.glsl > $@ printf '\0' >> $@ cat $< >> $@ printf '\0' >> $@ -out/%.png: src/%.ase +out/%.png: src/%.ase | out/ ${PRITE} -b $< --save-as $@ out/%.picture: out/picmake out/%.png diff --git a/src/input.c++ b/src/input.c++ new file mode 100644 index 0000000..68debb0 --- /dev/null +++ b/src/input.c++ @@ -0,0 +1,166 @@ +#include "input.h++" + +std::bitset input::_held, input::_pressed, input::_buffered, input::_buffer_mask; + +struct input::keyboard input::keyboard; +SDL_Scancode input::keyboard::keybinds[input::_LENGTH][2] = { + {SDL_SCANCODE_UP, SDL_SCANCODE_W}, + {SDL_SCANCODE_DOWN, SDL_SCANCODE_S}, + {SDL_SCANCODE_LEFT, SDL_SCANCODE_A}, + {SDL_SCANCODE_RIGHT, SDL_SCANCODE_D}, +}; +std::bitset input::keyboard::state[2]; + +SDL_JoystickID input::gamepad::joystick; +SDL_Gamepad *input::gamepad::controller; +SDL_GamepadButton input::gamepad::keybinds[input::_LENGTH][2] = { + {SDL_GAMEPAD_BUTTON_DPAD_UP, SDL_GAMEPAD_BUTTON_NORTH}, + {SDL_GAMEPAD_BUTTON_DPAD_DOWN, SDL_GAMEPAD_BUTTON_SOUTH}, + {SDL_GAMEPAD_BUTTON_DPAD_LEFT, SDL_GAMEPAD_BUTTON_WEST}, + {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, SDL_GAMEPAD_BUTTON_EAST}, +}; +std::bitset input::gamepad::state[2]; + +std::vector input::touch::positions; +std::bitset input::touch::state; + +void input::tickle(void) { + _buffered &= _buffer_mask; + _buffer_mask.set(); + _pressed = _held; + _held = keyboard.state[0] | keyboard.state[1] | gamepad.state[0] | gamepad.state[1] | touch.state ; + _pressed = ~_pressed & _held; + _buffered |= _pressed; + _buffered &= _held; +} + +void input::touch::refresh(void) { + state.reset(); + for (size_t i = 0; i < positions.size(); i++) { + if (positions[i].active) { + switch ((int) (positions[i].x * 5)) { + case 0: + state[input::LEFT] = true; + break; + case 1: + state[input::RIGHT] = true; + break; + case 3: + state[input::DOWN] = true; + break; + case 4: + state[input::UP] = true; + break; + default:; + } + } + } +} + +void input::event(SDL_Event const &evt) { + switch (evt.type) { + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + if (evt.key.repeat) { + break; + } + + for (unsigned key = 0; key < input::_LENGTH; key++) { + if (evt.key.scancode == keyboard.keybinds[key][0]) { + keyboard.state[0][key] = evt.key.down; + } + if (evt.key.scancode == keyboard.keybinds[key][1]) { + keyboard.state[1][key] = evt.key.down; + } + } + break; + + case SDL_EVENT_MOUSE_MOTION: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + case SDL_EVENT_MOUSE_WHEEL: + break; + + case SDL_EVENT_FINGER_UP: { + size_t const i = evt.tfinger.fingerID; + touch.positions[i].active = false; + touch::refresh(); + } break; + case SDL_EVENT_FINGER_DOWN: { + size_t const i = evt.tfinger.fingerID; + if (i >= touch.positions.size()) { + #if 0 + size_t const start = touch.allocated; + touch.allocated = i + 1; + touch.positions = realloc(touch.positions, sizeof (struct touch_vec) * touch.allocated); + if (i) { // hack for 0 - 1 = absurd-high number; all of RAM gets wiped + for (size_t index = start; index < i - 1; index++) { + touch.positions[index].active = 0; + } + } + #else + touch.positions.resize(i + 1); + #endif + } + touch.positions[i].x = evt.tfinger.x; + touch.positions[i].y = evt.tfinger.y; + touch.positions[i].active = true; + touch::refresh(); + } break; + case SDL_EVENT_FINGER_MOTION: { + size_t const i = evt.tfinger.fingerID; + touch.positions[i].x = evt.tfinger.x; + touch.positions[i].y = evt.tfinger.y; + touch::refresh(); + } break; + + case SDL_EVENT_GAMEPAD_ADDED: + if (gamepad.joystick != 0) { + break; + } + if ((gamepad.controller = SDL_OpenGamepad(evt.gdevice.which)) != NULL) { + gamepad.joystick = evt.gdevice.which; + } + break; + + case SDL_EVENT_GAMEPAD_REMOVED: + if (gamepad.joystick == evt.gdevice.which) { + SDL_CloseGamepad(gamepad.controller); + gamepad.controller = NULL; + gamepad.joystick = 0; + } + break; + + case SDL_EVENT_GAMEPAD_BUTTON_UP: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + if (gamepad.joystick == evt.gbutton.which) { + for (unsigned key = 0; key < input::_LENGTH; key++) { + if (evt.gbutton.button == gamepad.keybinds[key][0]) { + gamepad.state[0][key] = evt.gbutton.down; + } + if (evt.gbutton.button == gamepad.keybinds[key][1]) { + gamepad.state[1][key] = evt.gbutton.down; + } + } + } + break; + + case SDL_EVENT_JOYSTICK_AXIS_MOTION: + case SDL_EVENT_JOYSTICK_BALL_MOTION: + case SDL_EVENT_JOYSTICK_HAT_MOTION: + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: + case SDL_EVENT_JOYSTICK_ADDED: + break; // we dont care about these + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + case SDL_EVENT_GAMEPAD_REMAPPED: + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: + case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: + break; // we currently dont do anything about these + default: + break; + } +} diff --git a/src/input.h++ b/src/input.h++ new file mode 100644 index 0000000..3a1d13b --- /dev/null +++ b/src/input.h++ @@ -0,0 +1,58 @@ +#pragma once +#include +#include +#include + +class input final { + input() = delete; + public: + enum button { + UP, + DOWN, + LEFT, + RIGHT, + + _LENGTH // no. of checked inputs + }; + + static bool held(enum button which) { + return _held[which]; + } + static bool pressed(enum button which) { + return _pressed[which]; + } + static bool buffered(enum button which) { + return _buffered[which]; + } + static void unbuffer(enum button which) { + _buffer_mask[which] = false; + } + static void event(SDL_Event const &evt); + static void tickle(void); + + private: + + static std::bitset<_LENGTH> _held, _pressed, _buffered, _buffer_mask; + + static struct keyboard { + static SDL_Scancode keybinds[_LENGTH][2]; + static std::bitset<_LENGTH> state[2]; + } keyboard; + + static struct gamepad { + static SDL_JoystickID joystick; + static SDL_Gamepad *controller; + static SDL_GamepadButton keybinds[_LENGTH][2]; + static std::bitset<_LENGTH> state[2]; + } gamepad; + + static struct touch { + static void refresh(void); + struct position { + float x, y; + bool active; + }; + static std::vector positions; + static std::bitset<_LENGTH> state; + } touch; +}; diff --git a/src/main.c++ b/src/main.c++ index eb669a5..c3b7bdc 100644 --- a/src/main.c++ +++ b/src/main.c++ @@ -12,6 +12,7 @@ #include "batch.h" #include "assets.h++" #include "main.h++" +#include "input.h++" #define WINDOW_VIRTUAL 128 // screen buffer, ideally with some padding for the offscreen #define WINDOW_WIDTH 128 // viewport width @@ -34,7 +35,7 @@ static int framebuffer_init(void); SDL_AppResult SDL_AppInit(void **, int argc, char **argv) { clock_t begin = clock(); - SDL_Init(SDL_INIT_VIDEO); + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); @@ -48,7 +49,7 @@ SDL_AppResult SDL_AppInit(void **, int argc, char **argv) { int version = gladLoadGLES2((GLADloadfunc) SDL_GL_GetProcAddress); if (version == 0) { - puts("error: GLES2 failed to initialize"); + fputs("error: GLES2 failed to initialize\n", stderr); return SDL_APP_FAILURE; } fprintf(stderr, "info: GLES%u.%u\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)); @@ -98,20 +99,40 @@ SDL_AppResult SDL_AppEvent(void *, SDL_Event *evt) { return SDL_APP_SUCCESS; case SDL_EVENT_KEY_DOWN: - case SDL_EVENT_KEY_UP: - if (!evt->key.repeat && evt->key.down == true) { + if (!evt->key.repeat) { if (evt->key.scancode == SDL_SCANCODE_1) { square_pixels = !square_pixels; } else if (evt->key.scancode == SDL_SCANCODE_2) { integer_upscale = !integer_upscale; } } - break; - + // fallthrough + case SDL_EVENT_KEY_UP: case SDL_EVENT_MOUSE_MOTION: case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_WHEEL: + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_AXIS_MOTION: + case SDL_EVENT_JOYSTICK_BALL_MOTION: + case SDL_EVENT_JOYSTICK_HAT_MOTION: + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: + case SDL_EVENT_JOYSTICK_ADDED: + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + case SDL_EVENT_GAMEPAD_REMAPPED: + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: + case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: + input::event(*evt); break; case SDL_EVENT_WINDOW_SHOWN: @@ -120,24 +141,27 @@ SDL_AppResult SDL_AppEvent(void *, SDL_Event *evt) { case SDL_EVENT_WINDOW_MAXIMIZED: case SDL_EVENT_WINDOW_RESTORED: case SDL_EVENT_WINDOW_MOVED: - break; + break; // whatever + case SDL_EVENT_WINDOW_RESIZED: window_width = evt->window.data1; window_height = evt->window.data2; break; + case SDL_EVENT_WINDOW_MOUSE_ENTER: case SDL_EVENT_WINDOW_MOUSE_LEAVE: case SDL_EVENT_WINDOW_FOCUS_GAINED: case SDL_EVENT_WINDOW_FOCUS_LOST: case SDL_EVENT_WINDOW_CLOSE_REQUESTED: - break; + break; // whatever + case SDL_EVENT_WINDOW_EXPOSED: case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: - break; + break; // whatever these even are case SDL_EVENT_CLIPBOARD_UPDATE: - break; + break; // shush default: fprintf(stderr, "info: unknown event %x\n", evt->type); @@ -153,6 +177,8 @@ static struct { } fb; SDL_AppResult SDL_AppIterate(void *) { + input::tickle(); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glViewport(0, 0, WINDOW_VIRTUAL, WINDOW_VIRTUAL); glClearColor(0.0, 0.0, 0.0, 0.0);