"name": "Launch",
"onyxFiles": ["../src/build"],
"workingDir": "${workspaceFolder}/run_tree",
- "stopOnEntry": true
+ "stopOnEntry": false
// "preLaunchTask": "Build debug game"
}
]
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
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
MAJOR_VERSION :: 0
MINOR_VERSION :: 1
-// DEBUG :: true
+DEBUG :: true
#if runtime.arch == .X86_64 { #library_path "./lib" }
#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"
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 {
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 }) {
}
} else {
- stack << .{ .{tx, ty}, g, h, };
+ stack << .{ .{tx, ty}, g, f };
visited[.{ tx, ty }] = .{ top.pos, f };
}
}
}
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;
});
}
}
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.");
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;
use ogre
use ogre.ui
use runtime {type_info :: info}
+use core.misc {as_any}
Editor_Range :: struct {min, max: f32;}
Editor_Disabled :: struct {}
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 {
use core
use ogre
use ogre.ui
+use core.misc {as_any, any_nested_selector}
Item :: struct {
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;
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,
}
use core
+use core.misc {any_nested_selector}
// Flags to control how a field of a structure is being stored
// in the level file.
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);
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);
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();
}
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;
+++ /dev/null
-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, "<canvas>" };
-
+++ /dev/null
-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 };
-}
+++ /dev/null
-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;
-}
+++ /dev/null
-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;
-}
+++ /dev/null
-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;
-}
+++ /dev/null
-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);
-}
-
-
-
+++ /dev/null
-package ogre
-
-use glfw3 {glfwInit}
-
-ogre_init :: () -> bool {
- if !glfwInit() {
- return false;
- }
-
- return true;
-}
-
-ogre_setup :: () {
- shaders_init();
- fonts_init();
- immediate_init();
-}
+++ /dev/null
-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;
- }
-}
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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);
-}
+++ /dev/null
-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,
- };
-}
+++ /dev/null
-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 };
-}
+++ /dev/null
-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;
-
+++ /dev/null
-//
-// 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;
-}
--- /dev/null
+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;
+}