diff --git a/source/game/event.c b/source/game/event.c index c7cbd4a..41cec24 100644 --- a/source/game/event.c +++ b/source/game/event.c @@ -37,7 +37,7 @@ void Subscribe(struct Delegate *d, void (*event)(void *args)) d->len += 1; } -void Call(struct Delegate *d, void *args) +void Invoke(struct Delegate *d, void *args) { for (size_t i = 0; i < d->len; i++) { d->events[i](args); diff --git a/source/game/event.h b/source/game/event.h index ce7a4cd..03e47bc 100644 --- a/source/game/event.h +++ b/source/game/event.h @@ -17,4 +17,4 @@ struct Delegate NewDelegate(size_t capacity); void Subscribe(struct Delegate *d, void (*event)(void *args)); -void Call(struct Delegate *d, void *args); \ No newline at end of file +void Invoke(struct Delegate *d, void *args); \ No newline at end of file diff --git a/source/game/tetr.c b/source/game/tetr.c index c579f0d..fade61d 100644 --- a/source/game/tetr.c +++ b/source/game/tetr.c @@ -42,8 +42,8 @@ void TetrMapToTermBuf(struct TetrMap *map, struct Terminal *term) size_t map_i = y * map->wid + x; size_t buf_i = (y + map->y) * term->wid + (x + map->x) * 2; - struct TChar4 *a = &term->blks[buf_i]; - struct TChar4 *b = &term->blks[buf_i + 1]; + struct TChar4 *a = &term->bufs[buf_i]; + struct TChar4 *b = &term->bufs[buf_i + 1]; if (map->blks[map_i] == 0) { a->ch = '('; diff --git a/source/io/ctrl.c b/source/io/ctrl.c index c049964..d55d7fd 100644 --- a/source/io/ctrl.c +++ b/source/io/ctrl.c @@ -146,8 +146,6 @@ void CtrlSet( ctrl->binds.capacity = b_len; ctrl->binds.bkts = bind_bkts; memset(bind_bkts, 0, sizeof(struct ctrl_bkt) * b_len); - - } struct ctrl_bkt *get_bkt(struct ctrl_dict *dict, size_t i) diff --git a/source/main.c b/source/main.c index 3d62caf..cd35607 100644 --- a/source/main.c +++ b/source/main.c @@ -90,19 +90,60 @@ const struct CtrlBind ctrl_binds[12] = { { MOUSE, 0, JOYSTICK } }; -void Draw(struct Instance *game) +bool DrawUpdate(struct Terminal *term, struct Instance *game, char *buf) { - while (true) { - Call(&game->on_draw, game); + bool is_update; + + TermLock(term); + { + 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) { - Call(&game->on_update, game); + // Input + CtrlPoll(&game->ctrl, &game->rec_buf); + + // Game logic + Invoke(&game->on_update, game); + + // Draw + UpdateTerm(&game->term); } } diff --git a/source/term/term.c b/source/term/term.c index 821d545..0150bf1 100644 --- a/source/term/term.c +++ b/source/term/term.c @@ -18,41 +18,138 @@ struct TChar4 { struct Terminal { size_t wid; size_t hgt; - size_t area; u16f refresh_rate; - struct TChar4 *blks; + + size_t area; + size_t buf_size; + + struct TChar4 *bufs[2]; + u8f switch_read; + u8f switch_write; pthread_mutex_t mutex; - pthread_cond_t is_initialized; - pthread_cond_t draw_ready; + pthread_cond_t update; + + struct { + u8f is_writing : 1; + u8f resize : 1; + } flags; }; -struct Terminal NewTerm(size_t wid, size_t hgt) -{ - return (struct Terminal) { - .wid = wid, - .hgt = hgt, - .area = wid * hgt, - .refresh_rate = 60, - .blks = nullptr, - - .mutex = PTHREAD_MUTEX_INITIALIZER, - .is_initialized = PTHREAD_COND_INITIALIZER, - .draw_ready = PTHREAD_COND_INITIALIZER - }; -} - -size_t TermBufSize(struct Terminal *term) +size_t 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; return reset_str_len - + (max_color_str_len + 1) * term->area - + (term->hgt - 1) + + (max_color_str_len + 1) * area + + (hgt - 1) + 1; } +struct Terminal NewTerm(size_t wid, size_t hgt) +{ + size_t area = wid * hgt; + + return (struct Terminal) { + .wid = wid, + .hgt = hgt, + .refresh_rate = 60, + + .area = area, + .buf_size = 0, + + .bufs = nullptr, + .switch_read = 0, + .switch_write = 0, + + .mutex = PTHREAD_MUTEX_INITIALIZER, + .update = PTHREAD_COND_INITIALIZER, + + .flags.is_writing = true, + .flags.resize = false + }; +} + +void TermSetBufs(struct Terminal *term, struct TChar4 *buf0, struct TChar4 *buf1) +{ + term->buf_size = buf_size(term->area, term->hgt); + term->bufs[0] = buf0; + term->bufs[1] = buf1; +} + +void TermResize(struct Terminal *term, size_t wid, size_t hgt) +{ + size_t area = wid * hgt; + size_t buf_size = term_buf_size(area, hgt); + + pthread_mutex_lock(&term->mutex); + { + term->wid = wid; + term->hgt = hgt; + + term->area = area; + term->buf_size = buf_size; + + term->flags.resize = true; + + pthread_cond_signal(&term->update); + } + pthread_mutex_unlock(&term->mutex); +} + +void UpdateTerm(struct Terminal *term) +{ + pthread_mutex_lock(&term->mutex); + { + term->switch_read = term->switch_write; + term->switch_write = (term->switch_write + 1) % 2; + + term->flags.is_writing = false; + + pthread_cond_signal(&term->update); + } + pthread_mutex_unlock(&term->mutex); +} + +bool TermWaitUpdate(struct Terminal *term) +{ + while (term->flags.is_writing) { + pthread_cond_wait(&term->update, &term->mutex); + + if (term->flags.resize) { + term->flags.resize = false; + return false; + } + } + return true; +} + +void TermSignalSafe(struct Terminal *term) +{ + pthread_cond_signal(&term->update); +} + +void WaitSafeTerm(struct Terminal *term) +{ + pthread_mutex_lock(&term->mutex); + while (term->bufs == nullptr) { + pthread_cond_wait(&term->update, &term->mutex); + } + + pthread_mutex_unlock(&term->mutex); +} + +void TermLock(struct Terminal *term) +{ + pthread_mutex_lock(&term->mutex); +} + +void TermUnlock(struct Terminal *term) +{ + pthread_mutex_unlock(&term->mutex); +} + size_t printcol4(char *buf, size_t at, size_t max, u8f col, char ch) { if (col < 8) @@ -80,17 +177,17 @@ size_t printblk4(char *buf, size_t at, size_t max, struct TChar4 *blk) return snprintf(buf + at, max - at, "\x1b[%u;%um%c", bg, fg, blk->ch); } -size_t TermOut(struct Terminal *term, char *buf, size_t n) +size_t TermOut(struct Terminal *term, char *buf) { u8f last_bg = 0; u8f last_fg = 0; - size_t filled = snprintf(buf, n, "\x1b[H\x1b[0m"); + size_t filled = snprintf(buf, term->buf_size, "\x1b[H\x1b[0m"); for(size_t y = 0; y < term->hgt; y++) { for(size_t x = 0; x < term->wid; x++) { size_t i = y * term->wid + x; - struct TChar4 *blk = &term->blks[i]; + struct TChar4 *blk = &term->bufs[i]; // DEBUG if (blk->ch == 0) @@ -100,13 +197,13 @@ size_t TermOut(struct Terminal *term, char *buf, size_t n) if (blk->bg != 0 and blk->bg != last_bg) { last_bg = blk->bg; if (blk->fg != 0 and blk->fg != last_fg) { - filled += printblk4(buf, filled, n, blk); + filled += printblk4(buf, filled, term->buf_size, blk); last_fg = blk->fg; } else { - filled += printcol4(buf, filled, n, blk->bg, blk->ch); + filled += printcol4(buf, filled, term->buf_size, blk->bg, blk->ch); } } else if (blk->fg != 0 and blk->fg != last_fg) { - filled += printcol4(buf, filled, n, blk->fg, blk->ch); + filled += printcol4(buf, filled, term->buf_size, blk->fg, blk->ch); last_fg = blk->fg; } else { buf[filled] = blk->ch; diff --git a/source/term/term.h b/source/term/term.h index d3f9b0e..37cf81e 100644 --- a/source/term/term.h +++ b/source/term/term.h @@ -21,15 +21,34 @@ struct Terminal { size_t hgt; size_t area; u16f refresh_rate; - struct TChar4 *blks; + + struct TChar4 *bufs[2]; + size_t buf_size; + u8f switch_read; + u8f switch_write; pthread_mutex_t mutex; - pthread_cond_t is_initialized; - pthread_cond_t draw_ready; + pthread_cond_t update; + + struct { + u8f is_writing : 1; + u8f resize : 1; + } flags; }; struct Terminal NewTerm(size_t wid, size_t hgt); -size_t TermBufSize(struct Terminal *term); +void TermSetBufs(struct Terminal *term, struct TChar4 *buf0, struct TChar4 *buf1); -size_t TermOut(struct Terminal *term, char *buf, size_t max_chars); \ No newline at end of file +void TermResize(struct Terminal *term, size_t wid, size_t hgt); + +void UpdateTerm(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); \ No newline at end of file