From 8fbc67b21971d880c4ef7e02d0103b3e7289697d Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Thu, 22 Dec 2022 22:46:44 -0600 Subject: [PATCH] factored out rendering library --- .vscode/launch.json | 2 +- onyx-pkg.ini | 8 +- run_tree/run.sh | 6 +- src/build.onyx | 9 +- src/entity/components/collision_mask.onyx | 15 +- src/entity/components/patron.onyx | 4 +- src/entity/editor.onyx | 3 +- src/entity/items.onyx | 3 +- src/entity/schematics/player.onyx | 36 +- src/entity/store.onyx | 3 +- src/main.onyx | 19 +- src/ogre/canvas.onyx | 62 -- src/ogre/colors.onyx | 56 -- src/ogre/font.onyx | 265 -------- src/ogre/immediate.onyx | 215 ------- src/ogre/input.onyx | 186 ------ src/ogre/mesh.onyx | 90 --- src/ogre/ogre.onyx | 17 - src/ogre/shader.onyx | 193 ------ src/ogre/shaders/font.glsl | 40 -- src/ogre/shaders/imgui.glsl | 40 -- src/ogre/texture.onyx | 91 --- src/ogre/ui.onyx | 731 ---------------------- src/ogre/vecmath.onyx | 161 ----- src/ogre/window.onyx | 90 --- src/utils/any_utils.onyx | 47 -- src/utils/misc.onyx | 13 + 27 files changed, 61 insertions(+), 2344 deletions(-) delete mode 100644 src/ogre/canvas.onyx delete mode 100644 src/ogre/colors.onyx delete mode 100644 src/ogre/font.onyx delete mode 100644 src/ogre/immediate.onyx delete mode 100644 src/ogre/input.onyx delete mode 100644 src/ogre/mesh.onyx delete mode 100644 src/ogre/ogre.onyx delete mode 100644 src/ogre/shader.onyx delete mode 100644 src/ogre/shaders/font.glsl delete mode 100644 src/ogre/shaders/imgui.glsl delete mode 100644 src/ogre/texture.onyx delete mode 100644 src/ogre/ui.onyx delete mode 100644 src/ogre/vecmath.onyx delete mode 100644 src/ogre/window.onyx delete mode 100644 src/utils/any_utils.onyx create mode 100644 src/utils/misc.onyx diff --git a/.vscode/launch.json b/.vscode/launch.json index 66ac8cd..37150fb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "name": "Launch", "onyxFiles": ["../src/build"], "workingDir": "${workspaceFolder}/run_tree", - "stopOnEntry": true + "stopOnEntry": false // "preLaunchTask": "Build debug game" } ] diff --git a/onyx-pkg.ini b/onyx-pkg.ini index 9e3d0fc..a321e07 100644 --- a/onyx-pkg.ini +++ b/onyx-pkg.ini @@ -17,16 +17,14 @@ build_cmd= library= [dependencies] -git://onyxlang.io/repo/glfw3=0.0.2 -git://onyxlang.io/repo/opengles=0.0.2 git://onyxlang.io/repo/openal=0.0.2 -git://onyxlang.io/repo/stb_truetype=0.0.2 -git://onyxlang.io/repo/stb_image=0.0.2 +git://onyxlang.io/repo/ogre=0.0.8 [dependency_folders] +git://onyxlang.io/repo/openal=openal +git://onyxlang.io/repo/ogre=ogre git://onyxlang.io/repo/glfw3=glfw3 git://onyxlang.io/repo/opengles=opengles -git://onyxlang.io/repo/openal=openal git://onyxlang.io/repo/stb_truetype=stb_truetype git://onyxlang.io/repo/stb_image=stb_image diff --git a/run_tree/run.sh b/run_tree/run.sh index 27fb7ad..83d0bb3 100755 --- a/run_tree/run.sh +++ b/run_tree/run.sh @@ -1,9 +1,11 @@ dest=game.wasm case "$1" in - build) shift; onyx -V -I ../src build -o $dest $@ ;; + build) shift; onyx -V --tag -I ../src build -o $dest $@ ;; check) shift; onyx check -V -I ../src build $@ ;; run) onyx-run $dest ;; debug) onyx-run --debug $dest ;; - *) onyx run -V -I ../src build $@ ;; + *) onyx run -V --tag -I ../src build $@ ;; esac + +mv tags .. \ No newline at end of file diff --git a/src/build.onyx b/src/build.onyx index 9246fe2..5c2199d 100644 --- a/src/build.onyx +++ b/src/build.onyx @@ -4,7 +4,7 @@ package runtime.vars MAJOR_VERSION :: 0 MINOR_VERSION :: 1 -// DEBUG :: true +DEBUG :: true #if runtime.arch == .X86_64 { #library_path "./lib" } @@ -20,9 +20,6 @@ MINOR_VERSION :: 1 #load_all "./sfx" #load_all "./utils" -#load "./../lib/opengles/module" -#load "./../lib/glfw3/module" #load "./../lib/openal/module" -#load "./../lib/stb_truetype/module" -#load "./../lib/stb_image/module" -#load_all "./ogre" +#load "./../lib/ogre/module" +// #load_all "./ogre" diff --git a/src/entity/components/collision_mask.onyx b/src/entity/components/collision_mask.onyx index b798ca2..acbefb8 100644 --- a/src/entity/components/collision_mask.onyx +++ b/src/entity/components/collision_mask.onyx @@ -58,9 +58,12 @@ CollisionMaskComponent :: struct { start_pos := Vector2i.{ ~~start.x / grid_size, ~~start.y / grid_size }; target_pos := Vector2i.{ ~~target.x / grid_size, ~~target.y / grid_size }; - stack := array.make(.[ .{ pos=start_pos, g=0.0f, h=0.0f } ]); + stack := array.make(.[ .{ pos=start_pos, g=0.0f, f=0.0f } ]); + defer delete(^stack); visited: Map(Vector2i, #type struct{ prev: Vector2i; cost: f32 }); + defer delete(^visited); + found := false; while stack.count != 0 { @@ -87,7 +90,7 @@ CollisionMaskComponent :: struct { if array.contains(stack, #(it.pos == .{tx, ty})) do continue; g := cast(f32) (math.abs(dx) + math.abs(dy)) + top.g; - h := cast(f32) (math.abs(tx - start_pos.x) + math.abs(ty - start_pos.y)); + h := cast(f32) (math.abs(tx - target_pos.x) + math.abs(ty - target_pos.y)) / 2; f := g + h; if visited->has(.{ tx, ty }) { @@ -97,7 +100,7 @@ CollisionMaskComponent :: struct { } } else { - stack << .{ .{tx, ty}, g, h, }; + stack << .{ .{tx, ty}, g, f }; visited[.{ tx, ty }] = .{ top.pos, f }; } } @@ -105,10 +108,8 @@ CollisionMaskComponent :: struct { } array.sort(stack, (n1, n2) => { - f1 := n1.g + n1.h; - f2 := n2.g + n2.h; - if f1 < f2 do return 1; - if f2 < f1 do return -1; + if n1.f < n2.f do return 1; + if n2.f < n1.f do return -1; return 0; }); } diff --git a/src/entity/components/patron.onyx b/src/entity/components/patron.onyx index 366b0ea..2ec578c 100644 --- a/src/entity/components/patron.onyx +++ b/src/entity/components/patron.onyx @@ -135,7 +135,7 @@ PatronComponent :: struct { } if path.count == 0 { - array.clear(^path); + array.free(^path); collision_mask := scene->first_component(CollisionMaskComponent); if !(collision_mask->get_path(entity.pos, target_location, ^path)) { debug_log(.Warning, "No path for patron."); @@ -154,7 +154,7 @@ PatronComponent :: struct { entity.pos += delta * dt; if path_pos >= path.count { - array.clear(^path); + array.free(^path); target_entity := scene->get(target); target_location := target_entity.pos; diff --git a/src/entity/editor.onyx b/src/entity/editor.onyx index 8b980db..71c1c0c 100644 --- a/src/entity/editor.onyx +++ b/src/entity/editor.onyx @@ -13,6 +13,7 @@ use glfw3 use ogre use ogre.ui use runtime {type_info :: info} +use core.misc {as_any} Editor_Range :: struct {min, max: f32;} Editor_Disabled :: struct {} @@ -403,7 +404,7 @@ editor_draw :: () { y += 4; i := 0; - y, i = render_struct_fields(ptr_to_any(entity), i, x, y, w, h); + y, i = render_struct_fields(as_any(entity), i, x, y, w, h); y += 32; for^ entry: entity.components.entries { diff --git a/src/entity/items.onyx b/src/entity/items.onyx index dc74117..2ef7baa 100644 --- a/src/entity/items.onyx +++ b/src/entity/items.onyx @@ -2,6 +2,7 @@ use core use ogre use ogre.ui +use core.misc {as_any, any_nested_selector} Item :: struct { @@ -74,7 +75,7 @@ item_store_load_items_from_file :: (use this: ^Item_Store, path: str) { string.advance(^line, 1); string.strip_whitespace(^line); - member := get_any_for_member(ptr_to_any(current_item), var_name); + member := any_nested_selector(as_any(current_item), var_name); if member.data == null { debug_log(.Warning, "'{}' is not a valid member of Item on line {}.", var_name, line_number); continue; diff --git a/src/entity/schematics/player.onyx b/src/entity/schematics/player.onyx index 3b06c28..d293a2d 100644 --- a/src/entity/schematics/player.onyx +++ b/src/entity/schematics/player.onyx @@ -4,30 +4,30 @@ use glfw3 use ogre Player_Controls :: struct { - up : i32; - down : i32; - left : i32; - right : i32; - interact : i32; - pick_up : i32; + up : Keys; + down : Keys; + left : Keys; + right : Keys; + interact : Keys; + pick_up : Keys; } player_1_controls :: Player_Controls.{ - up = GLFW_KEY_W, - down = GLFW_KEY_S, - left = GLFW_KEY_A, - right = GLFW_KEY_D, - interact = GLFW_KEY_F, - pick_up = GLFW_KEY_G, + up = .W, + down = .S, + left = .A, + right = .D, + interact = .F, + pick_up = .G, } player_2_controls :: Player_Controls.{ - up = GLFW_KEY_UP, - down = GLFW_KEY_DOWN, - left = GLFW_KEY_LEFT, - right = GLFW_KEY_RIGHT, - interact = GLFW_KEY_COMMA, - pick_up = GLFW_KEY_PERIOD, + up = .UP, + down = .DOWN, + left = .LEFT, + right = .RIGHT, + interact = .COMMA, + pick_up = .PERIOD, } diff --git a/src/entity/store.onyx b/src/entity/store.onyx index 3536c9a..ae5edd7 100644 --- a/src/entity/store.onyx +++ b/src/entity/store.onyx @@ -1,5 +1,6 @@ use core +use core.misc {any_nested_selector} // Flags to control how a field of a structure is being stored // in the level file. @@ -163,7 +164,7 @@ scene_load_from_file :: (use this: ^Scene, filename: str, reset_scene := true) { string.strip_whitespace(^line); set_member :: macro (ptr: rawptr, type: type_expr) { - member := get_any_for_member(any.{ptr, type}, var_name); + member := any_nested_selector(any.{ptr, type}, var_name); if member.data == null { t_info := cast(^Type_Info_Struct) get_type_info(type); debug_log(.Warning, "'{}' is not a valid member of '{}' on line {}.", var_name, t_info.name, line_number); diff --git a/src/main.onyx b/src/main.onyx index 0ee681b..3ed2e18 100644 --- a/src/main.onyx +++ b/src/main.onyx @@ -48,15 +48,13 @@ update :: (dt: f32) { draw :: () { immediate_clear(.{0.15, 0.15, 0.2}); - defer ui.ui_end_frame(); - defer input_post_update(); defer { immediate_flush(); #if DEBUG { font_set_color(.{1,1,0}); font_print(debug_font, 0, 16, "FPS: {}", game_fps); - font_print(debug_font, 0, 32, "HEAP: {b16}", alloc.heap.get_watermark()); + font_print(debug_font, 0, 32, "HEAP: {}KB", (alloc.heap.get_watermark() - alloc.heap.get_freed_size()) / 1024); font_print(debug_font, 0, 48, "FREE: {}KB", alloc.heap.get_freed_size() / 1024); @@ -64,8 +62,6 @@ draw :: () { version_str := conv.format(version_buf, "Version: {}.{}", runtime.vars.MAJOR_VERSION, runtime.vars.MINOR_VERSION); font_print(debug_font, ~~window.width - font_get_width(debug_font, version_str), 16, version_str); } - - window->swap_buffers(); } game_draw(); @@ -83,22 +79,13 @@ draw :: () { } run :: () { - last := glfwGetTime(); - now := last; - seconds := 0.0; frame_count := 0; - while !(window->should_close()) { - window->poll_events(); - - now = glfwGetTime(); - dt := now - last; - last = now; - dt = math.clamp(dt, 0, 0.5); - + window->main_loop() { seconds += dt; frame_count += 1; + if seconds >= 1 { game_fps = ~~frame_count; seconds -= 1; diff --git a/src/ogre/canvas.onyx b/src/ogre/canvas.onyx deleted file mode 100644 index 7e85764..0000000 --- a/src/ogre/canvas.onyx +++ /dev/null @@ -1,62 +0,0 @@ -package ogre - -use core -use opengles - - -Canvas :: struct { - width, height: i32; - - framebuffer: GLint; - depth_stencil_buffer: GLint; - color_texture: GLint; -} - -canvas_make :: (width, height: i32) -> Canvas { - canvas: Canvas; - canvas.width = width; - canvas.height = height; - - glGenFramebuffers(1, ^canvas.framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, canvas.framebuffer); - - glGenTextures(1, ^canvas.color_texture); - glBindTexture(GL_TEXTURE_2D, canvas.color_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, null); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, canvas.color_texture, 0); - - glGenRenderbuffers(1, ^canvas.depth_stencil_buffer); - glBindRenderbuffer(GL_RENDERBUFFER, canvas.depth_stencil_buffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, canvas.depth_stencil_buffer); - - if glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE { - printf("[ERROR] Framebuffer is not complete!\n"); - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - return canvas; -} - -canvas_free :: (use canvas: ^Canvas) { - glDeleteFramebuffers(1, ^canvas.framebuffer); - glDeleteTextures(1, ^canvas.color_texture); - glDeleteRenderbuffers(1, ^canvas.depth_stencil_buffer); -} - -canvas_use :: (use canvas: ^Canvas) { - if canvas == null { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - update_view_matrix(global_window.width, global_window.height); - } else { - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - update_view_matrix(width, height); - } -} - -canvas_to_texture :: (canvas: ^Canvas) => Texture.{ canvas.color_texture, canvas.width, canvas.height, 3, "" }; - diff --git a/src/ogre/colors.onyx b/src/ogre/colors.onyx deleted file mode 100644 index 9a7cceb..0000000 --- a/src/ogre/colors.onyx +++ /dev/null @@ -1,56 +0,0 @@ -package ogre - -use core - -Color :: struct { - r, g, b : f32; - a := 1.0f; -} - -color_to_hsl :: (c: Color) -> (h: f32, s: f32, l: f32) { - r := c.r / 255; - g := c.g / 255; - b := c.b / 255; - cmax := math.max(math.max(r, g), b); - cmin := math.min(math.min(r, g), b); - delta := cmax - cmin; - - h := 0.0f; - if cmax == r { - m := (g - b) / delta; - while m >= 6 do m -= 6; - while m < 0 do m += 6; - h = 60 * m; - } - if cmax == g do h = 60 * (b - r) / delta + 2; - if cmax == b do h = 60 * (r - g) / delta + 4; - - l := (cmax + cmin) / 2; - s := delta / (1 - math.abs(2 * l - 1)); - - return h, s, l; -} - -hsl_to_color :: (h, s, l: f32) -> Color { - c := (1 - math.abs(2 * l - 1)) * s; - - h_term := h / 60; - while h_term < 0 do h_term += 2; - while h_term >= 0 do h_term -= 2; - - x := c * (1 - math.abs(h_term - 1)); - m := l - c / 2; - - r, g, b: f32; - if 0 <= h && h < 60 { r = c; g = x; b = 0; } - if 60 <= h && h < 120 { r = x; g = c; b = 0; } - if 120 <= h && h < 180 { r = 0; g = c; b = x; } - if 180 <= h && h < 240 { r = 0; g = x; b = c; } - if 240 <= h && h < 300 { r = x; g = 0; b = c; } - if 300 <= h && h < 360 { r = c; g = 0; b = x; } - - r = (r + m) * 255; - g = (g + m) * 255; - b = (b + m) * 255; - return .{ r, g, b, 1 }; -} diff --git a/src/ogre/font.onyx b/src/ogre/font.onyx deleted file mode 100644 index 9e95308..0000000 --- a/src/ogre/font.onyx +++ /dev/null @@ -1,265 +0,0 @@ -package ogre - -use core -use stb_truetype -use opengles - -#local { - font_registry: Map(FontDescriptor, Font); - font_vbo: GLint; - font_vao: GLint; - - font_shader: Shader; - font_color: Color; -} - -fonts_init :: () { - map.init(^font_registry); - - font_shader = shader_make_from_source(#file_contents "./shaders/font.glsl"); - shader_use(font_shader); - - glGenVertexArrays(1, ^font_vao); - glBindVertexArray(font_vao); - - font_interp_buffer: GLint; - glGenBuffers(1, ^font_interp_buffer); - glBindBuffer(GL_ARRAY_BUFFER, font_interp_buffer); - font_interp_data := f32.[ - 0.0, 0.0, - 1.0, 0.0, - 1.0, 1.0, - 0.0, 1.0, - ]; - glBufferData(GL_ARRAY_BUFFER, sizeof typeof font_interp_data, ~~^font_interp_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * sizeof f32, ~~0); - - font_index_buffer: GLint; - glGenBuffers(1, ^font_index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_index_buffer); - font_index_data := u8.[ 0, 1, 2, 0, 2, 3 ]; - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof typeof font_index_data, ~~^font_index_data, GL_STATIC_DRAW); - - glGenBuffers(1, ^font_vbo); - glBindBuffer(GL_ARRAY_BUFFER, font_vbo); - glBufferData(GL_ARRAY_BUFFER, 1024 * sizeof stbtt_aligned_quad, null, GL_STREAM_DRAW); - - for 1..5 { - glEnableVertexAttribArray(it); - glVertexAttribDivisor(it, 1); - } - glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~ 0); - glVertexAttribPointer(2, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~16); - glVertexAttribPointer(3, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~8); - glVertexAttribPointer(4, 2, GL_FLOAT, false, sizeof stbtt_aligned_quad, ~~24); - - glBindBuffer(GL_ARRAY_BUFFER, -1); - glBindVertexArray(-1); - - font_set_color(.{0,0,0}); -} - - -Font :: struct { - texture: GLint; - texture_width, texture_height: i32; - chars: [] stbtt_packedchar; - em: f32; -} - -font_make :: (fd: FontDescriptor) -> Font { - texture_size :: 256; - - char_data := memory.make_slice(stbtt_packedchar, 96); - - ttf_file := os.get_contents(fd.path); - if ttf_file.count == 0 { - println("Bad font"); - return .{}; - } - defer cfree(ttf_file.data); - - pixels := calloc(texture_size * texture_size); - defer cfree(pixels); - - ctx: stbtt_pack_context; - stbtt_PackBegin(^ctx, pixels, texture_size, texture_size, 0, 1); - stbtt_PackFontRange(^ctx, ttf_file.data, 0, ~~fd.size, #char " ", 96, char_data.data); - stbtt_PackEnd(^ctx); - - texture: GLint; - glGenTextures(1, ^texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture_size, texture_size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); - - font := Font.{ - texture = texture, - texture_width = texture_size, - texture_height = texture_size, - chars = char_data, - em = ~~fd.size, - }; - - font_registry[fd] = font; - - return font; -} - -font_set_color :: (color: Color) { - font_color = color; -} - -font_print :: (font: Font, x, y: f32, format: str, va: ..any) { - buf: [1024] u8; - msg := conv.format_va(buf, format, va); - font_draw(font, x, y, msg); -} - -font_draw :: (font: Font, x, y: f32, msg: str) { - quads: ^stbtt_aligned_quad = alloc.from_stack(msg.count * sizeof stbtt_aligned_quad); - quad_num := 0; - - x_, y_ := x, y; - - for msg { - if it == #char "\n" { - x_ = x; - y_ += font.em + 2; - } - - stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, - ~~(it - #char " "), ^x_, ^y_, ^quads[quad_num], false); - - quad_num += 1; - } - - font_render(font, quads[0 .. quad_num]); -} - -font_draw_centered :: (font: Font, x, y, max_width: f32, msg: str) { - quads: ^stbtt_aligned_quad = alloc.from_stack(msg.count * sizeof stbtt_aligned_quad); - quad_num := 0; - - width := font_get_width(font, msg); - x_, y_ := x, y; - x_ = (max_width - width) / 2 + x; - - for msg { - if it == #char "\n" { - x_ = (max_width - width) / 2 + x; - y_ += font.em + 2; - } - - stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, - ~~(it - #char " "), ^x_, ^y_, ^quads[quad_num], false); - - quad_num += 1; - } - - font_render(font, quads[0 .. quad_num]); -} - -#local font_render :: (font: Font, quads: [] stbtt_aligned_quad) { - // If this is being used in conjunction with the immediate - // rendering system, make sure the immediate objects are flushed - // before trying to render over them. - #if #defined(immediate_flush) { - immediate_flush(); - } - - glBindBuffer(GL_ARRAY_BUFFER, font_vbo); - glBufferSubData(GL_ARRAY_BUFFER, 0, quads.count * sizeof stbtt_aligned_quad, quads.data); - glBindBuffer(GL_ARRAY_BUFFER, -1); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, font.texture); - shader_use(font_shader); - shader_set_uniform(font_shader, #cstr "u_texture", 0); - shader_set_uniform(font_shader, #cstr "u_color", font_color); - - glDisable(GL_DEPTH_TEST); - glBindVertexArray(font_vao); - glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, ~~0, quads.count); - glBindTexture(GL_TEXTURE_2D, -1); - glBindVertexArray(-1); -} - -font_get_width :: (font: Font, msg: str) -> f32 { - x_, y_ := 0.0f, 0.0f; - width := 0.0f; - - quad: stbtt_aligned_quad; - for msg { - if it == #char "\n" { - width = math.max(width, x_); - x_ = 0; - y_ += font.em + 2; - continue; - } - - stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, - ~~(it - #char " "), ^x_, ^y_, ^quad, false); - } - - return math.max(x_, width); -} - -font_get_height :: (font: Font, msg: str) -> f32 { - x_, y_ := 0.0f, 0.0f; - width := 0.0f; - - quad: stbtt_aligned_quad; - for msg { - if it == #char "\n" { - width = math.max(width, x_); - x_ = 0; - y_ += font.em + 2; - continue; - } - - stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, - ~~(it - #char " "), ^x_, ^y_, ^quad, false); - } - - return y_ + font.em + 2; -} - -font_get_char_width :: (font: Font, ch: u8) -> f32 { - x, y := 0.0f, 0.0f; - quad: stbtt_aligned_quad; - - stbtt_GetPackedQuad(font.chars.data, font.texture_width, font.texture_height, - ~~(ch - #char " "), ^x, ^y, ^quad, false); - - return x; -} - - -FontDescriptor :: struct { - path : str; - size : u32; -} - -#match hash.to_u32 (fd: FontDescriptor) => { - name_hash := hash.to_u32(fd.path); - size_hash := hash.to_u32(fd.size); - return name_hash * 13 + size_hash * 17; -} - -#operator == (f1, f2: FontDescriptor) => f1.path == f2.path && f1.size == f2.size; - -font_lookup :: (fd := FontDescriptor.{ "assets/calibri.ttf", 12 }) -> Font { - if font_registry->has(fd) { - return font_registry[fd]; - } - - font := font_make(fd); - font_registry[fd] = font; - return font; -} diff --git a/src/ogre/immediate.onyx b/src/ogre/immediate.onyx deleted file mode 100644 index 0f37c76..0000000 --- a/src/ogre/immediate.onyx +++ /dev/null @@ -1,215 +0,0 @@ -package ogre - -use core -use opengles -use glfw3 - -immediate_init :: () { - memory.alloc_slice(^vertex_data, Maximum_Vertex_Count); - vertex_count = 0; - - imgui_shader = shader_make_from_source(#file_contents "./shaders/imgui.glsl"); - shader_set_uniform(imgui_shader, #cstr "u_texture_enabled", 0.0f); - shader_set_uniform(imgui_shader, #cstr "u_texture", 0); - - immediate_mesh = mesh_make(vertex_data, .[], GL_DYNAMIC_DRAW); - immediate_color = .{0,0,0}; -} - -immediate_flush :: (set_shader := true) { - if vertex_count == 0 do return; - - if set_shader { - shader_use(imgui_shader); - shader_set_uniform(imgui_shader, #cstr "u_texture_enabled", 1.0f if rendering_type == .Image else 0.0f); - } - - immediate_mesh.vertex_count = vertex_count; - mesh_update_verticies(immediate_mesh, vertex_data); - - mesh_draw(immediate_mesh); - - vertex_count = 0; - rendering_type = .Plain; - immediate_mesh.primitive = GL_TRIANGLES; -} - -immediate_clear :: (color: Color) { - glClearColor(color.r, color.g, color.b, color.a); - glClear(GL_COLOR_BUFFER_BIT); -} - -immediate_set_color :: (color: Color) { - immediate_color = color; -} - -immediate_vertex :: (x, y: f32, t_x := 0.0f, t_y := 0.0f) { - if vertex_count >= Maximum_Vertex_Count do immediate_flush(); - set_rendering_type(.Plain); - - vertex_data[vertex_count] = .{ .{x, y}, .{t_x, t_y}, immediate_color }; -} - -immediate_line :: (x1, y1, x2, y2: f32) { - if vertex_count >= Maximum_Vertex_Count do immediate_flush(); - set_rendering_type(.Line); - immediate_mesh.primitive = GL_LINES; - - vertex_data[vertex_count + 0] = .{ .{x1, y1}, .{0, 0}, immediate_color }; - vertex_data[vertex_count + 1] = .{ .{x2, y2}, .{0, 0}, immediate_color }; - vertex_count += 2; -} - -immediate_triangle :: (x1, x2, x3: Vector2) { - if vertex_count + 3 > Maximum_Vertex_Count do immediate_flush(); - set_rendering_type(.Plain); - - vertex_data[vertex_count + 0] = .{ x1, .{0,0}, immediate_color }; - vertex_data[vertex_count + 1] = .{ x2, .{0,0}, immediate_color }; - vertex_data[vertex_count + 2] = .{ x3, .{0,0}, immediate_color }; - vertex_count += 3; -} - -immediate_rectangle :: (x, y, w, h: f32) { - if vertex_count + 6 > Maximum_Vertex_Count do immediate_flush(); - set_rendering_type(.Plain); - - vertex_data[vertex_count + 0] = .{ .{x, y}, .{0,0}, immediate_color }; - vertex_data[vertex_count + 1] = .{ .{x+w, y}, .{0,0}, immediate_color }; - vertex_data[vertex_count + 2] = .{ .{x+w, y+h}, .{0,0}, immediate_color }; - vertex_data[vertex_count + 3] = .{ .{x, y}, .{0,0}, immediate_color }; - vertex_data[vertex_count + 4] = .{ .{x+w, y+h}, .{0,0}, immediate_color }; - vertex_data[vertex_count + 5] = .{ .{x, y+h}, .{0,0}, immediate_color }; - vertex_count += 6; -} - -immediate_image :: (image: ^Texture, x, y, w, h: f32) { - if vertex_count > 0 do immediate_flush(); - - set_rendering_type(.Image); - texture_use(image); - shader_use(imgui_shader); - shader_set_uniform(imgui_shader, #cstr "u_texture", 0); - - vertex_data[vertex_count + 0] = .{ .{x, y}, .{0,0}, immediate_color }; - vertex_data[vertex_count + 1] = .{ .{x+w, y}, .{1,0}, immediate_color }; - vertex_data[vertex_count + 2] = .{ .{x+w, y+h}, .{1,1}, immediate_color }; - vertex_data[vertex_count + 3] = .{ .{x, y}, .{0,0}, immediate_color }; - vertex_data[vertex_count + 4] = .{ .{x+w, y+h}, .{1,1}, immediate_color }; - vertex_data[vertex_count + 5] = .{ .{x, y+h}, .{0,1}, immediate_color }; - vertex_count += 6; -} - -immediate_subimage :: (image: ^Texture, x, y, w, h: f32, tx, ty, tw, th: f32) { - if vertex_count > 0 do immediate_flush(); - - set_rendering_type(.Image); - texture_use(image); - shader_use(imgui_shader); - shader_set_uniform(imgui_shader, #cstr "u_texture", 0); - - sx := tx / ~~ image.width; - sy := ty / ~~ image.height; - sw := tw / ~~ image.width; - sh := th / ~~ image.height; - - vertex_data[vertex_count + 0] = .{ .{x, y}, .{sx, sy}, immediate_color }; - vertex_data[vertex_count + 1] = .{ .{x+w, y}, .{sx+sw, sy}, immediate_color }; - vertex_data[vertex_count + 2] = .{ .{x+w, y+h}, .{sx+sw,sy+sh}, immediate_color }; - vertex_data[vertex_count + 3] = .{ .{x, y}, .{sx, sy}, immediate_color }; - vertex_data[vertex_count + 4] = .{ .{x+w, y+h}, .{sx+sw,sy+sh}, immediate_color }; - vertex_data[vertex_count + 5] = .{ .{x, y+h}, .{sx, sy+sh}, immediate_color }; - vertex_count += 6; -} - -immediate_ellipse :: () {} - -immediate_push_scissor :: (x, y, w, h: f32) { - if vertex_count > 0 do immediate_flush(); - - // Assuming that x, y, w, and h are in screen (window) coordinates. - x += offset.x; - y += offset.y; - - xi := cast(i32) x; - yi := cast(i32) y; - wi := cast(i32) w; - hi := cast(i32) h; - scissors << .{xi, yi, wi, hi}; - - glEnable(GL_SCISSOR_TEST); - glScissor(xi, global_window.height - yi - hi, wi, hi); -} - -immediate_pop_scissor :: () { - if scissors.count > 0 { - array.pop(^scissors); - } - - if scissors.count > 0 { - glEnable(GL_SCISSOR_TEST); - s := scissors[scissors.count - 1]; - glScissor(s.x, global_window.height - s.y - s.h, s.w, s.h); - } else { - glDisable(GL_SCISSOR_TEST); - } -} - -immediate_set_scroll :: (scroll_x, scroll_y: f32) { - offset = .{ scroll_x, scroll_y }; - update_model_matrix(offset); -} - -immediate_get_scroll :: () => offset; - -Immediate_Vertex :: struct { - pos: Vector2; - tex: Vector2; - color: Color; -} - -#local { - imgui_shader: Shader; - - Maximum_Vertex_Count :: 1023; - vertex_count: i32; - vertex_data: [] Immediate_Vertex; - - immediate_color: Color; - - immediate_mesh: ^Mesh(Immediate_Vertex); - - Rendering_Type :: enum { - Plain; - Line; - Image; - } - rendering_type := Rendering_Type.Plain; - - Scissor :: struct { - x, y, w, h: i32; - } - scissors: [..] Scissor; - - offset: Vector2; - - set_rendering_type :: (new_type: typeof rendering_type) { - if rendering_type != new_type { - immediate_flush(); - rendering_type = new_type; - } - } -} - - - -// @Relocate -move_towards :: (v: ^$T, target: T, diff: T) { - if math.abs(target - *v) <= diff { - *v = target; - return; - } - - if *v < target do *v += diff; - if *v > target do *v -= diff; -} diff --git a/src/ogre/input.onyx b/src/ogre/input.onyx deleted file mode 100644 index 38d656e..0000000 --- a/src/ogre/input.onyx +++ /dev/null @@ -1,186 +0,0 @@ -package ogre - -use package core -use package glfw3 - -// If you are offseting the mouse coordinate for world space -// or UI scrolling etc., set this function to be the function -// to ask for the current offset. Currently scaling the mouse -// coordinate is not supported, only linear translations. -Mouse_Offset_Function :: immediate_get_scroll - - -#local { - keys_this_frame : Set(Key_Descriptor) // Keys currently being pressed this frame - keys_last_frame : Set(Key_Descriptor) // Keys being pressed in the last frame - - key_codepoints : [..] u32 - - buttons_this_frame: [8] bool // Mouse buttons being pressed this frame - buttons_last_frame: [8] bool // Mouse buttons being pressed last frame - - scroll_x: f64 - scroll_y: f64 - - character_mode := false; -} - -#init () { - set.init(^keys_this_frame); - set.init(^keys_last_frame); -} - -Key_Descriptor :: struct { - key: u32; - scancode: u32 = 0; - mod: u32 = 0; -} -#match hash.to_u32 (use x: Key_Descriptor) => hash.to_u32(key); -#operator == (x, y: Key_Descriptor) => x.key == y.key; - -input_update :: () { - glfwGetCursorPos(global_window.glfw_window, ^mouse_x, ^mouse_y); -} - -input_post_update :: () { - set.clear(^keys_last_frame); - for keys_this_frame.entries do keys_last_frame << it.value; - - for 8 do buttons_last_frame[it] = buttons_this_frame[it]; - - last_mouse_x = mouse_x; - last_mouse_y = mouse_y; - scroll_x = 0; - scroll_y = 0; - - array.clear(^key_codepoints); -} - -input_get_chars_this_frame :: () -> [] u32 { - return key_codepoints; -} - -input_get_keys_this_frame :: () -> Iterator(Key_Descriptor) { - #persist index := 0; - - next :: (_: rawptr) -> (Key_Descriptor, bool) { - if index >= keys_this_frame.entries.count do return .{0}, false; - - while keys_last_frame->has(keys_this_frame.entries[index].value) { - index += 1; - if index >= keys_this_frame.entries.count do return .{0}, false; - } - - defer index += 1; - return keys_this_frame.entries[index].value, true; - } - - index = 0; - return .{ null, next }; -} - -input_capture_keys :: () { - character_mode = true; -} - -input_release_keys :: () { - character_mode = false; -} - -is_key_down :: (key) => !character_mode && set.has(^keys_this_frame, .{key}); -is_key_just_down :: (key) => !character_mode && set.has(^keys_this_frame, .{key}) && !set.has(^keys_last_frame, .{key}); -is_key_just_up :: (key) => !character_mode && !set.has(^keys_this_frame, .{key}) && set.has(^keys_last_frame, .{key}); - -is_button_down :: (button) => buttons_this_frame[button]; -is_button_just_down :: (button) => buttons_this_frame[button] && !buttons_last_frame[button]; -is_button_just_up :: (button) => !buttons_this_frame[button] && buttons_last_frame[button]; - -#local { - last_mouse_x: f64; - last_mouse_y: f64; - - mouse_x: f64; - mouse_y: f64; -} - -mouse_get_delta :: () -> (f64, f64) { - return mouse_x - last_mouse_x, mouse_y - last_mouse_y; -} - -mouse_get_delta_vector :: () -> Vector2 { - dmx, dmy := mouse_get_delta(); - return .{ ~~dmx, ~~dmy }; -} - -mouse_get_position :: () -> (f64, f64) { - mx, my := mouse_x, mouse_y; - #if #defined(Mouse_Offset_Function) { - scroll := Mouse_Offset_Function(); - mx -= ~~ scroll.x; - my -= ~~ scroll.y; - } - return mx, my; -} - -mouse_get_position_vector :: () -> Vector2 { - mx, my := mouse_x, mouse_y; - #if #defined(Mouse_Offset_Function) { - scroll := Mouse_Offset_Function(); - mx -= ~~ scroll.x; - my -= ~~ scroll.y; - } - return .{ ~~mx, ~~my }; -} - -mouse_get_scroll :: () -> (f64, f64) { - return scroll_x, scroll_y; -} - -mouse_get_scroll_vector :: () -> Vector2 { - return .{ ~~scroll_x, ~~scroll_y }; -} - -input_bind_glfw_events :: (window: GLFWwindow_p) { - glfwSetKeyCallback(window, #export_name input_key_event); - glfwSetCharCallback(window, #export_name input_char_event); - glfwSetMouseButtonCallback(window, #export_name input_button_event); - glfwSetScrollCallback(window, #export_name input_scroll_event); -} - -#local -input_button_event :: (window: GLFWwindow_p, button, action, mod: u32) { - if action == GLFW_PRESS { - buttons_this_frame[button] = true; - } - - if action == GLFW_RELEASE { - buttons_this_frame[button] = false; - } -} - -#local -input_key_event :: (window: GLFWwindow_p, key, scancode, action, mod: u32) { - if action == GLFW_PRESS { - keys_this_frame << .{ key, scancode, mod }; - } - - if action == GLFW_REPEAT { - set.remove(^keys_last_frame, .{key}); - } - - if action == GLFW_RELEASE { - set.remove(^keys_this_frame, .{ key }); - } -} - -#local -input_char_event :: (window: GLFWwindow_p, codepoint: u32) { - if !character_mode do return; - key_codepoints << codepoint; -} - -#local -input_scroll_event :: (window: GLFWwindow_p, xoff, yoff: f64) { - scroll_x = xoff; - scroll_y = yoff; -} diff --git a/src/ogre/mesh.onyx b/src/ogre/mesh.onyx deleted file mode 100644 index ba926aa..0000000 --- a/src/ogre/mesh.onyx +++ /dev/null @@ -1,90 +0,0 @@ -package ogre - -use core -use opengles - -Mesh :: struct (Vertex_Type: type_expr) { - handle: GLint; - vertex_handle: GLint; - index_handle: GLint; - - vertex_count: u32; - index_count: u32; - primitive: GLuint = GL_TRIANGLES; -} - -mesh_make :: (verticies: [] $T, indicies: [] u32, gl_hint := GL_STATIC_DRAW) -> ^Mesh(T) { - mesh := new(Mesh(T)); - mesh.vertex_count = verticies.count; - mesh.index_count = indicies.count; - - glGenVertexArrays(1, ^mesh.handle); - glBindVertexArray(mesh.handle); - - glGenBuffers(1, ^mesh.vertex_handle); - glBindBuffer(GL_ARRAY_BUFFER, mesh.vertex_handle); - glBufferData(GL_ARRAY_BUFFER, sizeof T * verticies.count, verticies.data, gl_hint); - - type_info :: runtime.info - vertex_info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(T); - vertex_attr := 0; - for attr: vertex_info.members { - defer vertex_attr += 1; - glEnableVertexAttribArray(vertex_attr); - - switch attr.type { - case Vector2 do glVertexAttribPointer(vertex_attr, 2, GL_FLOAT, false, sizeof T, ~~attr.offset); - case Vector3 do glVertexAttribPointer(vertex_attr, 3, GL_FLOAT, false, sizeof T, ~~attr.offset); - case u32 do glVertexAttribIPointer(vertex_attr, 1, GL_UNSIGNED_INT, sizeof T, ~~attr.offset); - case i32 do glVertexAttribIPointer(vertex_attr, 1, GL_INT, sizeof T, ~~attr.offset); - - // It would be nice to not have to have all the cases here. - // Instead allow for an extensible way of defining them at compile time. - case Color do glVertexAttribPointer(vertex_attr, 4, GL_FLOAT, false, sizeof T, ~~attr.offset); - - case #default { - buf: [256] u8; - msg := conv.str_format(buf, "Unknown type for GL vertex attribute, {}.", attr.type); - assert(false, msg); - } - } - } - - if indicies.count > 0 { - glGenBuffers(1, ^mesh.index_handle); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.index_handle); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof i32 * indicies.count, indicies.data, gl_hint); - } - - glBindVertexArray(-1); - - return mesh; -} - -mesh_update_verticies :: (use mesh: ^Mesh, verticies: [] mesh.Vertex_Type) { - // @TODO // Add bounds checking to arrays here. - - glBindBuffer(GL_ARRAY_BUFFER, vertex_handle); - glBufferSubData(GL_ARRAY_BUFFER, 0, verticies.count * sizeof mesh.Vertex_Type, verticies.data); - glBindBuffer(GL_ARRAY_BUFFER, -1); -} - -mesh_draw :: (use mesh: ^Mesh) { - glBindVertexArray(handle); - if index_count > 0 { - glDrawElements(primitive, index_count, GL_UNSIGNED_INT, ~~0); - } else { - glDrawArrays(primitive, 0, vertex_count); - } - glBindVertexArray(-1); -} - -mesh_free :: (mesh: ^Mesh) { - glDeleteBuffers(1, ^mesh.vertex_handle); - glDeleteBuffers(1, ^mesh.index_handle); - glDeleteVertexArrays(1, ^mesh.handle); - cfree(mesh); -} - - - diff --git a/src/ogre/ogre.onyx b/src/ogre/ogre.onyx deleted file mode 100644 index 4fd1082..0000000 --- a/src/ogre/ogre.onyx +++ /dev/null @@ -1,17 +0,0 @@ -package ogre - -use glfw3 {glfwInit} - -ogre_init :: () -> bool { - if !glfwInit() { - return false; - } - - return true; -} - -ogre_setup :: () { - shaders_init(); - fonts_init(); - immediate_init(); -} diff --git a/src/ogre/shader.onyx b/src/ogre/shader.onyx deleted file mode 100644 index b6bf3fa..0000000 --- a/src/ogre/shader.onyx +++ /dev/null @@ -1,193 +0,0 @@ -package ogre - -use core -use opengles - -Shader :: struct { - vs, fs: GLuint; - prog: GLuint; -} - -window_matrix_block_buffer: GLuint; -world_matrix_block_buffer: GLuint; - -shaders_init :: () { - glGenBuffers(1, ^window_matrix_block_buffer); - glGenBuffers(1, ^world_matrix_block_buffer); - - glBindBuffer(GL_UNIFORM_BUFFER, window_matrix_block_buffer); - glBufferData(GL_UNIFORM_BUFFER, sizeof f32 * 16, null, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_UNIFORM_BUFFER, world_matrix_block_buffer); - glBufferData(GL_UNIFORM_BUFFER, sizeof f32 * (16 + 16), null, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_UNIFORM_BUFFER, -1); - - glBindBufferBase(GL_UNIFORM_BUFFER, WINDOW_MATRIX_BLOCK, window_matrix_block_buffer); - glBindBufferBase(GL_UNIFORM_BUFFER, WORLD_MATRIX_BLOCK, world_matrix_block_buffer); -} - -shader_make :: (shader_path: str) -> Shader { - shader_source := os.get_contents(shader_path); - return shader_make_from_source(shader_source); -} - -shader_make_from_source :: (shader_source: str) -> Shader { - vs := compile_shader(shader_source, GL_VERTEX_SHADER); - fs := compile_shader(shader_source, GL_FRAGMENT_SHADER); - - prog := link_program(vs, fs); - - s := Shader.{vs, fs, prog}; - shader_link_window_matrix_block(s); - shader_link_world_matrix_block(s); - - return s; -} - -shader_use :: (shader: Shader) { - glUseProgram(shader.prog); -} - -#local { - WINDOW_MATRIX_BLOCK :: 0; - WORLD_MATRIX_BLOCK :: 1; -} - -shader_link_window_matrix_block :: (use shader: Shader) { - matrix_block_index := glGetUniformBlockIndex(prog, #cstr "u_window_matrix_block"); - if matrix_block_index == GL_INVALID_INDEX do return; - - glUniformBlockBinding(prog, matrix_block_index, WINDOW_MATRIX_BLOCK); -} - -shader_link_world_matrix_block :: (use shader: Shader) { - matrix_block_index := glGetUniformBlockIndex(prog, #cstr "u_world_matrix_block"); - if matrix_block_index == GL_INVALID_INDEX do return; - - glUniformBlockBinding(prog, matrix_block_index, WORLD_MATRIX_BLOCK); -} - -shader_set_uniform :: (shader: Shader, uniform: cstr, value: $T) { - glUseProgram(shader.prog); - location := glGetUniformLocation(shader.prog, uniform); - - set_uniform_internal(location, value); - - set_uniform_internal :: #match { - macro (location: GLint, value: u32) do glUniform1i(location, value); , - macro (location: GLint, value: f32) do glUniform1f(location, value); , - macro (location: GLint, value: Vector2) do glUniform2f(location, value.x, value.y); , - macro (location: GLint, value: Vector3) do glUniform3f(location, value.x, value.y, value.z); , - macro (location: GLint, value: Color) do glUniform4f(location, value.r, value.g, value.b, value.a); , - - macro (location: GLint, value: $T) { - buffer: [1024] u8; - assert(false, conv.format(buffer, "Bad shader_set_uniform case: {}", T)); - } - } -} - -update_view_matrix :: (width, height: u32) { - matrix : [16] f32; - top := 0.0f; - left := 0.0f; - right := cast(f32) width; - bottom := cast(f32) height; - far := 10.0f; - near := 0f; - - matrix[0] = 2 / (right - left); - matrix[5] = 2 / (top - bottom); - matrix[10] = -2 / (far - near); - matrix[12] = -(right + left) / (right - left); - matrix[13] = -(top + bottom) / (top - bottom); - matrix[14] = -(far + near) / (far - near); - matrix[15] = 1; - - glBindBuffer(GL_UNIFORM_BUFFER, window_matrix_block_buffer); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof typeof matrix, ^matrix); - glBindBuffer(GL_UNIFORM_BUFFER, -1); - - glViewport(0, 0, width, height); -} - -update_world_matrix :: () { - world_mat: [16] f32; - world_mat[0] = 1; - world_mat[5] = 1; - world_mat[10] = 1; - world_mat[15] = 1; - - glBindBuffer(GL_UNIFORM_BUFFER, world_matrix_block_buffer); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof typeof world_mat, ^world_mat); - glBindBuffer(GL_UNIFORM_BUFFER, -1); -} - -update_model_matrix :: (v: Vector2) { - model_mat: [16] f32; - model_mat[0] = 1; - model_mat[5] = 1; - model_mat[10] = 1; - model_mat[12] = v.x; - model_mat[13] = v.y; - model_mat[14] = 0; - model_mat[15] = 1; - - glBindBuffer(GL_UNIFORM_BUFFER, world_matrix_block_buffer); - glBufferSubData(GL_UNIFORM_BUFFER, 16 * sizeof f32, sizeof typeof model_mat, ^model_mat); - glBindBuffer(GL_UNIFORM_BUFFER, -1); -} - - -#local { - compile_shader :: (source: str, type: GLenum) -> GLint { - shader := glCreateShader(type); - - #persist VERTEX_HEADER := """ -#version 300 es -#define VERTEX_SHADER 1 -#define COMM out - """; - - #persist FRAGMENT_HEADER := """ -#version 300 es -#define FRAGMENT_SHADER 1 -#define COMM in - """; - - header := VERTEX_HEADER if type == GL_VERTEX_SHADER else FRAGMENT_HEADER; - sources : [] cptr(u8) = .[ cptr.make(header.data), cptr.make(source.data) ]; - source_lens : [] i32 = .[ header.count, source.count ]; - - glShaderSource(shader, 2, sources.data, source_lens.data); - glCompileShader(shader); - - success: GLint; - if glGetShaderiv(shader, GL_COMPILE_STATUS, ^success); success == GL_FALSE { - buf_data: [2048] u8; - buf := str.{ ~~buf_data, 0 }; - glGetShaderInfoLog(shader, 2048, ^buf.count, buf.data); - println(buf); - } - - return shader; - } - - link_program :: (vertex_shader, fragment_shader: GLint) -> GLuint { - prog := glCreateProgram(); - glAttachShader(prog, vertex_shader); - glAttachShader(prog, fragment_shader); - glLinkProgram(prog); - - success: GLint; - if glGetProgramiv(prog, GL_LINK_STATUS, ^success); success == GL_FALSE { - buf_data: [1024] u8; - buf := str.{ ~~buf_data, 0 }; - glGetProgramInfoLog(prog, 1024, ^buf.count, buf.data); - println(buf); - } - - return prog; - } -} diff --git a/src/ogre/shaders/font.glsl b/src/ogre/shaders/font.glsl deleted file mode 100644 index 8fdf5c9..0000000 --- a/src/ogre/shaders/font.glsl +++ /dev/null @@ -1,40 +0,0 @@ -precision mediump float; - -COMM vec2 v_texture; - -#ifdef VERTEX_SHADER - -layout(location = 0) in vec2 a_interp; -layout(location = 1) in vec2 a_pos_top_left; -layout(location = 2) in vec2 a_pos_bottom_right; -layout(location = 3) in vec2 a_tex_top_left; -layout(location = 4) in vec2 a_tex_bottom_right; - -layout(std140) uniform u_window_matrix_block { - mat4 u_window; -}; - -layout(std140) uniform u_world_matrix_block { - mat4 u_world; - mat4 u_model; -}; - -void main() { - gl_Position = u_window * u_world * u_model * vec4(mix(a_pos_top_left, a_pos_bottom_right, a_interp), 0, 1); - v_texture = mix(a_tex_top_left, a_tex_bottom_right, a_interp); -} - -#endif - -#ifdef FRAGMENT_SHADER - -uniform sampler2D u_texture; -uniform vec4 u_color; - -out vec4 fragColor; - -void main() { - fragColor = vec4(u_color.rgb, u_color.a * texture(u_texture, v_texture).a); -} - -#endif diff --git a/src/ogre/shaders/imgui.glsl b/src/ogre/shaders/imgui.glsl deleted file mode 100644 index 26c0260..0000000 --- a/src/ogre/shaders/imgui.glsl +++ /dev/null @@ -1,40 +0,0 @@ -precision mediump float; - -COMM vec4 v_col; -COMM vec2 v_tex; - -#ifdef VERTEX_SHADER - -layout(location = 0) in vec2 a_pos; -layout(location = 1) in vec2 a_tex; -layout(location = 2) in vec4 a_col; - -layout(std140) uniform u_window_matrix_block { - mat4 u_window; -}; - -layout(std140) uniform u_world_matrix_block { - mat4 u_world; - mat4 u_model; -}; - -void main() { - gl_Position = u_window * u_world * u_model * vec4(a_pos, 0, 1); - v_tex = a_tex; - v_col = a_col; -} - -#endif - -#ifdef FRAGMENT_SHADER - -uniform sampler2D u_texture; -uniform float u_texture_enabled; - -out vec4 fragColor; - -void main() { - fragColor = v_col * mix(vec4(1), texture(u_texture, v_tex), vec4(u_texture_enabled)); -} - -#endif diff --git a/src/ogre/texture.onyx b/src/ogre/texture.onyx deleted file mode 100644 index dbf3157..0000000 --- a/src/ogre/texture.onyx +++ /dev/null @@ -1,91 +0,0 @@ -package ogre - -use core -use opengles -use stb_image - -#local texture_cache: Map(str, Texture); - -Texture :: struct { - texture: GLint; - width, height, channels: i32; - filename: str; -} - -texture_lookup :: #match #local {} - -#overload -texture_lookup :: (filename: str) -> (Texture, bool) { - if texture_cache->has(filename) { - return texture_cache[filename], true; - } - - buffer: [512] u8; - memory.copy(~~ buffer, filename.data, math.min(filename.count, 511)); - return texture_lookup(cast(cstr) buffer); -} - -#overload -texture_lookup :: (path: cstr) -> (Texture, bool) { - filename := string.from_cstr(path); - if texture_cache->has(filename) { - return texture_cache[filename], true; - } - - tex: Texture; - tex.filename = filename; - pixels := stbi_load(path, ^tex.width, ^tex.height, ^tex.channels, 4); - if pixels == null { - printf("[WARN ] Failed to load texture: {}\n", filename); - return .{}, false; - } - defer stbi_image_free(pixels); - - glGenTextures(1, ^tex.texture); - glBindTexture(GL_TEXTURE_2D, tex.texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Are these sensible defaults? - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindTexture(GL_TEXTURE_2D, 0); - - // This assumes that the filename data is going to be persistant forever. - // Not a great assumption to make but is it really worth copying it? - texture_cache[filename] = tex; - printf("[INFO ] Loaded texture: {}\n", filename); - return tex, true; -} - -texture_free :: (use tex: ^Texture) { - glDeleteTextures(1, ^texture); -} - -texture_use :: (use tex: ^Texture, texture_binding := 0) { - glActiveTexture(GL_TEXTURE0 + texture_binding); - glBindTexture(GL_TEXTURE_2D, texture); -} - - -Texture_Wrap :: enum { - Clamp :: GL_CLAMP_TO_EDGE | 0; - Repeat :: GL_REPEAT | 0; - Mirrored_Repeat :: GL_MIRRORED_REPEAT | 0; -} - -texture_wrap :: (use tex: ^Texture, wrap: Texture_Wrap) { - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ~~ wrap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ~~ wrap); -} - -texture_cache_clear :: () { - for^ texture_cache.entries { - glDeleteTextures(1, ^it.value.texture); - } - - map.clear(^texture_cache); -} diff --git a/src/ogre/ui.onyx b/src/ogre/ui.onyx deleted file mode 100644 index 1242f11..0000000 --- a/src/ogre/ui.onyx +++ /dev/null @@ -1,731 +0,0 @@ -package ogre.ui - -// -// Very simple immediate mode UI -// - -use core -use opengles -use glfw3 -use ogre - -UI_Id :: u32 - -ui_end_frame :: () { - hot_item_depth_needed = hot_item_depth; - if !hot_item_was_set do set_hot_item(0); - hot_item_depth = 0; - hot_item_was_set = false; - - for^ animation_states.entries { - if !it.value.accessed_this_frame || (it.value.click_time == 0 && it.value.hover_time == 0) { - map.delete(^animation_states, it.key); - } - } - - for^ animation_states.entries { - it.value.accessed_this_frame = false; - } - - if active_countdown > 0 { - active_countdown -= 1; - if active_countdown == 0 { - set_active_item(0); - input_release_keys(); - } - } -} - -// -// Buttons -// -Button_Theme :: struct { - use text_theme := Text_Theme.{}; - use animation_theme := Animation_Theme.{}; - - background_color := Color.{ 0.1, 0.1, 0.1 }; - hover_color := Color.{ 0.3, 0.3, 0.3 }; - click_color := Color.{ 0.5, 0.5, 0.7 }; - - border_color := Color.{0.2, 0.2, 0.2}; - border_width := 2.0f; - - active := false; -} - -#local default_button_theme := Button_Theme.{}; - -draw_button :: (use r: Rect, text: str, theme := ^default_button_theme, site := #callsite, increment := 0) -> bool { - result := false; - - hash := get_site_hash(site, increment); - animation_state := get_animation(hash); - mx, my := mouse_get_position(); - - contains := Rect.contains(r, .{~~mx, ~~my}); - - if is_active_item(hash) { - renew_active_item(hash); - if is_button_just_up(GLFW_MOUSE_BUTTON_LEFT) { - if is_hot_item(hash) && contains { - result = true; - animation_state.click_time = 1.0f; - } - - set_active_item(0); - } - } elseif is_hot_item(hash) { - if is_button_down(GLFW_MOUSE_BUTTON_LEFT) { - set_active_item(hash); - } - } - - if contains { - set_hot_item(hash); - } - - if is_hot_item(hash) || theme.active { - move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed); - } else { - move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed); - } - - border_width := theme.border_width; - - immediate_set_color(theme.border_color); - immediate_rectangle(x, y, w, h); - - surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color); - surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color); - immediate_set_color(surface_color); - immediate_rectangle(x + border_width, y + border_width, w - border_width * 2, h - border_width * 2); - - font := font_lookup(.{theme.font_name, theme.font_size}); - font_height := font_get_height(font, text); - font_set_color(theme.text_color); - font_draw_centered(font, x, y + (h - font_height) / 2 + font.em - 2, w, text); - - move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed); - - return result; -} - - -// -// Sliders -// -Slider_Theme :: struct { - use text_theme := Text_Theme.{}; - use animation_theme := Animation_Theme.{}; - - box_color := Color.{ 0.1, 0.1, 0.1 }; - box_border_color := Color.{ 0.2, 0.2, 0.2 }; - box_border_width := 4.0f; // @InPixels - - bar_color := Color.{ 0.4, 0.4, 0.4 }; - bar_hover_color := Color.{ 0, 0, 1 }; - bar_hover_negative_color := Color.{ 1, 0, 0 }; // The color when value is less than 0 -} - -#local default_slider_theme := Slider_Theme.{}; - -draw_slider :: (use r: Rect, value: ^$T, min_value: T, max_value: T, theme := ^default_slider_theme, site := #callsite, increment := 0) -> bool { - result := false; - - hash := get_site_hash(site, increment); - state := get_animation(hash); - mx, my := mouse_get_position(); - - if is_hot_item(hash) { - if is_button_down(GLFW_MOUSE_BUTTON_LEFT) { - set_active_item(hash); - result = true; - - // Animate this? - sx := ~~mx - x; - - if T == i32 || T == i64 || T == u32 || T == u64 { - step_width := w / ~~math.abs(max_value - min_value); - percent := (sx + step_width / 2) / w; - *value = math.lerp(percent, min_value, max_value); - *value = math.clamp(*value, min_value, max_value); - - } else { - percent := sx / w; - *value = math.lerp(percent, min_value, max_value); - *value = math.clamp(*value, min_value, max_value); - } - } else { - set_active_item(0); - } - } - - if Rect.contains(r, .{ ~~mx, ~~my }) { - set_hot_item(hash); - } - - if is_hot_item(hash) { - move_towards(^state.hover_time, 1.0f, theme.hover_speed); - } else { - move_towards(^state.hover_time, 0.0f, theme.hover_speed); - } - - box_border_width := theme.box_border_width; - - bar_color := theme.bar_color; - if *value < 0 do bar_color = color_lerp(state.hover_time, bar_color, theme.bar_hover_negative_color); - else do bar_color = color_lerp(state.hover_time, bar_color, theme.bar_hover_color); - - immediate_set_color(theme.box_border_color); - immediate_rectangle(x, y, w, h); - - immediate_set_color(theme.box_border_color); - immediate_rectangle(x + box_border_width, y + box_border_width, w - box_border_width * 2, h - box_border_width * 2); - - box_width := cast(f32) (*value - min_value) / ~~(max_value - min_value); - box_width *= w - box_border_width * 2; - box_width = math.clamp(box_width, 0, w - box_border_width * 2); - immediate_set_color(bar_color); - immediate_rectangle(x + box_border_width, y + box_border_width, box_width, h - box_border_width * 2); - - return result; -} - -// -// Textbox -// -Textbox_Theme :: struct { - use text_theme := Text_Theme.{ - text_color = .{ 0, 0, 0 } - }; - - use animation_theme := Animation_Theme.{}; - - background_color := Color.{ 0.8, 0.8, 0.8 }; - hover_color := Color.{ 1.0, 1.0, 1.0 }; - click_color := Color.{ 0.5, 0.5, 0.7 }; - - border_color := Color.{ 0.2, 0.2, 0.2 }; - border_width := 6.0f; // @InPixels - - cursor_color := Color.{ 0.5, 0.5, 0.5 }; - cursor_width := 4.0f; // @InPixels - cursor_blink_speed := 0.04f; // Bigger is faster - - placeholder_text_color := Color.{ 0.5, 0.5, 0.5 }; -} - -#local { - default_textbox_theme := Textbox_Theme.{}; - - Textbox_Editing_State :: struct { - hash: UI_Id = 0; - - cursor_position: i32 = 0; - cursor_animation := 0.0f; - cursor_animation_speed := 0.02f; - - // @HACK // Otherwise the action keys are evaluated every frame. - action_key_timeout := 0.0f; - } - - textbox_editing_state := Textbox_Editing_State.{}; -} - -draw_textbox :: (use r: Rect, text_buffer: ^[..] u8, placeholder := null_str, theme := ^default_textbox_theme, site := #callsite, increment := 0) -> bool { - result := false; - - hash := get_site_hash(site, increment); - animation_state := get_animation(hash); - mx, my := mouse_get_position(); - - border_width := theme.border_width; - text_color := theme.text_color; - text := str.{text_buffer.data, text_buffer.count}; - if text.count == 0 && placeholder.count > 0 { - text = placeholder; - text_color = theme.placeholder_text_color; - } - - font := font_lookup(.{theme.font_name, theme.font_size}); - text_width := font_get_width(font, text); - text_height := font_get_height(font, text); - - text_x := x + border_width; - text_y := y + font.em + (h - text_height) / 2; - - contains := Rect.contains(r, .{~~mx, ~~my}); - - if is_hot_item(hash) && !is_active_item(hash) { - if is_button_down(GLFW_MOUSE_BUTTON_LEFT) && contains { - set_active_item(hash); - input_capture_keys(); - textbox_editing_state.hash = hash; - textbox_editing_state.cursor_animation_speed = theme.cursor_blink_speed; - } - } - - if is_active_item(hash) { - renew_active_item(hash); - if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) && !contains { - set_active_item(0); - input_release_keys(); - textbox_editing_state.hash = 0; - textbox_editing_state.cursor_position = 0; - } - } - - if contains { - set_hot_item(hash); - } - - if textbox_editing_state.hash == hash { - move_towards(^textbox_editing_state.cursor_animation, 0.0f, textbox_editing_state.cursor_animation_speed); - if textbox_editing_state.cursor_animation <= 0.0f do textbox_editing_state.cursor_animation = 1.0f; - - if is_button_down(GLFW_MOUSE_BUTTON_LEFT) && contains { - textbox_editing_state.cursor_animation = 1.0f; - textbox_editing_state.cursor_position = screen_to_cursor(^font, text_x, text_y, text, ~~mx, ~~my); - } - - for key: input_get_keys_this_frame() { - switch key.key { - case GLFW_KEY_ESCAPE { - set_active_item(0); - input_release_keys(); - } - - case GLFW_KEY_LEFT do textbox_editing_state.cursor_position -= 1; - case GLFW_KEY_RIGHT do textbox_editing_state.cursor_position += 1; - case GLFW_KEY_END do textbox_editing_state.cursor_position = text_buffer.count; - case GLFW_KEY_HOME do textbox_editing_state.cursor_position = 0; - - case GLFW_KEY_BACKSPACE { - if textbox_editing_state.cursor_position > 0 { - array.delete(text_buffer, textbox_editing_state.cursor_position - 1); - } - textbox_editing_state.cursor_position = math.max(~~0, textbox_editing_state.cursor_position - 1); - } - - case GLFW_KEY_DELETE { - array.delete(text_buffer, textbox_editing_state.cursor_position); - } - } - } - - for ch: input_get_chars_this_frame() { - array.insert(text_buffer, textbox_editing_state.cursor_position, ~~ch); - textbox_editing_state.cursor_position += 1; - result = true; - } - - textbox_editing_state.cursor_position = math.clamp(textbox_editing_state.cursor_position, 0, text_buffer.count); - textbox_editing_state.cursor_animation = 1.0f; - - text = str.{text_buffer.data, text_buffer.count}; - } - - if is_hot_item(hash) { - move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed); - } else { - move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed); - } - - immediate_push_scissor(x, y, w, h); - immediate_set_color(theme.border_color); - immediate_rectangle(x, y, w, h); - - surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color); - surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color); - immediate_set_color(surface_color); - immediate_rectangle(x + border_width, y + border_width, w - border_width * 2, h - border_width * 2); - - // Draw the cursor on textboxes - if is_active_item(hash) { - cursor := cursor_to_screen(^font, x + border_width, y + border_width, text, textbox_editing_state.cursor_position); - right_edge := x + w - border_width * 2; - if cursor.x > right_edge { - text_x -= cursor.x - right_edge; - cursor.x = right_edge - 2; - } - immediate_set_color(.{0,0,0}); - immediate_rectangle(cursor.x, cursor.y + 2, 2, h - border_width * 2 - 4); - } - - font_set_color(theme.text_color); - font_draw(font, text_x, text_y, text); // This is technically a frame late for updating the text? - - move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed); - - immediate_pop_scissor(); - return result; - - cursor_to_screen :: (font: ^Font, x, y: f32, text: str, cur_pos: i32) -> Vector2 { - cx := x; - cy := y; - - for text[0 .. cur_pos] { - if it == #char "\n" { - cx = 0; - cy += font.em + 2; - } else { - cx += font_get_char_width(*font, it); - } - } - - return .{ cx, cy }; - } - - screen_to_cursor :: (font: ^Font, x, y: f32, text: str, mouse_x, mouse_y: f32) -> i32 { - mx := mouse_x - x; - my := mouse_y - y; - - cx := 0.0f; - cy := 0.0f; - for pos: text.count { - if text[pos] == #char "\n" { - cx = 0; - cy += font.em + 2; - } else { - cx += font_get_char_width(*font, text[pos]); - } - - if cy >= my && cx >= mx { - return pos; - } - } - - return text.count; - } -} - - - - -// -// Checkboxes -// -Checkbox_Theme :: struct { - use text_theme := Text_Theme.{}; - use animation_theme := Animation_Theme.{}; - - box_color := Color.{ 0.2, 0.2, 0.2 }; - box_border_width := 4.0f; // @InPixels - box_size := 20.0f; // @InPixels - - checked_color := Color.{ 1, 0, 0 }; - checked_hover_color := Color.{ 1, 0.6, 0.6 }; - - background_color := Color.{ 0.05, 0.05, 0.05 }; // Background of the checkbox button. - hover_color := Color.{ 0.3, 0.3, 0.3 }; - click_color := Color.{ 0.5, 0.5, 0.7 }; -} - -#local default_checkbox_theme := Checkbox_Theme.{}; - -draw_checkbox :: (use r: Rect, value: ^bool, text: str, theme := ^default_checkbox_theme, site := #callsite, increment := 0) -> bool { - result := false; - - hash := get_site_hash(site, increment); - animation_state := get_animation(hash); - mx, my := mouse_get_position(); - - contains := Rect.contains(r, .{~~mx, ~~my}); - - if is_active_item(hash) { - renew_active_item(hash); - if is_button_just_up(GLFW_MOUSE_BUTTON_LEFT) { - if is_hot_item(hash) && contains { - result = true; - *value = !*value; - animation_state.click_time = 1.0f; - } - - set_active_item(0); - } - } elseif is_hot_item(hash) { - if is_button_down(GLFW_MOUSE_BUTTON_LEFT) { - set_active_item(hash); - } - } - - if contains { - set_hot_item(hash); - } - - if is_hot_item(hash) { - move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed); - } else { - move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed); - } - - box_border_width := theme.box_border_width; - box_size := theme.box_size; - - immediate_set_color(theme.box_color); - immediate_rectangle(x + 4, y + (h - box_size) / 2, box_size, box_size); - - surface_color : Color; - if *value { - surface_color = theme.checked_color; - surface_color = color_lerp(animation_state.hover_time, surface_color, theme.checked_hover_color); - - } else { - surface_color = theme.background_color; - surface_color = color_lerp(animation_state.hover_time, surface_color, theme.hover_color); - } - - surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color); - - immediate_set_color(surface_color); - immediate_rectangle(x + 4 + box_border_width, y + (h - box_size) / 2 + box_border_width, box_size - box_border_width * 2, box_size - box_border_width * 2); - - font := font_lookup(.{theme.font_name, theme.font_size}); - text_width := font_get_width(font, text); - text_height := font_get_height(font, text); - - font_set_color(theme.text_color); - font_draw(font, x + box_size + 4 * 2, y + font.em + (h - text_height) / 2, text); - - move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed); - - return result; -} - - -// -// Radio buttons -// -Radio_Theme :: struct { - use text_theme := Text_Theme.{}; - use animation_theme := Animation_Theme.{}; - - box_color := Color.{ 0.2, 0.2, 0.2 }; - box_border_width := 4.0f; // @InPixels - box_size := 20.0f; // @InPixels - - checked_color := Color.{ 0, 0, 1 }; - checked_hover_color := Color.{ 0.6, 0.6, 1 }; - - background_color := Color.{ 0.05, 0.05, 0.05 }; // Background of the checkbox button. - hover_color := Color.{ 0.3, 0.3, 0.3 }; - click_color := Color.{ 0.5, 0.5, 0.7 }; -} - -#local default_radio_theme := Radio_Theme.{}; - -draw_radio :: (use r: Rect, value: ^$T, set_to: T, text: str, theme := ^default_radio_theme, site := #callsite, increment := 0) -> bool { - result := false; - - hash := get_site_hash(site, increment); - animation_state := get_animation(hash); - mx, my := mouse_get_position(); - - contains := Rect.contains(r, .{~~mx, ~~my}); - - if is_active_item(hash) { - renew_active_item(hash); - if is_button_just_up(GLFW_MOUSE_BUTTON_LEFT) { - if is_hot_item(hash) && contains { - result = true; - *value = set_to; - animation_state.click_time = 1.0f; - } - - set_active_item(0); - } - } elseif is_hot_item(hash) { - if is_button_down(GLFW_MOUSE_BUTTON_LEFT) { - set_active_item(hash); - } - } - - if contains { - set_hot_item(hash); - } - - if is_hot_item(hash) { - move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed); - } else { - move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed); - } - - box_border_width := theme.box_border_width; - box_size := theme.box_size; - - immediate_set_color(theme.box_color); - immediate_rectangle(x + 4, y + (h - box_size) / 2, box_size, box_size); - - surface_color : Color; - if *value == set_to { - surface_color = theme.checked_color; - surface_color = color_lerp(animation_state.hover_time, surface_color, theme.checked_hover_color); - - } else { - surface_color = theme.background_color; - surface_color = color_lerp(animation_state.hover_time, surface_color, theme.hover_color); - } - - surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color); - - immediate_set_color(surface_color); - immediate_rectangle(x + 4 + box_border_width, y + (h - box_size) / 2 + box_border_width, box_size - box_border_width * 2, box_size - box_border_width * 2); - - font := font_lookup(.{theme.font_name, theme.font_size}); - text_width := font_get_width(font, text); - text_height := font_get_height(font, text); - - font_set_color(theme.text_color); - font_draw(font, x + box_size + 4 * 2, y + font.em + (h - text_height) / 2, text); - - move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed); - - return result; -} - - - - -scrolling_region_start :: (r: Rect, max_y_scroll := 10000.0f, site := #callsite, increment := 0) { - hash := get_site_hash(site, increment); - mx, my := mouse_get_position(); - state := ^scroll_states[hash]; - if state == null { - animation_states[hash] = .{}; - state = ^scroll_states[hash]; - } - - contains := Rect.contains(r, .{~~mx, ~~my}); - if contains { - scroll_delta := mouse_get_scroll_vector(); - state.xscroll -= scroll_delta.x * 20; - state.yscroll -= scroll_delta.y * 20; - - state.yscroll = math.clamp(state.yscroll, 0, max_y_scroll); - } - - immediate_flush(); - immediate_push_scissor(r.x, r.y, r.w, r.h); - immediate_set_scroll(-state.xscroll, -state.yscroll); -} - -scrolling_region_stop :: () { - immediate_flush(); - immediate_pop_scissor(); - immediate_set_scroll(0, 0); -} - - - -#local { - hot_item : UI_Id = 0 - hot_item_was_set := false - - hot_item_depth := 0; - hot_item_depth_needed := 0; - - active_item : UI_Id = 0 - active_countdown := 0 - - set_active_item :: (id: UI_Id) -> bool { - active_item = id; - active_countdown = 2; - return true; - } - - renew_active_item :: (id: UI_Id) { - if active_item == id { - active_countdown = 2; - } - } - - set_hot_item :: (id: UI_Id, force := false) -> bool { - if active_item != 0 do return false; - - if force { - hot_item_was_set = true; - hot_item = id; - return true; - } - - hot_item_depth += 1; - if hot_item_depth >= hot_item_depth_needed { - hot_item_was_set = true; - hot_item = id; - return true; - } - - return false; - } - - is_active_item :: (id: UI_Id) -> bool { - return active_item == id; - } - - is_hot_item :: (id: UI_Id) -> bool { - return hot_item == id; - } - - Text_Theme :: struct { - text_color := Color.{1, 1, 1}; - font_name := "./assets/fonts/calibri.ttf"; - font_size := 18; - } - - Animation_Theme :: struct { - hover_speed := 0.1f; - click_decay_speed := 0.08f; - } - - Animation_State :: struct { - hover_time := 0.0f; - click_time := 0.0f; - - accessed_this_frame := false; - } - - animation_states : Map(UI_Id, Animation_State); - - get_animation :: (id: UI_Id) -> ^Animation_State { - retval := ^animation_states[id]; - if retval == null { - animation_states[id] = .{}; - retval = ^animation_states[id]; - } - - retval.accessed_this_frame = true; - return retval; - } - - has_active_animation :: () -> bool { - for^ animation_states.entries { - if it.value.hover_time != 0.0f || it.value.hover_time != 0.0f do return true; - if it.value.click_time != 0.0f || it.value.click_time != 0.0f do return true; - } - - return false; - } - - - Scroll_State :: struct { - xscroll: f32; - yscroll: f32; - } - - scroll_states : Map(UI_Id, Scroll_State); - - get_site_hash :: (site: CallSite, increment := 0) -> UI_Id { - file_hash := core.hash.to_u32(site.file); - line_hash := core.hash.to_u32(site.line); - column_hash := core.hash.to_u32(site.column); - - return ~~ (file_hash * 0x472839 + line_hash * 0x6849210 + column_hash * 0x1248382 + increment); - } - - color_lerp :: macro (t: f32, c1, c2: Color) => Color.{ - r = c1.r * (1 - t) + c2.r * t, - g = c1.g * (1 - t) + c2.g * t, - b = c1.b * (1 - t) + c2.b * t, - a = c1.a * (1 - t) + c2.a * t, - }; -} diff --git a/src/ogre/vecmath.onyx b/src/ogre/vecmath.onyx deleted file mode 100644 index 583dd2c..0000000 --- a/src/ogre/vecmath.onyx +++ /dev/null @@ -1,161 +0,0 @@ -package ogre - -use core {hash, math, conv, string} - -@conv.Custom_Format.{format_vector2i} -@conv.Custom_Parse.{parse_vector2i} -Vector2i :: struct { - x, y: i32; - -} - -@conv.Custom_Format.{format_vector2} -@conv.Custom_Parse.{parse_vector2} -Vector2 :: struct { - x, y: f32; - - mag :: (v: Vector2) => math.sqrt(v.x * v.x + v.y * v.y); - - square_mag :: (v: Vector2) => v.x * v.x + v.y * v.y; - - norm :: (v: Vector2) -> Vector2 { - l := math.sqrt(v.x * v.x + v.y * v.y); - return .{ v.x / l, v.y / l }; - } - - - Zero :: Vector2.{0, 0} -} - -@conv.Custom_Format.{format_vector3i} -Vector3i :: struct { - x, y, z: i32; -} - -@conv.Custom_Format.{format_vector3} -Vector3 :: struct { - x, y, z: f32; - - mag :: (v: Vector3) => math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); - - neg :: (v: Vector3) => Vector3.{ -v.x, -v.y, -v.z }; - - dot :: (v1, v2: Vector3) -> f32 { - return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; - } - - norm :: (v: Vector3) -> Vector3 { - l := math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); - return .{ v.x / l, v.y / l, v.z / l }; - } - - cross :: (v1, v2: Vector3) -> Vector3 { - return .{ - v1.y * v2.z - v1.z * v2.y, - v1.z * v2.x - v1.x * v2.z, - v1.x * v2.y - v1.y * v2.x, - }; - } - - clamp :: (v: Vector3, min: Vector3, max: Vector3) -> Vector3 { - return .{ - math.clamp(v.x, min.x, max.x), - math.clamp(v.y, min.y, max.y), - math.clamp(v.z, min.z, max.z), - }; - } -} - -#operator + (v1, v2: Vector2i) => Vector2i.{ v1.x + v2.x, v1.y + v2.y }; -#operator - (v1, v2: Vector2i) => Vector2i.{ v1.x - v2.x, v1.y - v2.y }; -#operator * (v: Vector2i, s: i32) => Vector2i.{ v.x * s, v.y * s }; -#operator * (v1, v2: Vector2i) => Vector2i.{ v1.x * v2.x, v1.y * v2.y }; -#operator == (v1, v2: Vector2i) => v1.x == v2.x && v1.y == v2.y; -#match hash.to_u32 (v: Vector2i) => 13 * v.x + 17 * v.y; - -#operator + (v1, v2: Vector2) => Vector2.{ v1.x + v2.x, v1.y + v2.y }; -#operator - (v1, v2: Vector2) => Vector2.{ v1.x - v2.x, v1.y - v2.y }; -#operator * (v: Vector2, s: f32) => Vector2.{ v.x * s, v.y * s }; -#operator * (v1, v2: Vector2) => Vector2.{ v1.x * v2.x, v1.y * v2.y }; -#operator == (v1, v2: Vector2) => v1.x == v2.x && v1.y == v2.y; - -#operator + (v1, v2: Vector3) => Vector3.{ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; -#operator - (v1, v2: Vector3) => Vector3.{ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; -#operator * (v: Vector3, s: f32) => Vector3.{ v.x * s, v.y * s, v.z * s }; -#operator * (v1, v2: Vector3) => Vector3.{ v1.x * v2.x, v1.y * v2.y, v1.z * v2.z }; -#operator == (v1, v2: Vector3) => v1.x == v2.x && v1.y == v2.y && v1.z == v2.z; - -#operator + (v1, v2: Vector3i) => Vector3i.{ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; -#operator - (v1, v2: Vector3i) => Vector3i.{ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; -#operator * (v: Vector3i, s: i32) => Vector3i.{ v.x * s, v.y * s, v.z * s }; -#operator * (v1, v2: Vector3i) => Vector3i.{ v1.x * v2.x, v1.y * v2.y, v1.z * v2.z }; -#operator == (v1, v2: Vector3i) => v1.x == v2.x && v1.y == v2.y && v1.z == v2.z; - -#local { - format_vector2i :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector2i) { - conv.format(output, "({}, {})", v.x, v.y); - } - - format_vector2 :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector2) { - conv.format(output, "({}, {})", v.x, v.y); - } - - format_vector3 :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector3) { - conv.format(output, "({}, {}, {})", v.x, v.y, v.z); - } - - format_vector3i :: (output: ^conv.Format_Output, format: ^conv.Format, v: ^Vector3i) { - conv.format(output, "({}, {}, {})", v.x, v.y, v.z); - } - - parse_vector2i :: (output: ^Vector2i, line_: str, string_allocator: Allocator) -> bool { - line := line_; - xs := string.read_until(^line, #char " "); - string.advance(^line, 1); - ys := string.read_until(^line, #char " "); - - if xs == "" || ys == "" do return false; - - output.x = ~~ conv.str_to_i64(xs); - output.y = ~~ conv.str_to_i64(ys); - return true; - } - - parse_vector2 :: (output: ^Vector2, line_: str, string_allocator: Allocator) -> bool { - line := line_; - xs := string.read_until(^line, #char " "); - string.advance(^line, 1); - ys := string.read_until(^line, #char " "); - - if xs == "" || ys == "" do return false; - - output.x = ~~ conv.str_to_f64(xs); - output.y = ~~ conv.str_to_f64(ys); - return true; - } -} - - - -Rect :: struct { - x, y, w, h: f32; - - intersects :: (r1, r2: Rect) -> bool { - return r1.x < r2.x + r2.w - && r1.x + r1.w > r2.x - && r1.y < r2.y + r2.h - && r1.y + r1.h > r2.y; - } - - contains :: (r: Rect, p: Vector2) -> bool { - return r.x <= p.x && r.x + r.w >= p.x - && r.y <= p.y && r.y + r.h >= p.y; - } - - center :: (use r: Rect) => Vector2.{ r.x+r.w/2, r.y+r.h/2 }; - - top_left :: (use r: Rect) => Vector2.{ r.x, r.y }; - top_right :: (use r: Rect) => Vector2.{ r.x+r.w, r.y }; - bottom_left :: (use r: Rect) => Vector2.{ r.x, r.y+r.h }; - bottom_right :: (use r: Rect) => Vector2.{ r.x+r.w, r.y+r.h }; -} diff --git a/src/ogre/window.onyx b/src/ogre/window.onyx deleted file mode 100644 index 3c30bc0..0000000 --- a/src/ogre/window.onyx +++ /dev/null @@ -1,90 +0,0 @@ -package ogre - -use glfw3 -use opengles - -Window :: struct { - glfw_window: GLFWwindow_p; - width, height: i32; -} - -window_create :: (width, height: i32, name: cstr) -> Window { - #if runtime.compiler_os == .Linux { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - } else { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - } - - w := glfwCreateWindow(width, height, name); - - return .{ w, width, height }; -} - -window_use :: (w: ^Window) { - glfwMakeContextCurrent(w.glfw_window); - glfwSwapInterval(1); - - input_bind_glfw_events(w.glfw_window); - - // Provide sensible defaults for OpenGL - glInit(glfwGetLoadProcAddress()); - glEnable(GL_TEXTURE); - glEnable(GL_CULL_FACE); - glFrontFace(GL_CW); - glCullFace(GL_BACK); - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glfwGetWindowSize(w.glfw_window, ^w.width, ^w.height); - update_view_matrix(w.width, w.height); - - glfwSetWindowSizeCallback(w.glfw_window, #export_name (w: GLFWwindow_p, width, height: u32) { - global_window.width = width; - global_window.height = height; - update_view_matrix(width, height); - }); - - global_window = w; -} - -window_should_close :: (w: ^Window) -> bool { - return glfwWindowShouldClose(w.glfw_window); -} - -window_set_should_close :: (w: ^Window, b: bool) { - return glfwSetWindowShouldClose(w.glfw_window, b); -} - -window_swap_buffers :: (w: ^Window) { - glfwSwapBuffers(w.glfw_window); -} - -window_poll_events :: (_: ^Window) { - glfwPollEvents(); -} - -#inject Window { - should_close :: window_should_close; - set_should_close :: window_set_should_close; - swap_buffers :: window_swap_buffers; - poll_events :: window_poll_events; -} - -// -// These have to be macros because '#export_name' is used on the argument, -// which requires that they are compile time known functions. -// -// window_size_callback :: macro (w: ^Window, resize: (w: GLFWwindow_p, width, height: u32) -> void) { -// glfw3.glfwSetWindowSizeCallback(w.glfw_window, #export_name resize); -// } - - - - - -#package -global_window: ^Window; - diff --git a/src/utils/any_utils.onyx b/src/utils/any_utils.onyx deleted file mode 100644 index 7ded215..0000000 --- a/src/utils/any_utils.onyx +++ /dev/null @@ -1,47 +0,0 @@ -// -// The contents of this file will probably be merged with the -// core libraries in Onyx at some point. I just haven't flushed -// out the details yet on what everything should exactly do and -// be responsible for. -// - -use package core - -ptr_to_any :: (x: ^$T) -> any { - return .{x, T}; -} - -// -// This function looks up a member's offset and type (effectively -// an 'any'), given the base pointer and type in the form of an -// 'any' and the member_name, which is a '.' separate list of -// symbols. -// -get_any_for_member :: (base: any, member_name: str) -> any { - use package runtime.info - - name := member_name; - info := cast(^Type_Info_Struct) get_type_info(base.type); - assert(info.kind == .Struct, "bad type"); - - part_name := string.read_until(^name, #char "."); - string.advance(^name, 1); - - for info.members { - if it.name == part_name { - member_info := get_type_info(it.type); - if member_info.kind == .Struct && name != "" { - return get_any_for_member(any.{cast(^u8) base.data + it.offset, it.type}, name); - } else { - return any.{cast(^u8) base.data + it.offset, it.type}; - } - } - } - - return .{null, void}; -} - -with :: macro (v: $T, body: Code) { - it := v; - #unquote body; -} diff --git a/src/utils/misc.onyx b/src/utils/misc.onyx new file mode 100644 index 0000000..015dc6f --- /dev/null +++ b/src/utils/misc.onyx @@ -0,0 +1,13 @@ +package main + +use core {math} + +move_towards :: (v: ^$T, target: T, diff: T) { + if math.abs(target - *v) <= diff { + *v = target; + return; + } + + if *v < target do *v += diff; + if *v > target do *v -= diff; +} -- 2.25.1