aboutsummaryrefslogtreecommitdiff
path: root/teensy
diff options
context:
space:
mode:
Diffstat (limited to 'teensy')
-rw-r--r--teensy/teensy.h22
-rw-r--r--teensy/teensy_context.c5
-rw-r--r--teensy/teensy_list.h32
-rw-r--r--teensy/teensy_math.c19
-rw-r--r--teensy/teensy_mem.c2
-rw-r--r--teensy/teensy_renderer.c4
-rw-r--r--teensy/teensy_ui.c277
-rw-r--r--teensy/teensy_ui.h42
8 files changed, 377 insertions, 26 deletions
diff --git a/teensy/teensy.h b/teensy/teensy.h
index c272664..0e36a6e 100644
--- a/teensy/teensy.h
+++ b/teensy/teensy.h
@@ -6,10 +6,12 @@
#include "teensy_common.h"
#include "teensy_list.h"
-#define ty_vec2(x, y) ((ty_Vec2){x, y})
-#define ty_vec2i(x, y) ((ty_Vec2i){x, y})
-#define ty_color(R, G, B) ((ty_Color){R, G, B})
-#define ty_img_full(img) ((ty_Recti){0, 0, (img).width, (img).height})
+#define ty_vec2(x, y) ((ty_Vec2){x, y})
+#define ty_vec2i(x, y) ((ty_Vec2i){x, y})
+#define ty_color(R, G, B) ((ty_Color){R, G, B})
+#define ty_rect(x, y, w, h) ((ty_Rect){x, y, w, h})
+#define ty_recti(x, y, w, h) ((ty_Recti){x, y, w, h})
+#define ty_img_full(img) ((ty_Recti){0, 0, (img).width, (img).height})
#define ty_rect_start(rect) (ty_vec2(rect.x, rect.y))
#define ty_recti_start(rect) (ty_vec2i(rect.x, rect.y))
@@ -48,6 +50,9 @@ enum {
// for use in the editor
TY_BTN_DB_CTRL,
TY_BTN_DB_SHIFT,
+ TY_BTN_DB_LMB,
+ TY_BTN_DB_RMB,
+ TY_BTN_DB_MMB,
TY_BTN_COUNT,
};
@@ -107,6 +112,8 @@ void ty_deinit(void);
bool ty_button_down(ty_Button btn);
// If the button was pressed just now
bool ty_button_pressed(ty_Button btn);
+// Gets the mouse position; should only be used as debug or dev tools
+ty_Vec2i ty_mouse_pos(void);
// Whether or not the main loop should continue executing.
bool ty_is_game_running(void);
@@ -116,6 +123,9 @@ double ty_get_time(void);
// tic.
int ty_tick(void);
+bool ty_pointi_in_recti(ty_Vec2i point, ty_Recti rect);
+bool ty_point_in_rect(ty_Vec2 point, ty_Rect rect);
+
ty_Image ty_create_image(int w, int h, const ty_Color* data);
void ty_free_image(ty_Image img);
ty_Color ty_img_get_pixel(ty_Image img, ty_Vec2i pos);
@@ -149,9 +159,9 @@ void ty_draw_line(
ty_Vec2i end,
ty_Color color
);
-void ty_draw_text(ty_Font *font, ty_Vec2i pos, const char *text);
+void ty_draw_text(const ty_Font *font, ty_Vec2i pos, const char *text);
void ty_draw_text_fmt(
- ty_Font *font,
+ const ty_Font *font,
ty_Vec2i pos,
const char *fmt,
...
diff --git a/teensy/teensy_context.c b/teensy/teensy_context.c
index 547a5dd..91b9b90 100644
--- a/teensy/teensy_context.c
+++ b/teensy/teensy_context.c
@@ -46,6 +46,11 @@ bool ty_button_pressed(ty_Button btn)
return ctx.pressed[btn];
}
+ty_Vec2i ty_mouse_pos(void)
+{
+ return ty_platform_get_mouse();
+}
+
bool ty_is_game_running(void)
{
assert(is_init());
diff --git a/teensy/teensy_list.h b/teensy/teensy_list.h
index 6265e6a..12da8e0 100644
--- a/teensy/teensy_list.h
+++ b/teensy/teensy_list.h
@@ -16,26 +16,24 @@ typedef struct {
#define ty_list_cap(arr) (ty_list_get_header(arr)->cap)
#define ty_list_len(arr) (ty_list_get_header(arr)->len)
-#define ty_list_reserve(arr, amt) \
- do { \
- ty_List_Header *header = ty_list_get_header(arr); \
- if (amt > header->cap) { \
- header->cap = header->cap < TY_LIST_MIN_CAP \
- ? TY_LIST_MIN_CAP \
- : header->cap * TY_LIST_GROW_RATE; \
- header = ty_realloc( \
- header, \
- (sizeof(*(arr)) * amt) + sizeof(ty_List_Header) \
- ); \
- (arr) = (void*)(header + 1); \
- } \
+#define ty_list_reserve(arr, amt) \
+ do { \
+ ty_List_Header *header = ty_list_get_header(arr); \
+ if ((amt) > header->cap) { \
+ header->cap = (amt) < TY_LIST_MIN_CAP ? TY_LIST_MIN_CAP : (amt); \
+ header = ty_realloc( \
+ header, \
+ (sizeof(*(arr)) * (amt)) + sizeof(ty_List_Header) \
+ ); \
+ (arr) = (void*)(header + 1); \
+ } \
} while (0)
-#define ty_list_append(arr, elem) \
- do { \
+#define ty_list_append(arr, elem) \
+ do { \
ty_List_Header *header = ty_list_get_header(arr); \
- ty_list_reserve(arr, header->len + 1); \
- (arr)[header->len++] = (elem); \
+ ty_list_reserve(arr, header->len + 1); \
+ (arr)[header->len++] = (elem); \
} while (0)
#define ty_list_clear(arr) \
diff --git a/teensy/teensy_math.c b/teensy/teensy_math.c
new file mode 100644
index 0000000..79d89c1
--- /dev/null
+++ b/teensy/teensy_math.c
@@ -0,0 +1,19 @@
+#include "teensy.h"
+
+bool ty_pointi_in_recti(ty_Vec2i point, ty_Recti rect)
+{
+ return
+ point.x > rect.x &&
+ point.x < rect.x + rect.w &&
+ point.y > rect.y &&
+ point.y < rect.y + rect.h;
+}
+
+bool ty_point_in_rect(ty_Vec2 point, ty_Rect rect)
+{
+ return
+ point.x > rect.x &&
+ point.x < rect.x + rect.w &&
+ point.y > rect.y &&
+ point.y < rect.y + rect.h;
+}
diff --git a/teensy/teensy_mem.c b/teensy/teensy_mem.c
index 7e8dd58..40882a7 100644
--- a/teensy/teensy_mem.c
+++ b/teensy/teensy_mem.c
@@ -101,7 +101,7 @@ void *ty_alloc(size_t size)
allocations_cap *= 2;
allocations = realloc(
allocations,
- sizeof(struct alloc) * allocations_cap
+ sizeof(Alloc) * allocations_cap
);
if (!allocations)
ty_log_fatal(
diff --git a/teensy/teensy_renderer.c b/teensy/teensy_renderer.c
index 173fbed..1e24248 100644
--- a/teensy/teensy_renderer.c
+++ b/teensy/teensy_renderer.c
@@ -293,7 +293,7 @@ void ty_draw_line(
}
}
-void ty_draw_text(ty_Font *font, ty_Vec2i pos, const char *text)
+void ty_draw_text(const ty_Font *font, ty_Vec2i pos, const char *text)
{
for (const uint8_t *c = (const uint8_t*)text; *c != '\0'; c++) {
ty_Image glyph = font->glyphs[*c];
@@ -303,7 +303,7 @@ void ty_draw_text(ty_Font *font, ty_Vec2i pos, const char *text)
}
void ty_draw_text_fmt(
- ty_Font *font,
+ const ty_Font *font,
ty_Vec2i pos,
const char *fmt,
...
diff --git a/teensy/teensy_ui.c b/teensy/teensy_ui.c
new file mode 100644
index 0000000..af3e78f
--- /dev/null
+++ b/teensy/teensy_ui.c
@@ -0,0 +1,277 @@
+#include "teensy_ui.h"
+
+#include <assert.h>
+
+#include "teensy_list.h"
+
+#define TITLE_BAR_HEIGHT (8)
+#define TEXT_HEIGHT (8)
+
+enum {
+ CMD_RECT,
+ CMD_TEXT,
+ CMD_TARGET,
+ CMD_IMAGE,
+};
+typedef uint8_t Cmd_Kind;
+
+typedef struct {
+ const char *text;
+ ty_Recti rect;
+ ty_Color color;
+ const ty_Image *img;
+ Cmd_Kind kind;
+} Cmd;
+
+typedef struct {
+ const char *title;
+ ty_Recti rect;
+ ty_Image content;
+ uint32_t flags;
+
+ ty_Vec2i next_pos;
+} Window;
+
+typedef struct {
+ Window *active;
+ Window root;
+ Window windows[255];
+ int window_count;
+ tyui_Style style;
+ const ty_Font *font;
+ Cmd *cmds;
+
+ ty_Vec2i prev_mouse_pos;
+} Ctx;
+
+static
+tyui_Style default_style = {
+ .fg_normal = ty_color(200, 200, 200),
+ .bg_normal = ty_color(64, 64, 64),
+ .fg_hover = ty_color(255, 255, 255),
+ .bg_hover = ty_color(100, 100, 100),
+ .win_bg = ty_color(48, 48, 48),
+ .win_title = ty_color(64, 128, 128),
+};
+
+static
+Ctx uictx;
+
+static
+void rect_cmd(ty_Recti rect, ty_Color color)
+{
+ Cmd cmd = {};
+ cmd.kind = CMD_RECT;
+ cmd.rect = rect;
+ cmd.color = color;
+
+ ty_list_append(uictx.cmds, cmd);
+}
+
+static
+void text_cmd(const char *text, ty_Vec2i pos)
+{
+ Cmd cmd = {};
+ cmd.kind = CMD_TEXT;
+ cmd.text = text;
+ cmd.rect.x = pos.x;
+ cmd.rect.y = pos.y;
+
+ ty_list_append(uictx.cmds, cmd);
+}
+
+static
+void image_cmd(const ty_Image *img, ty_Vec2i pos)
+{
+ Cmd cmd = {};
+ cmd.kind = CMD_IMAGE;
+ cmd.img = img;
+ cmd.rect.x = pos.x;
+ cmd.rect.y = pos.y;
+ ty_list_append(uictx.cmds, cmd);
+}
+
+static
+void target_cmd(const ty_Image *target)
+{
+ Cmd cmd = {};
+ cmd.kind = CMD_TARGET;
+ cmd.img = target;
+ ty_list_append(uictx.cmds, cmd);
+}
+
+static
+ty_Vec2i next_pos(int height)
+{
+ ty_Vec2i next = uictx.active->next_pos;
+ uictx.active->next_pos.y += height;
+ return next;
+}
+
+static
+ty_Vec2i mouse_delta(void)
+{
+ ty_Vec2i cur = ty_mouse_pos();
+ return ty_vec2i(
+ cur.x - uictx.prev_mouse_pos.x,
+ cur.y - uictx.prev_mouse_pos.y
+ );
+}
+
+static
+Window create_window(const char *title, ty_Recti rect, uint32_t flags)
+{
+ Window win = {};
+ win.title = title;
+ win.rect = rect;
+ win.flags = flags;
+ win.content = ty_create_image(rect.w, rect.h, NULL);
+ return win;
+}
+
+void tyui_init(const ty_Font *font)
+{
+ assert(font);
+
+ uictx.cmds = ty_list_create();
+ ty_list_reserve(uictx.cmds, 256);
+
+ uint32_t root_flags = 0;
+ root_flags |= TYUI_WIN_NORESIZE;
+ root_flags |= TYUI_WIN_NOCLOSE;
+ root_flags |= TYUI_WIN_NOMOVE;
+ root_flags |= TYUI_WIN_INVISIBLE;
+
+ uictx.root = create_window(
+ "__ROOT__",
+ ty_recti(0, 0, 256, 256),
+ root_flags
+ );
+
+ uictx.style = default_style;
+ uictx.font = font;
+
+ uictx.active = &uictx.root;
+}
+
+void tyui_deinit(void)
+{
+ ty_list_free(uictx.cmds);
+
+ ty_free_image(uictx.root.content);
+ for (int i = 0; i < uictx.window_count; i++) {
+ ty_free_image(uictx.windows[i].content);
+ }
+}
+
+void tyui_draw(void)
+{
+ for (size_t i = 0; i < ty_list_len(uictx.cmds); i++) {
+ Cmd cmd = uictx.cmds[i];
+ switch (cmd.kind) {
+ case CMD_RECT:
+ ty_draw_rect(cmd.rect, cmd.color);
+ break;
+ case CMD_TEXT:
+ ty_draw_text(uictx.font, ty_recti_start(cmd.rect), cmd.text);
+ break;
+ case CMD_IMAGE:
+ ty_draw_image(*cmd.img, ty_recti_start(cmd.rect));
+ break;
+ case CMD_TARGET:
+ ty_draw_set_target(cmd.img);
+ if (cmd.img != NULL) ty_draw_clear(TY_COLOR_MAGENTA);
+ break;
+ }
+ }
+ ty_list_clear(uictx.cmds);
+
+ uictx.prev_mouse_pos = ty_mouse_pos();
+}
+
+bool tyui_begin_window_ex(
+ const char *title,
+ ty_Recti rect,
+ tyui_Id *id,
+ uint32_t flags,
+ bool *closed_ptr
+) {
+ assert(id);
+
+ bool closed = false;
+
+ if (closed_ptr)
+ closed = *closed_ptr;
+
+ if (uictx.active != &uictx.root) {
+ ty_log_err("cannot create window within another window");
+ return false;
+ }
+
+ if (closed)
+ return !closed;
+
+ if (*id == 0) {
+ *id = ++uictx.window_count;
+ uictx.windows[*id - 1] = create_window(title, rect, flags);
+ }
+
+ Window *win = &uictx.windows[*id - 1];
+ uictx.active = win;
+
+ win->next_pos = ty_vec2i(0, 0);
+
+ if (win->flags & TYUI_WIN_INVISIBLE)
+ goto done;
+
+ ty_Recti title_rect = win->rect;
+ title_rect.h = TEXT_HEIGHT;
+
+ ty_Vec2i mouse_pos = ty_mouse_pos();
+ ty_Vec2i md = mouse_delta();
+ mouse_pos.x -= md.x;
+ mouse_pos.y -= md.y;
+
+ if (ty_button_down(TY_BTN_DB_LMB) &&
+ ty_pointi_in_recti(mouse_pos, title_rect)
+ ) {
+ ty_Vec2i md = mouse_delta();
+ win->rect.x += md.x;
+ win->rect.y += md.y;
+
+ title_rect = win->rect;
+ title_rect.h = TEXT_HEIGHT;
+ }
+
+ rect_cmd(title_rect, uictx.style.win_title);
+ text_cmd(win->title, ty_recti_start(title_rect));
+
+ ty_Recti body_rect = win->rect;
+ body_rect.y += TEXT_HEIGHT;
+ rect_cmd(body_rect, uictx.style.win_bg);
+
+ target_cmd(&win->content);
+
+done:
+ return !closed;
+}
+
+void tyui_end_window(void)
+{
+ if (uictx.active == &uictx.root) {
+ ty_log_err("ending window with no window open");
+ return;
+ }
+
+ target_cmd(NULL);
+ ty_Vec2i content_pos = ty_recti_start(uictx.active->rect);
+ content_pos.y += TITLE_BAR_HEIGHT;
+ image_cmd(&uictx.active->content, content_pos);
+
+ uictx.active = &uictx.root;
+}
+
+void tyui_text(const char *text)
+{
+ text_cmd(text, next_pos(TEXT_HEIGHT));
+}
diff --git a/teensy/teensy_ui.h b/teensy/teensy_ui.h
new file mode 100644
index 0000000..9a1e33a
--- /dev/null
+++ b/teensy/teensy_ui.h
@@ -0,0 +1,42 @@
+#ifndef TEENSY_UI_H_
+#define TEENSY_UI_H_
+
+#include "teensy_common.h"
+#include "teensy.h"
+
+#define TYUI_WIN_NORESIZE (1 << 0)
+#define TYUI_WIN_NOCLOSE (1 << 1)
+#define TYUI_WIN_NOMOVE (1 << 2)
+#define TYUI_WIN_INVISIBLE (1 << 3)
+
+#define tyui_begin_window(title, rect, id) \
+ tyui_begin_window_ex(title, rect, id, 0, NULL)
+
+typedef struct {
+ ty_Color fg_normal;
+ ty_Color bg_normal;
+ ty_Color fg_hover;
+ ty_Color bg_hover;
+ ty_Color win_bg;
+ ty_Color win_title;
+} tyui_Style;
+
+typedef uint8_t tyui_Id;
+
+void tyui_init(const ty_Font *font);
+void tyui_deinit(void);
+
+void tyui_draw(void);
+
+bool tyui_begin_window_ex(
+ const char *title,
+ ty_Recti rect,
+ tyui_Id *id,
+ uint32_t flags,
+ bool *closed
+);
+void tyui_end_window(void);
+
+void tyui_text(const char *text);
+
+#endif // TEENSY_UI_H_