diff --git a/apps/demos/scenery/scenes/title.c b/apps/demos/scenery/scenes/title.c index 6af9e34..a642427 100644 --- a/apps/demos/scenery/scenes/title.c +++ b/apps/demos/scenery/scenes/title.c @@ -20,9 +20,9 @@ static void title_tick(State *state) { ((float)ctx.resolution.x / 2) - ((float)320 / 2), 64, 320, 128 })); /* draw the tick count as an example of dynamic text */ - size_t text_str_len = snprintf(NULL, 0, "%lu", state->ctx->frame_number) + 1; + size_t text_str_len = snprintf(NULL, 0, "%llu", state->ctx->frame_number) + 1; char *text_str = cmalloc(text_str_len); - snprintf(text_str, text_str_len, "%lu", state->ctx->frame_number); + snprintf(text_str, text_str_len, "%llu", state->ctx->frame_number); const char *font = "/fonts/kenney-pixel.ttf"; int text_h = 32; @@ -39,7 +39,6 @@ static void title_tick(State *state) { ); draw_text(text_str, (Vec2){ 0, 0 }, text_h, (Color) { 255, 255, 255, 255 }, font); - free(text_str); } diff --git a/include/twn_draw.h b/include/twn_draw.h index 58f1930..59850b3 100644 --- a/include/twn_draw.h +++ b/include/twn_draw.h @@ -22,6 +22,7 @@ TWN_API void draw_sprite(char const *path, TWN_API void draw_rectangle(Rect rect, Color color); /* pushes a filled circle onto the circle render queue */ +/* note that its edges may look jagged with a radius larger than 2048 */ TWN_API void draw_circle(Vec2 position, float radius, Color color); /* TODO: have font optional, with something minimal coming embedded */ diff --git a/src/rendering/twn_circles.c b/src/rendering/twn_circles.c index ec715a5..16eb8fe 100644 --- a/src/rendering/twn_circles.c +++ b/src/rendering/twn_circles.c @@ -22,18 +22,14 @@ void draw_circle(Vec2 position, float radius, Color color) { arrput(ctx.render_queue_2d, primitive); } -/* TODO: caching and reuse scheme */ -/* vertices_out and indices_out MUST BE FREED */ + void create_circle_geometry(Vec2 position, Color color, float radius, size_t num_vertices, - SDL_Vertex **vertices_out, - int **indices_out) + SDL_Vertex vertices[], + int indices[]) { - SDL_Vertex *vertices = cmalloc(sizeof *vertices * (num_vertices + 1)); - int *indices = cmalloc(sizeof *indices * (num_vertices * 3)); - /* the angle (in radians) to rotate by on each iteration */ float seg_rotation_angle = (360.0f / (float)num_vertices) * ((float)M_PI / 180); @@ -82,7 +78,4 @@ void create_circle_geometry(Vec2 position, index = num_vertices; indices[triangle_offset + 2] = (int)index; } - - *vertices_out = vertices; - *indices_out = indices; } diff --git a/src/rendering/twn_draw_c.h b/src/rendering/twn_draw_c.h index f2a6566..f4adb0c 100644 --- a/src/rendering/twn_draw_c.h +++ b/src/rendering/twn_draw_c.h @@ -126,12 +126,14 @@ void render(void); /* clears all render queues */ void render_queue_clear(void); +/* fills two existing arrays with the geometry data of a circle */ +/* the size of indices must be at least 3 times the number of vertices */ void create_circle_geometry(Vec2 position, Color color, float radius, size_t num_vertices, - SDL_Vertex **vertices_out, - int **indices_out); + SDL_Vertex vertices[], + int indices[]); struct QuadBatch { size_t size; /* how many primitives are in current batch */ diff --git a/src/rendering/twn_gl_15_rendering.c b/src/rendering/twn_gl_15_rendering.c index 9ca147e..a2cf4cb 100644 --- a/src/rendering/twn_gl_15_rendering.c +++ b/src/rendering/twn_gl_15_rendering.c @@ -87,6 +87,9 @@ typedef enum { static Pipeline pipeline_last_used = PIPELINE_NO; +#define CIRCLE_VERTICES_MAX 2048 + + void use_space_pipeline(void) { if (pipeline_last_used == PIPELINE_SPACE) return; @@ -166,16 +169,16 @@ void use_2d_pipeline(void) { void render_circle(const CirclePrimitive *circle) { - SDL_Vertex *vertices = NULL; - int *indices = NULL; - int num_vertices = (int)circle->radius; + static SDL_Vertex vertices[CIRCLE_VERTICES_MAX]; + static int indices[CIRCLE_VERTICES_MAX * 3]; + int num_vertices = MIN((int)circle->radius, CIRCLE_VERTICES_MAX-1); create_circle_geometry(circle->position, circle->color, circle->radius, num_vertices, - &vertices, - &indices); + vertices, + indices); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, @@ -196,9 +199,6 @@ void render_circle(const CirclePrimitive *circle) { glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - - SDL_free(vertices); - SDL_free(indices); } diff --git a/src/rendering/twn_text.c b/src/rendering/twn_text.c index 7a634e3..82cb153 100644 --- a/src/rendering/twn_text.c +++ b/src/rendering/twn_text.c @@ -31,6 +31,19 @@ typedef struct StringArena { static StringArena string_arena; +typedef struct FontFileBuffer { + size_t len; + unsigned char *buffer; +} FontFileBuffer; + +typedef struct FontFileCacheItem { + char *key; + FontFileBuffer value; +} FontFileCacheItem; + +static FontFileCacheItem *font_file_cache_hash; + + static void string_arena_init(StringArena *arena) { arena->head = cmalloc(sizeof *arena->head); arena->current_block = arena->head; @@ -102,13 +115,23 @@ static FontData *text_load_font_data(const char *path, int height_px) { unsigned char* bitmap = ccalloc(ctx.font_texture_size * ctx.font_texture_size, 1); { - unsigned char *buf = NULL; - int64_t buf_len = file_to_bytes(path, &buf); + unsigned char *buf = NULL; + int64_t buf_len = 0; + + /* if the file was already loaded just get it */ + FontFileCacheItem *font_file_ptr = shgetp_null(font_file_cache_hash, path); + if (font_file_ptr != NULL) { + buf = font_file_ptr->value.buffer; + buf_len = font_file_ptr->value.len; + } else { + buf_len = file_to_bytes(path, &buf); + FontFileBuffer buffer = { buf_len, buf }; + shput(font_file_cache_hash, path, buffer); + } + stbtt_InitFont(&font_data->info, buf, stbtt_GetFontOffsetForIndex(buf, 0)); /* might as well get these now, for later */ - font_data->file_bytes = buf; - font_data->file_bytes_len = buf_len; font_data->scale_factor = stbtt_ScaleForPixelHeight(&font_data->info, (float)height_px); stbtt_GetFontVMetrics( &font_data->info, @@ -142,7 +165,6 @@ static FontData *text_load_font_data(const char *path, int height_px) { static void text_destroy_font_data(FontData *font_data) { - SDL_free(font_data->file_bytes); delete_gpu_texture(font_data->texture); SDL_free(font_data); } @@ -192,7 +214,7 @@ static void text_draw_with(FontData* font_data, char* text, Vec2 position, Color static void ensure_font_cache(const char *font_path, int height_px) { - /* HACK: stupid, bad, don't do this */ + /* HACK: don't */ bool is_cached = false; for (size_t i = 0; i < arrlenu(ctx.text_cache.data); ++i) { FontData *font_data = ctx.text_cache.data[i]; @@ -229,6 +251,8 @@ void render_text(const TextPrimitive *text) { void text_cache_init(TextCache *cache) { arrsetlen(cache->data, 0); string_arena_init(&string_arena); + + sh_new_arena(font_file_cache_hash); } @@ -237,8 +261,13 @@ void text_cache_deinit(TextCache *cache) { text_destroy_font_data(ctx.text_cache.data[i]); } - arrfree(cache->data); + for (size_t i = 0; i < shlenu(font_file_cache_hash); ++i) { + SDL_free(font_file_cache_hash[i].value.buffer); + } + shfree(font_file_cache_hash); + string_arena_deinit(&string_arena); + arrfree(cache->data); } diff --git a/src/rendering/twn_text_c.h b/src/rendering/twn_text_c.h index f73648e..6b3b9c9 100644 --- a/src/rendering/twn_text_c.h +++ b/src/rendering/twn_text_c.h @@ -22,8 +22,6 @@ typedef struct FontData { stbtt_fontinfo info; const char *file_path; - unsigned char *file_bytes; - size_t file_bytes_len; GPUTexture texture;