diff --git a/gb.h b/gb.h index d22c437..b5057f6 100644 --- a/gb.h +++ b/gb.h @@ -2135,7 +2135,7 @@ GB_ALLOCATOR_PROC(gb_pool_allocator_proc) } -void +gb_inline void gb_qsort(void *base, isize count, isize size, gbCompareProc compare_proc) { qsort(base, count, size, compare_proc); @@ -2143,16 +2143,15 @@ gb_qsort(void *base, isize count, isize size, gbCompareProc compare_proc) -isize +gb_inline isize gb_binary_search(void const *base, isize count, isize size, void const *key, gbCompareProc compare_proc) { - isize start = 0, end = count; - isize result; + isize start = 0; + isize end = count; while (start < end) { isize mid = start + (end-start)/2; - - result = compare_proc(key, cast(u8 *)base + mid*size); + isize result = compare_proc(key, cast(u8 *)base + mid*size); if (result < 0) end = mid; else if (result > 0) @@ -2161,7 +2160,7 @@ gb_binary_search(void const *base, isize count, isize size, void const *key, gbC return mid; } - return 0; // TODO(bill): Should this be -1? + return -1; } diff --git a/gb_gl.h b/gb_gl.h index 97efc2f..f21e541 100644 --- a/gb_gl.h +++ b/gb_gl.h @@ -333,18 +333,15 @@ GBGL_DEF b32 gbgl_is_shader_in_use(gbglShader *shader); GBGL_DEF i32 gbgl_get_uniform(gbglShader *shader, char const *name); -#ifndef GBGL_UNIFORM_SET -#define GBGL_UNIFORM_SET +GBGL_DEF void gbgl_set_uniform_int (gbglShader *s, char const *name, i32 i); +GBGL_DEF void gbgl_set_uniform_float (gbglShader *s, char const *name, f32 f); +GBGL_DEF void gbgl_set_uniform_vec2 (gbglShader *s, char const *name, gbVec2 v); +GBGL_DEF void gbgl_set_uniform_vec3 (gbglShader *s, char const *name, gbVec3 v); +GBGL_DEF void gbgl_set_uniform_vec4 (gbglShader *s, char const *name, gbVec4 v); +GBGL_DEF void gbgl_set_uniform_mat4 (gbglShader *s, char const *name, gbMat4 const *m); +GBGL_DEF void gbgl_set_uniform_mat4_count(gbglShader *s, char const *name, gbMat4 const *m, isize count); +GBGL_DEF void gbgl_set_uniform_colour (gbglShader *s, char const *name, gbColour col); -#define gbgl_set_uniform_int(shdr, name, i) glUniform1i (gbgl_get_uniform(shdr, name), i) -#define gbgl_set_uniform_float(shdr, name, f) glUniform1f (gbgl_get_uniform(shdr, name), f) -#define gbgl_set_uniform_vec2(shdr, name, v) glUniform2fv (gbgl_get_uniform(shdr, name), 1, &v.x) -#define gbgl_set_uniform_vec3(shdr, name, v) glUniform3fv (gbgl_get_uniform(shdr, name), 1, &v.x) -#define gbgl_set_uniform_vec4(shdr, name, v) glUniform4fv (gbgl_get_uniform(shdr, name), 1, &v.x) -#define gbgl_set_uniform_mat4(shdr, name, mat) glUniformMatrix4fv(gbgl_get_uniform(shdr, name), 1, false, mat) -#define gbgl_set_uniform_mat4_count(shdr, name, mat, count) glUniformMatrix4fv(gbgl_get_uniform(shdr, name), count, false, mat) - -#endif //////////////////////////////////////////////////////////////// // @@ -519,12 +516,12 @@ GBGL_DEF gbglFont *gbgl_get_font (gbglFontCache *fc, char const *ttf_filenam GBGL_DEF gbglFont *gbgl_get_font_only(gbglFontCache *fc, char const *ttf_filename, f32 font_size); GBGL_DEF gbglFont *gbgl_cache_font (gbglFontCache *fc, char const *ttf_filename, f32 font_size); -GBGL_DEF i32 gbgl_font_glyph_map_search_proc(void const *a, void const *b); +GBGL_DEF GB_COMPARE_PROC(gbgl_font_glyph_map_search_proc); GBGL_DEF b32 gbgl_get_packed_font_dim (gbglFontCache *cache, gbglFontCachedTTF *ttf, i32 *width, i32 *height); GBGL_DEF gbglGlyphInfo *gbgl_get_glyph_info (gbglFont *font, char32 codepoint, isize *out_index); GBGL_DEF f32 gbgl_get_font_kern_amt_from_glyph_indices(gbglFont *font, isize left_index, isize right_index); -GBGL_DEF void gbgl_get_string_dimenstions (gbglFont *font, char const *str, f32 *out_width, f32 *out_height); +GBGL_DEF void gbgl_get_string_dimensions (gbglFont *font, char const *str, f32 *out_width, f32 *out_height); GBGL_DEF f32 gbgl_get_sub_string_width (gbglFont *font, char const *str, isize char_count); GBGL_DEF i32 gbgl_get_wrapped_line_count (gbglFont *font, char const *str, isize max_len, isize max_width); GBGL_DEF f32 gbgl_get_string_width (gbglFont *font, char const *str, isize max_len); @@ -561,6 +558,10 @@ GBGL_DEF f32 gbgl_get_string_width (gbglFont *font #define GBGL_PT_TO_PX_SCALE (96.0f / 72.0f) #endif +#ifndef GBGL_TAB_CHARACTER_WIDTH +#define GBGL_TAB_CHARACTER_WIDTH 4 +#endif + typedef struct gbglBasicVertex { f32 x, y; f32 u, v; @@ -613,6 +614,11 @@ GBGL_DEF void gbgl_bs_draw_circle(gbglBasicState *bs, gbVec2 p, f32 radius, gbCo GBGL_DEF void gbgl_bs_draw_circle_outline(gbglBasicState *bs, gbVec2 p, f32 radius, gbColour col, f32 thickness); +GBGL_DEF isize gbgl_bs_draw_substring(gbglBasicState *bs, gbglFont *font, i32 x, i32 y, gbColour col, char const *str, isize len); +GBGL_DEF isize gbgl_bs_draw_string (gbglBasicState *bs, gbglFont *font, i32 x, i32 y, gbColour col, char const *fmt, ...); +GBGL_DEF isize gbgl_bs_draw_string_va(gbglBasicState *bs, gbglFont *font, i32 x, i32 y, gbColour col, char const *fmt, va_list va); + + #if defined(__cplusplus) } @@ -1047,6 +1053,63 @@ gbgl_get_uniform(gbglShader *s, char const *name) } + +gb_inline void +gbgl_set_uniform_int(gbglShader *s, char const *name, i32 i) +{ + glUniform1i(gbgl_get_uniform(s, name), i); +} + +gb_inline void +gbgl_set_uniform_float(gbglShader *s, char const *name, f32 f) +{ + glUniform1f(gbgl_get_uniform(s, name), f); +} + +gb_inline void +gbgl_set_uniform_vec2(gbglShader *s, char const *name, gbVec2 v) +{ + glUniform2fv(gbgl_get_uniform(s, name), 1, v.e); +} + +gb_inline void +gbgl_set_uniform_vec3(gbglShader *s, char const *name, gbVec3 v) +{ + glUniform3fv(gbgl_get_uniform(s, name), 1, v.e); +} + +gb_inline void +gbgl_set_uniform_vec4(gbglShader *s, char const *name, gbVec4 v) +{ + glUniform4fv(gbgl_get_uniform(s, name), 1, v.e); +} + +gb_inline void +gbgl_set_uniform_mat4(gbglShader *s, char const *name, gbMat4 const *m) +{ + gbgl_set_uniform_mat4_count(s, name, m, 1); +} + +gb_inline void +gbgl_set_uniform_mat4_count(gbglShader *s, char const *name, gbMat4 const *m, isize count) +{ + glUniformMatrix4fv(gbgl_get_uniform(s, name), count, false, cast(f32 const *)m); +} + + +gb_inline void +gbgl_set_uniform_colour(gbglShader *s, char const *name, gbColour col) +{ + gbVec4 v; + v.r = col.r / 255.0f; + v.g = col.g / 255.0f; + v.b = col.b / 255.0f; + v.a = col.a / 255.0f; + gbgl_set_uniform_vec4(s, name, v); +} + + + //////////////////////////////////////////////////////////////// // // Render Buffer @@ -1603,8 +1666,7 @@ gbgl_cache_font(gbglFontCache *fc, char const *ttf_filename, f32 font_size) } -gb_inline i32 -gbgl_font_glyph_map_search_proc(void const *a, void const *b) +gb_inline GB_COMPARE_PROC(gbgl_font_glyph_map_search_proc) { gbglGlyphMapKVPair const *gm = cast(gbglGlyphMapKVPair const *)a; char32 ucp = *cast(char32 const *)b; @@ -1647,7 +1709,7 @@ gbgl_get_font_kern_amt_from_glyph_indices(gbglFont *font, isize left_index, isiz } void -gbgl_get_string_dimenstions(gbglFont *font, char const *str, f32 *out_width, f32 *out_height) +gbgl_get_string_dimensions(gbglFont *font, char const *str, f32 *out_width, f32 *out_height) { isize len, char_count, i; @@ -1811,7 +1873,7 @@ gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height) bs->linear_sampler = gbgl_generate_sampler(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); gbgl_load_shader_vf_from_source(&bs->ortho_tex_shader, - "#version 330 core\n" + "#version 410 core\n" "layout (location = 0) in vec4 a_position;\n" "layout (location = 1) in vec2 a_tex_coord;\n" "uniform mat4 u_ortho_mat;\n" @@ -1821,7 +1883,7 @@ gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height) " v_tex_coord = a_tex_coord;\n" "}\n", - "#version 330 core\n" + "#version 410 core\n" "precision mediump float;" "in vec2 v_tex_coord;\n" "layout (binding = 0) uniform sampler2D u_tex;\n" @@ -1831,7 +1893,7 @@ gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height) "}\n"); gbgl_load_shader_vf_from_source(&bs->ortho_col_shader, - "#version 330 core\n" + "#version 410 core\n" "precision mediump float;" "layout (location = 0) in vec4 a_position;\n" "uniform mat4 u_ortho_mat;\n" @@ -1839,7 +1901,7 @@ gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height) " gl_Position = u_ortho_mat * a_position;\n" "}\n", - "#version 330 core\n" + "#version 410 core\n" "uniform vec4 u_colour;\n" "out vec4 o_colour;\n" "void main(void) {\n" @@ -1848,7 +1910,7 @@ gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height) gbgl_load_shader_vf_from_source(&bs->font_shader, - "#version 330 core\n" + "#version 410 core\n" "layout (location = 0) in vec4 a_position;\n" "layout (location = 1) in vec2 a_tex_coord;\n" "uniform mat4 u_ortho_mat;\n" @@ -1858,15 +1920,15 @@ gbgl_bs_init(gbglBasicState *bs, i32 window_width, i32 window_height) " v_tex_coord = a_tex_coord;\n" "}\n", - "#version 330 core\n" + "#version 410 core\n" "in vec2 v_tex_coord;\n" - "layout (location = 0) uniform vec4 u_colour;\n" - "layout (binding = 0) uniform sampler2D u_tex;\n" + "uniform vec4 u_colour;\n" + "layout (binding = 0) uniform sampler2D u_tex;\n" "out vec4 o_colour;\n" - "void main(void {\n" + "void main(void) {\n" " float alpha = texture2D(u_tex, v_tex_coord).r;\n" - " o_colour = u_colour * alpha;\n" - "\n" + " o_colour = u_colour * alpha;\n" + "}\n" ); glGenVertexArrays(1, &bs->font_vao); @@ -1942,7 +2004,7 @@ gbgl_bs_draw_textured_rect(gbglBasicState *bs, gbglTexture *tex, gbVec2 pos, gbV bs->vertices[3].v = v_up ? 1.0f : 0.0f; gbgl_use_shader(&bs->ortho_tex_shader); - gbgl_set_uniform_mat4(&bs->ortho_tex_shader, "u_ortho_mat", bs->ortho_mat.e); + gbgl_set_uniform_mat4(&bs->ortho_tex_shader, "u_ortho_mat", &bs->ortho_mat); gbgl_bind_texture2d(tex, 0, bs->nearest_sampler); gbgl_vbo_copy(bs->vbo, bs->vertices, 4*gb_size_of(bs->vertices[0]), 0); @@ -1988,7 +2050,7 @@ gbgl__bs_setup_ortho_colour_state(gbglBasicState *bs, isize vertex_count, gbColo gbVec4 vcol = gb_vec4(col.r/255.0f, col.g/255.0f, col.b/255.0f, col.a/255.0f); gbgl_use_shader(&bs->ortho_col_shader); - gbgl_set_uniform_mat4(&bs->ortho_col_shader, "u_ortho_mat", bs->ortho_mat.e); + gbgl_set_uniform_mat4(&bs->ortho_col_shader, "u_ortho_mat", &bs->ortho_mat); gbgl_set_uniform_vec4(&bs->ortho_col_shader, "u_colour", vcol); gbgl_vbo_copy(bs->vbo, bs->vertices, vertex_count*gb_size_of(bs->vertices[0]), 0); @@ -2095,6 +2157,181 @@ gbgl_bs_draw_circle_outline(gbglBasicState *bs, gbVec2 p, f32 radius, gbColour c glDrawArrays(GL_LINE_LOOP, 0, 32); } +isize +gbgl_bs_draw_substring(gbglBasicState *bs, gbglFont *font, i32 x, i32 y, gbColour col, char const *str, isize len) +{ + isize char_count = gb_utf8_strnlen(str, len); + if (char_count <= 0) { + return 0; + } else { + char const *ptr = str; + + f32 sf = 1.0f / cast(f32)font->bitmap_width; + f32 tf = 1.0f / cast(f32)font->bitmap_height; + + f32 ox, oy; + f32 px, py; + + isize line_count = 1, glyph_count = 0, i; + f32 font_height = font->size; + i32 max_width = bs->text_params[GBGL_TEXT_PARAM_MAX_WIDTH].val_i32; + f32 max_width32 = cast(f32)max_width; + + gbglJustifyType justify = cast(gbglJustifyType)bs->text_params[GBGL_TEXT_PARAM_JUSTIFY].val_i32; + if (justify == GBGL_JUSTIFY_CENTRE) { + f32 width; + gbgl_get_string_dimensions(font, ptr, &width, NULL); + x = cast(i32)gb_round(cast(f32)x - width*0.5f); + } else if (justify == GBGL_JUSTIFY_RIGHT) { + f32 width; + gbgl_get_string_dimensions(font, ptr, &width, NULL); + x = cast(i32)gb_round(cast(f32)x - width); + } + + ox = x; + oy = y; + px = ox; + py = oy; + + for (i = 0; i < char_count; i++) { + char32 cp; + isize byte_len, curr_index, draw_this_glyph_count = 1, j; + gbglGlyphInfo *gi; + + byte_len = gb_utf8_decode_len(ptr, len-(ptr-str), &cp); + ptr += byte_len; + if (ptr - str > len) + break; + + gi = gbgl_get_glyph_info(font, cp, &curr_index); + if (!gi) { + gi = gbgl_get_glyph_info(font, ' ', &curr_index); + } + + if (cp == '\t') + draw_this_glyph_count = GBGL_TAB_CHARACTER_WIDTH; + + if (gi) { + for (j = 0; j < draw_this_glyph_count; j++) { + f32 s0, t0, s1, t1; + f32 x0, y0, x1, y1; + f32 kern = 0.0f; + + if (cp == '\r' || cp == '\n' || + (max_width > 0 && px - ox + gi->xadv >= max_width32)) { + px = ox; + + py -= font_height; + line_count += 2; + + if (cp == '\r' || cp == '\n') { + if (cp == '\r' && ptr[1] == '\n') + ptr++; + continue; + } + } + + s0 = cast(f32)gi->s0 * sf; + t0 = cast(f32)gi->t0 * tf; + s1 = cast(f32)gi->s1 * sf; + t1 = cast(f32)gi->t1 * tf; + + x0 = px + gi->xoff; + y0 = py - gi->yoff; + x1 = x0 + (gi->s1 - gi->s0); + y1 = y0 + (gi->t0 - gi->t1); + + bs->font_vertices[glyph_count*4 + 0].x = x0; + bs->font_vertices[glyph_count*4 + 0].y = y0; + bs->font_vertices[glyph_count*4 + 0].u = s0; + bs->font_vertices[glyph_count*4 + 0].v = t0; + + bs->font_vertices[glyph_count*4 + 1].x = x0; + bs->font_vertices[glyph_count*4 + 1].y = y1; + bs->font_vertices[glyph_count*4 + 1].u = s0; + bs->font_vertices[glyph_count*4 + 1].v = t1; + + bs->font_vertices[glyph_count*4 + 2].x = x1; + bs->font_vertices[glyph_count*4 + 2].y = y1; + bs->font_vertices[glyph_count*4 + 2].u = s1; + bs->font_vertices[glyph_count*4 + 2].v = t1; + + bs->font_vertices[glyph_count*4 + 3].x = x1; + bs->font_vertices[glyph_count*4 + 3].y = y0; + bs->font_vertices[glyph_count*4 + 3].u = s1; + bs->font_vertices[glyph_count*4 + 3].v = t0; + + glyph_count++; + + if (i < char_count-1) { + isize next_index; + char32 next_cp = 0; + gbglGlyphInfo *ngi; + + gb_utf8_decode_len(ptr, len-(ptr-str), &next_cp); + ngi = gbgl_get_glyph_info(font, next_cp, &next_index); + if (ngi) { + kern = gbgl_get_font_kern_amt_from_glyph_indices(font, curr_index, next_index); + } + } + + px += gi->xadv + kern; + } + } + } + + + { + isize sampler_handle = 0; + + gbgl_use_shader(&bs->font_shader); + gbgl_set_uniform_mat4(&bs->font_shader, "u_ortho_mat", &bs->ortho_mat); + gbgl_set_uniform_colour(&bs->font_shader, "u_colour", col); + GB_ASSERT(bs->text_params[GBGL_TEXT_PARAM_TEXTURE_FILTER].val_i32 < gb_count_of(bs->font_samplers)); + if (bs->text_params[GBGL_TEXT_PARAM_TEXTURE_FILTER].val_i32 < gb_count_of(bs->font_samplers)) + sampler_handle = bs->text_params[GBGL_TEXT_PARAM_TEXTURE_FILTER].val_i32; + + gbgl_bind_texture2d(&font->texture, 0, bs->font_samplers[sampler_handle]); + gbgl_vbo_copy(bs->font_vbo, bs->font_vertices, gb_size_of(bs->font_vertices[0]) * glyph_count * 4, 0); + + gbgl_vert_ptr_aa(0, 2, gbglBasicVertex, x); + gbgl_vert_ptr_aa(1, 2, gbglBasicVertex, u); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs->font_ebo); + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glDrawElements(GL_TRIANGLES, glyph_count*6, GL_UNSIGNED_SHORT, NULL); + + } + + return line_count; + } +} + +isize +gbgl_bs_draw_string(gbglBasicState *bs, gbglFont *font, i32 x, i32 y, gbColour col, char const *fmt, ...) +{ + isize len; + va_list va; + va_start(va, fmt); + len = gbgl_bs_draw_string_va(bs, font, x, y, col, fmt, va); + va_end(va); + return len; +} + +isize +gbgl_bs_draw_string_va(gbglBasicState *bs, gbglFont *font, i32 x, i32 y, gbColour col, char const *fmt, va_list va) +{ + isize len = gb_snprintf_va(bs->font_text_buffer, gb_size_of(bs->font_text_buffer), + fmt, va); + isize char_count = gb_utf8_strnlen(bs->font_text_buffer, len); + if (char_count <= 0) + return 0; + return gbgl_bs_draw_substring(bs, font, x, y, col, bs->font_text_buffer, len); +} + diff --git a/gb_math.h b/gb_math.h index 0a1994d..178043f 100644 --- a/gb_math.h +++ b/gb_math.h @@ -229,6 +229,9 @@ GB_MATH_DEF float gb_fast_exp(float x); // NOTE(bill): Only valid from -1 <= x GB_MATH_DEF float gb_fast_exp2(float x); // NOTE(bill): Only valid from -1 <= x <= +1 GB_MATH_DEF float gb_pow(float x, float y); // x^y +GB_MATH_DEF float gb_round(float x); +GB_MATH_DEF float gb_floor(float x); +GB_MATH_DEF float gb_ceil(float x); GB_MATH_DEF float gb_half_to_float(gbHalf value); GB_MATH_DEF gbHalf gb_float_to_half(float value); @@ -1059,6 +1062,15 @@ float gb_fast_exp2(float x) { return gb_fast_exp(GB_MATH_LOG_TWO * x); } +float gb_round(float x) { return (x >= 0.0f) ? gb_floor(x + 0.5f) : gb_ceil(x - 0.5f); } +float gb_floor(float x) { return (x >= 0.0f) ? (int)x : (int)(x-0.9999999999999999f); } +float gb_ceil(float x) { return (x < 0) ? (int)x : ((int)x)+1; } + + + + + + typedef union { unsigned int i; float f;