ok
This commit is contained in:
Julia 2024-04-29 15:01:48 -05:00
parent 3de83d481e
commit 2e976a8d2e
11 changed files with 231 additions and 96 deletions

View file

@ -1,35 +1,67 @@
#pragma once
#include "ringbuffer.h" #include "ringbuffer.h"
#include <string.h> #include <string.h>
struct rbuf_generic { struct ring_buf {
struct RingBufferHead head; struct RingBufferHead head;
u8 arr[]; u8 bytes[];
}; };
inline void *rbuf_start(RingBufferT T, struct rbuf_generic *rbuf, size_t i) void *get_ptr(RingBufferT T, struct RingBufferHead *head, size_t i)
{ {
size_t wrap_i = (rbuf->head.start + i) % T->LEN; struct ring_buf *ring = (struct ring_buf *)head;
return rbuf->arr + wrap_i * T->SIZE; return ring->bytes + T->SIZE * i;
} }
inline void *rbuf_tail(RingBufferT T, struct rbuf_generic *rbuf, size_t i) size_t RingBufferEmpty(RingBufferT T, struct RingBufferHead *head)
{ {
size_t wrap_i = (rbuf->head.start + rbuf->head.len + i) % T->LEN; return T->LEN - head->len;
return rbuf->arr + i * T->SIZE;
} }
void RingBufferTransfer(RingBufferT T, RingBuffer *dest, RingBuffer *tmp) void *RingBufferGet(RingBufferT T, struct RingBufferHead *head, size_t i)
{ {
struct rbuf_generic *write = dest; size_t wrap_i = (head->start + i) % T->LEN;
struct rbuf_generic *read = tmp; return get_ptr(T, head, wrap_i);
}
size_t copy_max = min_size(T->LEN - write->head.len, read->head.len); void *RingBufferNext(RingBufferT T, struct RingBufferHead *head)
{
size_t wrap_i = (head->start + head->len) % T->LEN;
return get_ptr(T, head, wrap_i);
}
void RingBufferAdd(RingBufferT T, struct RingBufferHead *dest, void *item)
{
memcpy(RingBufferNext(T, dest), item, T->SIZE);
}
void RingBufferTransfer(
RingBufferT T,
struct RingBufferHead *dest,
struct RingBufferHead *src
) {
size_t copy_max = min_size(T->LEN - dest->len, src->len);
for (size_t i = 0; i < copy_max; i++) { for (size_t i = 0; i < copy_max; i++) {
memcpy(rbuf_tail(T, write, i), rbuf_start(T, read, i), T->LEN); void *to = RingBufferGet(T, dest_head, dest->len + i);
void *from = RingBufferGet(T, src_head, i);
memcpy(to, from, T->SIZE);
} }
write->head.start += copy_max; dest->len += copy_max;
read->head.len -= copy_max; src->len -= copy_max;
}
size_t RingBufferOut(RingBufferT T, size_t n, void *dest, void *src_head)
{
struct ring_buf *src = src_head;
size_t copy_max = min_size(n, src->head.len);
for (size_t i = 0; i < copy_max; i++) {
void *to = (char *)dest + i * T->SIZE;
void *from = RingBufferGet(T, src, i);
memcpy(to, from, T->SIZE);
}
return copy_max;
} }

View file

@ -7,8 +7,6 @@
#include "fumotris.h" #include "fumotris.h"
typedef void *RingBuffer;
typedef const struct RingBufferT { typedef const struct RingBufferT {
size_t LEN; size_t LEN;
size_t SIZE; size_t SIZE;
@ -19,6 +17,27 @@ struct RingBufferHead {
u8f start; u8f start;
}; };
void RingBufferTransfer(RingBufferT T, RingBuffer *dest, RingBuffer *tmp); #define RINGBUF_HEAD_INIT ((struct RingBufferHead) { 0, 0 })
#define INIT_RING_BUF_T(len, type) &(struct RingBufferT) { len, sizeof(type) } size_t RingBufferEmpty(RingBufferT T, struct RingBufferHead *head);
void *RingBufferGet(
RingBufferT T,
struct RingBufferHead *head,
size_t i
);
void *RingBufferNext(RingBufferT T, struct RingBufferHead *head);
void RingBufferTransfer(
RingBufferT T,
struct RingBufferHead *dest,
struct RingBufferHead *tmp
);
size_t RingBufferOut(
RingBufferT T,
size_t n,
void *dest,
struct RingBufferHead *src
);

View file

@ -1,6 +1,6 @@
#include "fumotris.h" #include "fumotris.h"
inline size_t min_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;
} }

