Fumofumotris/source/io/ctrl.c

319 lines
6.2 KiB
C
Raw Normal View History

2024-03-25 05:34:59 +00:00
#include <iso646.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fumotris.h"
#define IO_BUF_SIZE 8
enum InputType {
KEY,
AXIS,
JOYSTICK,
WINDOW,
ESCAPE
};
struct InputRecord {
enum InputType type;
u16 id;
union {
struct {
bool is_down;
2024-03-26 20:11:58 +00:00
} key;
struct {
u64 value;
2024-03-25 05:34:59 +00:00
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
double timestamp;
};
2024-03-26 20:11:58 +00:00
struct InputBuffer {
struct InputRecord records[IO_BUF_SIZE];
2024-03-25 05:34:59 +00:00
size_t count;
2024-03-26 20:11:58 +00:00
pthread_mutex_t mutex;
2024-03-25 05:34:59 +00:00
};
2024-03-26 20:11:58 +00:00
struct InputBuffer NewInputBuffer()
{
struct InputBuffer buf;
buf.count = 0;
buf.mutex = PTHREAD_MUTEX_INITIALIZER;
return buf;
}
2024-03-25 05:34:59 +00:00
struct Axis {
2024-03-26 20:11:58 +00:00
u8 type;
2024-03-25 05:34:59 +00:00
union {
struct {
u32 value;
2024-03-26 20:11:58 +00:00
u32 is_down : 1;
u32 is_up : 1;
} key;
struct {
u64 value;
2024-03-25 05:34:59 +00:00
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
double last_pressed;
double last_released;
};
enum KeyCode {
LEFT,
RIGHT,
SOFT_DROP,
HARD_DROP,
ROTATE_CCW,
ROTATE_CW,
ROTATE_180,
SWAP,
ESC
};
enum AxisCode {
VSCROLL,
HSCROLL
};
enum JoystickCode {
MOUSE
};
typedef u32 hashtype;
hashtype Hash(void *item, size_t size)
{
u8* data = (u8*)item;
u32 h = 98317;
for (size_t i = 0; i < size; i++) {
h ^= data[i];
h *= 0x5bd1e995;
h ^= h >> 15;
}
return h;
}
struct ident {
u16 id;
enum InputType type;
};
hashtype hash_ident(u16f id, enum InputType type)
{
struct ident obj = { id, type };
return Hash(&obj, sizeof(struct ident));
}
2024-03-26 20:11:58 +00:00
struct code_bkt {
hashtype hash;
u16 code;
2024-03-25 05:34:59 +00:00
struct Axis axis;
};
2024-03-26 20:11:58 +00:00
struct bind_bkt {
hashtype hash;
u16 bind;
struct Axis *axis;
};
2024-03-25 05:34:59 +00:00
struct Ctrl {
2024-03-26 20:11:58 +00:00
struct {
size_t capacity;
size_t filled;
struct code_bkt *bkts;
} codes;
struct {
size_t capacity;
size_t filled;
struct bind_bkt *bkts;
} binds;
2024-03-25 05:34:59 +00:00
pthread_mutex_t mutex;
};
typedef struct Ctrl Ctrl;
2024-03-26 20:11:58 +00:00
Ctrl NewCtrl(struct code_bkt *codes, size_t c, struct bind_bkt *binds, size_t b)
2024-03-25 05:34:59 +00:00
{
2024-03-26 20:11:58 +00:00
memset(codes, 0, sizeof(struct code_bkt) * c);
memset(binds, 0, sizeof(struct bind_bkt) * b);
2024-03-25 05:34:59 +00:00
Ctrl ctrl;
2024-03-26 20:11:58 +00:00
ctrl.codes.bkts = codes;
ctrl.binds.bkts = binds;
2024-03-25 05:34:59 +00:00
ctrl.mutex = PTHREAD_MUTEX_INITIALIZER;
2024-03-26 20:11:58 +00:00
2024-03-25 05:34:59 +00:00
return ctrl;
}
2024-03-26 20:11:58 +00:00
void CtrlPoll(struct InputBuffer *buf)
2024-03-25 05:34:59 +00:00
{
2024-03-26 20:11:58 +00:00
for (size_t i = 0; i < buf->count; i++) {
struct InputRecord *rec = &buf->records[i];
switch (rec->type) {
case KEY:
key_update();
break;
case AXIS:
axis_update();
break;
case JOYSTICK:
joystick_update();
break;
}
}
2024-03-25 05:34:59 +00:00
}
2024-03-26 20:11:58 +00:00
struct ctrl_bkt *get_code_bkt(Ctrl *ctrl, size_t i)
2024-03-25 05:34:59 +00:00
{
2024-03-26 20:11:58 +00:00
assert(i < ctrl->codes.capacity);
return &ctrl->codes.bkts[i];
}
2024-03-25 05:34:59 +00:00
2024-03-26 20:11:58 +00:00
struct ctrl_bkt *get_bind_bkt(Ctrl *ctrl, size_t i)
{
assert(i < ctrl->binds.capacity);
return &ctrl->binds.bkts[i];
}
struct code_bkt *find_code(Ctrl *ctrl, hashtype hash)
{
const size_t index = hash % ctrl->codes.capacity;
size_t i = index;
2024-03-25 05:34:59 +00:00
2024-03-26 20:11:58 +00:00
while (i != index - 1) {
struct code_bkt *bkt = get_code_bkt(ctrl, i);
if (bkt->hash == 0)
return bkt;
2024-03-25 05:34:59 +00:00
2024-03-26 20:11:58 +00:00
i = (i + 1) % ctrl->codes.capacity;
2024-03-25 05:34:59 +00:00
}
return nullptr;
}
2024-03-26 20:11:58 +00:00
struct ctrl_bkt *find_bind(Ctrl *ctrl, hashtype hash)
2024-03-25 05:34:59 +00:00
{
2024-03-26 20:11:58 +00:00
const size_t index = hash % ctrl->binds.capacity;
size_t i = index;
2024-03-25 05:34:59 +00:00
2024-03-26 20:11:58 +00:00
while (i != index - 1) {
struct bind_bkt *bkt = get_bind_bkt(ctrl, i);
if (bkt->hash == 0)
return bkt;
i = (i + 1) % ctrl->binds.capacity;
2024-03-25 05:34:59 +00:00
}
return nullptr;
}
bool CtrlMap(Ctrl *ctrl, u16f bind, u16f code, enum InputType type)
{
2024-03-26 20:11:58 +00:00
if (ctrl->binds.filled == ctrl->binds.capacity)
2024-03-25 05:34:59 +00:00
return false;
2024-03-26 20:11:58 +00:00
hashtype code_hash = hash_ident(code, type);
struct code_bkt *code_bkt = find_code(ctrl, code_hash);
code_bkt->hash = code_hash;
code_bkt->code = code;
2024-03-25 05:34:59 +00:00
hashtype bind_hash = hash_ident(bind, type);
2024-03-26 20:11:58 +00:00
struct bind_bkt *bind_bkt = find_bind(ctrl, bind_hash);
bind_bkt->hash = bind_hash;
bind_bkt->bind = bind;
bind_bkt->axis = &code_bkt->axis;
2024-03-25 05:34:59 +00:00
2024-03-26 20:11:58 +00:00
ctrl->binds.filled += 1;
2024-03-25 05:34:59 +00:00
return true;
}
struct Axis *find_bind_axis(Ctrl *ctrl, u16f bind, enum InputType type)
{
hashtype bind_hash = hash_ident(bind, KEY);
struct ctrl_bkt *bind_bkt = find_bind(ctrl, bind_hash, bind_hash);
if (bind_bkt == nullptr)
return nullptr;
return &get_bkt(ctrl, bind_bkt->index)->axis;
}
2024-03-26 20:11:58 +00:00
struct Axis *CtrlGet(Ctrl *ctrl, u16f code, u8f type)
2024-03-25 05:34:59 +00:00
{
2024-03-26 20:11:58 +00:00
= struct ctrl_bkt *code_bkt = find_code(ctrl, code, type);
2024-03-25 05:34:59 +00:00
if (code_bkt == nullptr)
return nullptr;
return &code_bkt->axis;
}
bool CtrlUpdateKey(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, KEY);
if (axis == nullptr)
return false;
2024-03-26 20:11:58 +00:00
if (record->data.key.is_down) {
2024-03-25 05:34:59 +00:00
axis->last_pressed = record->timestamp;
} else {
axis->last_released = record->timestamp;
}
2024-03-26 20:11:58 +00:00
axis->data.axis.value = record->data.key.is_down;
2024-03-25 05:34:59 +00:00
return true;
}
bool CtrlUpdateAxis(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, AXIS);
if (axis == nullptr)
return false;
axis->data.axis.value = record->data.axis.value;
axis->last_pressed = record->timestamp;
return true;
}
bool CtrlUpdateJoystick(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, JOYSTICK);
if (axis == nullptr)
return false;
axis->data.joystick.x = record->data.joystick.x;
axis->data.joystick.y = record->data.joystick.y;
axis->last_pressed = record->timestamp;
return true;
}
bool CtrlUpdateWindow(Ctrl *ctrl, struct InputRecord *record)
{
struct Axis *axis = find_bind_axis(ctrl, record->id, WINDOW);
if (axis == nullptr)
return false;
axis->data.joystick.x = record->data.joystick.x;
axis->data.joystick.y = record->data.joystick.y;
axis->last_pressed = record->timestamp;
return true;
}