import std::io; import vtree; import cache; import ugui; import rl; import std::time; import std::collections::ringbuffer; import std::core::string; def Times = ringbuffer::RingBuffer(<time::NanoDuration, 128>); fn void Times.print_stats(×) { time::NanoDuration min, max, avg, x; min = times.get(0); for (usz i = 0; i < times.written; i++) { x = times.get(i); if (x < min) { min = x; } if (x > max) { max = x; } avg += x; } avg = (NanoDuration)((ulong)avg/128.0); io::printfn("min=%s, max=%s, avg=%s", min, max, avg); } struct TimeStats { time::NanoDuration min, max, avg; } fn TimeStats Times.get_stats(×) { time::NanoDuration min, max, avg, x; min = times.get(0); for (usz i = 0; i < times.written; i++) { x = times.get(i); if (x < min) { min = x; } if (x > max) { max = x; } avg += x; } avg = (NanoDuration)((ulong)avg/128.0); return TimeStats{.min = min, .max = max, .avg = avg}; } const ZString FONT_FS = ` #version 330 // Input vertex attributes (from vertex shader) in vec2 fragTexCoord; in vec4 fragColor; // Input uniform values uniform sampler2D texture0; uniform vec4 colDiffuse; // Output fragment color out vec4 finalColor; void main() { vec4 alpha = texture(texture0, fragTexCoord); finalColor = colDiffuse*fragColor; finalColor.a *= alpha.r; } `; fn int main(String[] args) { ugui::Ctx ui; ui.init()!!; ui.load_font("font1", "resources/hack-nerd.ttf", 16)!!; short width = 800; short height = 450; rl::set_config_flags(rl::FLAG_WINDOW_RESIZABLE); rl::init_window(width, height, "Ugui Test"); ui.input_window_size(width, height)!!; rl::set_target_fps(60); rl::enable_event_waiting(); isz frame; bool toggle = true; time::Clock clock; Times ui_times; Times draw_times; // font stuff rl::Shader font_shader = rl::load_shader_from_memory(null, FONT_FS); rl::Image font_atlas; rl::Texture2D font_texture; ugui::Id font_id = ui.get_font_id("font1"); // Main loop while (!rl::window_should_close()) { clock.mark(); /* Start Input Handling */ if (rl::is_window_resized()) { width = (short)rl::get_screen_width(); height = (short)rl::get_screen_height(); ui.input_window_size(width, height)!!; } ui.input_changefocus(rl::is_window_focused()); rl::Vector2 mpos = rl::get_mouse_position(); ui.input_mouse_abs((short)mpos.x, (short)mpos.y); ugui::MouseButtons buttons; buttons.btn_left = rl::is_mouse_button_down(rl::MOUSE_BUTTON_LEFT); buttons.btn_right = rl::is_mouse_button_down(rl::MOUSE_BUTTON_RIGHT); buttons.btn_middle = rl::is_mouse_button_down(rl::MOUSE_BUTTON_MIDDLE); ui.input_mouse_button(buttons); /* End Input Handling */ /* Start UI Handling */ ui.frame_begin()!!; // main div, fill the whole window ui.div_begin("main", ugui::Rect{.w=ui.width/2})!!; {| ui.layout_set_column()!!; if (ui.button("button0", ugui::Rect{0,0,30,30}, toggle)!!.mouse_press) { io::printn("press button0"); toggle = !toggle; } //ui.layout_next_column()!!; if (ui.button("button1", ugui::Rect{0,0,30,30})!!.mouse_press) { io::printn("press button1"); } //ui.layout_next_column()!!; if (ui.button("button2", ugui::Rect{0,0,30,30})!!.mouse_release) { io::printn("release button2"); } ui.layout_set_row()!!; ui.layout_next_row()!!; static float rf, gf, bf, af; ui.slider_ver("slider_r", ugui::Rect{0,0,30,100}, &rf)!!; ui.slider_ver("slider_g", ugui::Rect{0,0,30,100}, &gf)!!; ui.slider_ver("slider_b", ugui::Rect{0,0,30,100}, &bf)!!; ui.slider_ver("slider_a", ugui::Rect{0,0,30,100}, &af)!!; ui.layout_next_column()!!; ui.text_unbounded("text1", "Ciao Mamma\nAbilità ⚡")!!; ui.layout_next_column()!!; ui.button_label("Continua!")!!; |}; ui.div_end()!!; ui.div_begin("second", ugui::DIV_FILL, scroll_x: true, scroll_y: true)!!; {| ui.layout_set_column()!!; static float slider2 = 0.5; if (ui.slider_ver("slider", ugui::Rect{0,0,30,100}, &slider2)!!.update) { io::printfn("other slider: %f", slider2); } ui.button("button0", ugui::Rect{0,0,50,50})!!; ui.button("button1", ugui::Rect{0,0,50,50})!!; ui.button("button2", ugui::Rect{0,0,50,50})!!; ui.button("button3", ugui::Rect{0,0,50,50})!!; if (toggle) { ui.button("button4", ugui::Rect{0,0,50,50})!!; ui.button("button5", ugui::Rect{0,0,50,50})!!; ui.button("button6", ugui::Rect{0,0,50,50})!!; ui.button("button7", ugui::Rect{0,0,50,50})!!; } ui.layout_next_column()!!; ui.layout_set_row()!!; static float f1, f2; ui.slider_hor("hs1", ugui::Rect{0,0,100,30}, &f1)!!; ui.slider_hor("hs2", ugui::Rect{0,0,100,30}, &f2)!!; |}; ui.div_end()!!; // Timings counter TimeStats dts = draw_times.get_stats(); TimeStats uts = ui_times.get_stats(); ui.layout_set_floating()!!; ui.div_begin("fps", ugui::Rect{0, ui.height-60, 200, 60})!!; {| ui.layout_set_row()!!; ui.text_unbounded("ui avg", string::tformat("ui avg: %s\ndraw avg: %s\nTOT: %s", uts.avg, dts.avg, uts.avg+dts.avg))!!; |}; ui.div_end()!!; ui.frame_end()!!; /* End UI Handling */ ui_times.push(clock.mark()); //ui_times.print_stats(); /* Start UI Drawing */ rl::begin_drawing(); // ClearBackground(BLACK); rl::Color c; rl::Rectangle r; for (Cmd* cmd; (cmd = ui.cmd_queue.dequeue() ?? null) != null;) { switch (cmd.type) { case ugui::CmdType.CMD_RECT: c = rl::Color{ .r = cmd.rect.color.r, .g = cmd.rect.color.g, .b = cmd.rect.color.b, .a = cmd.rect.color.a, }; r = rl::Rectangle{ .x = cmd.rect.rect.x, .y = cmd.rect.rect.y, .height = cmd.rect.rect.h, .width = cmd.rect.rect.w, }; float rad = cmd.rect.radius; // for some weird-ass reason the straight forward inverse formula does not work float roundness = r.width > r.height ? (2.1*rad)/r.height : (2.1*rad)/r.width; rl::draw_rectangle_rounded(r, roundness, 0, c); case ugui::CmdType.CMD_UPDATE_ATLAS: if (cmd.update_atlas.id != font_id) { break; } //rl::unload_image(font_atlas); font_atlas.data = cmd.update_atlas.raw_buffer; font_atlas.width = cmd.update_atlas.width; font_atlas.height = cmd.update_atlas.height; font_atlas.mipmaps = 1; //font_atlas.format = rl::PixelFormat.PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; font_atlas.format = 1; if (rl::is_texture_ready(font_texture)) { rl::unload_texture(font_texture); } font_texture = rl::load_texture_from_image(font_atlas); case ugui::CmdType.CMD_SPRITE: if (cmd.sprite.texture_id != font_id) { break; } rl::Rectangle source = { .x = cmd.sprite.texture_rect.x, .y = cmd.sprite.texture_rect.y, .width = cmd.sprite.texture_rect.w, .height = cmd.sprite.texture_rect.h, }; rl::Vector2 position = { .x = cmd.sprite.rect.x, .y = cmd.sprite.rect.y, }; rl::begin_shader_mode(font_shader); rl::draw_texture_rec(font_texture, source, position, rl::WHITE); rl::end_shader_mode(); case ugui::CmdType.CMD_SCISSOR: if (cmd.scissor.rect.w == 0 && cmd.scissor.rect.h == 0) { rl::end_scissor_mode(); } else { rl::begin_scissor_mode(cmd.scissor.rect.x, cmd.scissor.rect.y, cmd.scissor.rect.w, cmd.scissor.rect.h); } default: io::printfn("Unknown cmd type: %s", cmd.type); } } draw_times.push(clock.mark()); //draw_times.print_stats(); rl::end_drawing(); /* End Drawing */ } rl::close_window(); ui.free(); return 0; } /* fn void! test_vtree() @test { vtree::VTree(<String>) vt; vt.init(10)!!; defer vt.free(); assert(vt.size() == 10, "Size is incorrect"); isz ref = vt.add("Ciao Mamma", 0)!!; String s = vt.get(ref)!!; assert(s == "Ciao Mamma", "String is incorrect"); isz par = vt.parentof(0)!!; assert(ref == par, "Not Root"); vt.print(); } def StrCache = cache::Cache(<int, String, 256>); fn void! test_cache() @test { StrCache cc; cc.init()!!; defer cc.free(); String*! r = cc.search(1); if (catch ex = r) { if (ex != SearchResult.MISSING) { return ex?; } } r = cc.get_or_insert(&&"Ciao Mamma", 1)!; assert(*r!! == "Ciao Mamma", "incorrect string"); } */