From 8ad3bf1f224f92c95e7d4bc3f49d6c5bbb35a894 Mon Sep 17 00:00:00 2001 From: Julia <145168563+julia-aph@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:13:13 -0500 Subject: [PATCH] gaming th j --- source/game/event.c | 71 ++++++++++++++++++--------------- source/game/event.h | 22 ++++++---- source/game/gametime.c | 19 +++------ source/game/gametime.h | 12 +++--- source/io/ctrl.c | 30 +++++++++++--- source/io/ctrl.h | 18 +++++---- source/io/input.c | 19 ++++++--- source/io/input.h | 3 +- source/io/platforms/platform.h | 2 +- source/io/platforms/win.c | 41 ++++++------------- source/main.c | 25 +++++++----- test.exe | Bin 82089 -> 82098 bytes 12 files changed, 146 insertions(+), 116 deletions(-) diff --git a/source/game/event.c b/source/game/event.c index a8ac7ad..fe2a9da 100644 --- a/source/game/event.c +++ b/source/game/event.c @@ -1,51 +1,58 @@ -#include -#include -#include -#include -#include +#include "event.h" -#include "fumotris.h" +#define INIT_CAPACITY 16 -struct Delegate { - size_t len; - size_t capacity; - void (**events)(void *args); -}; - -size_t delegate_size(size_t capacity) -{ - return sizeof(void(*)(void *)) * capacity; +size_t clbks_size(size_t capacity) { + return sizeof(union func) * 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; - *d = (struct Delegate) { + *event = (struct Event) { + .clbks = callbacks, .len = 0, - .capacity = capacity, - .events = malloc(delegate_size(capacity)) + .capacity = INIT_CAPACITY, }; return true; } -void Subscribe(struct Delegate *d, void (*event)(void *args)) +void FreeEvent(struct Event *event) { - if (d->len == d->capacity) { - d->capacity *= 2; - d->events = realloc(d->events, delegate_size(d->capacity)); - } - - d->events[d->len] = event; - d->len += 1; + free(event->clbks); } -void Invoke(struct Delegate *d, void *args) +bool EventSubscribe(struct Event *event, union func callback) { - for (size_t i = 0; i < d->len; i++) { - d->events[i](args); + if (event->len == event->capacity) { + 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); } } \ No newline at end of file diff --git a/source/game/event.h b/source/game/event.h index a3ae0cf..5e4182a 100644 --- a/source/game/event.h +++ b/source/game/event.h @@ -6,15 +6,23 @@ #include #include "fumotris.h" +#include "gametime.h" -struct Delegate { - size_t len; - size_t capacity; - void (**events)(void *args); +union func { + void (*generic)(void *arg); + void (*update)(Time dt); }; -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); \ No newline at end of file +bool EventSubscribe(struct Event *event, union func callback); + +void EventInvoke(struct Event *event, void *arg); + +void EventInvokeUpdate(struct Event *event, Time dt); \ No newline at end of file diff --git a/source/game/gametime.c b/source/game/gametime.c index 635a645..50d9b43 100644 --- a/source/game/gametime.c +++ b/source/game/gametime.c @@ -1,24 +1,17 @@ +#include "gametime.h" #include -#include -#ifdef _WIN32 -#include "win.h" -#endif +#define ONE_E_9 1000000000 -struct Time { - u32 sec; - u32 nsec; -}; - -struct Time TimeNow() +Time TimeNow() { struct timespec ts; - // Need to check for failiure 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; timespec_get(&ts, TIME_UTC); diff --git a/source/game/gametime.h b/source/game/gametime.h index 61c8dd6..630a436 100644 --- a/source/game/gametime.h +++ b/source/game/gametime.h @@ -1,11 +1,11 @@ #pragma once #include +#include -struct Time { - u32 sec; - u32 nsec; -}; +#include "fumotris.h" -struct Time TimeNow(); +typedef u64 Time; -double TimeNowDouble(); +Time TimeNow(); + +double TimeNowD(); diff --git a/source/io/ctrl.c b/source/io/ctrl.c index 7e25593..cea9ca6 100644 --- a/source/io/ctrl.c +++ b/source/io/ctrl.c @@ -1,5 +1,7 @@ #include "ctrl.h" +#include + #define INIT_SIZE 16 bool CreateCtrl(struct Controller *ctrl) @@ -142,7 +144,7 @@ void dispatch_update(struct InputAxis *axis, struct InputRecord *rec) 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++) { struct InputAxis *axis = ctrl->pending_buf.axes[i]; @@ -150,22 +152,38 @@ bool CtrlPoll(struct Controller *ctrl) axis->is_up = 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++) { struct InputRecord *rec = &ctrl->buf.recs[i]; union InputID rec_id = to_id(rec->bind, rec->type); struct InputAxis *axis = find_axis(&ctrl->binds, rec_id); + if (axis == nullptr) continue; dispatch_update(axis, rec); - - ctrl->pending_buf.axes[i] = axis; + ctrl->pending_buf.axes[ctrl->pending_buf.len++] = 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; } diff --git a/source/io/ctrl.h b/source/io/ctrl.h index ce82582..ab6f2e3 100644 --- a/source/io/ctrl.h +++ b/source/io/ctrl.h @@ -1,6 +1,5 @@ #pragma once #include -#include #include #include #include @@ -11,8 +10,8 @@ #include "input.h" struct InputAxis { - struct Time last_pressed; - struct Time last_released; + Time last_pressed; + Time last_released; union { struct Button but; @@ -46,15 +45,18 @@ struct ctrl_axis_vec { struct Controller { struct InputBuffer buf; - struct { - struct InputAxis *axes[IO_BUF_SIZE]; - u16f len; - } pending_buf; + + struct InputAxis *pending_axes[IO_BUF_SIZE]; + char string_input[IO_BUF_SIZE]; + + u8f pending_axes_len; + u8f string_input_len; struct ctrl_axis_vec axis_vec; struct ctrl_dict codes; struct ctrl_dict binds; }; +size_t a = sizeof(struct Controller); 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); -bool CtrlPoll(struct Controller *ctrl); +bool CtrlPoll(struct Controller *ctrl, struct InputThreadHandle *hand); enum ControlCode { LEFT, diff --git a/source/io/input.c b/source/io/input.c index 7332cd3..93e91c6 100644 --- a/source/io/input.c +++ b/source/io/input.c @@ -6,13 +6,13 @@ struct InputRecord *buf_get(struct InputBuffer *buf, size_t i) { return buf->recs + (buf->start + i) % IO_BUF_SIZE; } -size_t max_size(size_t a, size_t b) { - return a > b ? a : b; +size_t min_size(size_t a, size_t b) { + return a < b ? a : b; } 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++) *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 }; while (!hand->is_terminating) { - printf("\tinput cycle"); if (!PlatformReadInput(&tmp_buf)) { hand->err = true; return nullptr; @@ -45,7 +44,13 @@ void *input_thread_loop(void *arg) if (hand->err) 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); if (hand->err) @@ -57,7 +62,11 @@ void *input_thread_loop(void *arg) bool BeginInputThread(struct InputThreadHandle *hand, struct InputBuffer *buf) { + hand->buf = buf; 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; } diff --git a/source/io/input.h b/source/io/input.h index 48d40d2..78dda40 100644 --- a/source/io/input.h +++ b/source/io/input.h @@ -48,7 +48,7 @@ union InputData { }; struct InputRecord { - struct Time time; + Time time; union { struct Button but; @@ -76,6 +76,7 @@ struct InputThreadHandle { pthread_t thread; pthread_mutex_t mutex; + pthread_cond_t buf_read; int err; bool is_terminating; diff --git a/source/io/platforms/platform.h b/source/io/platforms/platform.h index ec995b9..c5fcb49 100644 --- a/source/io/platforms/platform.h +++ b/source/io/platforms/platform.h @@ -20,4 +20,4 @@ bool PlatformReadInput(struct InputBuffer *buf); bool PlatformStopInput(); -bool PlatformWait(struct Time relative); \ No newline at end of file +bool PlatformWait(Time duration); \ No newline at end of file diff --git a/source/io/platforms/win.c b/source/io/platforms/win.c index 7b2825f..1e644bd 100644 --- a/source/io/platforms/win.c +++ b/source/io/platforms/win.c @@ -6,13 +6,7 @@ #include "input.h" struct windows { - union { - HANDLE input_hands[2]; - struct { - HANDLE input_hand; - HANDLE early_exit_hand; - }; - }; + HANDLE input_hand; HANDLE timer; } win; @@ -26,10 +20,6 @@ bool init_handles() if (win.timer == NULL) return false; - win.early_exit_hand = CreateEventW(NULL, FALSE, FALSE, NULL); - if (win.early_exit_hand == NULL) - return false; - return true; } @@ -68,7 +58,7 @@ bool PlatformGetRefreshRate(u16f *out) 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->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; } -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) { rec->type = JOYSTICK; @@ -99,15 +89,15 @@ bool copy_mouse_event(struct InputRecord *rec, MOUSE_EVENT_RECORD *win_mouse) 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) { case KEY_EVENT: - copy_key_event(rec, &win_rec->Event.KeyEvent); + read_key_event(rec, &win_rec->Event.KeyEvent); return true; 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: return false; @@ -120,22 +110,17 @@ bool copy_rec(struct InputRecord *rec, INPUT_RECORD *win_rec) 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; INPUT_RECORD win_buf[max_records]; DWORD filled; - + if (!ReadConsoleInputW(win.input_hand, win_buf, max_records, &filled)) return false; struct InputRecord rec = { .time = TimeNow() }; for (size_t i = 0; i < filled; i++) { - if (!copy_rec(&rec, win_buf + i)) + if (!read_rec(&rec, win_buf + i)) continue; InputBufferAdd(buf, &rec); @@ -146,15 +131,15 @@ bool PlatformReadInput(struct InputBuffer *buf) 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; - duration.QuadPart = -10000000 * relative.sec - relative.nsec / 100; + LARGE_INTEGER nsec_div_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; DWORD result = WaitForSingleObject(win.timer, INFINITE); diff --git a/source/main.c b/source/main.c index d2314cc..4ba0caf 100644 --- a/source/main.c +++ b/source/main.c @@ -10,7 +10,6 @@ #include "input.h" #include "fumotris.h" #include "term.h" -#include "tetr.h" #include "event.h" #include "platform.h" @@ -20,6 +19,14 @@ void ErrorExit(char *message) exit(1); } +struct Game { + struct Event Start; + struct Event Draw; + struct Event Update; + + Time time; +}; + int main() { if (!PlatformInit()) @@ -29,20 +36,20 @@ int main() if (!CreateCtrl(&ctrl)) ErrorExit("Out of memory"); - struct InputThreadHandle input; - if (!BeginInputThread(&input, &ctrl.buf)) + struct Game game; + CreateEvent(&game.Update); + + struct InputThreadHandle input_hand; + if (!BeginInputThread(&input_hand, &ctrl.buf)) ErrorExit("Input handle failed to initialize"); CtrlMap(&ctrl, 0, BUTTON, 'A'); while (true) { - bool poll = CtrlPoll(&ctrl); - printf("poll: %u\n", poll); + if(!CtrlPoll(&ctrl, &input_hand)) + ErrorExit("Poll failed"); - struct InputAxis *a = CtrlGet(&ctrl, 0, BUTTON); - printf("get: %llu\n", a); - - printf("val: %u\n", a->but.value); + EventInvokeUpdate(&game.Update, nullptr); } return 0; diff --git a/test.exe b/test.exe index 0f79fc9247e3c18aae0a3f73d470ac84372fc348..0c466d47bde780d73be10102387ba15f951637b7 100644 GIT binary patch delta 21033 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 C_a!v| delta 20727 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