th j
This commit is contained in:
Julia 2024-04-22 17:13:13 -05:00
parent 599c41ef1b
commit 8ad3bf1f22
12 changed files with 146 additions and 116 deletions

View file

@ -1,51 +1,58 @@
#include <iso646.h> #include "event.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "fumotris.h" #define INIT_CAPACITY 16
struct Delegate { size_t clbks_size(size_t capacity) {
size_t len; return sizeof(union func) * capacity;
size_t capacity;
void (**events)(void *args);
};
size_t delegate_size(size_t capacity)
{
return sizeof(void(*)(void *)) * capacity;
} }
bool NewDelegate(struct Delegate *d, size_t capacity) bool CreateEvent(struct Event *event)
{ {
void (**events)(void *args) = malloc(delegate_size(capacity)); union func *callbacks = malloc(clbks_size(INIT_CAPACITY));
if (events == nullptr) if (callbacks == nullptr)
return false; return false;
*d = (struct Delegate) { *event = (struct Event) {
.clbks = callbacks,
.len = 0, .len = 0,
.capacity = capacity, .capacity = INIT_CAPACITY,
.events = malloc(delegate_size(capacity))
}; };
return true; return true;
} }
void Subscribe(struct Delegate *d, void (*event)(void *args)) void FreeEvent(struct Event *event)
{ {
if (d->len == d->capacity) { free(event->clbks);
d->capacity *= 2;
d->events = realloc(d->events, delegate_size(d->capacity));
}
d->events[d->len] = event;
d->len += 1;
} }
void Invoke(struct Delegate *d, void *args) bool EventSubscribe(struct Event *event, union func callback)
{ {
for (size_t i = 0; i < d->len; i++) { if (event->len == event->capacity) {
d->events[i](args); size_t new_cap = event->capacity * 2;
union func *new_clbks = realloc(event->clbks, clbks_size(new_cap));
if (new_clbks == nullptr)
return false;
event->clbks = new_clbks;
event->capacity = new_cap;
}
event->clbks[event->len++] = callback;
return true;
}
void EventInvoke(struct Event *event, void *arg)
{
for (size_t i = 0; i < event->len; i++) {
event->clbks[i].generic(arg);
}
}
void EventInvokeUpdate(struct Event *event, u64 dt)
{
for (size_t i = 0; i < event->len; i++) {
event->clbks[i].update(dt);
} }
} }

View file

@ -6,15 +6,23 @@
#include <stdlib.h> #include <stdlib.h>
#include "fumotris.h" #include "fumotris.h"
#include "gametime.h"
struct Delegate { union func {
size_t len; void (*generic)(void *arg);
size_t capacity; void (*update)(Time dt);
void (**events)(void *args);
}; };
bool NewDelegate(struct Delegate *d, size_t capacity); struct Event {
union func *clbks;
size_t len;
size_t capacity;
};
void Subscribe(struct Delegate *d, void (*event)(void *args)); bool CreateEvent(struct Event *event);
void Invoke(struct Delegate *d, void *args); bool EventSubscribe(struct Event *event, union func callback);
void EventInvoke(struct Event *event, void *arg);
void EventInvokeUpdate(struct Event *event, Time dt);

View file

