diff --git a/module.jai b/module.jai index 55bf6b7..6a1e9b3 100644 --- a/module.jai +++ b/module.jai @@ -169,13 +169,13 @@ draw_plot :: (key: string, size: Vector2, xdata: []float64, yarrays: [][]float64 plot.x = xx child_pos.x; plot.y = xx child_pos.y; - //plot_size = .{plot_size.x, min(260.0, plot_size.y / workspace.f64_arrays.count)}; - if plot.width < 0 || plot.height < 0 { log("[Warning] The plot has dimensions lower than 0."); } else { if plot.width != cast(s32) size.x || plot.height != cast(s32) size.y { - plot_resize(plot, xx size.x, xx size.y); + plot.width = xx size.x; + plot.height = xx size.y; + Simp.texture_resize_render_target(plot.texture, xx size.x, xx size.y); } ar : float = cast(float) plot.width / cast(float) plot.height; @@ -197,19 +197,25 @@ draw_plot :: (key: string, size: Vector2, xdata: []float64, yarrays: [][]float64 } } - glBindFramebuffer(GL_FRAMEBUFFER, plot.fbo); + reset_fbo : GLint; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, *reset_fbo); + defer glBindFramebuffer(GL_FRAMEBUFFER, xx reset_fbo); - glViewport(xx plot.left_bearing, xx plot.bottom_bearing, - xx (plot.width - plot.left_bearing), xx (plot.height - plot.bottom_bearing)); + reset_program : GLint; + glGetIntegerv(GL_CURRENT_PROGRAM, *reset_program); + defer glUseProgram(xx reset_program); - glClearColor(colors.background.x, colors.background.y, colors.background.z, 0.0); - glClear(GL_COLOR_BUFFER_BIT); + Simp.set_render_target(plot.texture); + + Simp.clear_render_target(colors.background.x, colors.background.y, colors.background.z, 1.0); draw_axis(plot, plot.plot_style, colors); if plot.plot_style == .SCALE_MARKER draw_scale(plot, colors); + glUseProgram(data_shader); + glViewport(xx plot.left_bearing, xx plot.bottom_bearing, xx (plot.width - plot.left_bearing), xx (plot.height - plot.bottom_bearing)); @@ -220,9 +226,7 @@ draw_plot :: (key: string, size: Vector2, xdata: []float64, yarrays: [][]float64 glBufferData(GL_ARRAY_BUFFER, plot.xfloat.count * size_of(float), plot.xfloat.data, GL_DYNAMIC_DRAW); glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, size_of(float), null); - for yfloat: plot.yfloats { - - glBindFramebuffer(GL_FRAMEBUFFER, plot.fbo); + for yfloat : plot.yfloats { glBindBuffer(GL_ARRAY_BUFFER, plot.yvbo); glEnableVertexAttribArray(1); @@ -242,8 +246,6 @@ draw_plot :: (key: string, size: Vector2, xdata: []float64, yarrays: [][]float64 (plot.ymin), (plot.ymax), -1.0, 1.0); - glUseProgram(data_shader); - glUniformMatrix4fv(glGetUniformLocation(data_shader, "model"), 1, GL_TRUE, xx *model); glUniformMatrix4fv(glGetUniformLocation(data_shader, "proj"), 1, GL_TRUE, xx *proj); @@ -253,15 +255,10 @@ draw_plot :: (key: string, size: Vector2, xdata: []float64, yarrays: [][]float64 glDrawArrays(GL_LINE_STRIP, 0, xx (plot.xfloat.count)); primitives_rendered_this_frame += plot.xfloat.count - 1; - - //glBindFramebuffer(GL_READ_FRAMEBUFFER, plot.msfbo); - //glBindFramebuffer(GL_DRAW_FRAMEBUFFER, plot.fbo); - //glBlitFramebuffer(0, 0, plot.width, plot.height, 0, 0, plot.width, plot.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); } - ImGui.Image(cast(ImGui.ImTextureID) plot.texture, size, .{0.0, 1.0}, .{1.0, 0.0}); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + ImGui.Image(cast(ImGui.ImTextureID) plot.texture.gl_handle, size, .{0.0, 1.0}, .{1.0, 0.0}); plot.last_frame = frame; } @@ -287,24 +284,17 @@ free_old_plots :: () { } } -init :: (_win_width: s32, _win_height: s32, _mouse_wheel_zoom : bool) { +init :: (_window: Window_Type, _win_width: s32, _win_height: s32, _mouse_wheel_zoom : bool) { + window = _window; win_width = _win_width; win_height = _win_height; mouse_wheel_zoom = _mouse_wheel_zoom; - error := FT_Init_FreeType(*ftlib); - if error { - log("[Error] FreeType could not initialise. That is very bad!"); - log(" with error code %.", error); - } + JetBrainsMonoRegular = Simp.get_font_at_size("fonts", "JetBrainsMono-Regular.ttf", 14); + assert(JetBrainsMonoRegular != null); data_shader = make_shader(data_vertex_shader_text, data_fragment_shader_text); line_shader = make_shader(line_vertex_shader_text, line_fragment_shader_text); - text_shader = make_shader(text_vertex_shader_text, text_fragment_shader_text); - - window_projection_matrix = orthographic_projection_matrix(0.0, xx win_width, xx win_height, 0.0, -1.0, 1.0); - - init_font(*JetBrainsMonoRegular, "JetBrainsMono-Regular.ttf", 12); glEnable(GL_MULTISAMPLE); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); @@ -316,23 +306,97 @@ window_resize :: (_win_width: s32, _win_height: s32) { win_width = _win_width; win_height = _win_height; - window_projection_matrix = orthographic_projection_matrix(0.0, xx win_width, xx win_height, 0.0, -1.0, 1.0); } -new_frame :: (_mouse: Vector2, _mouse_delta: Vector2, _mouse_wheel_delta: float, _mouse_left: bool) { +new_frame :: () { frame += 1; - mouse = _mouse; - mouse_delta = _mouse_delta; - mouse_wheel_delta = _mouse_wheel_delta; - mouse_left = _mouse_left; primitives_rendered_this_frame = 0; + + mouse_delta = .{}; + mouse_wheel_delta = 0; + + x, y := get_mouse_pointer_position(window, false); + mouse = .{cast(float, x), cast(float, y)}; +} + +handle_input :: (events: []Input.Event) { + // @Hack Input module for android treats touch inputs as mouse button left, but you need to set the "mouse" + // position to something valid before triggering the click so update it here. + // @TODO(Charles): This can now be updated as modules/Input has touch! :ImGuiAndroidInput + #if OS == .ANDROID { + WC :: #import "Window_Creation"; + Math :: #import "Math"; + touch_x, touch_y, success := WC.get_mouse_pointer_position(true); + touch_x_f := cast(float) touch_x; + touch_y_f := cast(float) touch_y; + if !success { + // ImGui wants -FLT_MAX, -FLT_MAX to indicate no mouse. + FLT_MAX :: Math.FLOAT32_MAX; + touch_x_f = -FLT_MAX; + touch_y_f = -FLT_MAX; + } + + // @Hack when releasing screen, need to have the mouse position set to where we released. + touch_on_release := mouse; + + mouse = .{touch_x_f, touch_y_f}; + } + + // NOTE(Charles): On windows mouse position is handled in ImGui_ImplWin32_NewFrame with GetCusorPos on tick. The + // Imgui examples also respond to WM_MOUSEMOVE, but it's not clear why? + // modules/Input "doesn't have mouse move events yet", it only gives us the delta. + + for event: events { + // :Win32InputMissing AddFocusEvent, could be done by checking Input.input_application_has_focus for change. + if event.type == { + case .KEYBOARD; + if event.key_code == { + // :Win32InputMissing mouse extra buttons, SetCapturing?, Mouse source + // case .MOUSE_BUTTON_LEFT; io.AddMouseButtonEvent(io, xx ImGui.MouseButton.Left , xx event.key_pressed); + + case .MOUSE_BUTTON_LEFT; + // @Hack + #if OS == .ANDROID { + if !event.key_pressed { + mouse = .{touch_on_release.x, touch_on_release.y}; + } + } + if event.key_pressed + mouse_left = true; + else + mouse_left = false; + + case .MOUSE_BUTTON_RIGHT; + //io.AddMouseButtonEvent(io, xx ImGui.MouseButton.Right , xx event.key_pressed); + + case .MOUSE_BUTTON_MIDDLE; + //io.AddMouseButtonEvent(io, xx ImGui.MouseButton.Middle, xx event.key_pressed); + + case; + //imgui_key := to_imgui_key(event.key_code); + //// :Win32InputMissing Input only gives us single ctrl, shift, alt, not left/right. ImGui example sends + //// one event for either, then an extra for left right. + //if imgui_key != .None { + // // :Win32InputMissing SetKeyEventNativeData gets called for some legacy reason? + // io.AddKeyEvent(io, imgui_key, xx event.key_pressed); + //} + } + + case .MOUSE_WHEEL; + mouse_wheel_delta += event.wheel_delta / cast(float, event.typical_wheel_delta); + } + } + + mouse_delta += .{cast(float, Input.mouse_delta_x), cast(float, Input.mouse_delta_y)}; } get_primitives_rendered :: () -> int { return primitives_rendered_this_frame; } +JetBrainsMonoRegular : *Simp.Dynamic_Font; + #scope_file #import "Basic"; @@ -340,7 +404,14 @@ get_primitives_rendered :: () -> int { #import "Hash_Table"; #import "Math"; ImGui :: #import,dir "../imgui-lib"; +Simp :: #import "Simp"; +#import "stb_rect_pack"; +#import "File"; +Input :: #import "Input"; +#import "Window_Creation"; + +window : Window_Type; frame : s64; mouse : Vector2; mouse_delta : Vector2; @@ -365,10 +436,7 @@ Plot :: struct { plot_style : PLOT_STYLE; - msfbo : GLuint; - mstexture : GLuint; - fbo : GLuint; - texture : GLuint; + texture: *Simp.Texture; vao : GLuint; xvbo : GLuint; @@ -410,10 +478,6 @@ data_colors := Vector4.[ ]; free_plot :: (plot: *Plot) { - glDeleteTextures(1, *plot.texture); - glDeleteTextures(1, *plot.mstexture); - glDeleteFramebuffers(1, *plot.fbo); - glDeleteFramebuffers(1, *plot.msfbo); glDeleteVertexArrays(1, *plot.vao); glDeleteBuffers(1, *plot.xvbo); glDeleteBuffers(1, *plot.yvbo); @@ -429,63 +493,16 @@ init_plot :: (plot: *Plot, key: string, width: s32, height: s32) { plot.width = 1024; plot.height = 1024; - glGenFramebuffers(1, *plot.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, plot.fbo); - glGenTextures(1, *plot.texture); - glBindTexture(GL_TEXTURE_2D, plot.texture); + plot.texture = Simp.texture_create_render_target(width, height, .RGBA8, .sRGB); - glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, xx plot.width, xx plot.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, plot.texture, 0); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - if glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE { - log("[ERROR] FRAMEBUFFER: Framebuffer is not complete!"); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - glGenFramebuffers(1, *plot.msfbo); - glBindFramebuffer(GL_FRAMEBUFFER, plot.msfbo); - - glGenTextures(1, *plot.mstexture); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, plot.mstexture); - - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_SRGB8_ALPHA8, xx plot.width, xx plot.height, GL_TRUE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, plot.mstexture, 0); - - if glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE { - log("[ERROR] FRAMEBUFFER: Framebuffer is not complete!"); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } glGenVertexArrays(1, *plot.vao); glBindVertexArray(plot.vao); glGenBuffers(1, *plot.xvbo); glGenBuffers(1, *plot.yvbo); -} -plot_resize :: (plot: *Plot, width: s32, height: s32) { - plot.width = width; - plot.height = height; - - glBindTexture(GL_TEXTURE_2D, plot.texture); - - if width > 0 && height > 0 { - glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, xx plot.width, xx plot.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); - } - - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, plot.mstexture); - - if width > 0 && height > 0 { - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_SRGB8_ALPHA8, xx plot.width, xx plot.height, GL_TRUE); - } } truncate :: (x: float, n: s32) -> float { @@ -534,13 +551,15 @@ draw_axis :: (using plot: Plot, style: PLOT_STYLE, colors: PlotColors) { array_add(*positions, .{cast(float) xpos, 0.0}); array_add(*positions, .{cast(float) xpos, cast(float) (content_height )}); - to_render := tprint("%", formatFloat(cast(float) xxx, trailing_width = 1, zero_removal = .NO)); - label_size := calculate_string_draw_size(*JetBrainsMonoRegular, to_render); + label_width := Simp.prepare_text(JetBrainsMonoRegular, tprint("%", formatFloat(cast(float) xxx, + trailing_width = 1, zero_removal = .NO))); if style == .TICK_MARKS { - render_string(*JetBrainsMonoRegular, to_render, - .{xpos + left_bearing - (label_size.x / 2.0), xx (plot.height - bottom_bearing + 4.0)}, - colors.text, plot.width, plot.height); + + Simp.draw_prepared_text(JetBrainsMonoRegular, + xx (xpos + left_bearing - (label_width / 2.0)), + xx (4.0), + .{1, 1, 1, 1}); } } @@ -548,17 +567,19 @@ draw_axis :: (using plot: Plot, style: PLOT_STYLE, colors: PlotColors) { for 0..y_ticks { ypos : s64 = cast(s64) (cast(float) it / cast(float) y_ticks * (content_height )); yyy := ((0.5) - cast(float) it / cast(float) y_ticks) / zoom + 0.5; - yyy = yyy * (ymax - pos.y) + (1 - yyy) * (ymin - pos.y); + yyy = yyy * (ymin - pos.y) + (1 - yyy) * (ymax - pos.y); array_add(*positions, .{0.0, cast(float) ypos}); array_add(*positions, .{cast(float) (content_width ), cast(float) ypos}); - to_render := tprint("%", formatFloat(cast(float) yyy, trailing_width = 1, zero_removal = .NO)); - label_size := calculate_string_draw_size(*JetBrainsMonoRegular, to_render); + label_width := Simp.prepare_text(JetBrainsMonoRegular, tprint("%", formatFloat(cast(float) yyy, trailing_width = 1, + zero_removal = .NO))); if style == .TICK_MARKS { - render_string(*JetBrainsMonoRegular, to_render, - .{xx cast(s64) (left_bearing - label_size.x - 4.0), xx cast(s64) (ypos - label_size.y / 2.0)}, - colors.text, plot.width, plot.height); + + Simp.draw_prepared_text(JetBrainsMonoRegular, + xx (xx cast(s64) (left_bearing - label_width - 4.0)), + xx (cast(s64) (ypos + JetBrainsMonoRegular.character_height)), + .{1, 1, 1, 1}); } } } @@ -607,38 +628,35 @@ draw_scale :: (using plot: Plot, colors: PlotColors) { positions : [..]Vector2; defer array_reset(*positions); - // array_add(*positions, .{0.0, 0.0}); - // array_add(*positions, .{xx width, 0.0}); - - // array_add(*positions, .{xx width, 0.0}); - // array_add(*positions, .{xx width, xx height}); - - // array_add(*positions, .{xx width, xx height}); - // array_add(*positions, .{0.0, xx height}); - - // array_add(*positions, .{0.0, xx height}); - // array_add(*positions, .{0.0, 0.0}); - array_add(*positions, .{5.0, 5.0}); - array_add(*positions, .{5.0 + content_width / 10.0, 5.0}); + array_add(*positions, .{1.0, 1.0}); + array_add(*positions, .{1.0 + content_width / 10.0, 1.0}); - to_render := tprint("%", formatFloat(cast(float) extent_x / zoom / 10.0, trailing_width = 1, zero_removal = .NO)); - label_size := calculate_string_draw_size(*JetBrainsMonoRegular, to_render); - render_string(*JetBrainsMonoRegular, to_render, - .{xx cast(s64) (5.0 + content_width / 10.0), xx height - label_size.y - 5.0}, - colors.text, plot.width, plot.height); + glViewport(0, 0, xx width, xx (height)); - array_add(*positions, .{5.0, 5.0}); - array_add(*positions, .{5.0, 5.0 + content_height / 10.0}); + label_width := Simp.prepare_text(JetBrainsMonoRegular, tprint("%", formatFloat(cast(float) extent_x / zoom / 10.0, + trailing_width = 1, zero_removal = .NO))); - to_render = tprint("%", formatFloat(cast(float) extent_y / zoom / 10.0, trailing_width = 1, zero_removal = .NO)); - label_size = calculate_string_draw_size(*JetBrainsMonoRegular, to_render); - render_string(*JetBrainsMonoRegular, to_render, - .{xx cast(s64) (5.0), height - 5.0 - content_height / 10.0 - label_size.y}, - colors.text, plot.width, plot.height); + Simp.draw_prepared_text(JetBrainsMonoRegular, + xx (5.0 + content_width / 10.0), + xx (0), + .{1, 1, 1, 1}); - glViewport(0, 0, xx width, xx height); + array_add(*positions, .{1.0, 1.0}); + array_add(*positions, .{1.0, 1.0 + content_height / 10.0}); + + label_width = Simp.prepare_text(JetBrainsMonoRegular, tprint("%", formatFloat(cast(float) extent_y / zoom / 10.0, + trailing_width = 1, zero_removal = .NO))); + + + Simp.draw_prepared_text(JetBrainsMonoRegular, + xx (0), + xx (5.0 + content_height / 10.0), + .{1, 1, 1, 1}); + + + //glViewport(xx left_bearing, xx bottom_bearing, xx (width - left_bearing), xx (height - bottom_bearing)); scale_vao : GLuint; glGenVertexArrays(1, *scale_vao); @@ -653,7 +671,6 @@ draw_scale :: (using plot: Plot, colors: PlotColors) { glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, size_of(Vector2), null); proj := orthographic_projection_matrix(0.0, cast(float) (width), 0.0, cast(float) (height), -1.0, 1.0); - //proj := orthographic_projection_matrix(xmin * zoom, xmax * zoom, ymin * zoom, ymax * zoom, -1.0, 1.0); glUseProgram(line_shader); @@ -682,362 +699,8 @@ is_in_rect :: (pos: Vector2, size: Vector2, test: Vector2) -> bool { return true; } - -// FONTS - -#import "freetype-2.12.1"; -#import "harfbuzz"; -#import "stb_rect_pack"; -#import "File"; - -ftlib : FT_Library; - -ATLAS_SIZE :: 2048; - -JetBrainsMonoRegular: Font; - -JetBrainsMonoRegular_text :: #run read_entire_file(tprint("%/JetBrainsMono-Regular.ttf", #filepath)); - -Glyph :: struct { - utf32 : u32; - index : u32; - - x, y : s16; - width, height : u32; - - bearing_x, bearing_y : s16; - - y_max, y_min : s16; - - ascent : s16; - advance : s16; - - uv0, uv1 : Vector2; - - bitmap : *u8; -} - -Font :: struct { - face : FT_Face; - - glyphs : Table(u32, Glyph); - - graphics_font : GraphicsFont; - - hb : *hb_font_t; -} - -init_font :: (using font: *Font, filename: string, size: s32) { - - pixel_size := size * 96.0 / 72.0; - //pixel_size := size; - - //FT_New_Face(ftlib, filename.data, 0, *face); - - FT_New_Memory_Face(ftlib, JetBrainsMonoRegular_text.data, JetBrainsMonoRegular_text.count, 0, *face); - - //error := FT_Set_Pixel_Sizes(face, 0, xx size); - error := FT_Set_Char_Size(face, 0, size * 64, 0, 96); - if error - log("%", to_string(FT_Error_String(error))); - - rects : [..] stbrp_rect; - defer array_free(rects); - - nodes : [ATLAS_SIZE] stbrp_node; - - stbrpcontext : stbrp_context; - stbrp_init_target(*stbrpcontext, ATLAS_SIZE, ATLAS_SIZE, nodes.data, nodes.count); - - atlas : *u8 = alloc(ATLAS_SIZE * ATLAS_SIZE); - defer free(atlas); - - - for 0..face.num_glyphs { - error = FT_Load_Glyph(face, cast(u32) it, FT_LOAD_RENDER); - if error - log("%", to_string(FT_Error_String(error))); - - array_add(*rects, stbrp_rect.{cast(s32) face.glyph.glyph_index, cast(s32) face.glyph.bitmap.width, - cast(s32) face.glyph.bitmap.rows, 0, 0, 0}); - - glyph : Glyph; - glyph.utf32 = cast(u32) it; - glyph.index = face.glyph.glyph_index; - glyph.bearing_x = cast,trunc(s16) face.glyph.bitmap_left; - glyph.bearing_y = cast,trunc(s16) face.glyph.bitmap_top; - glyph.width = face.glyph.bitmap.width; - glyph.height = face.glyph.bitmap.rows; - glyph.advance = cast(s16) face.glyph.advance.x >> 6; - glyph.bitmap = alloc(glyph.height * glyph.width); - memcpy(glyph.bitmap, face.glyph.bitmap.buffer, glyph.height * glyph.width); - - table_set(*font.glyphs, glyph.index, glyph); - } - - stbrp_pack_rects(*stbrpcontext, rects.data, cast(s32) rects.count); - - - copybitmaptoatlas :: (bitmap : *u8, width: s32, height: s32, atlas: *u8, destx: s32, desty: s32) { - if (destx >= ATLAS_SIZE) - destx = ATLAS_SIZE - 1; - - if (desty >= ATLAS_SIZE) - desty = ATLAS_SIZE - 1; - - for j: 0..height - 1 { - for i: 0..width - 1 { - atlas[(desty + j) * ATLAS_SIZE + (destx + i)] = bitmap[j * width + i]; - } - } - } - - for rect : rects { - glyph : *Glyph = table_find_pointer(*font.glyphs, cast(u32) rect.id); - if (glyph.bitmap) { - glyph.x = cast,trunc(s16) rect.x; - glyph.y = cast,trunc(s16) rect.y; - copybitmaptoatlas(glyph.bitmap, cast(s32) glyph.width, cast(s32) glyph.height, atlas, cast(s32) rect.x, cast(s32) rect.y); - } - } - - graphics_init_font(*font.graphics_font, atlas); - - blob : *hb_blob_t = hb_blob_create(JetBrainsMonoRegular_text.data, JetBrainsMonoRegular_text.count, .HB_MEMORY_MODE_READONLY, null, null); - - hb_face : *hb_face_t = hb_face_create(blob, 0); - hb = hb_font_create(hb_face); - hb_font_set_ppem(hb, xx pixel_size, xx pixel_size); - hb_font_set_scale(hb, cast(s32) pixel_size * 64, cast(s32) pixel_size * 64); -} - -render_string :: (font: *Font, text: string, pos: Vector2, colour: Vector3 = .{1.0, 1.0, 1.0}, fb_width: s32, fb_height: s32, - nicebackground := false) { - if !text - return; - - if nicebackground { - render_string(font, text, pos + .{3.0, 3.0}, xyz(0.0), fb_width, fb_height, false); - } - - buf : *hb_buffer_t = hb_buffer_create(); - hb_buffer_add_utf8(buf, text.data, xx text.count, 0, -1); - - hb_buffer_set_direction(buf, hb_direction_t.LTR); - hb_buffer_set_script(buf, hb_script_t.HB_SCRIPT_LATIN); - hb_buffer_set_language(buf, hb_language_from_string("en", -1)); - - features : [1]hb_feature_t; - //features[0].tag = HB_TAG(#char "c", #char "a", #char "l", #char "t"); - //features[0].value = 1; - //features[0].start = HB_FEATURE_GLOBAL_START; - //features[0].end = HB_FEATURE_GLOBAL_END; - - hb_shape(font.hb, buf, features.data, features.count); - - glyph_count : u32; - glyph_info : *hb_glyph_info_t = hb_buffer_get_glyph_infos(buf, *glyph_count); - glyph_pos : *hb_glyph_position_t = hb_buffer_get_glyph_positions(buf, *glyph_count); - - vertices : [..] Vector2; - tex : [..] Vector2; - - defer array_reset(*vertices); - defer array_reset(*tex); - - render_pos := pos; - - draw_size := calculate_string_draw_size(font, text); - - for i : 0..glyph_count - 1 { - glyphid : hb_codepoint_t = glyph_info[i].codepoint; - x_offset : hb_position_t = glyph_pos[i].x_offset; - y_offset : hb_position_t = glyph_pos[i].y_offset; - x_advance : hb_position_t = glyph_pos[i].x_advance; - y_advance : hb_position_t = glyph_pos[i].y_advance; - - glyph : *Glyph = table_find_pointer(*font.glyphs, glyphid); - - //v0 := render_pos + xy(xx glyph.bearing_x, xx -glyph.bearing_y + draw_size.y); - v0 := render_pos + xy(cast(float) x_offset + cast(float) glyph.bearing_x, - cast(float) y_offset - cast(float) glyph.bearing_y + draw_size.y); - #if Y_IS_UP { - t0 := xy(cast(float) (glyph.x) / ATLAS_SIZE, (ATLAS_SIZE - (cast(float) (glyph.y))) / ATLAS_SIZE); - } else { - t0 := xy(cast(float) glyph.x / ATLAS_SIZE, cast(float) glyph.y / ATLAS_SIZE); - } - - #if Y_IS_UP { - array_add(*vertices, v0); - array_add(*vertices, v0 + xy(0.0, cast(float) glyph.height)); - array_add(*vertices, v0 + xy(cast(float) glyph.width, 0.0)); - - array_add(*vertices, v0 + xy(cast(float) glyph.width, 0.0)); - array_add(*vertices, v0 + xy(0.0, cast(float) glyph.height)); - array_add(*vertices, v0 + xy(cast(float) glyph.width, cast(float) glyph.height)); - - array_add(*tex, t0); - array_add(*tex, t0 + xy(0.0, -cast(float) (glyph.height) / ATLAS_SIZE)); - array_add(*tex, t0 + xy(cast(float) (glyph.width) / ATLAS_SIZE, 0.0)); - - array_add(*tex, t0 + xy(cast(float) (glyph.width) / ATLAS_SIZE, 0.0)); - array_add(*tex, t0 + xy(0.0, -cast(float) (glyph.height) / ATLAS_SIZE)); - array_add(*tex, t0 + xy(cast(float) (glyph.width) / ATLAS_SIZE, -cast(float) (glyph.height) / ATLAS_SIZE)); - } else { - array_add(*vertices, v0); - array_add(*vertices, v0 + xy(cast(float) glyph.width, 0.0)); - array_add(*vertices, v0 + xy(0.0, cast(float) glyph.height)); - - array_add(*vertices, v0 + xy(cast(float) glyph.width, 0.0)); - array_add(*vertices, v0 + xy(cast(float) glyph.width, cast(float) glyph.height)); - array_add(*vertices, v0 + xy(0.0, cast(float) glyph.height)); - - array_add(*tex, t0); - array_add(*tex, t0 + xy(0.0, cast(float) glyph.height / ATLAS_SIZE)); - array_add(*tex, t0 + xy(cast(float) glyph.width / ATLAS_SIZE, cast(float) glyph.height / ATLAS_SIZE)); - - array_add(*tex, t0 + xy(cast(float) glyph.width / ATLAS_SIZE, cast(float) glyph.height / ATLAS_SIZE)); - array_add(*tex, t0 + xy(cast(float) glyph.width / ATLAS_SIZE, 0.0)); - array_add(*tex, t0); - } - - render_pos += xy(xx x_advance / 64.0, xx y_advance / 64.0); - } - - graphics_render_font(*font.graphics_font, vertices, tex, colour, fb_width, fb_height); - - hb_buffer_destroy(buf); -} - -HB_TAG :: (c1: u8, c2: u8, c3: u8, c4: u8) -> hb_tag_t #expand { - return cast(hb_tag_t)(((cast(u32)(c1)&0xFF)<<24)|((cast(u32)(c2)&0xFF)<<16)|((cast(u32)(c3)&0xFF)<<8)|(cast(u32)(c4)&0xFF)); -} - -HB_FEATURE_GLOBAL_END :: cast,no_check(u32) -1; - -calculate_string_draw_size :: (font: *Font, text: string) -> Vector2 { - if !text - return .{}; - - buf : *hb_buffer_t = hb_buffer_create(); - hb_buffer_add_utf8(buf, text.data, xx text.count, 0, -1); - - hb_buffer_set_direction(buf, hb_direction_t.LTR); - hb_buffer_set_script(buf, hb_script_t.HB_SCRIPT_LATIN); - hb_buffer_set_language(buf, hb_language_from_string("en", -1)); - - features : [1]hb_feature_t; - features[0].tag = HB_TAG(#char "c", #char "a", #char "l", #char "t"); - features[0].value = 1; - features[0].start = HB_FEATURE_GLOBAL_START; - features[0].end = HB_FEATURE_GLOBAL_END; - - hb_shape(font.hb, buf, features.data, features.count); - glyph_count_u : u32; - glyph_info : *hb_glyph_info_t = hb_buffer_get_glyph_infos(buf, *glyph_count_u); - glyph_pos : *hb_glyph_position_t = hb_buffer_get_glyph_positions(buf, *glyph_count_u); - - glyph_count : s32 = xx glyph_count_u; - - size : Vector2; - - for i : 0..glyph_count - 1 { - glyphid : hb_codepoint_t = glyph_info[i].codepoint; - x_offset : hb_position_t = glyph_pos[i].x_offset; - y_offset : hb_position_t = glyph_pos[i].y_offset; - x_advance : hb_position_t = glyph_pos[i].x_advance; - y_advance : hb_position_t = glyph_pos[i].y_advance; - - glyph : *Glyph = table_find_pointer(*font.glyphs, glyphid); - - size.y = max(size.y, xx glyph.height); - size.x += x_advance / 64.0; - - } - - hb_buffer_destroy(buf); - - return size; -} - -// RENDERING - data_shader : GLuint; line_shader : GLuint; -text_shader : GLuint; - -Y_IS_UP :: true; - -window_projection_matrix : Matrix4; - -GraphicsFont :: struct { - atlasid : GLuint; - - vao: GLuint; - vbo : GLuint; -} - -graphics_init_font :: (graphics_font: *GraphicsFont, atlas: *u8) { - glGenTextures(1, *graphics_font.atlasid); - glBindTexture(GL_TEXTURE_2D, graphics_font.atlasid); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, ATLAS_SIZE, ATLAS_SIZE, 0, GL_RED, GL_UNSIGNED_BYTE, atlas); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -} - -graphics_render_font :: (graphics_font: *GraphicsFont, vertices: []Vector2, tex: []Vector2, color: Vector3, - fb_width: s32, fb_height: s32) { - vao : GLuint; - glGenVertexArrays(1, *vao); - - glViewport(0, 0, xx fb_width, xx fb_height); - - glBindVertexArray(vao); - - posvbo : GLuint; - glGenBuffers(1, *posvbo); - glBindBuffer(GL_ARRAY_BUFFER, posvbo); - glBufferData(GL_ARRAY_BUFFER, size_of(Vector2) * vertices.count, vertices.data, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, size_of(Vector2), null); - - texvbo : GLuint; - glGenBuffers(1, *texvbo); - glBindBuffer(GL_ARRAY_BUFFER, texvbo); - glBufferData(GL_ARRAY_BUFFER, size_of(Vector2) * tex.count, tex.data, GL_STATIC_DRAW); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, size_of(Vector2), null); - - - proj: Matrix4 = orthographic_projection_matrix(0.0, xx fb_width, xx fb_height, 0.0, -1.0, 1.0); - - view : Matrix4 = identity_of(Matrix4); - - model : Matrix4 = identity_of(Matrix4); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, graphics_font.atlasid); - - glUseProgram(text_shader); - glUniformMatrix4fv(glGetUniformLocation(text_shader, "proj"), 1, GL_TRUE, cast(*float) *proj); - glUniformMatrix4fv(glGetUniformLocation(text_shader, "view"), 1, GL_TRUE, cast(*float) *view); - glUniformMatrix4fv(glGetUniformLocation(text_shader, "model"), 1, GL_TRUE, cast(*float) *model); - glUniform3fv(glGetUniformLocation(text_shader, "data_color"), 1, *color.x); - - glDrawArrays(GL_TRIANGLES, 0, cast(u32) vertices.count); - primitives_rendered_this_frame += vertices.count / 3; - - glDeleteBuffers(1, *posvbo); - glDeleteBuffers(1, *texvbo); - glDeleteVertexArrays(1, *vao); - - glBindVertexArray(0); -} make_shader :: (vertex_shader_text: string, fragment_shader_text: string) -> GLuint { success : s32; @@ -1153,87 +816,3 @@ void main() { color = vec4(data_color.rgb, float_to_srgb(data_color.a)); } DONE - -//////////////////////// -// shader to render text -//////////////////////// - -text_vertex_shader_text : string = #string DONE -#version 330 core - -in vec2 data_pos; -in vec2 data_tex; - -out vec2 tex; - -uniform mat4 proj; -uniform mat4 view; -uniform mat4 model; - -void main() { - gl_Position = proj * view * model * vec4(data_pos, 0.0, 1.0); - tex = vec2(data_tex.x, 1.0 - data_tex.y); -} -DONE - -text_fragment_shader_text : string = #string DONE -#version 330 core - -in vec2 tex; - -out vec4 color; - -uniform sampler2D sampler; -uniform vec3 data_color; - -float float_to_srgb(float l) { - if (l < 0.0031308) { - return l * 12.92; - } else { - return 1.055 * pow(l, 0.41666) - 0.055; - } -} - -vec4 linear_to_srgb(vec4 linear) { - vec4 srgb; - - if (linear.x < 0.0031308) { - srgb.x = linear.x * 12.92; - } else { - srgb.x = 1.055 * pow(linear.x, 0.41666) - 0.055; - } - - if (linear.y < 0.0031308) { - srgb.y = linear.y * 12.92; - } else { - srgb.y = 1.055 * pow(linear.y, 0.41666) - 0.055; - } - - if (linear.z < 0.0031308) { - srgb.z = linear.z * 12.92; - } else { - srgb.z = 1.055 * pow(linear.z, 0.41666) - 0.055; - } - - srgb.w = linear.w; - - return srgb; -} - -float float_to_linear(float s) { - if (s <= 0.04045) { - return s / 12.92; - } else { - return pow((s + 0.055) / 1.055, 2.4); - } -} - -vec4 srgb_to_linear(vec4 srgb) { - return vec4(float_to_linear(srgb.r), float_to_linear(srgb.g), float_to_linear(srgb.b), srgb.a); -} - -void main() { - float sampled = texture(sampler, tex).r; - color = vec4(data_color, float_to_srgb(sampled)); -} -DONE