From c909d28587a3a7536030c3341003b8225ef0a84c Mon Sep 17 00:00:00 2001 From: Jason Hilder Date: Tue, 23 Jun 2026 08:06:08 +0200 Subject: [PATCH] Added embed roms and cleaned up selecting roms. Added 2 new helper functions one to load a rom selected on system and anothe to load a rom into memory from the embedded roms. --- src/simulator/gui.odin | 1 + src/simulator/gui_file_loader.odin | 96 +++++++++++++++++++++++------- src/simulator/gui_tab_disasm.odin | 2 - src/simulator/simulator.odin | 5 ++ 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src/simulator/gui.odin b/src/simulator/gui.odin index 677fe42..8daa459 100644 --- a/src/simulator/gui.odin +++ b/src/simulator/gui.odin @@ -25,6 +25,7 @@ BUTTON_WIDTH :: 120 // Fonts BIG_FONT_SIZE :: 20 KEYPAD_FONT_SIZE :: 18 +LINE_HEIGHT :: 22 Layout :: struct { control_bar : rl.Rectangle, diff --git a/src/simulator/gui_file_loader.odin b/src/simulator/gui_file_loader.odin index 629ce87..ec5dd34 100644 --- a/src/simulator/gui_file_loader.odin +++ b/src/simulator/gui_file_loader.odin @@ -1,5 +1,6 @@ package simulator +import "core:strings" import "core:fmt" import "core:log" import rl "vendor:raylib" @@ -32,18 +33,7 @@ gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) { ret := tfd.openFileDialog("Open File Dialog", nil, 0, nil, nil, 0,) rom_path := string(ret) if rom_path == "" do return - - // Reset machine state - emu.reset_machine(sim.machine) - - // load new rom - rom_size, err := emu.load_rom(sim.machine, rom_path) - if err != nil { - // @TODO: update status bar here - panic("failed to load rom!") - } - sim.rom_loaded = true - sim.disasm_count = disassemble_rom_n(sim.machine.memory[:], 0x200, 0x200 + u16(rom_size), sim.disasm[:]) + load_selected_rom(sim, rom_path) } // drop-zone occupies the panel's content area, minus space for the button @@ -78,7 +68,7 @@ gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) { rl.UnloadDroppedFiles(dropped_file) } - // FOLDER SECTION: + // Embedded Rom Section: // --------------------------------------------- bottom_bounds := rl.Rectangle { x = bounds.x, @@ -86,16 +76,82 @@ gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) { width = rect.width - (PADDING_X * 2), height = rect.height - top_bounds_height - (PADDING_X * 2) } - rl.GuiPanel(bottom_bounds, nil) + rl.GuiPanel(bottom_bounds, "ROM List") - bottom_btn_rect := rl.Rectangle { - bottom_bounds.x, - bottom_bounds.y, - rect.width - (PADDING_X * 2), - BUTTON_HEIGHT, + panel_rect := rl.Rectangle { + x = bottom_bounds.x, + y = bottom_bounds.y + PANEL_HEADER, + width = rect.width - (PADDING_X * 2), + height = rect.height - top_bounds_height - (PADDING_X * 2) - PANEL_HEADER } - rl.GuiButton(bottom_btn_rect, "Open ROM Folder") + content_rect := rl.Rectangle { + x = panel_rect.x, + y = panel_rect.y - PANEL_HEADER, + width = panel_rect.width + PANEL_HEADER, + height = f32(len(roms)) * LINE_HEIGHT + } + + view: rl.Rectangle + rl.GuiScrollPanel(panel_rect, nil, content_rect, &sim.rompick_scroll, &view) + + rl.BeginScissorMode(i32(view.x), i32(view.y), i32(view.width), i32(view.height)) + defer rl.EndScissorMode() + + for path, index in roms { + y_pos := panel_rect.y + f32(index * LINE_HEIGHT) + sim.rompick_scroll.y + + row_rect := rl.Rectangle { + x = view.x, + y = y_pos, + width = view.width, + height = LINE_HEIGHT, + } + + // make selected visible + if path.name == sim.selected_rom { + rl.DrawRectangleRec(row_rect, rl.ColorAlpha(rl.SKYBLUE, 0.25)) + } + + // hover rows + mouse := rl.GetMousePosition() + if rl.CheckCollisionPointRec(mouse, row_rect) { + rl.DrawRectangleRec(row_rect, rl.ColorAlpha(rl.WHITE, 0.08)) + if rl.IsMouseButtonPressed(.LEFT) { + sim.selected_rom = path.name + load_embedded_rom(sim, path.name, roms[index].data) + } + } + + txt := fmt.tprintf("%v: %v", (index + 1), path.name) + rl.DrawTextEx( + sim.font, + strings.clone_to_cstring(txt, context.temp_allocator), + {panel_rect.x + PADDING_X + sim.rompick_scroll.x, y_pos + (LINE_HEIGHT - 18) * 0.5}, + 18, 1, + rl.WHITE + ) + } +} + +load_selected_rom :: proc(sim: ^Simulator, rom_path: string) { + emu.reset_machine(sim.machine) + rom_size, err := emu.load_rom(sim.machine, rom_path) + if err != nil { + // @TODO: update status bar here + panic("failed to load rom!") + } + sim.rom_loaded = true + sim.paused = true + sim.disasm_count = disassemble_rom_n(sim.machine.memory[:], 0x200, 0x200 + u16(rom_size), sim.disasm[:]) +} + +load_embedded_rom :: proc(sim: ^Simulator, path: string, data: []byte) { + emu.reset_machine(sim.machine) + copy(sim.machine.memory[0x200:], data) + sim.rom_loaded = true + sim.paused = true + sim.disasm_count = disassemble_rom_n(sim.machine.memory[:], 0x200, 0x200 + u16(len(data)), sim.disasm[:]) } disassemble_rom_n :: proc(memory: []u8, start_addr: u16, end_addr: u16, out: []Instruction) -> int { diff --git a/src/simulator/gui_tab_disasm.odin b/src/simulator/gui_tab_disasm.odin index 7c50ca0..be7aed1 100644 --- a/src/simulator/gui_tab_disasm.odin +++ b/src/simulator/gui_tab_disasm.odin @@ -27,8 +27,6 @@ gui_tab_disasm :: proc(rect: rl.Rectangle, sim: ^Simulator) { } rl.GuiPanel(panel_rect, nil) - LINE_HEIGHT :: 22 - // Total height of all instructions content_rect := rl.Rectangle { x = panel_rect.x, diff --git a/src/simulator/simulator.odin b/src/simulator/simulator.odin index c9d7c3d..c0fb5f4 100644 --- a/src/simulator/simulator.odin +++ b/src/simulator/simulator.odin @@ -3,6 +3,9 @@ package simulator import emu "../machine" import rl "vendor:raylib" +// Embed roms +roms := #load_directory("../roms") + // CHIP-8 ROM can be at most 3584 bytes (4096 - 0x200 reserved) // Each instruction is 2 bytes, 3584 / 2 = 1792 instructions. MAX_INSTRUCTIONS :: 1792 @@ -25,6 +28,8 @@ Simulator :: struct { font: rl.Font, active_tab: i32, mem_scroll: rl.Vector2, + rompick_scroll: rl.Vector2, + selected_rom: string, // disassembly props disasm: [MAX_INSTRUCTIONS]Instruction, disasm_follow: bool,