safdasf
fas
This commit is contained in:
parent
370ef5e0c5
commit
c941f8b7fb
|
@ -12,7 +12,7 @@ struct Delegate {
|
||||||
void (**events)(void *args);
|
void (**events)(void *args);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t delegate_size(size_t capacity)
|
size_t delegate_size(size_t capacity)
|
||||||
{
|
{
|
||||||
return sizeof(void(*)(void *)) * capacity;
|
return sizeof(void(*)(void *)) * capacity;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,8 @@ void TetrMapToTermBuf(struct TetrMap *map, struct Terminal *term)
|
||||||
size_t map_i = y * map->wid + x;
|
size_t map_i = y * map->wid + x;
|
||||||
size_t buf_i = (y + map->y) * term->wid + (x + map->x) * 2;
|
size_t buf_i = (y + map->y) * term->wid + (x + map->x) * 2;
|
||||||
|
|
||||||
struct TChar4 *a = &term->bufs[buf_i];
|
struct TChar4 *a = &term->blks[buf_i];
|
||||||
struct TChar4 *b = &term->bufs[buf_i + 1];
|
struct TChar4 *b = &term->blks[buf_i + 1];
|
||||||
|
|
||||||
if (map->blks[map_i] == 0) {
|
if (map->blks[map_i] == 0) {
|
||||||
a->ch = '(';
|
a->ch = '(';
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include <assert.h>
|
|
||||||
#include <iso646.h>
|
#include <iso646.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -80,7 +79,7 @@ hashtype Hash(void *item, size_t size)
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
hashtype hash_ident(u16f value, u8f type)
|
hashtype hash_id(u16f value, u8f type)
|
||||||
{
|
{
|
||||||
struct id {
|
struct id {
|
||||||
u16 id;
|
u16 id;
|
||||||
|
@ -108,49 +107,51 @@ struct Ctrl {
|
||||||
struct ctrl_dict codes;
|
struct ctrl_dict codes;
|
||||||
struct ctrl_dict binds;
|
struct ctrl_dict binds;
|
||||||
|
|
||||||
|
struct RecordBuffer buf;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
pthread_mutex_t mutex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ctrl NewCtrl()
|
bool NewCtrl(struct Ctrl *ctrl, size_t code_cap, size_t bind_cap)
|
||||||
{
|
{
|
||||||
struct Ctrl ctrl = (struct Ctrl) {
|
struct ctrl_bkt *code_bkts = calloc(code_cap, sizeof(struct ctrl_bkt));
|
||||||
.codes = (struct ctrl_dict) {
|
struct ctrl_bkt *bind_bkts = calloc(bind_cap, sizeof(struct ctrl_bkt));
|
||||||
.capacity = 0,
|
struct Axis *axes = calloc(code_cap, sizeof(struct Axis));
|
||||||
.filled = 0,
|
|
||||||
.bkts = nullptr
|
|
||||||
},
|
|
||||||
.binds = (struct ctrl_dict) {
|
|
||||||
.capacity = 0,
|
|
||||||
.filled = 0,
|
|
||||||
.bkts = nullptr
|
|
||||||
},
|
|
||||||
|
|
||||||
.mutex = PTHREAD_MUTEX_INITIALIZER
|
if (code_bkts == nullptr or bind_bkts == nullptr or axes == nullptr)
|
||||||
};
|
return false;
|
||||||
return ctrl;
|
|
||||||
|
for (size_t i = 0; i < code_cap; i++) {
|
||||||
|
code_bkts[i].axis = axes + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CtrlSet(
|
*ctrl = (struct Ctrl) {
|
||||||
struct Ctrl *ctrl,
|
.codes = (struct ctrl_dict) {
|
||||||
struct ctrl_bkt *code_bkts,
|
.capacity = code_cap,
|
||||||
struct ctrl_bkt *bind_bkts,
|
.filled = 0,
|
||||||
struct Axis *axes,
|
.bkts = code_bkts,
|
||||||
size_t c_len,
|
},
|
||||||
size_t b_len
|
.binds = (struct ctrl_dict) {
|
||||||
) {
|
.capacity = bind_cap,
|
||||||
ctrl->codes.capacity = c_len;
|
.filled = 0,
|
||||||
ctrl->codes.bkts = code_bkts;
|
.bkts = bind_bkts,
|
||||||
memset(code_bkts, 0, sizeof(struct ctrl_bkt) * c_len);
|
},
|
||||||
|
|
||||||
ctrl->binds.capacity = b_len;
|
.buf = (struct RecordBuffer) {
|
||||||
ctrl->binds.bkts = bind_bkts;
|
.count = 0,
|
||||||
memset(bind_bkts, 0, sizeof(struct ctrl_bkt) * b_len);
|
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeCtrl(struct Ctrl *ctrl)
|
||||||
|
{
|
||||||
|
free(ctrl->codes.bkts);
|
||||||
|
free(ctrl->binds.bkts);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ctrl_bkt *get_bkt(struct ctrl_dict *dict, size_t i)
|
struct ctrl_bkt *get_bkt(struct ctrl_dict *dict, size_t i)
|
||||||
{
|
{
|
||||||
assert(i < dict->capacity);
|
|
||||||
return &dict->bkts[i];
|
return &dict->bkts[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,18 +162,18 @@ void set_bkt(struct ctrl_bkt *bkt, hashtype hash, u16f value, u8f type)
|
||||||
bkt->type = type;
|
bkt->type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t wrap(size_t x, size_t wrap)
|
size_t wrap_index(size_t i, size_t max)
|
||||||
{
|
{
|
||||||
return x % (SIZE_MAX - wrap + 1);
|
return i % (SIZE_MAX - max + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find_or_set(struct ctrl_dict *dict, struct ctrl_bkt **out, u16f value, u8f type)
|
bool find_or_set(struct ctrl_dict *dict, struct ctrl_bkt **out, u16f value, u8f type)
|
||||||
{
|
{
|
||||||
hashtype hash = hash_ident(value, type);
|
hashtype hash = hash_id(value, type);
|
||||||
const size_t index = hash % dict->capacity;
|
const size_t index = hash % dict->capacity;
|
||||||
|
|
||||||
size_t i = index;
|
size_t i = index;
|
||||||
while (i != wrap(index - 1, dict->capacity)) {
|
while (i != wrap_index(index - 1, dict->capacity)) {
|
||||||
struct ctrl_bkt *bkt = get_bkt(dict, i);
|
struct ctrl_bkt *bkt = get_bkt(dict, i);
|
||||||
|
|
||||||
if (bkt->hash == 0) {
|
if (bkt->hash == 0) {
|
||||||
|
@ -196,18 +197,18 @@ bool find_or_set(struct ctrl_dict *dict, struct ctrl_bkt **out, u16f value, u8f
|
||||||
|
|
||||||
struct ctrl_bkt *find(struct ctrl_dict *dict, u16f value, u8f type)
|
struct ctrl_bkt *find(struct ctrl_dict *dict, u16f value, u8f type)
|
||||||
{
|
{
|
||||||
hashtype hash = hash_ident(value, type);
|
hashtype hash = hash_id(value, type);
|
||||||
const size_t index = hash % dict->capacity;
|
const size_t index = hash % dict->capacity;
|
||||||
|
|
||||||
size_t i = index;
|
size_t i = index;
|
||||||
while (i != wrap(index - 1, dict->capacity)) {
|
while (i != wrap_index(index - 1, dict->capacity)) {
|
||||||
struct ctrl_bkt *bkt = get_bkt(dict, i);
|
struct ctrl_bkt *bkt = get_bkt(dict, i);
|
||||||
if (bkt->hash == 0)
|
if (bkt->hash == 0)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
if (bkt->value == value and bkt->type == type) {
|
if (bkt->value == value and bkt->type == type)
|
||||||
return bkt;
|
return bkt;
|
||||||
}
|
|
||||||
next:
|
next:
|
||||||
i = (i + 1) % dict->capacity;
|
i = (i + 1) % dict->capacity;
|
||||||
};
|
};
|
||||||
|
@ -226,16 +227,16 @@ struct Axis *find_axis(struct ctrl_dict *dict, u16f value, u8f type)
|
||||||
|
|
||||||
bool CtrlMap(struct Ctrl *ctrl, u16f code, u16f bind, u8f type)
|
bool CtrlMap(struct Ctrl *ctrl, u16f code, u16f bind, u8f type)
|
||||||
{
|
{
|
||||||
assert(ctrl->codes.filled < ctrl->codes.capacity);
|
if (ctrl->codes.filled >= ctrl->codes.capacity or ctrl->binds.filled >= ctrl->binds.capacity) {
|
||||||
assert(ctrl->binds.filled < ctrl->binds.capacity);
|
printf("fatal error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
struct ctrl_bkt *code_bkt;
|
struct ctrl_bkt *code_bkt;
|
||||||
find_or_set(&ctrl->codes, &code_bkt, code, type);
|
find_or_set(&ctrl->codes, &code_bkt, code, type);
|
||||||
assert(code_bkt != nullptr);
|
|
||||||
|
|
||||||
struct ctrl_bkt *bind_bkt;
|
struct ctrl_bkt *bind_bkt;
|
||||||
bool bind_existed = find_or_set(&ctrl->binds, &bind_bkt, bind, type);
|
bool bind_existed = find_or_set(&ctrl->binds, &bind_bkt, bind, type);
|
||||||
assert(bind_bkt != nullptr);
|
|
||||||
|
|
||||||
if(bind_existed and bind_bkt->axis == code_bkt->axis)
|
if(bind_existed and bind_bkt->axis == code_bkt->axis)
|
||||||
return false;
|
return false;
|
||||||
|
@ -276,10 +277,10 @@ void update_joystick(struct Axis *axis, struct Record *record)
|
||||||
axis->last_pressed = record->timestamp;
|
axis->last_pressed = record->timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CtrlPoll(struct Ctrl *ctrl, struct RecordBuffer *rec_buf)
|
bool CtrlPoll(struct Ctrl *ctrl)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < rec_buf->count; i++) {
|
for (size_t i = 0; i < ctrl->buf.count; i++) {
|
||||||
struct Record *rec = &rec_buf->records[i];
|
struct Record *rec = &ctrl->buf.records[i];
|
||||||
|
|
||||||
struct Axis *axis = find_axis(&ctrl->binds, rec->id, rec->type);
|
struct Axis *axis = find_axis(&ctrl->binds, rec->id, rec->type);
|
||||||
if (axis == nullptr)
|
if (axis == nullptr)
|
||||||
|
@ -300,6 +301,6 @@ bool CtrlPoll(struct Ctrl *ctrl, struct RecordBuffer *rec_buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rec_buf->count = 0;
|
ctrl->buf.count = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -99,14 +99,16 @@ struct Ctrl {
|
||||||
struct ctrl_dict codes;
|
struct ctrl_dict codes;
|
||||||
struct ctrl_dict binds;
|
struct ctrl_dict binds;
|
||||||
|
|
||||||
|
struct RecordBuffer buf;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
pthread_mutex_t mutex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ctrl NewCtrl();
|
bool NewCtrl(struct Ctrl *ctrl, size_t code_cap, size_t bind_cap);
|
||||||
|
|
||||||
|
void FreeCtrl(struct Ctrl *ctrl);
|
||||||
|
|
||||||
bool CtrlMap(struct Ctrl *ctrl, u16f code, u16f bind, u8f type);
|
bool CtrlMap(struct Ctrl *ctrl, u16f code, u16f bind, u8f type);
|
||||||
|
|
||||||
struct Axis *CtrlGet(struct Ctrl *ctrl, u16f code, u8f type);
|
struct Axis *CtrlGet(struct Ctrl *ctrl, u16f code, u8f type);
|
||||||
|
|
||||||
bool CtrlPoll(struct Ctrl *ctrl, struct RecordBuffer *buf);
|
bool CtrlPoll(struct Ctrl *ctrl);
|
|
@ -14,13 +14,13 @@
|
||||||
|
|
||||||
void *block_input(void *args_ptr)
|
void *block_input(void *args_ptr)
|
||||||
{
|
{
|
||||||
struct RecordBuffer *buf = args_ptr;
|
struct RecordBuffer *rec_buf = args_ptr;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
success = WindowsBlockInput(buf);
|
success = WindowsBlockInput(rec_buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -32,9 +32,9 @@ void *block_input(void *args_ptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartInput(struct Ctrl *ctrl, struct RecordBuffer *buf)
|
void StartInput(struct Ctrl *ctrl)
|
||||||
{
|
{
|
||||||
pthread_create(&ctrl->thread, nullptr, block_input, buf);
|
pthread_create(&ctrl->thread, nullptr, block_input, &ctrl->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JoinInput(struct Ctrl *ctrl)
|
void JoinInput(struct Ctrl *ctrl)
|
||||||
|
|
|
@ -8,6 +8,6 @@
|
||||||
#include "ctrl.h"
|
#include "ctrl.h"
|
||||||
#include "fumotris.h"
|
#include "fumotris.h"
|
||||||
|
|
||||||
void StartInput(Ctrl *ctrl, struct RecordBuffer *buf);
|
void StartInput(struct Ctrl *ctrl);
|
||||||
|
|
||||||
void JoinInput(Ctrl *ctrl);
|
void JoinInput(struct Ctrl *ctrl);
|
|
@ -10,17 +10,22 @@
|
||||||
#include "winhandler.h"
|
#include "winhandler.h"
|
||||||
#include "term.h"
|
#include "term.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
bool WindowsInit(struct Terminal *term)
|
bool WindowsInit(struct Terminal *term)
|
||||||
{
|
{
|
||||||
if (!WinInitHandles())
|
if (!WinInitHandles())
|
||||||
return false;
|
return false;
|
||||||
|
printf("shid ");
|
||||||
|
|
||||||
if (!WinInitConsole())
|
if (!WinInitConsole()) {
|
||||||
|
printf("%u\n", GetLastError());
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
printf("console");
|
||||||
if (!WinGetRefreshRate(&term->refresh_rate))
|
if (!WinGetRefreshRate(&term->refresh_rate))
|
||||||
return false;
|
return false;
|
||||||
|
printf("???");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "term.h"
|
||||||
|
|
||||||
bool WindowsInit();
|
bool WindowsInit(struct Terminal *term);
|
||||||
|
|
||||||
bool WindowsBlockInput(struct RecordBuffer *buf);
|
bool WindowsBlockInput(struct RecordBuffer *buf);
|
||||||
|
|
||||||
|
|
|
@ -14,31 +14,22 @@
|
||||||
|
|
||||||
struct Windows {
|
struct Windows {
|
||||||
HANDLE input_handle;
|
HANDLE input_handle;
|
||||||
HANDLE draw_handles[2];
|
HANDLE timer;
|
||||||
};
|
};
|
||||||
static struct Windows windows;
|
static struct Windows win;
|
||||||
|
|
||||||
bool WinInitHandles()
|
bool WinInitHandles()
|
||||||
{
|
{
|
||||||
windows.input_handle = GetStdHandle(STD_INPUT_HANDLE);
|
win.input_handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
if (windows.input_handle == INVALID_HANDLE_VALUE)
|
if (win.input_handle == INVALID_HANDLE_VALUE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
windows.draw_handles[0] = CreateWaitableTimer(
|
win.timer = CreateWaitableTimer(
|
||||||
NULL, // Timer attributes
|
NULL, // Timer attributes
|
||||||
TRUE, // Manual reset
|
TRUE, // Manual reset
|
||||||
NULL // Name
|
NULL // Name
|
||||||
);
|
);
|
||||||
if (!windows.draw_handles[0])
|
if (!win.timer)
|
||||||
return false;
|
|
||||||
|
|
||||||
windows.draw_handles[1] = CreateEvent(
|
|
||||||
NULL, // Event attributes
|
|
||||||
FALSE, // Manual reset
|
|
||||||
FALSE, // Initial state
|
|
||||||
NULL // Name
|
|
||||||
);
|
|
||||||
if (!windows.draw_handles[1])
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -51,12 +42,15 @@ bool WinInitConsole()
|
||||||
| ENABLE_MOUSE_INPUT
|
| ENABLE_MOUSE_INPUT
|
||||||
| ENABLE_WINDOW_INPUT
|
| ENABLE_WINDOW_INPUT
|
||||||
| ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
| ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
return SetConsoleMode(windows.input_handle, mode);
|
return SetConsoleMode(win.input_handle, mode) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WinGetRefreshRate(u32f *out)
|
bool WinGetRefreshRate(u16f *out)
|
||||||
{
|
{
|
||||||
LPDEVMODE mode;
|
DEVMODE mode;
|
||||||
|
mode.dmSize = sizeof(DEVMODE);
|
||||||
|
mode.dmDriverExtra = 0;
|
||||||
|
|
||||||
if(!EnumDisplaySettingsA(
|
if(!EnumDisplaySettingsA(
|
||||||
NULL, // Device name (null for current)
|
NULL, // Device name (null for current)
|
||||||
ENUM_CURRENT_SETTINGS, // Mode
|
ENUM_CURRENT_SETTINGS, // Mode
|
||||||
|
@ -64,7 +58,7 @@ bool WinGetRefreshRate(u32f *out)
|
||||||
))
|
))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*out = mode->dmDisplayFrequency;
|
*out = mode.dmDisplayFrequency;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,8 +106,8 @@ bool dispatch_record(struct Record *record, INPUT_RECORD win_record)
|
||||||
case MOUSE_EVENT:
|
case MOUSE_EVENT:
|
||||||
return set_mouse_record(record, win_record.Event.MouseEvent);
|
return set_mouse_record(record, win_record.Event.MouseEvent);
|
||||||
case WINDOW_BUFFER_SIZE_EVENT:
|
case WINDOW_BUFFER_SIZE_EVENT:
|
||||||
set_window_record(record, win_record.Event.WindowBufferSizeEvent);
|
// TODO: Handle window resizing
|
||||||
break;
|
return false;
|
||||||
default:
|
default:
|
||||||
record->type = ESCAPE;
|
record->type = ESCAPE;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +121,7 @@ bool WinBlockInput(struct RecordBuffer *buf)
|
||||||
DWORD count;
|
DWORD count;
|
||||||
|
|
||||||
if (!ReadConsoleInput(
|
if (!ReadConsoleInput(
|
||||||
windows.input_handle, // Input handle
|
win.input_handle, // Input handle
|
||||||
win_buf, // Record buffer
|
win_buf, // Record buffer
|
||||||
win_size, // Record buffer length
|
win_size, // Record buffer length
|
||||||
&count // Out number of records
|
&count // Out number of records
|
||||||
|
@ -160,7 +154,7 @@ bool WinWait(struct timespec relative)
|
||||||
duration.QuadPart = -10000000 * relative.tv_sec - relative.tv_nsec / 100;
|
duration.QuadPart = -10000000 * relative.tv_sec - relative.tv_nsec / 100;
|
||||||
|
|
||||||
if (!SetWaitableTimer(
|
if (!SetWaitableTimer(
|
||||||
windows.draw_handles[0], // Timer
|
win.timer, // Timer
|
||||||
&duration, // Duration
|
&duration, // Duration
|
||||||
0, // Period
|
0, // Period
|
||||||
NULL, // Completion coroutine
|
NULL, // Completion coroutine
|
||||||
|
@ -169,12 +163,7 @@ bool WinWait(struct timespec relative)
|
||||||
))
|
))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DWORD result = WaitForMultipleObjects(
|
DWORD result = WaitForSingleObject(win.timer, INFINITE);
|
||||||
2, // Handle count
|
|
||||||
windows.draw_handles, // Handles
|
|
||||||
FALSE, // Wait for all
|
|
||||||
INFINITE // Timeout
|
|
||||||
);
|
|
||||||
if (result != WAIT_OBJECT_0)
|
if (result != WAIT_OBJECT_0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ bool WinInitHandles();
|
||||||
|
|
||||||
bool WinInitConsole();
|
bool WinInitConsole();
|
||||||
|
|
||||||
bool WinGetRefreshRate(u32f *out);
|
bool WinGetRefreshRate(u16f *out);
|
||||||
|
|
||||||
bool WinBlockInput(struct RecordBuffer *buf);
|
bool WinBlockInput(struct RecordBuffer *buf);
|
||||||
|
|
||||||
|
|
142
source/main.c
142
source/main.c
|
@ -16,16 +16,6 @@
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Instance {
|
|
||||||
struct Terminal term;
|
|
||||||
struct Ctrl ctrl;
|
|
||||||
struct RecordBuffer rec_buf;
|
|
||||||
|
|
||||||
struct Delegate on_start;
|
|
||||||
struct Delegate on_draw;
|
|
||||||
struct Delegate on_update;
|
|
||||||
};
|
|
||||||
|
|
||||||
const u8 I[16] = {
|
const u8 I[16] = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
|
@ -68,6 +58,16 @@ const u8 L[9] = {
|
||||||
0, 0, 0
|
0, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Instance {
|
||||||
|
struct Ctrl ctrl;
|
||||||
|
|
||||||
|
struct Delegate on_start;
|
||||||
|
struct Delegate on_update;
|
||||||
|
struct Delegate on_draw;
|
||||||
|
|
||||||
|
struct Terminal term;
|
||||||
|
};
|
||||||
|
|
||||||
struct CtrlBind {
|
struct CtrlBind {
|
||||||
enum CtrlCode code;
|
enum CtrlCode code;
|
||||||
u16 bind;
|
u16 bind;
|
||||||
|
@ -90,117 +90,65 @@ const struct CtrlBind ctrl_binds[12] = {
|
||||||
{ MOUSE, 0, JOYSTICK }
|
{ MOUSE, 0, JOYSTICK }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool DrawUpdate(struct Terminal *term, struct Instance *game, char *buf)
|
void *Update(void *args)
|
||||||
{
|
{
|
||||||
bool is_update;
|
struct Instance *game = args;
|
||||||
|
|
||||||
TermLock(term);
|
struct TChar4 blks[game->term.area];
|
||||||
{
|
game->term.blks = blks;
|
||||||
is_update = TermWaitUpdate(term);
|
|
||||||
if(is_update) {
|
|
||||||
Invoke(&game->on_draw, game);
|
|
||||||
TermOut(term, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TermUnlock(term);
|
|
||||||
|
|
||||||
return is_update;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Draw(struct Terminal *term, struct Instance *game)
|
|
||||||
{
|
|
||||||
struct TChar4 buf0[term->area];
|
|
||||||
struct TChar4 buf1[term->area];
|
|
||||||
|
|
||||||
TermLock(term);
|
|
||||||
{
|
|
||||||
TermSetBufs(term, buf0, buf1);
|
|
||||||
}
|
|
||||||
TermUnlock(term);
|
|
||||||
TermSignalSafe(term);
|
|
||||||
|
|
||||||
char buf[term->buf_size];
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (!DrawUpdate(term, game, buf))
|
|
||||||
break;
|
|
||||||
|
|
||||||
puts(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update(struct Instance *game)
|
|
||||||
{
|
|
||||||
WaitSafeTerm(&game->term);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Input
|
// Input
|
||||||
CtrlPoll(&game->ctrl, &game->rec_buf);
|
CtrlPoll(&game->ctrl);
|
||||||
|
|
||||||
// Game logic
|
// Game logic
|
||||||
Invoke(&game->on_update, game);
|
Invoke(&game->on_update, game);
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
UpdateTerm(&game->term);
|
TermOut(&game->term);
|
||||||
|
puts(game->term.buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loop(struct Ctrl *ctrl, struct RecordBuffer *rec_buf)
|
void Loop(struct Instance *game)
|
||||||
{
|
{
|
||||||
pthread_t draw_thread;
|
|
||||||
pthread_create(&draw_thread, nullptr, Draw, &term);
|
|
||||||
|
|
||||||
pthread_t update_thread;
|
pthread_t update_thread;
|
||||||
pthread_create(&update_thread, nullptr, Update, &term);
|
pthread_create(&update_thread, nullptr, Update, (void *)game);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Start(struct Instance *game)
|
||||||
|
{
|
||||||
|
if (!NewCtrl(&game->ctrl, code_count, code_count))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < code_count; i++) {
|
||||||
|
const struct CtrlBind *bind = &ctrl_binds[i];
|
||||||
|
CtrlMap(&game->ctrl, bind->code, bind->bind, bind->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NewTerm(&game->term, 20, 20))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
struct Instance game;
|
||||||
|
Start(&game);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if(!WindowsInit())
|
if(!WindowsInit(&game.term)) {
|
||||||
|
printf("FUCK");
|
||||||
exit(1);
|
exit(1);
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ctrl_bkt code_bkts[code_count];
|
|
||||||
struct ctrl_dict codes = {
|
|
||||||
.capacity = code_count,
|
|
||||||
.filled = 0,
|
|
||||||
.bkts = code_bkts
|
|
||||||
};
|
|
||||||
struct ctrl_bkt bind_bkts[code_count];
|
|
||||||
struct ctrl_dict binds = {
|
|
||||||
.capacity = code_count,
|
|
||||||
.filled = 0,
|
|
||||||
.bkts = bind_bkts
|
|
||||||
};
|
|
||||||
struct Axis axes[code_count];
|
|
||||||
struct Ctrl ctrl = NewCtrl(&codes, &binds, axes);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < code_count; i++) {
|
|
||||||
const struct CtrlBind *bind = &ctrl_binds[i];
|
|
||||||
CtrlMap(&ctrl, bind->code, bind->bind, bind->type);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
printf("does it work");
|
||||||
|
|
||||||
struct RecordBuffer rec_buf = {
|
StartInput(&game.ctrl);
|
||||||
.count = 0,
|
Loop(&game);
|
||||||
.mutex = PTHREAD_MUTEX_INITIALIZER
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Instance game = {
|
JoinInput(&game.ctrl);
|
||||||
.term = NewTerm(20, 20),
|
|
||||||
.ctrl = NewCtrl(),
|
|
||||||
|
|
||||||
.on_start = NewDelegate(16),
|
|
||||||
.on_draw = NewDelegate(16),
|
|
||||||
.on_update = NewDelegate(16)
|
|
||||||
};
|
|
||||||
|
|
||||||
StartInput(&ctrl, &rec_buf);
|
|
||||||
Loop(&ctrl, &rec_buf);
|
|
||||||
|
|
||||||
JoinInput(&ctrl);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -18,133 +18,182 @@ struct TChar4 {
|
||||||
struct Terminal {
|
struct Terminal {
|
||||||
size_t wid;
|
size_t wid;
|
||||||
size_t hgt;
|
size_t hgt;
|
||||||
u16f refresh_rate;
|
|
||||||
|
|
||||||
size_t area;
|
size_t area;
|
||||||
|
struct TChar4 *blks;
|
||||||
|
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
struct TChar4 *buf;
|
u16f refresh_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t buf_size(size_t area, size_t hgt)
|
size_t term_buf_size(size_t area, size_t hgt)
|
||||||
{
|
{
|
||||||
static const size_t max_color_str_len = 10;
|
|
||||||
static const size_t reset_str_len = 7;
|
static const size_t reset_str_len = 7;
|
||||||
|
static const size_t max_color_str_len = 10;
|
||||||
|
|
||||||
return reset_str_len
|
return reset_str_len + (max_color_str_len + 1) * area + hgt + 1;
|
||||||
+ (max_color_str_len + 1) * area
|
|
||||||
+ (hgt - 1)
|
|
||||||
+ 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Terminal NewTerm(size_t wid, size_t hgt)
|
size_t blks_size(size_t area)
|
||||||
{
|
{
|
||||||
size_t area = wid * hgt;
|
return area * sizeof(struct TChar4);
|
||||||
|
|
||||||
return (struct Terminal) {
|
|
||||||
.wid = wid,
|
|
||||||
.hgt = hgt,
|
|
||||||
.refresh_rate = 60,
|
|
||||||
|
|
||||||
.area = area,
|
|
||||||
.buf_size = 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TermSetBufs(struct Terminal *term, struct TChar4 *buf)
|
bool NewTerm(struct Terminal *term, size_t wid, size_t hgt)
|
||||||
{
|
|
||||||
term->buf_size = buf_size(term->area, term->hgt);
|
|
||||||
term->buf = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TermResize(struct Terminal *term, size_t wid, size_t hgt)
|
|
||||||
{
|
{
|
||||||
size_t area = wid * hgt;
|
size_t area = wid * hgt;
|
||||||
size_t buf_size = term_buf_size(area, hgt);
|
size_t buf_size = term_buf_size(area, hgt);
|
||||||
|
|
||||||
term->wid = wid;
|
struct TChar4 *tchs = malloc(blks_size(area));
|
||||||
term->hgt = hgt;
|
char *buf = malloc(buf_size);
|
||||||
|
|
||||||
term->area = area;
|
if (tchs == nullptr or buf == nullptr)
|
||||||
term->buf_size = buf_size;
|
return false;
|
||||||
|
|
||||||
|
*term = (struct Terminal) {
|
||||||
|
.wid = wid,
|
||||||
|
.hgt = hgt,
|
||||||
|
.area = area,
|
||||||
|
.blks = tchs,
|
||||||
|
|
||||||
|
.buf_size = buf_size,
|
||||||
|
.buf = buf,
|
||||||
|
|
||||||
|
.refresh_rate = 60,
|
||||||
|
};
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t printblk4(char *buf, size_t at, size_t max, struct TChar4 *blk)
|
bool ResizeTerm(struct Terminal *term, size_t wid, size_t hgt)
|
||||||
{
|
{
|
||||||
u8f bg;
|
size_t area = wid * hgt;
|
||||||
if (blk->bg < 8)
|
size_t buf_size = term_buf_size(area, hgt);
|
||||||
bg = blk->bg + 40;
|
|
||||||
else
|
|
||||||
bg = blk->bg + 92;
|
|
||||||
|
|
||||||
u8f fg;
|
struct TChar4 *tchs = realloc(term->blks, blks_size(area));
|
||||||
if (blk->fg < 8)
|
char *buf = realloc(term->buf, buf_size);
|
||||||
fg = blk->fg + 30;
|
if (tchs == nullptr or buf == nullptr)
|
||||||
else
|
return false;
|
||||||
fg = blk->fg + 82;
|
|
||||||
|
|
||||||
return snprintf(buf + at, max - at, "\x1b[%u;%um%c", bg, fg, blk->ch);
|
term->blks = tchs;
|
||||||
|
term->buf = buf;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTerm(struct Terminal *term)
|
||||||
|
{
|
||||||
|
free(term->blks);
|
||||||
|
free(term->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t u8_to_buf(char *buf, u8f x)
|
size_t u8_to_buf(char *buf, u8f x)
|
||||||
{
|
{
|
||||||
|
size_t len = 1;
|
||||||
|
|
||||||
|
if (x > 9) {
|
||||||
|
u8f o, t;
|
||||||
|
|
||||||
|
o = x % 10;
|
||||||
|
t = x / 10;
|
||||||
|
|
||||||
|
if (x > 99) {
|
||||||
|
u8f h;
|
||||||
|
|
||||||
|
t %= 10;
|
||||||
|
h = t / 10;
|
||||||
|
len = 3;
|
||||||
|
|
||||||
|
buf[0] = h + 48;
|
||||||
|
buf[1] = t + 48;
|
||||||
|
buf[2] = o + 48;
|
||||||
|
} else {
|
||||||
|
len = 2;
|
||||||
|
|
||||||
|
buf[0] = t + 48;
|
||||||
|
buf[1] = o + 48;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf[0] = x + 48;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t print4(char *buf, struct TChar4 *blk)
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t tch4_dif_to_buf(char *buf, struct TChar4 *dif, struct TChar4 *blk)
|
||||||
{
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
if (dif->bg != blk->bg) {
|
||||||
|
dif->bg = blk->bg;
|
||||||
u8f bg = blk->bg + (blk->bg < 8 ? 40 : 92);
|
u8f bg = blk->bg + (blk->bg < 8 ? 40 : 92);
|
||||||
|
|
||||||
|
buf[len++] = '\x1b';
|
||||||
|
buf[len++] = '[';
|
||||||
|
len += u8_to_buf(buf + len, bg);
|
||||||
|
|
||||||
|
if (dif->fg != blk->fg) {
|
||||||
|
dif->fg = blk->fg;
|
||||||
u8f fg = blk->fg + (blk->fg < 8 ? 30 : 82);
|
u8f fg = blk->fg + (blk->fg < 8 ? 30 : 82);
|
||||||
|
|
||||||
memcpy(buf, "\x1b[", 2);
|
buf[len++] = ';';
|
||||||
|
len += u8_to_buf(buf + len, fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t TermOut_(struct Terminal *term, char *buf)
|
buf[len++] = 'm';
|
||||||
{
|
} else if (dif->fg != blk->fg) {
|
||||||
struct TChar4 last;
|
dif->fg = blk->fg;
|
||||||
|
u8f fg = blk->fg + (blk->fg < 8 ? 30 : 82);
|
||||||
|
|
||||||
size_t filled = 0;
|
buf[len++] = '\x1b';
|
||||||
memcpy(buf, "\x1b[H\x1b[0m", 7);
|
buf[len++] = '[';
|
||||||
|
len += u8_to_buf(buf + len, fg);
|
||||||
|
buf[len++] = 'm';
|
||||||
|
}
|
||||||
|
buf[len++] = blk->ch;
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t TermOut(struct Terminal *term, char *buf)
|
size_t TermOut(struct Terminal *term)
|
||||||
{
|
{
|
||||||
u8f last_bg = 0;
|
struct TChar4 dif;
|
||||||
u8f last_fg = 0;
|
|
||||||
|
|
||||||
size_t filled = snprintf(buf, term->buf_size, "\x1b[H\x1b[0m");
|
size_t len = 7;
|
||||||
|
memcpy(term->buf, "\x1b[H\x1b[0m", 7);
|
||||||
|
|
||||||
for (size_t y = 0; y < term->hgt; y++) {
|
for (size_t y = 0; y < term->hgt; y++) {
|
||||||
for (size_t x = 0; x < term->wid; x++) {
|
for (size_t x = 0; x < term->wid; x++) {
|
||||||
size_t i = y * term->wid + x;
|
size_t i = y * term->wid + x;
|
||||||
struct TChar4 *blk = &term->buf[i];
|
struct TChar4 *blk = &term->blks[i];
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
if (blk->ch == 0)
|
if (blk->ch == 0)
|
||||||
blk->ch = '#';
|
blk->ch = '#';
|
||||||
// DEBUG
|
// DEBUG
|
||||||
|
|
||||||
if (blk->bg != 0 and blk->bg != last_bg) {
|
len += tch4_dif_to_buf(term->buf + len, &dif, blk);
|
||||||
last_bg = blk->bg;
|
|
||||||
if (blk->fg != 0 and blk->fg != last_fg) {
|
|
||||||
filled += printblk4(buf, filled, term->buf_size, blk);
|
|
||||||
last_fg = blk->fg;
|
|
||||||
} else {
|
|
||||||
filled += printcol4(buf, filled, term->buf_size, blk->bg, blk->ch);
|
|
||||||
}
|
}
|
||||||
} else if (blk->fg != 0 and blk->fg != last_fg) {
|
term->buf[len++] = '\n';
|
||||||
filled += printcol4(buf, filled, term->buf_size, blk->fg, blk->ch);
|
|
||||||
last_fg = blk->fg;
|
|
||||||
} else {
|
|
||||||
buf[filled] = blk->ch;
|
|
||||||
filled += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term->buf[len] = 0;
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
buf[filled] = '\n';
|
|
||||||
filled += 1;
|
/*int main()
|
||||||
}
|
{
|
||||||
buf[filled] = 0;
|
struct Terminal term;
|
||||||
return filled;
|
NewTerm(&term, 20, 20);
|
||||||
|
|
||||||
|
for (int i = 0; i < 20 * 20; i++) {
|
||||||
|
term.blks[i].ch = 'l';
|
||||||
|
term.blks[i].bg = 0;
|
||||||
|
term.blks[i].fg = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t len = TermOut(&term);
|
||||||
|
puts(term.buf);
|
||||||
|
|
||||||
|
printf("hi");
|
||||||
|
return 0;
|
||||||
|
}*/
|
|
@ -20,35 +20,18 @@ struct Terminal {
|
||||||
size_t wid;
|
size_t wid;
|
||||||
size_t hgt;
|
size_t hgt;
|
||||||
size_t area;
|
size_t area;
|
||||||
u16f refresh_rate;
|
struct TChar4 *blks;
|
||||||
|
|
||||||
struct TChar4 *bufs[2];
|
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
u8f switch_read;
|
char *buf;
|
||||||
u8f switch_write;
|
|
||||||
|
|
||||||
pthread_mutex_t mutex;
|
u16f refresh_rate;
|
||||||
pthread_cond_t update;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u8f is_writing : 1;
|
|
||||||
u8f resize : 1;
|
|
||||||
} flags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Terminal NewTerm(size_t wid, size_t hgt);
|
bool NewTerm(struct Terminal *term, size_t wid, size_t hgt);
|
||||||
|
|
||||||
void TermSetBufs(struct Terminal *term, struct TChar4 *buf0, struct TChar4 *buf1);
|
bool ResizeTerm(struct Terminal *term, size_t wid, size_t hgt);
|
||||||
|
|
||||||
void TermResize(struct Terminal *term, size_t wid, size_t hgt);
|
void FreeTerm(struct Terminal *term);
|
||||||
|
|
||||||
void UpdateTerm(struct Terminal *term);
|
size_t TermOut(struct Terminal *term);
|
||||||
bool TermWaitUpdate(struct Terminal *term);
|
|
||||||
|
|
||||||
void TermSignalSafe(struct Terminal *term);
|
|
||||||
void WaitSafeTerm(struct Terminal *term);
|
|
||||||
|
|
||||||
void TermLock(struct Terminal *term);
|
|
||||||
void TermUnlock(struct Terminal *term);
|
|
||||||
|
|
||||||
size_t TermOut(struct Terminal *term, char *buf);
|
|
Loading…
Reference in a new issue