@ -1,24 +1,17 @@
#include "gametime.h"
#include <time.h> #include <time.h>
#include <stdbool.h>
#ifdef _WIN32 #define ONE_E_9 1000000000
#include "win.h"
#endif
struct Time { Time TimeNow()
u32 sec;
u32 nsec;
};
struct Time TimeNow()
{ {
struct timespec ts; struct timespec ts;
// Need to check for failiure
timespec_get(&ts, TIME_UTC); timespec_get(&ts, TIME_UTC);
return (struct Time) { ts.tv_sec, ts.tv_nsec };
return ts.tv_nsec + ts.tv_sec * ONE_E_9;
} }
double TimeNowDouble() double TimeNowD()
{ {
struct timespec ts; struct timespec ts;
timespec_get(&ts, TIME_UTC); timespec_get(&ts, TIME_UTC);

View file

@ -1,11 +1,11 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
struct Time { #include "fumotris.h"
u32 sec;
u32 nsec;
};
struct Time TimeNow(); typedef u64 Time;
double TimeNowDouble(); Time TimeNow();
double TimeNowD();

View file

@ -1,5 +1,7 @@
#include "ctrl.h" #include "ctrl.h"
#include <pthread.h>
#define INIT_SIZE 16 #define INIT_SIZE 16
bool CreateCtrl(struct Controller *ctrl) bool CreateCtrl(struct Controller *ctrl)
@ -142,7 +144,7 @@ void dispatch_update(struct InputAxis *axis, struct InputRecord *rec)
axis->data = rec->data; axis->data = rec->data;
} }
bool CtrlPoll(struct Controller *ctrl) bool read_input_buf(struct Controller *ctrl)
{ {
for (size_t i = 0; i < ctrl->pending_buf.len; i++) { for (size_t i = 0; i < ctrl->pending_buf.len; i++) {
struct InputAxis *axis = ctrl->pending_buf.axes[i]; struct InputAxis *axis = ctrl->pending_buf.axes[i];
@ -150,21 +152,37 @@ bool CtrlPoll(struct Controller *ctrl)
axis->is_up = false; axis->is_up = false;
axis->is_down = false; axis->is_down = false;
} }
ctrl->pending_buf.len = ctrl->buf.len; ctrl->pending_buf.len = 0;
for (size_t i = 0; i < ctrl->buf.len; i++) { for (size_t i = 0; i < ctrl->buf.len; i++) {
struct InputRecord *rec = &ctrl->buf.recs[i]; struct InputRecord *rec = &ctrl->buf.recs[i];
union InputID rec_id = to_id(rec->bind, rec->type); union InputID rec_id = to_id(rec->bind, rec->type);
struct InputAxis *axis = find_axis(&ctrl->binds, rec_id); struct InputAxis *axis = find_axis(&ctrl->binds, rec_id);
if (axis == nullptr) if (axis == nullptr)
continue; continue;
dispatch_update(axis, rec); dispatch_update(axis, rec);
ctrl->pending_buf.axes[ctrl->pending_buf.len++] = axis;
ctrl->pending_buf.axes[i] = axis;
} }
ctrl->buf.len = 0; ctrl->buf.len = 0;
return true;
}
bool CtrlPoll(struct Controller *ctrl, struct InputThreadHandle *hand)
{
if (pthread_mutex_lock(&hand->mutex) != 0)
return false;
read_input_buf(ctrl);
if (pthread_cond_signal(&hand->buf_read) != 0)
return false;
if (pthread_mutex_unlock(&hand->mutex) != 0)
return false;
return true; return true;
} }

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <iso646.h> #include <iso646.h>
#include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -11,8 +10,8 @@
#include "input.h" #include "input.h"
struct InputAxis { struct InputAxis {
struct Time last_pressed; Time last_pressed;
struct Time last_released; Time last_released;
union { union {
struct Button but; struct Button but;
@ -46,15 +45,18 @@ struct ctrl_axis_vec {
struct Controller { struct Controller {
struct InputBuffer buf; struct InputBuffer buf;
struct {
struct InputAxis *axes[IO_BUF_SIZE]; struct InputAxis *pending_axes[IO_BUF_SIZE];
u16f len; char string_input[IO_BUF_SIZE];
} pending_buf;
u8f pending_axes_len;
u8f string_input_len;
struct ctrl_axis_vec axis_vec; struct ctrl_axis_vec axis_vec;
struct ctrl_dict codes; struct ctrl_dict codes;
struct ctrl_dict binds; struct ctrl_dict binds;
}; };
size_t a = sizeof(struct Controller);
bool CreateCtrl(struct Controller *ctrl); bool CreateCtrl(struct Controller *ctrl);
@ -64,7 +66,7 @@ bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind);
struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u16f type); struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u16f type);
bool CtrlPoll(struct Controller *ctrl); bool CtrlPoll(struct Controller *ctrl, struct InputThreadHandle *hand);
enum ControlCode { enum ControlCode {
LEFT, LEFT,

View file

@ -6,13 +6,13 @@ struct InputRecord *buf_get(struct InputBuffer *buf, size_t i) {
return buf->recs + (buf->start + i) % IO_BUF_SIZE; return buf->recs + (buf->start + i) % IO_BUF_SIZE;
} }
size_t max_size(size_t a, size_t b) { size_t min_size(size_t a, size_t b) {
return a > b ? a : b; return a < b ? a : b;
} }
void InputBufferTransfer(struct InputBuffer *dest, struct InputBuffer *src) void InputBufferTransfer(struct InputBuffer *dest, struct InputBuffer *src)
{ {
size_t copy_amt = IO_BUF_SIZE - max_size(dest->len, src->len); size_t copy_amt = min_size(IO_BUF_SIZE - dest->len, src->len);
for (size_t i = 0; i < copy_amt; i++) for (size_t i = 0; i < copy_amt; i++)
*buf_get(dest, dest->len + i) = *buf_get(src, i); *buf_get(dest, dest->len + i) = *buf_get(src, i);
@ -35,7 +35,6 @@ void *input_thread_loop(void *arg)
struct InputBuffer tmp_buf = { .len = 0, .start = 0 }; struct InputBuffer tmp_buf = { .len = 0, .start = 0 };
while (!hand->is_terminating) { while (!hand->is_terminating) {
printf("\tinput cycle");
if (!PlatformReadInput(&tmp_buf)) { if (!PlatformReadInput(&tmp_buf)) {
hand->err = true; hand->err = true;
return nullptr; return nullptr;
@ -45,7 +44,13 @@ void *input_thread_loop(void *arg)
if (hand->err) if (hand->err)
return nullptr; return nullptr;
InputBufferTransfer(&tmp_buf, hand->buf); while (tmp_buf.len == IO_BUF_SIZE) {
hand->err = pthread_cond_wait(&hand->buf_read, &hand->mutex);
if (hand->err)
return nullptr;
}
InputBufferTransfer(hand->buf, &tmp_buf);
hand->err = pthread_mutex_unlock(&hand->mutex); hand->err = pthread_mutex_unlock(&hand->mutex);
if (hand->err) if (hand->err)
@ -57,7 +62,11 @@ void *input_thread_loop(void *arg)
bool BeginInputThread(struct InputThreadHandle *hand, struct InputBuffer *buf) bool BeginInputThread(struct InputThreadHandle *hand, struct InputBuffer *buf)
{ {
hand->buf = buf;
hand->mutex = PTHREAD_MUTEX_INITIALIZER; hand->mutex = PTHREAD_MUTEX_INITIALIZER;
hand->buf_read = PTHREAD_COND_INITIALIZER;
hand->err = 0;
return pthread_create(&hand->thread, nullptr, input_thread_loop, hand) == 0; return pthread_create(&hand->thread, nullptr, input_thread_loop, hand) == 0;
} }

View file

@ -48,7 +48,7 @@ union InputData {
}; };
struct InputRecord { struct InputRecord {
struct Time time; Time time;
union { union {
struct Button but; struct Button but;
@ -76,6 +76,7 @@ struct InputThreadHandle {
pthread_t thread; pthread_t thread;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t buf_read;
int err; int err;
bool is_terminating; bool is_terminating;

View file

@ -20,4 +20,4 @@ bool PlatformReadInput(struct InputBuffer *buf);
bool PlatformStopInput(); bool PlatformStopInput();
bool PlatformWait(struct Time relative); bool PlatformWait(Time duration);

View file

@ -6,13 +6,7 @@
#include "input.h" #include "input.h"
struct windows { struct windows {
union { HANDLE input_hand;
HANDLE input_hands[2];
struct {
HANDLE input_hand;
HANDLE early_exit_hand;
};
};
HANDLE timer; HANDLE timer;
} win; } win;
@ -26,10 +20,6 @@ bool init_handles()
if (win.timer == NULL) if (win.timer == NULL)
return false; return false;
win.early_exit_hand = CreateEventW(NULL, FALSE, FALSE, NULL);
if (win.early_exit_hand == NULL)
return false;
return true; return true;
} }
@ -68,7 +58,7 @@ bool PlatformGetRefreshRate(u16f *out)
return true; return true;
} }
void copy_key_event(struct InputRecord *rec, KEY_EVENT_RECORD *win_key) void read_key_event(struct InputRecord *rec, KEY_EVENT_RECORD *win_key)
{ {
rec->type = BUTTON; rec->type = BUTTON;
rec->bind = win_key->wVirtualKeyCode; rec->bind = win_key->wVirtualKeyCode;
@ -77,7 +67,7 @@ void copy_key_event(struct InputRecord *rec, KEY_EVENT_RECORD *win_key)
rec->is_up = !win_key->bKeyDown; rec->is_up = !win_key->bKeyDown;
} }
bool copy_mouse_event(struct InputRecord *rec, MOUSE_EVENT_RECORD *win_mouse) bool read_mouse_event(struct InputRecord *rec, MOUSE_EVENT_RECORD *win_mouse)
{ {
if (win_mouse->dwEventFlags == MOUSE_MOVED) { if (win_mouse->dwEventFlags == MOUSE_MOVED) {
rec->type = JOYSTICK; rec->type = JOYSTICK;
@ -99,15 +89,15 @@ bool copy_mouse_event(struct InputRecord *rec, MOUSE_EVENT_RECORD *win_mouse)
return false; return false;
} }
bool copy_rec(struct InputRecord *rec, INPUT_RECORD *win_rec) bool read_rec(struct InputRecord *rec, INPUT_RECORD *win_rec)
{ {
switch (win_rec->EventType) { switch (win_rec->EventType) {
case KEY_EVENT: case KEY_EVENT:
copy_key_event(rec, &win_rec->Event.KeyEvent); read_key_event(rec, &win_rec->Event.KeyEvent);
return true; return true;
case MOUSE_EVENT: case MOUSE_EVENT:
return copy_mouse_event(rec, &win_rec->Event.MouseEvent); return read_mouse_event(rec, &win_rec->Event.MouseEvent);
case WINDOW_BUFFER_SIZE_EVENT: case WINDOW_BUFFER_SIZE_EVENT:
return false; return false;
@ -120,11 +110,6 @@ bool copy_rec(struct InputRecord *rec, INPUT_RECORD *win_rec)
bool PlatformReadInput(struct InputBuffer *buf) bool PlatformReadInput(struct InputBuffer *buf)
{ {
DWORD wait_status = WaitForMultipleObjects(2, win.input_hands, FALSE, 0);
if (wait_status != 0)
return wait_status == 1;
DWORD max_records = IO_BUF_SIZE - buf->len; DWORD max_records = IO_BUF_SIZE - buf->len;
INPUT_RECORD win_buf[max_records]; INPUT_RECORD win_buf[max_records];
DWORD filled; DWORD filled;
@ -135,7 +120,7 @@ bool PlatformReadInput(struct InputBuffer *buf)
struct InputRecord rec = { .time = TimeNow() }; struct InputRecord rec = { .time = TimeNow() };
for (size_t i = 0; i < filled; i++) { for (size_t i = 0; i < filled; i++) {
if (!copy_rec(&rec, win_buf + i)) if (!read_rec(&rec, win_buf + i))
continue; continue;
InputBufferAdd(buf, &rec); InputBufferAdd(buf, &rec);
@ -146,15 +131,15 @@ bool PlatformReadInput(struct InputBuffer *buf)
bool PlatformStopInput() bool PlatformStopInput()
{ {
return SetEvent(win.early_exit_hand) == 0; return CancelSynchronousIo(win.input_hand);
} }
bool PlatformWait(struct Time relative) bool PlatformWait(Time duration)
{ {
LARGE_INTEGER duration; LARGE_INTEGER nsec_div_100;
duration.QuadPart = -10000000 * relative.sec - relative.nsec / 100; nsec_div_100.QuadPart = -duration / 100;
if (!SetWaitableTimer(win.timer, &duration, 0, NULL, NULL, FALSE)) if (!SetWaitableTimer(win.timer, &nsec_div_100, 0, NULL, NULL, FALSE))
return false; return false;
DWORD result = WaitForSingleObject(win.timer, INFINITE); DWORD result = WaitForSingleObject(win.timer, INFINITE);

View file

@ -10,7 +10,6 @@
#include "input.h" #include "input.h"
#include "fumotris.h" #include "fumotris.h"
#include "term.h" #include "term.h"
#include "tetr.h"
#include "event.h" #include "event.h"
#include "platform.h" #include "platform.h"
@ -20,6 +19,14 @@ void ErrorExit(char *message)
exit(1); exit(1);
} }
struct Game {
struct Event Start;
struct Event Draw;
struct Event Update;
Time time;
};
int main() int main()
{ {
if (!PlatformInit()) if (!PlatformInit())
@ -29,20 +36,20 @@ int main()
if (!CreateCtrl(&ctrl)) if (!CreateCtrl(&ctrl))
ErrorExit("Out of memory"); ErrorExit("Out of memory");
struct InputThreadHandle input; struct Game game;
if (!BeginInputThread(&input, &ctrl.buf)) CreateEvent(&game.Update);
struct InputThreadHandle input_hand;
if (!BeginInputThread(&input_hand, &ctrl.buf))
ErrorExit("Input handle failed to initialize"); ErrorExit("Input handle failed to initialize");
CtrlMap(&ctrl, 0, BUTTON, 'A'); CtrlMap(&ctrl, 0, BUTTON, 'A');
while (true) { while (true) {
bool poll = CtrlPoll(&ctrl); if(!CtrlPoll(&ctrl, &input_hand))
printf("poll: %u\n", poll); ErrorExit("Poll failed");
struct InputAxis *a = CtrlGet(&ctrl, 0, BUTTON); EventInvokeUpdate(&game.Update, nullptr);
printf("get: %llu\n", a);
printf("val: %u\n", a->but.value);
} }
return 0; return 0;

BIN
test.exe

Binary file not shown.