--- /dev/null
+#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);
+}
--- /dev/null
+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;
#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"
}
-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();
#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
+++ /dev/null
-#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);
-}
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 :: () {
--- /dev/null
+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);
+ }
+}
+