aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriamcheeseman <[email protected]>2026-05-11 08:42:59 -0400
committeriamcheeseman <[email protected]>2026-05-11 08:42:59 -0400
commitcd15c9789c9eeb9ec2fa367c39872685597e0c17 (patch)
treedf52093b99ba7bb7d1ce7903caed487df382b803
parent18a5d0af4664a1e50d1e69a5ecbcd91a34246ed4 (diff)
text rendering
-rw-r--r--dc/dc.c85
-rw-r--r--teensy/teensy.h16
-rw-r--r--teensy/teensy_renderer.c54
3 files changed, 147 insertions, 8 deletions
diff --git a/dc/dc.c b/dc/dc.c
index 0d69710..bccc82f 100644
--- a/dc/dc.c
+++ b/dc/dc.c
@@ -13,6 +13,7 @@
#define TILE_SIZE 16
struct ty_image img;
+struct ty_font font;
void tick(void)
{
@@ -59,10 +60,57 @@ void tick(void)
ty_color(0xFF, 0xF0, 0x80)
);
- ty_draw_end();
+ ty_draw_text(&font, ty_vec2i(5, SCREEN_HEIGHT - 5 - 8), "hello, world!");
double frame_time = ty_get_time() - start;
- ty_log_debug("%g ms, %g FPS", frame_time * 1000, 1.0 / frame_time);
+
+ char ms_fmt[] = "%.2g ms";
+ int ms_width = ty_font_width(&font, ms_fmt, frame_time * 1000);
+
+ ty_draw_rect(
+ (struct ty_recti){
+ 5, 5,
+ ms_width, 8,
+ },
+ TY_COLOR_BLACK
+ );
+ ty_draw_text_fmt(
+ &font,
+ ty_vec2i(5, 5),
+ ms_fmt,
+ frame_time * 1000
+ );
+
+ char fps_fmt[] = "%4d fps";
+ int fps_width = ty_font_width(&font, fps_fmt, (int)(1.0 / frame_time));
+
+ ty_draw_rect(
+ (struct ty_recti){
+ 5, 5 + 8,
+ fps_width, 8,
+ },
+ TY_COLOR_BLACK
+ );
+ ty_draw_text_fmt(
+ &font,
+ ty_vec2i(5, 5 + 8),
+ fps_fmt,
+ (int)(1.0 / frame_time)
+ );
+
+ ty_draw_end();
+}
+
+struct ty_image load_qoi_image(const char *path)
+{
+ qoi_desc desc;
+ void *data = qoi_read(path, &desc, 3);
+ if (!data)
+ ty_log_fatal(TY_ERR_IO, "failed to read image");
+ struct ty_image img = ty_create_image(desc.width, desc.height, data);
+ free(data);
+
+ return img;
}
int main(void)
@@ -75,21 +123,42 @@ int main(void)
};
ty_init(hints);
- qoi_desc desc;
- void *data = qoi_read("test_img.qoi", &desc, 3);
- if (!data)
- ty_log_fatal(TY_ERR_IO, "failed to read image");
- img = ty_create_image(desc.width, desc.height, data);
- free(data);
+ img = load_qoi_image("test_img.qoi");
+
+ char font_chars[] =
+ "abcdefghijklmnopqrstuvwxyz0123456789"
+ "!\"'#$%&()*+,-./@[]\\^_`{}|~:;<>=? "
+ ;
+ struct ty_image font_img = load_qoi_image("font.qoi");
+
+ int glyph_height = 8;
+
+ for (int i = 0; font_chars[i] != '\0'; i++) {
+ struct ty_image glyph = ty_create_image(
+ font_img.width,
+ glyph_height,
+ font_img.data + font_img.width * glyph_height * i
+ );
+
+
+ ty_font_add_glyph(
+ &font,
+ *(uint8_t*)&font_chars[i],
+ glyph
+ );
+ }
while (ty_is_game_running()) {
int ticks = ty_tick();
for (int i = 0; i < ticks; i++)
tick();
+
+ ty_free_temp_allocs();
// ty_sleep(1000 / hints.ticrate);
}
ty_free_image(img);
+ ty_free_image(font_img);
ty_deinit();
return 0;
diff --git a/teensy/teensy.h b/teensy/teensy.h
index 1f082f9..0b7829c 100644
--- a/teensy/teensy.h
+++ b/teensy/teensy.h
@@ -1,6 +1,8 @@
#ifndef TEENSY_H_
#define TEENSY_H_
+#include <limits.h>
+
#include "teensy_common.h"
#include "teensy_context.h"
#include "teensy_list.h"
@@ -68,6 +70,10 @@ struct ty_image {
int height;
};
+struct ty_font {
+ struct ty_image glyphs[CHAR_MAX];
+};
+
struct ty_renderer {
struct ty_image screen;
};
@@ -92,6 +98,9 @@ void ty_img_set_pixel(
struct ty_color color
);
+void ty_font_add_glyph(struct ty_font *font, uint8_t c, struct ty_image img);
+int ty_font_width(struct ty_font *font, const char *fmt, ...);
+
void ty_draw_clear(struct ty_color col);
void ty_draw_image(struct ty_image img, struct ty_vec2i pos);
void ty_draw_image_ex(
@@ -105,6 +114,13 @@ void ty_draw_line(
struct ty_vec2i end,
struct ty_color color
);
+void ty_draw_text(struct ty_font *font, struct ty_vec2i pos, const char *text);
+void ty_draw_text_fmt(
+ struct ty_font *font,
+ struct ty_vec2i pos,
+ const char *fmt,
+ ...
+);
void ty_draw_end(void);
void ty_sleep(uint64_t ms);
diff --git a/teensy/teensy_renderer.c b/teensy/teensy_renderer.c
index b29e485..b51d2a9 100644
--- a/teensy/teensy_renderer.c
+++ b/teensy/teensy_renderer.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
+#include <stdarg.h>
#include "teensy_context.h"
#include "teensy_list.h"
@@ -91,6 +92,31 @@ void ty_img_set_pixel(
img.data[pos.y * img.width + pos.x] = color;
}
+// This function technically is not needed, but I may want unicode support in
+// the future, when an abstraction like this is needed.
+void ty_font_add_glyph(struct ty_font *font, uint8_t c, struct ty_image img)
+{
+ font->glyphs[c] = img;
+}
+
+int ty_font_width(struct ty_font *font, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ int len = vsnprintf(NULL, 0, fmt, args);
+ char *text = ty_talloc(sizeof(char) * (len + 1));
+ va_end(args);
+
+ va_start(args, fmt);
+ vsnprintf(text, len + 1, fmt, args);
+ va_end(args);
+
+ int width = 0;
+ for (uint8_t *c = (uint8_t*)text; *c != '\0'; c++)
+ width += font->glyphs[*c].width;
+ return width;
+}
+
void ty_draw_clear(struct ty_color col)
{
assert(is_renderer_init());
@@ -211,6 +237,34 @@ void ty_draw_line(
}
}
+void ty_draw_text(struct ty_font *font, struct ty_vec2i pos, const char *text)
+{
+ for (const uint8_t *c = (const uint8_t*)text; *c != '\0'; c++) {
+ struct ty_image glyph = font->glyphs[*c];
+ ty_draw_image(glyph, pos);
+ pos.x += glyph.width;
+ }
+}
+
+void ty_draw_text_fmt(
+ struct ty_font *font,
+ struct ty_vec2i pos,
+ const char *fmt,
+ ...
+) {
+ va_list args;
+ va_start(args, fmt);
+ int len = vsnprintf(NULL, 0, fmt, args);
+ char *text = ty_talloc(sizeof(char) * (len + 1));
+ va_end(args);
+
+ va_start(args, fmt);
+ vsnprintf(text, len + 1, fmt, args);
+ va_end(args);
+
+ ty_draw_text(font, pos, text);
+}
+
void ty_draw_end(void)
{
assert(is_renderer_init());