mm
ok
This commit is contained in:
parent
3de83d481e
commit
2e976a8d2e
|
@ -1,35 +1,67 @@
|
|||
#pragma once
|
||||
#include "ringbuffer.h"
|
||||
#include <string.h>
|
||||
|
||||
struct rbuf_generic {
|
||||
struct ring_buf {
|
||||
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;
|
||||
return rbuf->arr + wrap_i * T->SIZE;
|
||||
struct ring_buf *ring = (struct ring_buf *)head;
|
||||
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 rbuf->arr + i * T->SIZE;
|
||||
return T->LEN - head->len;
|
||||
}
|
||||
|
||||
void RingBufferTransfer(RingBufferT T, RingBuffer *dest, RingBuffer *tmp)
|
||||
void *RingBufferGet(RingBufferT T, struct RingBufferHead *head, size_t i)
|
||||
{
|
||||
struct rbuf_generic *write = dest;
|
||||
struct rbuf_generic *read = tmp;
|
||||
size_t wrap_i = (head->start + i) % T->LEN;
|
||||
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++) {
|
||||
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;
|
||||
read->head.len -= copy_max;
|
||||
dest->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;
|
||||
}
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
#include "fumotris.h"
|
||||
|
||||
typedef void *RingBuffer;
|
||||
|
||||
typedef const struct RingBufferT {
|
||||
size_t LEN;
|
||||
size_t SIZE;
|
||||
|
@ -19,6 +17,27 @@ struct RingBufferHead {
|
|||
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
|
||||
);
|
|
@ -1,6 +1,6 @@
|
|||
#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;
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define nullptr ((void *)0)
|
||||
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint_fast8_t u8f;
|
||||
|
||||
|
@ -28,7 +30,9 @@ typedef int_fast32_t i32f;
|
|||
typedef int64_t i64;
|
||||
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] = {
|
||||
0, 0, 0, 0,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "ctrl.h"
|
||||
|
||||
#include "ringbuffer.h"
|
||||
|
||||
#define INIT_SIZE 16
|
||||
|
||||
bool CreateCtrl(struct Controller *ctrl)
|
||||
|
@ -12,7 +14,7 @@ bool CreateCtrl(struct Controller *ctrl)
|
|||
return false;
|
||||
|
||||
*ctrl = (struct Controller) {
|
||||
.recs.len = 0,
|
||||
.recs.head = RINGBUF_HEAD_INIT,
|
||||
.pending_buf.len = 0,
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -99,14 +101,14 @@ struct InputAxis *find_axis(struct ctrl_dict *dict, union InputID id)
|
|||
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 };
|
||||
}
|
||||
|
||||
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 *bind_bkt = find_or_set(&ctrl->binds, to_id(bind, type));
|
||||
struct ctrl_bkt *code_bkt = find_set(&ctrl->codes, as_id(code, type));
|
||||
struct ctrl_bkt *bind_bkt = find_set(&ctrl->binds, as_id(bind, type));
|
||||
|
||||
if (code_bkt->axis == nullptr)
|
||||
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 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)
|
||||
return nullptr;
|
||||
|
||||
|
@ -152,7 +154,7 @@ void CtrlPoll(struct Controller *ctrl)
|
|||
}
|
||||
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 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->recs.len = 0;
|
||||
ctrl->recs.head.len = 0;
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
|
@ -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);
|
||||
|
||||
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 {
|
||||
LEFT,
|
||||
|
|
|
@ -3,65 +3,114 @@
|
|||
|
||||
#include "platform.h"
|
||||
|
||||
void *input_thread_loop(void *arg)
|
||||
{
|
||||
struct InputThreadHandle *hand = arg;
|
||||
const struct RingBufferT IO_BUF_T = {
|
||||
.LEN = IO_BUF_SIZE,
|
||||
.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 };
|
||||
|
||||
while (!hand->is_terminating) {
|
||||
if (!PlatformReadInput(&tmp_in, &tmp_str))
|
||||
if (!PlatformReadInput(&tmp_recs, &tmp_str)) {
|
||||
hand->err = true;
|
||||
return nullptr;
|
||||
}
|
||||
printf("input read, len:%u\n", hand->recs->head.len);
|
||||
|
||||
if (hand->err = pthread_mutex_lock(&hand->mutex))
|
||||
return nullptr;
|
||||
for (int i = 0; i < hand->recs->head.len; i++) {
|
||||
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))
|
||||
if (pthread_mutex_lock(&hand->mutex) != 0) {
|
||||
hand->err = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RingBufferTransfer(IO_BUF_T, hand->in, &tmp_in);
|
||||
RingBufferTransfer(STR_BUF_T, hand->str, &tmp_str);
|
||||
|
||||
if (hand->err = pthread_mutex_unlock(&hand->mutex))
|
||||
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;
|
||||
}
|
||||
|
||||
bool BeginInputThread(
|
||||
struct InputThreadHandle *hand,
|
||||
struct InputHandle *hand,
|
||||
struct InputRecordBuf *in,
|
||||
struct InputStringBuf *str
|
||||
) {
|
||||
*hand = (struct InputThreadHandle) {
|
||||
.in = in,
|
||||
*hand = (struct InputHandle) {
|
||||
.recs = in,
|
||||
.str = str,
|
||||
|
||||
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
.consume = PTHREAD_COND_INITIALIZER,
|
||||
|
||||
.err = 0,
|
||||
.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;
|
||||
|
||||
if (!PlatformStopInput())
|
||||
return false;
|
||||
|
||||
if (!pthread_mutex_destroy(&hand->mutex))
|
||||
if (pthread_mutex_destroy(&hand->mutex) != 0)
|
||||
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 true;
|
||||
|
|
|
@ -68,8 +68,8 @@ struct InputRecord {
|
|||
};
|
||||
};
|
||||
|
||||
RingBufferT IO_BUF_T = INIT_RING_BUF_T(IO_BUF_SIZE, struct InputRecord);
|
||||
RingBufferT STR_BUF_T = INIT_RING_BUF_T(STR_BUF_SIZE, char);
|
||||
extern const struct RingBufferT IO_BUF_T;
|
||||
extern const struct RingBufferT STR_BUF_T;
|
||||
|
||||
struct InputRecordBuf {
|
||||
struct RingBufferHead head;
|
||||
|
@ -81,22 +81,26 @@ struct InputStringBuf {
|
|||
char buf[STR_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct InputThreadHandle {
|
||||
struct InputRecordBuf *in;
|
||||
struct InputHandle {
|
||||
struct InputRecordBuf *recs;
|
||||
struct InputStringBuf *str;
|
||||
|
||||
pthread_t thread;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t consume;
|
||||
pthread_cond_t is_consumed;
|
||||
|
||||
int err;
|
||||
bool is_terminating;
|
||||
};
|
||||
|
||||
bool BeginInputThread(
|
||||
struct InputThreadHandle *hand,
|
||||
struct InputHandle *hand,
|
||||
struct InputRecordBuf *in,
|
||||
struct InputStringBuf *str
|
||||
);
|
||||
|
||||
bool EndInputThread(struct InputThreadHandle *hand);
|
||||
bool EndInputThread(struct InputHandle *hand);
|
||||
|
||||
bool InputAquire(struct InputHandle *hand);
|
||||
|
||||
bool InputRelease(struct InputHandle *hand);
|
|
@ -5,6 +5,7 @@
|
|||
#include "gametime.h"
|
||||
#include "input.h"
|
||||
#include "parseinput.h"
|
||||
#include "ringbuffer.h"
|
||||
|
||||
#define MOUSE_MOVE (MOUSE_EVENT | MOUSE_MOVED)
|
||||
#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()
|
||||
{
|
||||
win.input_hand = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
@ -127,46 +133,56 @@ bool dispatch_rec(
|
|||
u8f type = rec->type | (rec->is_mouse & rec->mouse.flags);
|
||||
|
||||
switch (type) {
|
||||
case KEY_EVENT:
|
||||
case KEY_EVENT: {
|
||||
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);
|
||||
str->head.len += UCS2ToUTF8(to, rec->key.ucs2_char);
|
||||
|
||||
return true;
|
||||
}
|
||||
case MOUSE_MOVE: {
|
||||
ReadJoystick(out, 0, rec->mouse.pos.x, rec->mouse.pos.y);
|
||||
return true;
|
||||
|
||||
case MOUSE_VWHEEL:
|
||||
case MOUSE_HWHEEL:
|
||||
ReadAxis(out, rec->mouse.is_hwheel, rec->mouse.but);
|
||||
return true;
|
||||
}
|
||||
case MOUSE_VWHEEL: {
|
||||
ReadAxis(out, 0, rec->mouse.but);
|
||||
|
||||
case WINDOW_BUFFER_SIZE_EVENT:
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
|
||||
bool PlatformReadInput(struct InputRecordBuf *in, struct InputStringBuf *str)
|
||||
bool PlatformReadInput(struct InputRecordBuf *recs, struct InputStringBuf *str)
|
||||
{
|
||||
DWORD max_records = IO_BUF_SIZE - in->len;
|
||||
struct win_rec win_buf[max_records];
|
||||
DWORD read_max = RingBufferEmpty(&IO_BUF_T, &recs->head);
|
||||
union record win_buf[read_max];
|
||||
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;
|
||||
|
||||
Time now = TimeNow();
|
||||
|
||||
for (size_t i = 0; i < filled; i++) {
|
||||
size_t rec_i = (in->start + in->len) % IO_BUF_SIZE;
|
||||
struct InputRecord *rec = &in->buf[rec_i];
|
||||
struct InputRecord *rec = RingBufferNext(&IO_BUF_T, &recs->head);
|
||||
|
||||
if (dispatch_rec(rec, str, win_buf + i)) {
|
||||
if (dispatch_rec(rec, str, &win_buf->native + i)) {
|
||||
rec->time = now;
|
||||
in->len += 1;
|
||||
recs->head.len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,20 +36,27 @@ int main()
|
|||
if (!CreateCtrl(&ctrl))
|
||||
ErrorExit("Out of memory");
|
||||
|
||||
CtrlMap(&ctrl, 0, BUTTON, 'A');
|
||||
|
||||
struct Game game;
|
||||
CreateEvent(&game.Update);
|
||||
|
||||
struct InputThreadHandle input_hand;
|
||||
struct InputHandle input_hand;
|
||||
if (!BeginInputThread(&input_hand, &ctrl.recs, &ctrl.str))
|
||||
ErrorExit("Input handle failed to initialize");
|
||||
|
||||
CtrlMap(&ctrl, 0, BUTTON, 'A');
|
||||
|
||||
_sleep(1000000);
|
||||
while (true) {
|
||||
if(!CtrlPoll(&ctrl, &input_hand))
|
||||
ErrorExit("Poll failed");
|
||||
if (!InputAquire(&input_hand))
|
||||
ErrorExit("Aquire failed");
|
||||
|
||||
EventInvokeUpdate(&game.Update, nullptr);
|
||||
//printf("%u\n", ctrl.recs.head.len);
|
||||
//CtrlPoll(&ctrl);
|
||||
|
||||
if (!InputRelease(&input_hand))
|
||||
ErrorExit("Release failed");
|
||||
|
||||
EventInvokeUpdate(&game.Update, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue