restructuring the project a little bit
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 15 Jul 2021 20:55:30 +0000 (15:55 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 15 Jul 2021 20:55:30 +0000 (15:55 -0500)
data/test_console.onyx [new file with mode: 0644]
src/app.onyx [new file with mode: 0644]
src/build.onyx
src/main.onyx
src/test_console.onyx [deleted file]
src/ui/window.onyx
src/wasm.onyx [new file with mode: 0644]

diff --git a/data/test_console.onyx b/data/test_console.onyx
new file mode 100644 (file)
index 0000000..b738107
--- /dev/null
@@ -0,0 +1,68 @@
+#if (package runtime).Runtime != (package runtime).Runtime_Wasi {
+    #error "This file should only be included in the 'wasi' runtime."
+}
+
+use package core
+#private_file wasm :: package wasm_utils
+
+// Testing running on the console
+main :: (args: [] cstr) {
+    
+    // wasm_data := #file_contents "data/test.wasm";
+    assert(args.count > 1, "Expected WASM file path as argument");
+    wasm_data := io.get_contents(args[1] |> string.from_cstr());
+    
+    wasm_binary := wasm.load(wasm_data);
+    for ^entry: wasm_binary.sections.entries {
+        printf("Section: {}\nOffset: {}\n", entry.key, entry.value);
+    }
+
+    wasm_sections := wasm.parse_sections(^wasm_binary, context.allocator);
+    defer wasm.free_sections(^wasm_sections);
+
+    i := 0;
+    for ^code: wasm_sections.code_section {
+        i += 1;
+        printf("Function {}\n", i);
+        for instr: wasm.instruction_iterator(^wasm_binary, code) {
+            printf("{p}\n", instr);
+        }
+        print("\n");
+    }
+
+
+    // printf("Code:\n{}\n", wasm_sections.code_section);
+
+    // type_section := wasm.parse_type_section(^wasm_binary);
+    // printf("Types:\n{}\n", type_section);
+
+    // import_section := wasm.parse_import_section(^wasm_binary);
+    // printf("Imports:\n{p}\n", import_section);
+
+    // export_section := wasm.parse_export_section(^wasm_binary);
+    // printf("Exports:\n{p}\n", export_section);
+
+    // function_section := wasm.parse_function_section(^wasm_binary);
+    // printf("Functions:\n{p}\n", function_section);
+
+    // start_function := wasm.parse_start_section(^wasm_binary);
+    // printf("Start function: {}\n", start_function);
+
+    // memory_section := wasm.parse_memory_section(^wasm_binary);
+    // printf("Memories:\n{p}\n", memory_section);
+
+    // table_section := wasm.parse_table_section(^wasm_binary);
+    // printf("Tables:\n{p}\n", table_section);
+
+    // global_section := wasm.parse_global_section(^wasm_binary);
+    // printf("Globals:\n{p}\n", global_section);
+
+    // element_section := wasm.parse_element_section(^wasm_binary);
+    // printf("Elements:\n{p}\n", element_section);
+
+    // data_section := wasm.parse_data_section(^wasm_binary);
+    // for e: data_section do printf("Data: {} {} {}\n", e.memory_index, e.offset, e.data.count);
+
+    // code_section := wasm.parse_code_section(^wasm_binary);
+    // printf("Code:\n{p}\n", code_section.count);
+}
diff --git a/src/app.onyx b/src/app.onyx
new file mode 100644 (file)
index 0000000..cc78e11
--- /dev/null
@@ -0,0 +1,351 @@
+package app
+
+use package core
+
+#private_file events :: package js_events
+#private_file gl     :: package gl
+#private_file gfx    :: package immediate_mode
+#private_file ui     :: package ui
+#private_file config :: package config
+#private_file wasm   :: package wasm_utils
+
+use package debug { init as debug_init, debug_log, draw_debug_log }
+use package core.intrinsics.onyx { __initialize }
+
+@Relocate search_buffer: string.String_Buffer;
+
+debug_log_y_offset := 0.0f;
+debug_log_y_scroll := 0.0f;
+debug_log_y_offset_target := 0.0f;
+
+background_tile_texture : gfx.Texture;
+
+on_file_load_callbacks : map.Map(u32, (file_event: ^events.Event) -> void);
+
+analyzer_state : Wasm_Analyzer_State;
+
+init :: () {
+    debug_init();
+
+    gl.init("main_canvas");
+    events.init();
+    gfx.immediate_renderer_init();
+
+    ui.init_ui();
+
+    map.init(^on_file_load_callbacks);
+
+    color_file := events.request_file(config.color_scheme_file);
+    map.put(^on_file_load_callbacks, color_file, load_colors);
+
+    load_background_tile_texture();
+    load_fonts();
+
+    search_buffer = string.buffer_make(memory.make_slice(u8, 256));
+
+    gl.enable(gl.BLEND);
+    gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
+
+    analyzer_state->init();
+
+    load_background_tile_texture :: () {
+        background_tile_texture = gfx.load_texture(32, 32, #file_contents "res/images/background_tile.data", gl.RGB, gl.RGB);
+        gl.bindTexture(gl.TEXTURE_2D, background_tile_texture.texture);
+
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
+
+        gl.bindTexture(gl.TEXTURE_2D, -1);
+    }
+
+    load_colors :: (event: ^events.Event) {
+        json :: package json
+
+        assert(event.kind == .FileRequest, "Bad event type");
+        assert(event.file.status == .Success, "Failed to load color file");
+
+        color_data := memory.make_slice(u8, event.file.size);
+        defer if color_data.count > 0 do cfree(color_data.data);
+        events.get_requested_file_data(event.file.file_id, color_data);
+
+        arena := alloc.arena.make(context.allocator, 4096);
+        defer alloc.arena.free(^arena);
+        colors := json.decode(color_data, alloc.arena.make_allocator(^arena));
+        defer json.free(colors);
+
+        config.Colors.dark_background = decode_color(colors.root["dark_background"]);
+        config.Colors.background      = decode_color(colors.root["background"]);
+        config.Colors.foreground      = decode_color(colors.root["foreground"]);
+
+        config.Colors.keyword         = decode_color(colors.root["keyword"]);
+        config.Colors.value           = decode_color(colors.root["value"]);
+        config.Colors.jumppoint       = decode_color(colors.root["jumppoint"]);
+
+        config.Colors.primary         = decode_color(colors.root["primary"]);
+        config.Colors.primary_light   = decode_color(colors.root["primary_light"]);
+        config.Colors.primary_dark    = decode_color(colors.root["primary_dark"]);
+        config.Colors.primary_text    = decode_color(colors.root["primary_text"]);
+
+        config.Colors.secondary       = decode_color(colors.root["secondary"]);
+        config.Colors.secondary_light = decode_color(colors.root["secondary_light"]);
+        config.Colors.secondary_dark  = decode_color(colors.root["secondary_dark"]);
+        config.Colors.secondary_text  = decode_color(colors.root["secondary_text"]);
+
+        decode_color :: (v: ^json.Value) -> gfx.Color4 {
+            return .{
+                r = ~~v[0]->as_float(),
+                g = ~~v[1]->as_float(),
+                b = ~~v[2]->as_float(),
+            };
+        }
+
+        analyzer_state->init();
+
+        debug_log(.Info, "Successfully loaded colorscheme.", null);
+    }
+
+    load_fonts :: () {
+        use type_info;
+
+        // Dumb check to see if the array is uninitialized
+        if fonts_loading.capacity == 0 do array.init(^fonts_loading, 4);
+
+        fonts_info := cast(^Type_Info_Struct) get_type_info(config.Fonts_Container);
+        for ^member: fonts_info.members {
+            info := cast(^Type_Info_Struct) get_type_info(member.type);
+
+            font_name := member.name;
+
+            font_index    := *cast(^i32) info.parameters[0].data;
+            fnt_file_name := *cast(^str) info.parameters[1].data;
+            tex_file_name := *cast(^str) info.parameters[2].data;
+
+            debug_log(.Info, "Loading font '{}' with index {} from '{}' and '{}'\n", font_name, font_index, fnt_file_name, tex_file_name);
+
+            fnt_file_id := events.request_file(fnt_file_name);
+            tex_file_id := events.request_file(tex_file_name);
+
+            map.put(^on_file_load_callbacks, fnt_file_id, font_file_loaded);
+            map.put(^on_file_load_callbacks, tex_file_id, font_file_loaded);
+
+            array.push(^fonts_loading, .{ font_index, font_name, fnt_file_id, tex_file_id });
+        }
+
+        Loading_Font :: struct {
+            font_index  : u32;
+            font_name   : str;
+
+            fnt_file_id : u32;
+            tex_file_id : u32;
+
+            fnt_file_size := cast(u32) 0;
+            tex_file_size := cast(u32) 0;
+        }
+        #persist fonts_loading : [..] Loading_Font;
+
+        font_file_loaded :: (ev: ^events.Event) {
+            lf: ^Loading_Font = null;
+
+            for ^entry: fonts_loading {
+                if entry.fnt_file_id == ev.file.file_id { entry.fnt_file_size = ev.file.size; lf = entry; }
+                if entry.tex_file_id == ev.file.file_id { entry.tex_file_size = ev.file.size; lf = entry; }
+            }
+
+            assert(lf != null, "Loaded a file for a font that was not registered.");
+
+            if lf.fnt_file_size > 0 && lf.tex_file_size > 0 {
+                fnt_data := memory.make_slice(u8, lf.fnt_file_size);
+                tex_data := memory.make_slice(u8, lf.tex_file_size);
+                defer {
+                    cfree(fnt_data.data); 
+                    cfree(tex_data.data); 
+                }
+
+                @ErrorHandling
+                assert(events.get_requested_file_data(lf.fnt_file_id, fnt_data), "Failed to get bmfont file data.");
+                assert(events.get_requested_file_data(lf.tex_file_id, tex_data), "Failed to get texture data.");
+
+                font := ui.create_font(fnt_data, tex_data);
+                ui.register_font(lf.font_index, font);
+
+                debug_log(.Info, "Successfully loaded font '{}'.", lf.font_name);
+
+                ui.use_font(lf.font_index);
+            }
+        }
+    }
+}
+
+handle_event :: (event: ^events.Event) {
+    switch event.kind {
+        case .MouseDown do switch event.mouse.button {
+            case .Left      do ui.button_pressed(.Left);
+            case .Right     do ui.button_pressed(.Right);
+            case .Middle    do ui.button_pressed(.Middle);
+        }
+
+        case .MouseUp do switch event.mouse.button {
+            case .Left      do ui.button_released(.Left);
+            case .Right     do ui.button_released(.Right);
+            case .Middle    do ui.button_released(.Middle);
+        }
+
+        case .MouseMove do ui.update_mouse_position(~~ event.mouse.pos_x, ~~ event.mouse.pos_y);
+
+        case .MouseWheel do switch event.mouse.button {
+            case .WheelUp   do ui.button_pressed(.WheelUp);
+            case .WheelDown do ui.button_pressed(.WheelDown);
+        }
+
+        case .KeyDown, .KeyUp {
+            modifiers : ui.Keyboard_State.Key_Event.Modifiers;
+            if event.keyboard.modifiers & .CTRL  do modifiers |= .CTRL;
+            if event.keyboard.modifiers & .ALT   do modifiers |= .ALT;
+            if event.keyboard.modifiers & .META  do modifiers |= .META;
+            if event.keyboard.modifiers & .SHIFT do modifiers |= .SHIFT;
+
+            if event.kind == .KeyDown {
+                ui.key_down(event.keyboard.keycode, modifiers);   @KeycodeIsWrong // .keycode is apparently not browser independent...
+
+                if event.keyboard->get_name() == "F5" {
+                    refresh :: () -> void #foreign "decompiler" "refresh" ---
+                    refresh();
+                    break;
+                }
+
+                if event.keyboard->get_name() == "F7" {
+                    debug_log_y_offset_target = 1 - debug_log_y_offset_target;
+                    break;
+                }
+
+                if event.keyboard->get_name() == "Tab" {
+                    toggle_sidebar(^analyzer_state);
+                    break;
+                }
+
+            } else {
+                ui.key_up(event.keyboard.keycode, modifiers);    @KeycodeIsWrong // see above
+            }
+        }
+
+        case .Resize {
+            gl.setSize(event.resize.width, event.resize.height);
+            gfx.set_window_size(event.resize.width, event.resize.height);
+        }
+
+        case .FileRequest {
+            if f := map.get(^on_file_load_callbacks, event.file.file_id); f != null_proc {
+                f(event);
+
+            } else {
+                printf("Warning: No callback set for file id {}.\n", event.file.file_id);
+            }
+        }
+
+        case .FileDropped {
+            debug_log(.Info, "File with size {} and status {} was dropped.\n", event.file.size, event.file.status);
+
+            wasm_data := memory.make_slice(u8, event.file.size);
+            events.get_requested_file_data(event.file.file_id, wasm_data);
+
+            // This transfers ownership of wasm_data to the analyzer_state
+            load_wasm_binary(^analyzer_state, wasm_data);
+        }
+    }
+}
+
+update :: (dt: f32) {
+}
+
+draw :: () {
+    bg_color := config.Colors.background;
+    gl.clearColor(bg_color.r, bg_color.g, bg_color.b, bg_color.a);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
+    window_width, window_height := gfx.get_window_size();
+    window_rectangle := ui.Rectangle.{ 0, 0, ~~window_width, ~~window_height };
+    menu_bar, main_area := ui.Flow.split_horizontal(window_rectangle, top_height=32);
+
+    ui.workspace_start(main_area);
+    draw_background_lines(~~window_width, ~~window_height, line_color=config.Colors.background);
+
+    ui.draw_rect(0, 0, 20, 20, color=.{1,0,0});
+
+    ui.workspace_end();
+
+    draw_sidebar(^analyzer_state);
+
+    // Menu bar drawing
+    {
+        gfx.push_matrix();
+        defer gfx.pop_matrix();
+        
+        gfx.identity();
+        draw_menu_bar(^menu_bar);
+    }
+
+    // Debug log drawing
+    {
+        ui.move_towards(^debug_log_y_offset, debug_log_y_offset_target, 0.07f);
+
+        if debug_log_y_offset > 0.0f {
+            top_half, _ := ui.Flow.split_horizontal(window_rectangle, top_percent=.5);
+            height := ui.Rectangle.height(top_half);
+            top_half.y0 -= height * (1 - debug_log_y_offset);
+            top_half.y1 -= height * (1 - debug_log_y_offset);
+            draw_debug_log(top_half, ^debug_log_y_scroll);
+        }
+    }
+
+    gfx.flush();
+    ui.end_frame();
+
+    draw_menu_bar :: (menu_bar_: ^ui.Rectangle) {
+        menu_bar := *menu_bar_;
+        ui.draw_rect(menu_bar, color=config.Colors.background);
+
+        menu_button_theme := ui.default_button_theme;
+        menu_button_theme.border_width = 2;
+        menu_button_theme.font_size = .9;
+        menu_button_theme.font = 0;
+
+        menu_textbox_theme := ui.default_textbox_theme;
+        menu_textbox_theme.border_width = 2;
+        menu_textbox_theme.font_size = .9;
+
+        button_rect : ui.Rectangle;
+
+        button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
+        ui.button(button_rect, "File", theme=^menu_button_theme);
+        button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
+        ui.button(button_rect, "Edit", theme=^menu_button_theme);
+        button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
+        ui.button(button_rect, "View", theme=^menu_button_theme);
+        button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
+        ui.button(button_rect, "Help", theme=^menu_button_theme);
+
+        _, search_rect := ui.Flow.split_vertical(menu_bar, right_width=300);
+        ui.textbox(search_rect, ^search_buffer, "Search", theme=^menu_textbox_theme);
+    }
+
+    draw_background_lines :: (width: f32, height: f32, line_color := gfx.Color4.{0.2, 0.2, 0.2}, line_spacing := 32.0f) {
+        gl :: package gl
+
+        trans := gfx.global_renderer->get_transform();
+        sx    := trans.scale.x * line_spacing;
+        sy    := trans.scale.y * line_spacing;
+        tx    := -trans.translation.x / sx;
+        ty    := -trans.translation.y / sy;
+
+        gfx.push_matrix();
+        gfx.identity();
+        gfx.set_texture(^background_tile_texture);
+        gfx.textured_rect(.{ 0, 0 }, .{ width, height }, .{ tx, ty }, .{ width / sx, height / sy }, color=line_color); 
+        gfx.set_texture(); 
+        gfx.pop_matrix();
+    }
+}
+
+#private_file background_tile_texture : gfx.Texture;
index a651694d60891548463b780d6d4957520ab7f075..0ad8357abcf87ff2fcc8c0bc9ded6aa37ab3efdc 100644 (file)
     #load "modules/bmfont/module"
 
     #load "src/main"
+    
+    #load "src/app"
+    #load "src/wasm"
+
     #load "src/ui/window"
     #load "src/debug_log"
 }
 
 #if (package runtime).Runtime == (package runtime).Runtime_Wasi {
-    #load "src/test_console"
+    #load "data/test_console"
 }
 
index 6974ab986fc5795ba661df5821677d4bb0300ed1..15006860b3a694d4da5e3a86e02e6271bc741d83 100644 (file)
@@ -1,74 +1,19 @@
 
-use package core
-
 #private_file events :: package js_events
-#private_file gl     :: package gl
-#private_file gfx    :: package immediate_mode
-#private_file ui     :: package ui
 #private_file config :: package config
-#private_file wasm   :: package wasm_utils
-
-use package debug { init as debug_init, debug_log, draw_debug_log }
-
-search_buffer: string.String_Buffer;
-background_tile_texture : gfx.Texture;
-on_file_load_callbacks : map.Map(u32, (file_event: ^events.Event) -> void);
-
-wasm_data : [] u8;
-
-debug_log_y_offset := 0.0f;
-debug_log_y_scroll := 0.0f;
-debug_log_y_offset_target := 0.0f;
+#private_file app    :: package app
 
 main :: (args: [] cstr) {
-    init();
+    app.init();
 
     start_loop :: () -> void #foreign "decompiler" "start_loop" ---
     start_loop();
 }
 
-init :: () {
-    debug_init();
-
-    gl.init("main_canvas");
-    events.init();
-    gfx.immediate_renderer_init();
-
-    ui.init_ui();
-
-    map.init(^on_file_load_callbacks);
-
-    color_file := events.request_file(config.color_scheme_file);
-    map.put(^on_file_load_callbacks, color_file, load_colors);
-
-    load_fonts();
-
-    search_buffer = string.buffer_make(memory.make_slice(u8, 256));
-
-    gl.enable(gl.BLEND);
-    gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
-
-    {
-        background_tile_texture = gfx.load_texture(32, 32, #file_contents "res/images/background_tile.data", gl.RGB, gl.RGB);
-        gl.bindTexture(gl.TEXTURE_2D, background_tile_texture.texture);
-
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
-
-        gl.bindTexture(gl.TEXTURE_2D, -1);
-    }
-
-    test_window.size = .{ 800, 800 };
-    test_window.border_width = 8.0f;
-}
-
-
-last_time := 0;
 #export "loop" () {
     time_now :: () -> i32 #foreign "decompiler" "time_now" --- ;
 
+    #persist last_time := 0;
     if last_time == 0 do last_time = time_now();
 
     now := time_now();
@@ -77,346 +22,24 @@ last_time := 0;
 
     #if #defined(config.ONLY_UPDATE_ON_EVENTS) {
         if poll_events() {
-            update(dt);
-            draw();
+            app.update(dt);
+            app.draw();
         }
 
     } else {
         poll_events();
-        update(dt);
-        draw();
+        app.update(dt);
+        app.draw();
     }
 }
 
-@Temporary window_width := 0
-@Temporary window_height := 0
-
 poll_events :: () -> bool {
     had_event := false;
 
     for event: events.consume() {
         had_event = true;
-        switch event.kind {
-            case .MouseDown do switch event.mouse.button {
-                case .Left      do ui.button_pressed(.Left);
-                case .Right     do ui.button_pressed(.Right);
-                case .Middle    do ui.button_pressed(.Middle);
-            }
-
-            case .MouseUp do switch event.mouse.button {
-                case .Left      do ui.button_released(.Left);
-                case .Right     do ui.button_released(.Right);
-                case .Middle    do ui.button_released(.Middle);
-            }
-
-            case .MouseMove do ui.update_mouse_position(~~ event.mouse.pos_x, ~~ event.mouse.pos_y);
-
-            case .MouseWheel do switch event.mouse.button {
-                case .WheelUp   do ui.button_pressed(.WheelUp);
-                case .WheelDown do ui.button_pressed(.WheelDown);
-            }
-
-            case .KeyDown, .KeyUp {
-                modifiers : ui.Keyboard_State.Key_Event.Modifiers;
-                if event.keyboard.modifiers & .CTRL  do modifiers |= .CTRL;
-                if event.keyboard.modifiers & .ALT   do modifiers |= .ALT;
-                if event.keyboard.modifiers & .META  do modifiers |= .META;
-                if event.keyboard.modifiers & .SHIFT do modifiers |= .SHIFT;
-
-                if event.kind == .KeyDown {
-                    ui.key_down(event.keyboard.keycode, modifiers);   @KeycodeIsWrong // .keycode is apparently not browser independent...
-
-                    if event.keyboard->get_name() == "F5" {
-                        refresh :: () -> void #foreign "decompiler" "refresh" ---
-                        refresh();
-                    }
-
-                    if event.keyboard->get_name() == "F7" {
-                        debug_log_y_offset_target = 1 - debug_log_y_offset_target;
-                    }
-
-                } else {
-                    ui.key_up(event.keyboard.keycode, modifiers);    @KeycodeIsWrong // see above
-                }
-            }
-
-            case .Resize {
-                window_width = event.resize.width;
-                window_height = event.resize.height;
-
-                gl.setSize(event.resize.width, event.resize.height);
-                gfx.set_window_size(event.resize.width, event.resize.height);
-            }
-
-            case .FileRequest {
-                if f := map.get(^on_file_load_callbacks, event.file.file_id); f != null_proc {
-                    f(event);
-
-                } else {
-                    printf("Warning: No callback set for file id {}.\n", event.file.file_id);
-                }
-            }
-
-            case .FileDropped {
-                debug_log(.Info, "File with size {} and status {} was dropped.\n", event.file.size, event.file.status);
-
-                if wasm_data.count > 0 do memory.free_slice(^wasm_data);
-
-                wasm_data = memory.make_slice(u8, event.file.size);
-                events.get_requested_file_data(event.file.file_id, wasm_data);
-
-                wasm_module := wasm.load(wasm_data);
-                defer wasm.free(^wasm_module);
-
-                for ^entry: wasm_module.sections.entries {
-                    debug_log(.Info, "Section: {}\nOffset: {}\n", entry.key, entry.value);
-                }
-
-                wasm_sections := wasm.parse_sections(^wasm_module);
-                for instr: wasm.instruction_iterator(^wasm_module, ^wasm_sections.code_section[1]) {
-                    debug_log(.Info, "{}\n", instr);
-                }
-            }
-        }
+        app.handle_event(event);
     }
 
     return had_event;
 }
