free will privileges

loosely copy pasted and C++-ified from project fywi
This commit is contained in:
zlago 2025-11-23 19:57:48 +01:00
parent d69c8e3a5e
commit ba340d9127
5 changed files with 264 additions and 14 deletions

View File

@ -9,7 +9,7 @@ CXXFLAGS ?= -std=c++20 -Wall -Wpedantic -Wextra -g -Og
LDFLAGS ?= LDFLAGS ?=
NAME := suwi NAME := suwi
libs := m z portaudio SDL3 libs := m z SDL3
includes := src/ includes := src/
cflags := $(addprefix -I,${includes}) ${CFLAGS} cflags := $(addprefix -I,${includes}) ${CFLAGS}
cxxflags := $(addprefix -I,${includes}) ${CXXFLAGS} cxxflags := $(addprefix -I,${includes}) ${CXXFLAGS}

View File

@ -9,19 +9,19 @@ pictures := $(patsubst src/%.ase,out/%.picture, $(wildcard src/*.ase))
out/suwi.assets: ${shaders} ${pictures} | out/assetsmk out/suwi.assets: ${shaders} ${pictures} | out/assetsmk
printf '%s\0' $^ | sed -nz 'p;s:.*/::p' | $| -c0f out/suwi.assets -F - -N - 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 $< > $@ awk -f utl/vert.awk $< > $@
printf '\0' >> $@ printf '\0' >> $@
awk -f utl/frag.awk $< >> $@ awk -f utl/frag.awk $< >> $@
printf '\0' >> $@ 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 > $@ awk -f utl/vert.awk src/default.glsl > $@
printf '\0' >> $@ printf '\0' >> $@
cat $< >> $@ cat $< >> $@
printf '\0' >> $@ printf '\0' >> $@
out/%.png: src/%.ase out/%.png: src/%.ase | out/
${PRITE} -b $< --save-as $@ ${PRITE} -b $< --save-as $@
out/%.picture: out/picmake out/%.png out/%.picture: out/picmake out/%.png

166
src/input.c++ Normal file
View File

@ -0,0 +1,166 @@
#include "input.h++"
std::bitset<input::_LENGTH> 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::_LENGTH> 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::_LENGTH> input::gamepad::state[2];
std::vector<struct input::touch::position> input::touch::positions;
std::bitset<input::_LENGTH> 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;
}
}

58
src/input.h++ Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include <SDL3/SDL_events.h>
#include <bitset>
#include <vector>
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<struct position> positions;
static std::bitset<_LENGTH> state;
} touch;
};

View File

@ -12,6 +12,7 @@
#include "batch.h" #include "batch.h"
#include "assets.h++" #include "assets.h++"
#include "main.h++" #include "main.h++"
#include "input.h++"
#define WINDOW_VIRTUAL 128 // screen buffer, ideally with some padding for the offscreen #define WINDOW_VIRTUAL 128 // screen buffer, ideally with some padding for the offscreen
#define WINDOW_WIDTH 128 // viewport width #define WINDOW_WIDTH 128 // viewport width
@ -34,7 +35,7 @@ static int framebuffer_init(void);
SDL_AppResult SDL_AppInit(void **, int argc, char **argv) { SDL_AppResult SDL_AppInit(void **, int argc, char **argv) {
clock_t begin = clock(); 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_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 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); int version = gladLoadGLES2((GLADloadfunc) SDL_GL_GetProcAddress);
if (version == 0) { if (version == 0) {
puts("error: GLES2 failed to initialize"); fputs("error: GLES2 failed to initialize\n", stderr);
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} }
fprintf(stderr, "info: GLES%u.%u\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)); 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; return SDL_APP_SUCCESS;
case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP: if (!evt->key.repeat) {
if (!evt->key.repeat && evt->key.down == true) {
if (evt->key.scancode == SDL_SCANCODE_1) { if (evt->key.scancode == SDL_SCANCODE_1) {
square_pixels = !square_pixels; square_pixels = !square_pixels;
} else if (evt->key.scancode == SDL_SCANCODE_2) { } else if (evt->key.scancode == SDL_SCANCODE_2) {
integer_upscale = !integer_upscale; integer_upscale = !integer_upscale;
} }
} }
break; // fallthrough
case SDL_EVENT_KEY_UP:
case SDL_EVENT_MOUSE_MOTION: case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_MOUSE_WHEEL: 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; break;
case SDL_EVENT_WINDOW_SHOWN: 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_MAXIMIZED:
case SDL_EVENT_WINDOW_RESTORED: case SDL_EVENT_WINDOW_RESTORED:
case SDL_EVENT_WINDOW_MOVED: case SDL_EVENT_WINDOW_MOVED:
break; break; // whatever
case SDL_EVENT_WINDOW_RESIZED: case SDL_EVENT_WINDOW_RESIZED:
window_width = evt->window.data1; window_width = evt->window.data1;
window_height = evt->window.data2; window_height = evt->window.data2;
break; break;
case SDL_EVENT_WINDOW_MOUSE_ENTER: case SDL_EVENT_WINDOW_MOUSE_ENTER:
case SDL_EVENT_WINDOW_MOUSE_LEAVE: case SDL_EVENT_WINDOW_MOUSE_LEAVE:
case SDL_EVENT_WINDOW_FOCUS_GAINED: case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST: case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_EVENT_WINDOW_CLOSE_REQUESTED: case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
break; break; // whatever
case SDL_EVENT_WINDOW_EXPOSED: case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED: case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
break; break; // whatever these even are
case SDL_EVENT_CLIPBOARD_UPDATE: case SDL_EVENT_CLIPBOARD_UPDATE:
break; break; // shush
default: default:
fprintf(stderr, "info: unknown event %x\n", evt->type); fprintf(stderr, "info: unknown event %x\n", evt->type);
@ -153,6 +177,8 @@ static struct {
} fb; } fb;
SDL_AppResult SDL_AppIterate(void *) { SDL_AppResult SDL_AppIterate(void *) {
input::tickle();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glViewport(0, 0, WINDOW_VIRTUAL, WINDOW_VIRTUAL); glViewport(0, 0, WINDOW_VIRTUAL, WINDOW_VIRTUAL);
glClearColor(0.0, 0.0, 0.0, 0.0); glClearColor(0.0, 0.0, 0.0, 0.0);