From: Brendan Hansen Date: Sat, 6 Nov 2021 21:43:02 +0000 (-0500) Subject: font coloring and font wrapping at width X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=9384761a0a0589911c87218d89a77a8c9d17cbc9;p=heartbreak.git font coloring and font wrapping at width --- diff --git a/Makefile b/Makefile index f8a10be..25d8e61 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ build/%.o: src/%.c $(CC) $(FLAGS) $(INCLUDES) -o $@ $(LIBS) -c $< tests/%.wasm: tests/%.onyx misc/onyx/* - onyx compile $< -o $@ + onyx compile -V $< -o $@ clean: rm -f $(OBJECT_FILES) 2>/dev/null @@ -21,3 +21,5 @@ $(TARGET): $(OBJECT_FILES) $(CC) $(FLAGS) -o $@ $^ $(LIBS) all: $(TARGET) tests/simp.wasm +run: all + ./bin/heartbreak tests/simp.wasm diff --git a/include/gfx.h b/include/gfx.h index ac3f38e..5fe5c19 100644 --- a/include/gfx.h +++ b/include/gfx.h @@ -39,6 +39,7 @@ typedef struct Font { u64 magic_number; char *name; + f32 size; GLint texture; @@ -78,7 +79,7 @@ typedef struct ImmediateRenderer { Font* active_font; bh_arr(mat3) world_transforms; - i32 last_world_transforms_count; + b32 world_transform_dirty; GLuint matrix_block_buffer; } ImmediateRenderer; @@ -91,7 +92,7 @@ void gfx_immediate_renderer_push_triangle(ImmediateRenderer *ir, f32 x1, f32 y1, f32 u1, f32 v1, f32 x2, f32 y2, f32 u2, f32 v2, f32 x3, f32 y3, f32 u3, f32 v3); -void gfx_immediate_renderer_render_text(ImmediateRenderer *ir, f32 x, f32 y, char* msgptr, i32 msglen); +void gfx_immediate_renderer_render_text(ImmediateRenderer *ir, f32 x, f32 y, char* msgptr, i32 msglen, f32 max_width); void gfx_immediate_renderer_update_window_size(ImmediateRenderer *ir, f32 width, f32 height); diff --git a/misc/onyx/heartbreak_graphics.onyx b/misc/onyx/heartbreak_graphics.onyx index 20bca46..85bf8e0 100644 --- a/misc/onyx/heartbreak_graphics.onyx +++ b/misc/onyx/heartbreak_graphics.onyx @@ -19,18 +19,18 @@ rectangle :: (mode: FillMode, x, y, w, h: f32) -> void #foreign "heartbreak" "gr circle :: (mode: FillMode, x, y, r: f32, segments: i32 = 24) -> void #foreign "heartbreak" "graphics_circle" --- ellipse :: (mode: FillMode, x, y, r1, r2: f32, segments: i32 = 24) -> void #foreign "heartbreak" "graphics_ellipse" --- arc :: (mode: FillMode, x, y, r, a1, a2: f32, segments: i32 = 24) -> void #foreign "heartbreak" "graphics_arc" --- -print :: (text: str, x, y: f32) -> void #foreign "heartbreak" "graphics_print" --- +print :: (text: str, x, y: f32, max_width: f32 = -1) -> void #foreign "heartbreak" "graphics_print" --- // // Transforms // -origin :: () -> void #foreign "heartbreak" "graphics_origin" --- -translate :: (x, y: f32) -> void #foreign "heartbreak" "graphics_translate" --- -scale :: (x, y: f32) -> void #foreign "heartbreak" "graphics_scale" --- -shear :: (x, y: f32) -> void #foreign "heartbreak" "graphics_shear" --- +origin :: () -> void #foreign "heartbreak" "graphics_origin" --- +translate :: (x, y: f32) -> void #foreign "heartbreak" "graphics_translate" --- +scale :: (x, y: f32) -> void #foreign "heartbreak" "graphics_scale" --- +shear :: (x, y: f32) -> void #foreign "heartbreak" "graphics_shear" --- rotate :: (angle: f32) -> void #foreign "heartbreak" "graphics_rotate" --- -push :: () -> void #foreign "heartbreak" "graphics_push" --- -pop :: () -> void #foreign "heartbreak" "graphics_pop" --- +push :: () -> void #foreign "heartbreak" "graphics_push" --- +pop :: () -> void #foreign "heartbreak" "graphics_pop" --- // // Objects diff --git a/src/gfx.c b/src/gfx.c index a212170..b27b714 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -18,7 +18,7 @@ static const char* SIMPLE_SHADER_VERTEX = "#version 300 es\n" "\n" "void main() {\n" " gl_Position = u_view * vec4((u_world * vec3(a_vertex, 1)).xy, 0, 1);\n" -" v_color = a_color * u_color;\n" +" v_color = a_color;\n" " v_texture = a_texture;\n" "}"; @@ -136,6 +136,8 @@ Shader gfx_shader_make_from_source(const char *vertex_src, const char *fragment_ } static void gfx_immediate_renderer_update_world_transform(ImmediateRenderer *ir) { + if (!ir->world_transform_dirty) return; + // TODO: Speed this process up either but changing mat3 to be a mat4x3 or something... f32* d = bh_arr_last(ir->world_transforms).data; f32 dumb_way_of_converting_a_matrix[] = { @@ -147,6 +149,8 @@ static void gfx_immediate_renderer_update_world_transform(ImmediateRenderer *ir) glBindBuffer(GL_UNIFORM_BUFFER, ir->matrix_block_buffer); glBufferSubData(GL_UNIFORM_BUFFER, 16 * sizeof(f32), 12 * sizeof(f32), dumb_way_of_converting_a_matrix); glBindBuffer(GL_UNIFORM_BUFFER, 0); + + ir->world_transform_dirty = 0; } void gfx_immediate_renderer_init(ImmediateRenderer *ir, bh_allocator allocator) { @@ -253,7 +257,7 @@ void gfx_immediate_renderer_init(ImmediateRenderer *ir, bh_allocator allocator) gfx_image_unbind(ir); ir->current_color = (ImmediateColor) { 1, 1, 1, 1 }; - ir->last_world_transforms_count = 0; + ir->world_transform_dirty = 1; ir->active_font = gfx_font_load(ir, "/usr/share/fonts/nerd-fonts-complete/TTF/mononoki-Regular Nerd Font Complete Mono.ttf", 32.0f); } @@ -265,21 +269,22 @@ void gfx_immediate_renderer_flush(ImmediateRenderer *ir) { glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(ImmediateVertex) * ir->tris_vertex_count, ir->tris_vertex_data); glBindBuffer(GL_ARRAY_BUFFER, -1); - glUseProgram(ir->tris_shader.program); - if (bh_arr_length(ir->world_transforms) != ir->last_world_transforms_count) { - gfx_immediate_renderer_update_world_transform(ir); - } + gfx_immediate_renderer_update_world_transform(ir); + glUseProgram(ir->tris_shader.program); glBindVertexArray(ir->tris_vertex_array); glDrawArrays(GL_TRIANGLES, 0, ir->tris_vertex_count); glBindVertexArray(-1); ir->tris_vertex_count = 0; - ir->last_world_transforms_count = bh_arr_length(ir->world_transforms); } void gfx_immediate_renderer_set_color(ImmediateRenderer *ir, ImmediateColor color) { ir->current_color = color; + + glBindBuffer(GL_UNIFORM_BUFFER, ir->matrix_block_buffer); + glBufferSubData(GL_UNIFORM_BUFFER, sizeof(f32) * (16 + 12), 4 * sizeof(f32), &color); + glBindBuffer(GL_UNIFORM_BUFFER, 0); } void gfx_immediate_renderer_push_vertex(ImmediateRenderer *ir, f32 x, f32 y, f32 u, f32 v) { @@ -307,18 +312,30 @@ void gfx_immediate_renderer_push_triangle(ImmediateRenderer *ir, ir->tris_vertex_count += 3; } -void gfx_immediate_renderer_render_text(ImmediateRenderer *ir, f32 x, f32 y, char* msgptr, i32 msglen) { +void gfx_immediate_renderer_render_text(ImmediateRenderer *ir, f32 x, f32 y, char* msgptr, i32 msglen, f32 max_width) { if (ir->tris_vertex_count > 0) gfx_immediate_renderer_flush(ir); stbtt_aligned_quad* quads = (stbtt_aligned_quad *) alloca(msglen * sizeof(stbtt_aligned_quad)); i32 quad_num = 0; + f32 origx = x; + while (msglen--) { stbtt_GetPackedQuad(ir->active_font->char_data, FONT_INTERNAL_IMAGE_SIZE, FONT_INTERNAL_IMAGE_SIZE, *msgptr - ir->active_font->first_character, &x, &y, &quads[quad_num], 0); + if (max_width > 0 && x - origx >= max_width) { + x = origx; + y += ir->active_font->size; + + stbtt_GetPackedQuad(ir->active_font->char_data, + FONT_INTERNAL_IMAGE_SIZE, FONT_INTERNAL_IMAGE_SIZE, + *msgptr - ir->active_font->first_character, + &x, &y, &quads[quad_num], 0); + } + msgptr++, quad_num++; } @@ -330,6 +347,8 @@ void gfx_immediate_renderer_render_text(ImmediateRenderer *ir, f32 x, f32 y, cha glBindTexture(GL_TEXTURE_2D, ir->active_font->texture); glUseProgram(ir->font_shader.program); glUniform1i(ir->font_shader.texture_uniform, 1); + + gfx_immediate_renderer_update_world_transform(ir); glBindVertexArray(ir->font_vertex_array); glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (void *) 0, quad_num); glBindVertexArray(-1); @@ -360,17 +379,23 @@ void gfx_immediate_renderer_push_state(ImmediateRenderer *ir) { gfx_immediate_renderer_flush(ir); mat3 new_top = bh_arr_last(ir->world_transforms); bh_arr_push(ir->world_transforms, new_top); + + ir->world_transform_dirty = 1; } void gfx_immediate_renderer_pop_state(ImmediateRenderer *ir) { gfx_immediate_renderer_flush(ir); bh_arr_pop(ir->world_transforms); + + ir->world_transform_dirty = 1; } void gfx_immediate_renderer_origin(ImmediateRenderer *ir) { gfx_immediate_renderer_flush(ir); mat3* top = &bh_arr_last(ir->world_transforms); mat3_identity(top); + + ir->world_transform_dirty = 1; } void gfx_immediate_renderer_translate(ImmediateRenderer *ir, f32 dx, f32 dy) { @@ -387,6 +412,7 @@ void gfx_immediate_renderer_translate(ImmediateRenderer *ir, f32 dx, f32 dy) { mat3_mul(&new_top, bh_arr_last(ir->world_transforms), trans); bh_arr_last(ir->world_transforms) = new_top; + ir->world_transform_dirty = 1; } void gfx_immediate_renderer_scale(ImmediateRenderer *ir, f32 sx, f32 sy) { @@ -403,6 +429,7 @@ void gfx_immediate_renderer_scale(ImmediateRenderer *ir, f32 sx, f32 sy) { mat3_mul(&new_top, bh_arr_last(ir->world_transforms), scale); bh_arr_last(ir->world_transforms) = new_top; + ir->world_transform_dirty = 1; } void gfx_immediate_renderer_rotate(ImmediateRenderer *ir, f32 angle) { @@ -422,6 +449,7 @@ void gfx_immediate_renderer_rotate(ImmediateRenderer *ir, f32 angle) { mat3_mul(&new_top, bh_arr_last(ir->world_transforms), rotate); bh_arr_last(ir->world_transforms) = new_top; + ir->world_transform_dirty = 1; } void gfx_immediate_renderer_shear(ImmediateRenderer *ir, f32 kx, f32 ky) { @@ -438,6 +466,7 @@ void gfx_immediate_renderer_shear(ImmediateRenderer *ir, f32 kx, f32 ky) { mat3_mul(&new_top, bh_arr_last(ir->world_transforms), shear); bh_arr_last(ir->world_transforms) = new_top; + ir->world_transform_dirty = 1; } @@ -530,6 +559,7 @@ Font* gfx_font_load(ImmediateRenderer *ir, char* font_path, i32 font_size) { font->first_character = FONT_FIRST_CHAR; font->last_character = FONT_FIRST_CHAR + FONT_CHAR_COUNT - 1; font->char_data = font_char_data; + font->size = (f32) font_size; return font; } diff --git a/src/heartbreak_graphics.c b/src/heartbreak_graphics.c index 506e886..00c4656 100644 --- a/src/heartbreak_graphics.c +++ b/src/heartbreak_graphics.c @@ -149,13 +149,14 @@ HEARTBREAK_DEF(arc, (WASM_I32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, return NULL; } -HEARTBREAK_DEF(print, (WASM_I32, WASM_I32, WASM_F32, WASM_F32), ()) { +HEARTBREAK_DEF(print, (WASM_I32, WASM_I32, WASM_F32, WASM_F32, WASM_F32), ()) { char* str_data = wasm_memory_data(wasm_memory) + params->data[0].of.i32; u32 str_size = params->data[1].of.i32; f32 x = params->data[2].of.f32; f32 y = params->data[3].of.f32; - gfx_immediate_renderer_render_text(&renderer, x, y, str_data, str_size); + f32 max_width = params->data[4].of.f32; + gfx_immediate_renderer_render_text(&renderer, x, y, str_data, str_size, max_width); return NULL; } diff --git a/tests/simp.onyx b/tests/simp.onyx index e7387cc..ddec249 100644 --- a/tests/simp.onyx +++ b/tests/simp.onyx @@ -82,5 +82,6 @@ draw :: () { hb.graphics.setColor(0, 0, 1); hb.graphics.arc(.Fill, 300, 300, 100, math.PI / 4, math.PI * 7 / 4); - hb.graphics.print("Hello, World!", 100, 100); + hb.graphics.setColor(0, 1, 1); + hb.graphics.print("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+`~[{}]\|<,>./?'\";:", 100, 100, 200 + math.sin(t) * 100); }