View file

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#define nullptr ((void*)0) #define nullptr ((void *)0)
typedef uint8_t u8; typedef uint8_t u8;
typedef uint_fast8_t u8f; typedef uint_fast8_t u8f;
@ -28,7 +30,9 @@ typedef int_fast32_t i32f;
typedef int64_t i64; typedef int64_t i64;
typedef int_fast64_t i64f; typedef int_fast64_t i64f;
inline size_t min_size(size_t a, size_t b);
size_t min_size(size_t a, size_t b);
/*const u8 I[16] = { /*const u8 I[16] = {
0, 0, 0, 0, 0, 0, 0, 0,

View file

@ -1,5 +1,7 @@
#include "ctrl.h" #include "ctrl.h"
#include "ringbuffer.h"
#define INIT_SIZE 16 #define INIT_SIZE 16
bool CreateCtrl(struct Controller *ctrl) bool CreateCtrl(struct Controller *ctrl)
@ -12,7 +14,7 @@ bool CreateCtrl(struct Controller *ctrl)
return false; return false;
*ctrl = (struct Controller) { *ctrl = (struct Controller) {
.recs.len = 0, .recs.head = RINGBUF_HEAD_INIT,
.pending_buf.len = 0, .pending_buf.len = 0,
.axis_vec = (struct ctrl_axis_vec) { .axis_vec = (struct ctrl_axis_vec) {
@ -49,7 +51,7 @@ size_t wrap_index(size_t i, size_t max) {
return i % (SIZE_MAX - max + 1); return i % (SIZE_MAX - max + 1);
} }
struct ctrl_bkt *find_or_set(struct ctrl_dict *dict, union InputID id) struct ctrl_bkt *find_set(struct ctrl_dict *dict, union InputID id)
{ {
size_t i = id.hash % dict->capacity; size_t i = id.hash % dict->capacity;
@ -99,14 +101,14 @@ struct InputAxis *find_axis(struct ctrl_dict *dict, union InputID id)
return bkt->axis; return bkt->axis;
} }
union InputID to_id(u16f value, u16f type) { union InputID as_id(u16f value, u16f type) {
return (union InputID) { .value = value, .type = type }; return (union InputID) { .value = value, .type = type };
} }
bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind) bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind)
{ {
struct ctrl_bkt *code_bkt = find_or_set(&ctrl->codes, to_id(code, type)); struct ctrl_bkt *code_bkt = find_set(&ctrl->codes, as_id(code, type));
struct ctrl_bkt *bind_bkt = find_or_set(&ctrl->binds, to_id(bind, type)); struct ctrl_bkt *bind_bkt = find_set(&ctrl->binds, as_id(bind, type));
if (code_bkt->axis == nullptr) if (code_bkt->axis == nullptr)
code_bkt->axis = &ctrl->axis_vec.axes[ctrl->axis_vec.len++]; code_bkt->axis = &ctrl->axis_vec.axes[ctrl->axis_vec.len++];
@ -120,7 +122,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)
{ {
struct ctrl_bkt *code_bkt = find(&ctrl->codes, to_id(code, type)); struct ctrl_bkt *code_bkt = find(&ctrl->codes, as_id(code, type));
if (code_bkt == nullptr) if (code_bkt == nullptr)
return nullptr; return nullptr;
@ -152,7 +154,7 @@ void CtrlPoll(struct Controller *ctrl)
} }
ctrl->pending_buf.len = 0; ctrl->pending_buf.len = 0;
for (size_t i = 0; i < ctrl->recs.len; i++) { for (size_t i = 0; i < ctrl->recs.head.len; i++) {
struct InputRecord *rec = &ctrl->recs.buf[i]; struct InputRecord *rec = &ctrl->recs.buf[i];
struct InputAxis *axis = find_axis(&ctrl->binds, rec->id); struct InputAxis *axis = find_axis(&ctrl->binds, rec->id);
@ -164,12 +166,12 @@ void CtrlPoll(struct Controller *ctrl)
ctrl->pending_buf.axes[ctrl->pending_buf.len++] = axis; ctrl->pending_buf.axes[ctrl->pending_buf.len++] = axis;
} }
ctrl->recs.len = 0; ctrl->recs.head.len = 0;
} }
size_t CtrlInputString(struct Controller *ctrl, size_t n, char *buf) size_t CtrlInputString(struct Controller *ctrl, size_t n, char *buf)
{ {
size_t copy_max = min_size(ctrl->str.len, n); return RingBufferOut(&STR_BUF_T, n, buf, &ctrl->str.head);
} }
/*int main() /*int main()

View file

@ -68,7 +68,9 @@ 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, struct InputThreadHandle *hand); void CtrlPoll(struct Controller *ctrl);
size_t CtrlInputString(struct Controller *ctrl, size_t n, char *buf);
enum ControlCode { enum ControlCode {
LEFT, LEFT,

View file

@ -3,65 +3,114 @@
#include "platform.h" #include "platform.h"
void *input_thread_loop(void *arg) const struct RingBufferT IO_BUF_T = {
{ .LEN = IO_BUF_SIZE,
struct InputThreadHandle *hand = arg; .SIZE = sizeof(struct InputRecord)
};
struct InputRecordBuf tmp_in = { .head.len = 0, .head.start = 0 }; const struct RingBufferT STR_BUF_T = {
.LEN = STR_BUF_SIZE,
.SIZE = sizeof(char)
};
void *input_worker(void *arg)
{
struct InputHandle *hand = arg;
struct InputRecordBuf tmp_recs = { .head.len = 0, .head.start = 0 };
struct InputStringBuf tmp_str = { .head.len = 0, .head.start = 0 }; struct InputStringBuf tmp_str = { .head.len = 0, .head.start = 0 };
while (!hand->is_terminating) { while (!hand->is_terminating) {
if (!PlatformReadInput(&tmp_in, &tmp_str)) if (!PlatformReadInput(&tmp_recs, &tmp_str)) {
hand->err = true;
return nullptr; return nullptr;
}
printf("input read, len:%u\n", hand->recs->head.len);
if (hand->err = pthread_mutex_lock(&hand->mutex)) for (int i = 0; i < hand->recs->head.len; i++) {
return nullptr; struct InputRecord *rec = RingBufferGet(&IO_BUF_T, &hand->recs->head, i);
printf("\ti:%u, type:%u, but:%u\n", i, rec->id.type, rec->id.bind);
while (tmp_in.head.len == IO_BUF_SIZE) {
if (hand->err = pthread_cond_wait(&hand->consume, &hand->mutex))
return nullptr;
} }
RingBufferTransfer(IO_BUF_T, hand->in, &tmp_in); if (pthread_mutex_lock(&hand->mutex) != 0) {
RingBufferTransfer(STR_BUF_T, hand->str, &tmp_str); hand->err = true;
if (hand->err = pthread_mutex_unlock(&hand->mutex))
return nullptr; return nullptr;
}
while (tmp_recs.head.len == IO_BUF_SIZE) {
if (pthread_cond_wait(&hand->is_consumed, &hand->mutex) != 0) {
hand->err = true;
return nullptr;
}
}
RingBufferTransfer(&IO_BUF_T, &hand->recs->head, &tmp_recs.head);
RingBufferTransfer(&STR_BUF_T, &hand->str->head, &tmp_str.head);
if (pthread_mutex_unlock(&hand->mutex) != 0) {
hand->err = true;
return nullptr;
}
} }
return nullptr; return nullptr;
} }
bool BeginInputThread( bool BeginInputThread(
struct InputThreadHandle *hand, struct InputHandle *hand,
struct InputRecordBuf *in, struct InputRecordBuf *in,
struct InputStringBuf *str struct InputStringBuf *str
) { ) {
*hand = (struct InputThreadHandle) { *hand = (struct InputHandle) {
.in = in, .recs = in,
.str = str, .str = str,
.mutex = PTHREAD_MUTEX_INITIALIZER,
.consume = PTHREAD_COND_INITIALIZER,
.err = 0, .err = 0,
.is_terminating = false, .is_terminating = false,
}; };
return pthread_create(&hand->thread, nullptr, input_thread_loop, hand) == 0; if (pthread_mutex_init(&hand->mutex, nullptr) != 0)
return false;
if (pthread_cond_init(&hand->is_consumed, nullptr) != 0)
return false;
if (pthread_create(&hand->thread, nullptr, input_worker, hand) != 0)
return false;
return true;
} }
bool EndInputThread(struct InputThreadHandle *hand) bool EndInputThread(struct InputHandle *hand)
{ {
hand->is_terminating = true; hand->is_terminating = true;
if (!PlatformStopInput()) if (!PlatformStopInput())
return false; return false;
if (!pthread_mutex_destroy(&hand->mutex)) if (pthread_mutex_destroy(&hand->mutex) != 0)
return false; return false;
if (!pthread_join(hand->thread, nullptr)) if (pthread_join(hand->thread, nullptr) != 0)
return false;
return true;
}
bool InputAquire(struct InputHandle *hand)
{
if (pthread_mutex_lock(&hand->mutex) != 0)
return false;
return true;
}
bool InputRelease(struct InputHandle *hand)
{
if (pthread_cond_signal(&hand->is_consumed) != 0)
return false;
if (pthread_mutex_unlock(&hand->mutex) != 0)
return false; return false;
return true; return true;

View file

@ -68,8 +68,8 @@ struct InputRecord {
}; };
}; };
RingBufferT IO_BUF_T = INIT_RING_BUF_T(IO_BUF_SIZE, struct InputRecord); extern const struct RingBufferT IO_BUF_T;
RingBufferT STR_BUF_T = INIT_RING_BUF_T(STR_BUF_SIZE, char); extern const struct RingBufferT STR_BUF_T;
struct InputRecordBuf { struct InputRecordBuf {
struct RingBufferHead head; struct RingBufferHead head;
@ -81,22 +81,26 @@ struct InputStringBuf {
char buf[STR_BUF_SIZE]; char buf[STR_BUF_SIZE];
}; };
struct InputThreadHandle { struct InputHandle {
struct InputRecordBuf *in; struct InputRecordBuf *recs;
struct InputStringBuf *str; struct InputStringBuf *str;
pthread_t thread; pthread_t thread;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t consume; pthread_cond_t is_consumed;
int err; int err;
bool is_terminating; bool is_terminating;
}; };
bool BeginInputThread( bool BeginInputThread(
struct InputThreadHandle *hand, struct InputHandle *hand,
struct InputRecordBuf *in, struct InputRecordBuf *in,
struct InputStringBuf *str struct InputStringBuf *str
); );
bool EndInputThread(struct InputThreadHandle *hand); bool EndInputThread(struct InputHandle *hand);
bool InputAquire(struct InputHandle *hand);
bool InputRelease(struct InputHandle *hand);

View file

@ -5,6 +5,7 @@
#include "gametime.h" #include "gametime.h"
#include "input.h" #include "input.h"
#include "parseinput.h" #include "parseinput.h"
#include "ringbuffer.h"
#define MOUSE_MOVE (MOUSE_EVENT | MOUSE_MOVED) #define MOUSE_MOVE (MOUSE_EVENT | MOUSE_MOVED)
#define MOUSE_VWHEEL (MOUSE_EVENT | MOUSE_WHEELED) #define MOUSE_VWHEEL (MOUSE_EVENT | MOUSE_WHEELED)
@ -71,6 +72,11 @@ struct win_rec {
}; };
}; };
union record {
struct win_rec native;
INPUT_RECORD win;
};
bool init_handles() bool init_handles()
{ {
win.input_hand = GetStdHandle(STD_INPUT_HANDLE); win.input_hand = GetStdHandle(STD_INPUT_HANDLE);
@ -127,46 +133,56 @@ bool dispatch_rec(
u8f type = rec->type | (rec->is_mouse & rec->mouse.flags); u8f type = rec->type | (rec->is_mouse & rec->mouse.flags);
switch (type) { switch (type) {
case KEY_EVENT: case KEY_EVENT: {
ReadButton(out, rec->key.vk_code, rec->key.is_down); ReadButton(out, rec->key.vk_code, rec->key.is_down);
str->len += UCS2ToUTF8(&str->buf[str->len], rec->key.ucs2_char);
return true;
case MOUSE_MOVE: char *to = RingBufferGet(&STR_BUF_T, &str->head, str->head.len);
ReadJoystick(out, 0, rec->mouse.pos.x, rec->mouse.pos.y); str->head.len += UCS2ToUTF8(to, rec->key.ucs2_char);
return true;
case MOUSE_VWHEEL: return true;
case MOUSE_HWHEEL: }
ReadAxis(out, rec->mouse.is_hwheel, rec->mouse.but); case MOUSE_MOVE: {
return true; ReadJoystick(out, 0, rec->mouse.pos.x, rec->mouse.pos.y);
case WINDOW_BUFFER_SIZE_EVENT: return true;
return false; }
// TODO: Handle window resizing case MOUSE_VWHEEL: {
ReadAxis(out, 0, rec->mouse.but);
return true;
}
case MOUSE_HWHEEL: {
ReadAxis(out, 1, rec->mouse.but);
return true;
}
case WINDOW_BUFFER_SIZE_EVENT: {
// TODO: Handle window resizing
return false;
}
} }
return false; return false;
} }
bool PlatformReadInput(struct InputRecordBuf *in, struct InputStringBuf *str) bool PlatformReadInput(struct InputRecordBuf *recs, struct InputStringBuf *str)
{ {
DWORD max_records = IO_BUF_SIZE - in->len; DWORD read_max = RingBufferEmpty(&IO_BUF_T, &recs->head);
struct win_rec win_buf[max_records]; union record win_buf[read_max];
DWORD filled; DWORD filled;
if (!ReadConsoleInputW(win.input_hand, win_buf, max_records, &filled)) if (!ReadConsoleInputW(win.input_hand, &win_buf->win, read_max, &filled))
return false; return false;
Time now = TimeNow(); Time now = TimeNow();
for (size_t i = 0; i < filled; i++) { for (size_t i = 0; i < filled; i++) {
size_t rec_i = (in->start + in->len) % IO_BUF_SIZE; struct InputRecord *rec = RingBufferNext(&IO_BUF_T, &recs->head);
struct InputRecord *rec = &in->buf[rec_i];
if (dispatch_rec(rec, str, win_buf + i)) { if (dispatch_rec(rec, str, &win_buf->native + i)) {
rec->time = now; rec->time = now;
in->len += 1; recs->head.len += 1;
} }
} }

View file

@ -36,20 +36,27 @@ int main()
if (!CreateCtrl(&ctrl)) if (!CreateCtrl(&ctrl))
ErrorExit("Out of memory"); ErrorExit("Out of memory");
CtrlMap(&ctrl, 0, BUTTON, 'A');
struct Game game; struct Game game;
CreateEvent(&game.Update); CreateEvent(&game.Update);
struct InputThreadHandle input_hand; struct InputHandle input_hand;
if (!BeginInputThread(&input_hand, &ctrl.recs, &ctrl.str)) if (!BeginInputThread(&input_hand, &ctrl.recs, &ctrl.str))
ErrorExit("Input handle failed to initialize"); ErrorExit("Input handle failed to initialize");
CtrlMap(&ctrl, 0, BUTTON, 'A'); _sleep(1000000);
while (true) { while (true) {
if(!CtrlPoll(&ctrl, &input_hand)) if (!InputAquire(&input_hand))
ErrorExit("Poll failed"); ErrorExit("Aquire failed");
//printf("%u\n", ctrl.recs.head.len);
//CtrlPoll(&ctrl);
EventInvokeUpdate(&game.Update, nullptr); if (!InputRelease(&input_hand))
ErrorExit("Release failed");
EventInvokeUpdate(&game.Update, 0);
} }
return 0; return 0;

BIN
test.exe

Binary file not shown.