-
-update :: (dt: f32) {
-    t += dt;
-
-    if ui.is_key_just_down(~~#char "L") {
-        color_file := events.request_file(config.color_scheme_file);
-        map.put(^on_file_load_callbacks, color_file, load_colors);
-
-        debug_log(.Info, "Requested updated colorscheme.", null);
-    }
-}
-
-t := 0.0f;
-test_window : ui.Window_State;
-
-draw :: () {
-    bg_color := config.Colors.background;
-    gl.clearColor(bg_color.r, bg_color.g, bg_color.b, bg_color.a);
-    gl.clear(gl.COLOR_BUFFER_BIT);
-
-    window_rectangle := ui.Rectangle.{ 0, 0, ~~window_width, ~~window_height };
-    menu_bar, main_area := ui.Flow.split_horizontal(window_rectangle, top_height=32);
-
-    ui.workspace_start(main_area);
-    draw_background_lines(~~window_width, ~~window_height, line_color=config.Colors.background);
-
-    ui.draw_rect(0, 0, 20, 20, color=.{1,0,0});
-
-    {
-        test_window.position = .{ 200, 200 };
-
-        ui.window_start(^test_window);
-        defer ui.window_end();
-
-        test_button_theme := ui.default_button_theme;
-        test_button_theme.font = config.Fonts.Calibri.index;
-
-        if ui.button(.{ 0, 0, 400, 300 }, "Top-Left", theme=^test_button_theme) do search_buffer.count = 0;
-        ui.textbox(.{ 0, 300, 400, 350 }, ^search_buffer);
-    }
-
-    ui.workspace_end();
-
-    {
-        gfx.push_matrix();
-        defer gfx.pop_matrix();
-        
-        gfx.identity();
-        draw_menu_bar(^menu_bar);
-    }
-
-    {
-        ui.move_towards(^debug_log_y_offset, debug_log_y_offset_target, 0.07f);
-
-        if debug_log_y_offset > 0.0f {
-            top_half, _ := ui.Flow.split_horizontal(window_rectangle, top_percent=.5);
-            height := ui.Rectangle.height(top_half);
-            top_half.y0 -= height * (1 - debug_log_y_offset);
-            top_half.y1 -= height * (1 - debug_log_y_offset);
-            draw_debug_log(top_half, ^debug_log_y_scroll);
-        }
-    }
-
-    gfx.flush();
-    ui.end_frame();
-}
-
-#private_file
-draw_menu_bar :: (menu_bar_: ^ui.Rectangle) {
-    menu_bar := *menu_bar_;
-    ui.draw_rect(menu_bar, color=config.Colors.background);
-
-    menu_button_theme := ui.default_button_theme;
-    menu_button_theme.border_width = 2;
-    menu_button_theme.font_size = .9;
-    menu_button_theme.font = 0;
-
-    menu_textbox_theme := ui.default_textbox_theme;
-    menu_textbox_theme.border_width = 2;
-    menu_textbox_theme.font_size = .9;
-
-    button_rect : ui.Rectangle;
-
-    button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
-    ui.button(button_rect, "File", theme=^menu_button_theme);
-    button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
-    ui.button(button_rect, "Edit", theme=^menu_button_theme);
-    button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
-    ui.button(button_rect, "View", theme=^menu_button_theme);
-    button_rect, menu_bar = ui.Flow.split_vertical(menu_bar, left_width=100);
-    ui.button(button_rect, "Help", theme=^menu_button_theme);
-
-    _, search_rect := ui.Flow.split_vertical(menu_bar, right_width=300);
-    ui.textbox(search_rect, ^search_buffer, "Search", theme=^menu_textbox_theme);
-}
-
-#private_file
-draw_background_lines :: (width: f32, height: f32, line_color := gfx.Color4.{0.2, 0.2, 0.2}, line_spacing := 32.0f) {
-    gl :: package gl
-
-    trans := gfx.global_renderer->get_transform();
-    sx    := trans.scale.x * line_spacing;
-    sy    := trans.scale.y * line_spacing;
-    tx    := -trans.translation.x / sx;
-    ty    := -trans.translation.y / sy;
-
-    gfx.push_matrix();
-    gfx.identity();
-    gfx.set_texture(^background_tile_texture);
-    gfx.textured_rect(.{ 0, 0 }, .{ width, height }, .{ tx, ty }, .{ width / sx, height / sy }, color=line_color); 
-    gfx.set_texture(); 
-    gfx.pop_matrix();
-}
-
-
-@Relocate
-#private_file
-load_colors :: (event: ^events.Event) {
-    json :: package json
-
-    assert(event.kind == .FileRequest, "Bad event type");
-    assert(event.file.status == .Success, "Failed to load color file");
-
-    color_data := memory.make_slice(u8, event.file.size);
-    defer if color_data.count > 0 do cfree(color_data.data);
-    events.get_requested_file_data(event.file.file_id, color_data);
-
-    arena := alloc.arena.make(context.allocator, 4096);
-    defer alloc.arena.free(^arena);
-    colors := json.decode(color_data, alloc.arena.make_allocator(^arena));
-    defer json.free(colors);
-
-    config.Colors.dark_background = decode_color(colors.root["dark_background"]);
-    config.Colors.background      = decode_color(colors.root["background"]);
-    config.Colors.foreground      = decode_color(colors.root["foreground"]);
-
-    config.Colors.keyword         = decode_color(colors.root["keyword"]);
-    config.Colors.value           = decode_color(colors.root["value"]);
-    config.Colors.jumppoint       = decode_color(colors.root["jumppoint"]);
-
-    config.Colors.primary         = decode_color(colors.root["primary"]);
-    config.Colors.primary_light   = decode_color(colors.root["primary_light"]);
-    config.Colors.primary_dark    = decode_color(colors.root["primary_dark"]);
-    config.Colors.primary_text    = decode_color(colors.root["primary_text"]);
-
-    config.Colors.secondary       = decode_color(colors.root["secondary"]);
-    config.Colors.secondary_light = decode_color(colors.root["secondary_light"]);
-    config.Colors.secondary_dark  = decode_color(colors.root["secondary_dark"]);
-    config.Colors.secondary_text  = decode_color(colors.root["secondary_text"]);
-
-    decode_color :: (v: ^json.Value) -> gfx.Color4 {
-        return .{
-            r = ~~v[0]->as_float(),
-            g = ~~v[1]->as_float(),
-            b = ~~v[2]->as_float(),
-        };
-    }
-
-    @Temporary
-    test_window.border_color = config.Colors.primary;
-    test_window.background_color = config.Colors.dark_background;
-    test_window.active_color = config.Colors.background;
-
-    debug_log(.Info, "Successfully loaded colorscheme.", null);
-}
-
-@Relocate
-#private_file
-load_fonts :: () {
-    use type_info;
-
-    // Dumb check to see if the array is uninitialized
-    if fonts_loading.capacity == 0 do array.init(^fonts_loading, 4);
-
-    fonts_info := cast(^Type_Info_Struct) get_type_info(config.Fonts_Container);
-    for ^member: fonts_info.members {
-        info := cast(^Type_Info_Struct) get_type_info(member.type);
-
-        font_name := member.name;
-
-        font_index    := *cast(^i32) info.parameters[0].data;
-        fnt_file_name := *cast(^str) info.parameters[1].data;
-        tex_file_name := *cast(^str) info.parameters[2].data;
-
-        debug_log(.Info, "Loading font '{}' with index {} from '{}' and '{}'\n", font_name, font_index, fnt_file_name, tex_file_name);
-
-        fnt_file_id := events.request_file(fnt_file_name);
-        tex_file_id := events.request_file(tex_file_name);
-
-        map.put(^on_file_load_callbacks, fnt_file_id, font_file_loaded);
-        map.put(^on_file_load_callbacks, tex_file_id, font_file_loaded);
-
-        array.push(^fonts_loading, .{ font_index, font_name, fnt_file_id, tex_file_id });
-    }
-
-    Loading_Font :: struct {
-        font_index  : u32;
-        font_name   : str;
-
-        fnt_file_id : u32;
-        tex_file_id : u32;
-
-        fnt_file_size := cast(u32) 0;
-        tex_file_size := cast(u32) 0;
-    }
-    #persist fonts_loading : [..] Loading_Font;
-
-    font_file_loaded :: (ev: ^events.Event) {
-        lf: ^Loading_Font = null;
-
-        for ^entry: fonts_loading {
-            if entry.fnt_file_id == ev.file.file_id { entry.fnt_file_size = ev.file.size; lf = entry; }
-            if entry.tex_file_id == ev.file.file_id { entry.tex_file_size = ev.file.size; lf = entry; }
-        }
-
-        assert(lf != null, "Loaded a file for a font that was not registered.");
-
-        if lf.fnt_file_size > 0 && lf.tex_file_size > 0 {
-            fnt_data := memory.make_slice(u8, lf.fnt_file_size);
-            tex_data := memory.make_slice(u8, lf.tex_file_size);
-            defer {
-                cfree(fnt_data.data); 
-                cfree(tex_data.data); 
-            }
-
-            @ErrorHandling
-            assert(events.get_requested_file_data(lf.fnt_file_id, fnt_data), "Failed to get bmfont file data.");
-            assert(events.get_requested_file_data(lf.tex_file_id, tex_data), "Failed to get texture data.");
-
-            font := ui.create_font(fnt_data, tex_data);
-            ui.register_font(lf.font_index, font);
-
-            debug_log(.Info, "Successfully loaded font '{}'.", lf.font_name);
-
-            ui.use_font(lf.font_index);
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/test_console.onyx b/src/test_console.onyx
deleted file mode 100644 (file)
index b738107..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#if (package runtime).Runtime != (package runtime).Runtime_Wasi {
-    #error "This file should only be included in the 'wasi' runtime."
-}
-
-use package core
-#private_file wasm :: package wasm_utils
-
-// Testing running on the console
-main :: (args: [] cstr) {
-    
-    // wasm_data := #file_contents "data/test.wasm";
-    assert(args.count > 1, "Expected WASM file path as argument");
-    wasm_data := io.get_contents(args[1] |> string.from_cstr());
-    
-    wasm_binary := wasm.load(wasm_data);
-    for ^entry: wasm_binary.sections.entries {
-        printf("Section: {}\nOffset: {}\n", entry.key, entry.value);
-    }
-
-    wasm_sections := wasm.parse_sections(^wasm_binary, context.allocator);
-    defer wasm.free_sections(^wasm_sections);
-
-    i := 0;
-    for ^code: wasm_sections.code_section {
-        i += 1;
-        printf("Function {}\n", i);
-        for instr: wasm.instruction_iterator(^wasm_binary, code) {
-            printf("{p}\n", instr);
-        }
-        print("\n");
-    }
-
-
-    // printf("Code:\n{}\n", wasm_sections.code_section);
-
-    // type_section := wasm.parse_type_section(^wasm_binary);
-    // printf("Types:\n{}\n", type_section);
-
-    // import_section := wasm.parse_import_section(^wasm_binary);
-    // printf("Imports:\n{p}\n", import_section);
-
-    // export_section := wasm.parse_export_section(^wasm_binary);
-    // printf("Exports:\n{p}\n", export_section);
-
-    // function_section := wasm.parse_function_section(^wasm_binary);
-    // printf("Functions:\n{p}\n", function_section);
-
-    // start_function := wasm.parse_start_section(^wasm_binary);
-    // printf("Start function: {}\n", start_function);
-
-    // memory_section := wasm.parse_memory_section(^wasm_binary);
-    // printf("Memories:\n{p}\n", memory_section);
-
-    // table_section := wasm.parse_table_section(^wasm_binary);
-    // printf("Tables:\n{p}\n", table_section);
-
-    // global_section := wasm.parse_global_section(^wasm_binary);
-    // printf("Globals:\n{p}\n", global_section);
-
-    // element_section := wasm.parse_element_section(^wasm_binary);
-    // printf("Elements:\n{p}\n", element_section);
-
-    // data_section := wasm.parse_data_section(^wasm_binary);
-    // for e: data_section do printf("Data: {} {} {}\n", e.memory_index, e.offset, e.data.count);
-
-    // code_section := wasm.parse_code_section(^wasm_binary);
-    // printf("Code:\n{p}\n", code_section.count);
-}
index 221cfbc42943e6b4588e6a82106f36e095eff569..7e76953fe52122ff1761e24b1fd67bdbf254f6ff 100644 (file)
@@ -49,7 +49,7 @@ window_start :: (use state: ^Window_State, site := #callsite, increment := 0) {
 
     gfx.push_scissor(x, y, w, h);
     gfx.push_matrix();
-    gfx.apply_transform(.{ translation = position, scale = .{ 1, 1 } });
+    gfx.apply_transform(.{ translation = .{ x, y }, scale = .{ 1, 1 } });
 }
 
 window_end :: () {
diff --git a/src/wasm.onyx b/src/wasm.onyx
new file mode 100644 (file)
index 0000000..1ef66c9
--- /dev/null
@@ -0,0 +1,87 @@
+package app
+
+use package core
+
+#private_file ui     :: package ui
+#private_file gfx    :: package immediate_mode
+#private_file config :: package config
+#private_file wasm   :: package wasm_utils
+
+use package core.intrinsics.onyx { __initialize }
+
+Wasm_Analyzer_State :: struct {
+    allocator := context.allocator;
+
+    wasm_data     : [] u8;
+    wasm_binary   : wasm.WasmBinary;
+    wasm_sections : wasm.WasmSections;
+
+    windows : map.Map(u32, ui.Window_State);
+
+    sidebar_window    := ui.Window_State.{ .{0,0}, .{400,400} };
+    sidebar_expansion := 0.0f;
+    sidebar_expansion_target := 0.0f;
+
+    init :: (use state: ^Wasm_Analyzer_State) {
+        __initialize(state);
+
+        sidebar_window.border_width = 0;
+        sidebar_window.border_color = .{ 0, 0, 0 };
+        sidebar_window.background_color = config.Colors.dark_background;
+        sidebar_window.active_color     = config.Colors.background;
+    }
+}
+
+load_wasm_binary :: (use state: ^Wasm_Analyzer_State, @transfers_ownership data: [] u8) {
+    if wasm_data.count > 0 do memory.free_slice(^wasm_data);
+
+    wasm_data = data;
+    wasm_binary   = wasm.load(wasm_data, allocator);
+    wasm_sections = wasm.parse_sections(^wasm_binary, allocator);
+}
+
+toggle_sidebar :: (use state: ^Wasm_Analyzer_State) {
+    sidebar_expansion_target = 1 - sidebar_expansion_target;
+}
+
+draw_sidebar :: (use state: ^Wasm_Analyzer_State, y_offset := 32.0f) {
+    ui.move_towards(^sidebar_expansion, sidebar_expansion_target, 0.08f);
+    if sidebar_expansion <= 0.0f do return;
+
+    window_width, window_height := gfx.get_window_size();
+    sidebar_window.position = .{    (sidebar_expansion - 1) * sidebar_window.size.x, y_offset };
+    sidebar_window.size.y   = ~~window_height - y_offset;
+
+    sidebar_rectangle := ui.Rectangle.{ 0, 0, sidebar_window.size.x, sidebar_window.size.y };
+
+    ui.window_start(^sidebar_window);
+    defer ui.window_end();
+
+    #persist x_scroll := 0.0f;
+    #persist y_scroll := 0.0f;
+
+    ui.scrollable_region_start(sidebar_rectangle, ^x_scroll, ^y_scroll);
+    defer ui.scrollable_region_stop();
+
+    if wasm_data.count == 0 {
+        ui.draw_text(.{ 0, 0, sidebar_window.size.x, 50 }, "No loaded WASM binary.");
+        return;
+    }
+
+    @HACK @HACK @HACK
+    sidebar_rectangle.y1 += 100000.0f;
+
+    text_buffer : [512] u8;
+    text_rect   : ui.Rectangle;
+    button_rect : ui.Rectangle;
+
+    text_rect, sidebar_rectangle = ui.Flow.split_horizontal(sidebar_rectangle, top_height=50);
+    s := conv.str_format("Function count: {}\n", ~~text_buffer, wasm_sections.code_section.count);
+    ui.draw_text(text_rect, s);
+
+    for i: wasm_sections.code_section.count {
+        button_rect, sidebar_rectangle = ui.Flow.split_horizontal(sidebar_rectangle, top_height=40);
+        ui.button(button_rect, conv.str_format("Function {}", ~~text_buffer, i), increment=i);
+    }
+}
+