Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b4e968d1c | |||
| 52cc1e08b6 | |||
| 6605d86916 | |||
| cccc4fb06c |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+81
-47
@@ -3,29 +3,36 @@ package simulator
|
|||||||
import emu "../machine"
|
import emu "../machine"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
// Initial window size
|
// @ Window
|
||||||
WINDOW_WIDTH :: 1920
|
WINDOW_WIDTH :: 1920
|
||||||
WINDOW_HEIGHT :: 1080
|
WINDOW_HEIGHT :: 1080
|
||||||
|
|
||||||
// @TODO: If this grows lets move it into its own file
|
// @ Layout proportions
|
||||||
// ─── Layout constants ───────────────────────────────────────────────────
|
// Sidebar takes 20% of screen width on each side; display takes the rest.
|
||||||
SIDEBAR_PERCENT :: 0.20
|
// The center column splits vertically: 40% display, 60% debug panel.
|
||||||
DISPLAY_PERCENT :: 0.30
|
SIDEBAR_PERCENT :: f32(0.20)
|
||||||
|
DISPLAY_V_RATIO :: f32(0.40)
|
||||||
|
// @ Fixed heights
|
||||||
CONTROL_BAR_H :: f32(50)
|
CONTROL_BAR_H :: f32(50)
|
||||||
STATUS_BAR_H :: f32(30)
|
STATUS_BAR_H :: f32(30)
|
||||||
PANEL_PADDING :: 10
|
// @ Layout constants
|
||||||
PANEL_HEADER :: 24
|
PADDING_X :: f32(10)
|
||||||
|
PADDING_Y :: f32(8)
|
||||||
|
PANEL_HEADER :: f32(24)
|
||||||
|
// @ Buttons
|
||||||
BUTTON_HEIGHT :: 30
|
BUTTON_HEIGHT :: 30
|
||||||
BUTTON_WIDTH :: 120
|
BUTTON_WIDTH :: 120
|
||||||
|
// @ Fonts
|
||||||
BIG_FONT_SIZE :: 20
|
BIG_FONT_SIZE :: 20
|
||||||
KEYPAD_FONT_SIZE :: 18
|
KEYPAD_FONT_SIZE :: 18
|
||||||
|
|
||||||
Layout :: struct {
|
Layout :: struct {
|
||||||
control_bar : rl.Rectangle,
|
control_bar : rl.Rectangle,
|
||||||
left_panel : rl.Rectangle,
|
file_loader : rl.Rectangle,
|
||||||
|
keypad : rl.Rectangle,
|
||||||
display : rl.Rectangle,
|
display : rl.Rectangle,
|
||||||
bottom_panel : rl.Rectangle,
|
bottom_panel : rl.Rectangle,
|
||||||
right_panel : rl.Rectangle,
|
cpu : rl.Rectangle,
|
||||||
status_bar : rl.Rectangle,
|
status_bar : rl.Rectangle,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +53,7 @@ run_gui :: proc(sim: ^Simulator) {
|
|||||||
rl.GuiLoadStyle("./assets/raygui_styles/style_dark.rgs")
|
rl.GuiLoadStyle("./assets/raygui_styles/style_dark.rgs")
|
||||||
|
|
||||||
rl.GuiSetFont(font)
|
rl.GuiSetFont(font)
|
||||||
rl.GuiSetStyle(.DEFAULT, cast(i32)rl.GuiDefaultProperty.TEXT_SIZE, 18)
|
rl.GuiSetStyle(.DEFAULT, i32(rl.GuiDefaultProperty.TEXT_SIZE), 18)
|
||||||
|
|
||||||
// Draw each of the components in its own window within the main window
|
// Draw each of the components in its own window within the main window
|
||||||
for !rl.WindowShouldClose() {
|
for !rl.WindowShouldClose() {
|
||||||
@@ -79,9 +86,26 @@ run_gui :: proc(sim: ^Simulator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Top
|
||||||
|
// ------------------------------------------
|
||||||
gui_control_bar(layout.control_bar, sim)
|
gui_control_bar(layout.control_bar, sim)
|
||||||
gui_left_panel(layout.left_panel, sim)
|
|
||||||
|
// Left
|
||||||
|
// ------------------------------------------
|
||||||
|
gui_file_loader(layout.file_loader, sim)
|
||||||
|
gui_key_pad(layout.keypad, sim.machine.keypad, sim.font)
|
||||||
|
|
||||||
|
// Center
|
||||||
|
// ------------------------------------------
|
||||||
gui_screen(layout.display, sim)
|
gui_screen(layout.display, sim)
|
||||||
|
|
||||||
|
// Right
|
||||||
|
// ------------------------------------------
|
||||||
|
gui_cpu(layout.cpu, sim)
|
||||||
|
|
||||||
|
// Bottom
|
||||||
|
// ------------------------------------------
|
||||||
|
gui_bottom_tabs(layout.bottom_panel, sim)
|
||||||
gui_status_bar(layout.status_bar, sim)
|
gui_status_bar(layout.status_bar, sim)
|
||||||
|
|
||||||
rl.EndDrawing()
|
rl.EndDrawing()
|
||||||
@@ -95,64 +119,74 @@ run_gui :: proc(sim: ^Simulator) {
|
|||||||
|
|
||||||
// @TODO: If this grows lets move it into its own file
|
// @TODO: If this grows lets move it into its own file
|
||||||
calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout {
|
calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout {
|
||||||
top_h := CONTROL_BAR_H
|
// Control bar is a fixed height frozen at top of gui, all items start below it.
|
||||||
bottom_h := STATUS_BAR_H
|
y_pos := CONTROL_BAR_H
|
||||||
content_h := screen_height - top_h - bottom_h
|
x_pos := f32(0)
|
||||||
content_y := top_h
|
|
||||||
|
|
||||||
sidebar_w := screen_width * SIDEBAR_PERCENT
|
// Usable gui vertical space
|
||||||
|
visible_height := screen_height - CONTROL_BAR_H - STATUS_BAR_H
|
||||||
|
sidebar_width := screen_width * SIDEBAR_PERCENT
|
||||||
|
display_width := screen_width - (sidebar_width * 2) - sidebar_width
|
||||||
|
display_height := visible_height * DISPLAY_V_RATIO
|
||||||
|
|
||||||
screen_h_ratio := 0.40
|
x_center := sidebar_width
|
||||||
bottom_panel_h := content_h * f32(1.0 - screen_h_ratio)
|
y_center := screen_width - sidebar_width * 2
|
||||||
screen_h := content_h * f32(screen_h_ratio)
|
|
||||||
memory_h := content_h - screen_h
|
|
||||||
|
|
||||||
center_x := sidebar_w
|
|
||||||
center_w := screen_width - sidebar_w * 2
|
|
||||||
|
|
||||||
return Layout {
|
return Layout {
|
||||||
|
// Left Area
|
||||||
control_bar = rl.Rectangle{
|
control_bar = rl.Rectangle{
|
||||||
x = 0,
|
x = 0,
|
||||||
y = 0,
|
y = 0,
|
||||||
width = screen_width,
|
width = screen_width,
|
||||||
height = top_h,
|
height = CONTROL_BAR_H,
|
||||||
},
|
},
|
||||||
|
file_loader = rl.Rectangle{
|
||||||
left_panel = rl.Rectangle{
|
|
||||||
x = 0,
|
x = 0,
|
||||||
y = top_h,
|
y = y_pos,
|
||||||
width = sidebar_w,
|
width = sidebar_width,
|
||||||
height = content_h,
|
height = visible_height / 3
|
||||||
|
},
|
||||||
|
keypad = rl.Rectangle{
|
||||||
|
x = 0,
|
||||||
|
y = (y_pos + visible_height - visible_height / 2),
|
||||||
|
width = sidebar_width,
|
||||||
|
height = visible_height / 2
|
||||||
},
|
},
|
||||||
|
|
||||||
// CHIP-8 screen (top center)
|
// ------------------------------------------
|
||||||
|
// Center Area
|
||||||
display = rl.Rectangle{
|
display = rl.Rectangle{
|
||||||
x = center_x,
|
x = sidebar_width,
|
||||||
y = top_h,
|
y = y_pos,
|
||||||
width = center_w,
|
width = display_width,
|
||||||
height = screen_h,
|
height = display_height,
|
||||||
},
|
},
|
||||||
|
|
||||||
// MEMORY / DEBUG panel (bottom center)
|
// ------------------------------------------
|
||||||
|
// Bottom Area
|
||||||
bottom_panel = rl.Rectangle{
|
bottom_panel = rl.Rectangle{
|
||||||
x = center_x,
|
x = sidebar_width,
|
||||||
y = top_h + screen_h,
|
y = y_pos + display_height,
|
||||||
width = center_w,
|
width = screen_width - sidebar_width,
|
||||||
height = memory_h,
|
height = visible_height - display_height,
|
||||||
},
|
},
|
||||||
|
|
||||||
right_panel = rl.Rectangle{
|
// ------------------------------------------
|
||||||
x = screen_width - sidebar_w,
|
// Right Area
|
||||||
y = top_h,
|
cpu = rl.Rectangle {
|
||||||
width = sidebar_w,
|
x = sidebar_width + display_width,
|
||||||
height = content_h,
|
y = y_pos,
|
||||||
|
width = sidebar_width * 2,
|
||||||
|
height = display_height
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// Bottom Area
|
||||||
status_bar = rl.Rectangle{
|
status_bar = rl.Rectangle{
|
||||||
x = 0,
|
x = x_pos,
|
||||||
y = screen_height - bottom_h,
|
y = y_pos + visible_height,
|
||||||
width = screen_width,
|
width = screen_width,
|
||||||
height = bottom_h,
|
height = STATUS_BAR_H,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
gui_bottom_tabs :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
|
rl.DrawRectangleLinesEx(rect, 1, rl.GRAY)
|
||||||
|
|
||||||
|
// Setup tab bar
|
||||||
|
tabs := [?]cstring{ "Memory", "Disassembly", "Log" }
|
||||||
|
|
||||||
|
tab_bar_rect := rl.Rectangle{
|
||||||
|
rect.x,
|
||||||
|
rect.y,
|
||||||
|
rect.width,
|
||||||
|
BUTTON_HEIGHT + PADDING_Y
|
||||||
|
}
|
||||||
|
|
||||||
|
// inside draw loop:
|
||||||
|
rl.GuiTabBar(tab_bar_rect, &tabs[0], i32(len(tabs)), &sim.active_tab)
|
||||||
|
|
||||||
|
bounds := rl.Rectangle {
|
||||||
|
x = rect.x + PADDING_X,
|
||||||
|
y = rect.y + PADDING_Y + tab_bar_rect.height,
|
||||||
|
width = rect.width - (PADDING_X * 2),
|
||||||
|
height = rect.height - (PADDING_Y * 2) - tab_bar_rect.height,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sim.active_tab {
|
||||||
|
case 0: // draw registers panel
|
||||||
|
gui_tab_memory(bounds, sim)
|
||||||
|
case 1: // draw memory panel
|
||||||
|
case 2: // draw display panel
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,15 +3,16 @@ package simulator
|
|||||||
import "core:log"
|
import "core:log"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
PADDING :: 10
|
|
||||||
|
|
||||||
gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
||||||
|
|
||||||
// Cursor moves for every btn call places them left to right with padding
|
rl.DrawTextEx(sim.font, "Octal Cookie Chip 8 Sim ", {rect.x + PADDING_X, rect.y + 12}, 25, 1, rl.WHITE)
|
||||||
cursor : f32 = rect.x + PANEL_PADDING
|
text_size := rl.MeasureTextEx(sim.font, "Octal Cookie Chip 8 Sim ", 25, 1)
|
||||||
|
|
||||||
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PANEL_PADDING, "RUN") {
|
// Cursor moves for every btn call places them left to right with padding
|
||||||
|
cursor : f32 = text_size.x + 5 + rect.x + PADDING_X
|
||||||
|
|
||||||
|
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "RUN") {
|
||||||
if sim.rom_loaded {
|
if sim.rom_loaded {
|
||||||
sim.paused = false
|
sim.paused = false
|
||||||
sim.running = true
|
sim.running = true
|
||||||
@@ -20,14 +21,18 @@ gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PANEL_PADDING, "PAUSE") {
|
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "PAUSE") {
|
||||||
sim.paused = true
|
sim.paused = true
|
||||||
sim.running = false
|
sim.running = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "RESET") {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
btn :: proc(cursor: ^f32, rect: rl.Rectangle, h, w, gap: f32, label: cstring) -> bool {
|
btn :: proc(cursor: ^f32, rect: rl.Rectangle, h, w, gap: f32, label: cstring) -> bool {
|
||||||
r := rl.Rectangle{cursor^, rect.y + PADDING, w, h}
|
r := rl.Rectangle{cursor^, rect.y + PADDING_X, w, h}
|
||||||
cursor^ += w + gap
|
cursor^ += w + gap
|
||||||
return rl.GuiButton(r, label)
|
return rl.GuiButton(r, label)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
CPU_SECTION_H :: 100 // enough for 3 rows of labels
|
||||||
|
REG_CELL_H :: 40 // fixed, won't grow with the panel
|
||||||
|
|
||||||
|
gui_cpu :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
|
rl.DrawRectangleLinesEx(rect, 1, rl.GRAY)
|
||||||
|
|
||||||
|
bounds := rl.Rectangle {
|
||||||
|
x = rect.x + PADDING_X,
|
||||||
|
y = rect.y + PADDING_Y,
|
||||||
|
width = rect.width - (PADDING_X * 2),
|
||||||
|
height = rect.height - (PADDING_Y * 2),
|
||||||
|
}
|
||||||
|
rl.GuiPanel(bounds, "CPU / Registers")
|
||||||
|
|
||||||
|
cpu_rect := rl.Rectangle {
|
||||||
|
x = bounds.x + PADDING_X,
|
||||||
|
y = bounds.y + PADDING_Y + PANEL_HEADER,
|
||||||
|
width = bounds.width - (PADDING_X * 2),
|
||||||
|
height = CPU_SECTION_H - (PADDING_Y * 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grid constants
|
||||||
|
COLS :: 2
|
||||||
|
ROWS :: 3
|
||||||
|
LRATIO :: f32(0.6)
|
||||||
|
|
||||||
|
cell_w := cpu_rect.width / COLS
|
||||||
|
cell_h := cpu_rect.height / ROWS
|
||||||
|
|
||||||
|
labels := [5]string{ "Progam Counter", "Increment pointer", "Stack Pointer", "Delay Timer", "Sound Timer" }
|
||||||
|
values := [5]u16{
|
||||||
|
sim.machine.pc,
|
||||||
|
sim.machine.i,
|
||||||
|
u16(sim.machine.sp),
|
||||||
|
u16(sim.machine.delay_timer),
|
||||||
|
u16(sim.machine.sound_timer),
|
||||||
|
}
|
||||||
|
|
||||||
|
for index in 0..<5 {
|
||||||
|
col := index % COLS
|
||||||
|
row := index / COLS
|
||||||
|
|
||||||
|
cell_x := cpu_rect.x + f32(col) * cell_w
|
||||||
|
cell_y := cpu_rect.y + f32(row) * cell_h
|
||||||
|
|
||||||
|
label_rect := rl.Rectangle{cell_x + 20, cell_y, cell_w,cell_h}
|
||||||
|
box_rect := rl.Rectangle{cell_x + cell_w * LRATIO, cell_y, cell_w * (1 - LRATIO), cell_h}
|
||||||
|
|
||||||
|
rl.GuiLabel(label_rect, rl.TextFormat("%s", labels[index]))
|
||||||
|
rl.DrawRectangleLinesEx(box_rect, 1, rl.DARKGRAY)
|
||||||
|
|
||||||
|
// Right-aligned value
|
||||||
|
value_text := rl.TextFormat("0x%04X", values[index])
|
||||||
|
text_w := rl.MeasureText(value_text, 18)
|
||||||
|
value_x := box_rect.x + box_rect.width - f32(text_w) - 4
|
||||||
|
rl.GuiLabel({value_x, box_rect.y, box_rect.width, box_rect.height}, value_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
register_bounds := rl.Rectangle {
|
||||||
|
x = bounds.x,
|
||||||
|
y = bounds.y + PANEL_HEADER + PADDING_Y + CPU_SECTION_H,
|
||||||
|
width = bounds.width,
|
||||||
|
height = bounds.height - PANEL_HEADER - PADDING_Y - CPU_SECTION_H,
|
||||||
|
}
|
||||||
|
rl.GuiPanel(register_bounds, "Registers")
|
||||||
|
|
||||||
|
register_rect := rl.Rectangle {
|
||||||
|
x = register_bounds.x + PADDING_X,
|
||||||
|
y = register_bounds.y + PADDING_Y + PANEL_HEADER,
|
||||||
|
width = register_bounds.width - (PADDING_X * 2),
|
||||||
|
height = register_bounds.height - (PADDING_Y * 2) - PANEL_HEADER,
|
||||||
|
}
|
||||||
|
|
||||||
|
// V registers grid (V0–VF, 16 registers)
|
||||||
|
REG_COLS :: 4
|
||||||
|
REG_ROWS :: 4
|
||||||
|
|
||||||
|
reg_cell_w := register_rect.width / REG_COLS
|
||||||
|
|
||||||
|
for index in 0..<16 {
|
||||||
|
col := index % REG_COLS
|
||||||
|
row := index / REG_COLS
|
||||||
|
|
||||||
|
cell_x := register_rect.x + f32(col) * reg_cell_w
|
||||||
|
cell_y := register_rect.y + f32(row) * REG_CELL_H
|
||||||
|
|
||||||
|
label_rect := rl.Rectangle{cell_x + 20, cell_y, reg_cell_w, REG_CELL_H}
|
||||||
|
box_rect := rl.Rectangle{cell_x + reg_cell_w * LRATIO, cell_y, reg_cell_w * (1 - LRATIO), REG_CELL_H}
|
||||||
|
|
||||||
|
rl.GuiLabel(label_rect, rl.TextFormat("V%X", index))
|
||||||
|
rl.DrawRectangleLinesEx(box_rect, 1, rl.DARKGRAY)
|
||||||
|
|
||||||
|
// Right-aligned value
|
||||||
|
value_text := rl.TextFormat("0x%02X", sim.machine.v[index])
|
||||||
|
text_w := rl.MeasureText(value_text, 18)
|
||||||
|
value_x := box_rect.x + box_rect.width - f32(text_w) - 4
|
||||||
|
rl.GuiLabel({value_x, box_rect.y, box_rect.width, box_rect.height}, value_text)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import "core:log"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
import emu "../machine"
|
||||||
|
import tfd "../../external/tinyfiledialogs"
|
||||||
|
|
||||||
|
gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
|
rl.DrawRectangleLinesEx(rect, 1, rl.GRAY)
|
||||||
|
|
||||||
|
bounds := rl.Rectangle {
|
||||||
|
x = rect.x + PADDING_X,
|
||||||
|
y = rect.y + PADDING_Y,
|
||||||
|
width = rect.width - (PADDING_X * 2),
|
||||||
|
height = rect.height - (PADDING_Y * 2),
|
||||||
|
}
|
||||||
|
rl.GuiPanel(bounds, "Rom / File")
|
||||||
|
|
||||||
|
// drop-zone occupies the panel's content area, minus space for the button
|
||||||
|
drop_zone := rl.Rectangle {
|
||||||
|
bounds.x + PADDING_X,
|
||||||
|
bounds.y + PADDING_Y,
|
||||||
|
bounds.width - (PADDING_X * 2),
|
||||||
|
bounds.height - ((PADDING_Y * 2) + (BUTTON_HEIGHT + PADDING_Y))
|
||||||
|
}
|
||||||
|
|
||||||
|
// centered drop-zone text
|
||||||
|
text: cstring = "Drop a CHIP-8 ROM here"
|
||||||
|
text_width := rl.MeasureText(text, BIG_FONT_SIZE)
|
||||||
|
text_x := drop_zone.x + (drop_zone.width - f32(text_width)) / 2
|
||||||
|
text_y := drop_zone.y + (drop_zone.height - f32(BIG_FONT_SIZE)) / 2
|
||||||
|
rl.DrawTextEx(sim.font, text, {text_x, text_y}, BIG_FONT_SIZE, 1, rl.WHITE)
|
||||||
|
|
||||||
|
// open rom button below drop-zone
|
||||||
|
btn_rect := rl.Rectangle {
|
||||||
|
drop_zone.x,
|
||||||
|
drop_zone.y + drop_zone.height + PADDING_Y,
|
||||||
|
drop_zone.width,
|
||||||
|
BUTTON_HEIGHT,
|
||||||
|
}
|
||||||
|
|
||||||
|
if rl.GuiButton(btn_rect, "Open ROM") {
|
||||||
|
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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle file drop
|
||||||
|
if rl.IsFileDropped() {
|
||||||
|
dropped_file := rl.LoadDroppedFiles()
|
||||||
|
if dropped_file.count > 0 {
|
||||||
|
mouse := rl.GetMousePosition()
|
||||||
|
|
||||||
|
if rl.CheckCollisionPointRec(mouse, drop_zone) {
|
||||||
|
path_str := string(dropped_file.paths[0])
|
||||||
|
log.info("file dropped: ", path_str)
|
||||||
|
// @TODO: Stop sim, reset mem etc, load new rom
|
||||||
|
} else {
|
||||||
|
log.info("File dropped outside drop zone, ignoring")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rl.UnloadDroppedFiles(dropped_file)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import "core:strings"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
|
||||||
|
gui_key_pad :: proc(rect: rl.Rectangle, display: [16]bool, font: rl.Font) {
|
||||||
|
rl.DrawRectangleLinesEx(rect, 1, rl.GRAY)
|
||||||
|
|
||||||
|
bounds := rl.Rectangle {
|
||||||
|
x = rect.x + PADDING_X,
|
||||||
|
y = rect.y + PADDING_Y,
|
||||||
|
width = rect.width - (PADDING_X * 2),
|
||||||
|
height = rect.height - (PADDING_Y * 2),
|
||||||
|
}
|
||||||
|
rl.GuiPanel(bounds, "Input / Keypad")
|
||||||
|
|
||||||
|
content := rl.Rectangle {
|
||||||
|
bounds.x,
|
||||||
|
bounds.y + PANEL_HEADER,
|
||||||
|
bounds.width,
|
||||||
|
bounds.height - PANEL_HEADER,
|
||||||
|
}
|
||||||
|
|
||||||
|
Key :: struct {
|
||||||
|
label: string,
|
||||||
|
index: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := [16]Key {
|
||||||
|
{"1", 1}, {"2", 2}, {"3", 3}, {"C", 12},
|
||||||
|
{"4", 4}, {"5", 5}, {"6", 6}, {"D", 13},
|
||||||
|
{"7", 7}, {"8", 8}, {"9", 9}, {"E", 14},
|
||||||
|
{"A", 10}, {"0", 0}, {"B", 11}, {"F", 15},
|
||||||
|
}
|
||||||
|
|
||||||
|
btn_width := content.width / 4
|
||||||
|
btn_height := content.height / 4
|
||||||
|
|
||||||
|
for val, idx in keys {
|
||||||
|
str := strings.clone_to_cstring(val.label)
|
||||||
|
defer delete(str)
|
||||||
|
|
||||||
|
ri := idx / 4
|
||||||
|
ci := idx % 4
|
||||||
|
irect := rl.Rectangle {
|
||||||
|
x = content.x + btn_width * f32(ci),
|
||||||
|
y = content.y + btn_height * f32(ri),
|
||||||
|
width = btn_width,
|
||||||
|
height = btn_height,
|
||||||
|
}
|
||||||
|
|
||||||
|
if display[val.index] { rl.DrawRectangleRec(irect, rl.BLACK) }
|
||||||
|
|
||||||
|
rl.DrawRectangleLinesEx(irect, 1, rl.GRAY)
|
||||||
|
rl.DrawTextEx(
|
||||||
|
font,
|
||||||
|
str,
|
||||||
|
rl.Vector2{irect.x + btn_width / 2, irect.y + btn_height / 2},
|
||||||
|
KEYPAD_FONT_SIZE,
|
||||||
|
1,
|
||||||
|
rl.WHITE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,14 @@ package simulator
|
|||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
gui_screen :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
gui_screen :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
|
bounds := rl.Rectangle {
|
||||||
|
x = rect.x + PADDING_X,
|
||||||
|
y = rect.y + PADDING_Y,
|
||||||
|
width = rect.width - (PADDING_X * 2),
|
||||||
|
height = rect.height - (PADDING_Y * 2),
|
||||||
|
}
|
||||||
|
rl.GuiPanel(bounds, nil)
|
||||||
|
|
||||||
s := sim.machine
|
s := sim.machine
|
||||||
|
|
||||||
// 2 : 1
|
// 2 : 1
|
||||||
@@ -12,14 +20,14 @@ gui_screen :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
|
|
||||||
// create viewport for the ratio
|
// create viewport for the ratio
|
||||||
view := rect
|
view := rect
|
||||||
avail_space := rect.width / rect.height
|
avail_space := bounds.width / bounds.height
|
||||||
|
|
||||||
if avail_space > aspect_ratio {
|
if avail_space > aspect_ratio {
|
||||||
view.width = rect.height * aspect_ratio
|
view.width = bounds.height * aspect_ratio
|
||||||
view.x = rect.x + (rect.width - view.width) * 0.5
|
view.x = bounds.x + (bounds.width - view.width) * 0.5
|
||||||
} else {
|
} else {
|
||||||
view.height = rect.width / aspect_ratio
|
view.height = bounds.width / aspect_ratio
|
||||||
view.y = rect.y + (rect.height - view.height) * 0.5
|
view.y = bounds.y + (bounds.height - view.height) * 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
// get scale
|
// get scale
|
||||||
@@ -32,9 +40,7 @@ gui_screen :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
// center frame
|
// center frame
|
||||||
x := i32(view.x + (view.width - f32(draw_w)) * 0.5)
|
x := i32(view.x + (view.width - f32(draw_w)) * 0.5)
|
||||||
y := i32(view.y + (view.height - f32(draw_h)) * 0.5)
|
y := i32(view.y + (view.height - f32(draw_h)) * 0.5)
|
||||||
|
|
||||||
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
||||||
rl.DrawRectangleLinesEx(view, 2, rl.WHITE)
|
|
||||||
|
|
||||||
if !sim.rom_loaded {
|
if !sim.rom_loaded {
|
||||||
// centered drop-zone text
|
// centered drop-zone text
|
||||||
@@ -3,12 +3,14 @@ package simulator
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
StatusIconShape :: enum { CIRCLE, SQUARE }
|
||||||
|
|
||||||
// @TODO: render status bar text
|
// @TODO: render status bar text
|
||||||
gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
// Left to right text draws
|
// Left to right text draws
|
||||||
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
||||||
|
|
||||||
cursor: f32 = rect.x + PADDING
|
cursor: f32 = rect.x + PADDING_X
|
||||||
cy := rect.y + rect.height * 0.5
|
cy := rect.y + rect.height * 0.5
|
||||||
|
|
||||||
if sim.running && !sim.paused {
|
if sim.running && !sim.paused {
|
||||||
@@ -23,7 +25,7 @@ gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
// FPS set far right
|
// FPS set far right
|
||||||
fps_text := fmt.ctprintf("FPS: %d", rl.GetFPS())
|
fps_text := fmt.ctprintf("FPS: %d", rl.GetFPS())
|
||||||
fps_width := rl.MeasureTextEx(sim.font, fps_text, f32(sim.font.baseSize), 1).x
|
fps_width := rl.MeasureTextEx(sim.font, fps_text, f32(sim.font.baseSize), 1).x
|
||||||
fps_x := rect.x + rect.width - PADDING - fps_width
|
fps_x := rect.x + rect.width - PADDING_X - fps_width
|
||||||
|
|
||||||
rl.DrawTextEx(
|
rl.DrawTextEx(
|
||||||
sim.font,
|
sim.font,
|
||||||
@@ -35,8 +37,6 @@ gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusIconShape :: enum { CIRCLE, SQUARE }
|
|
||||||
|
|
||||||
status_icon :: proc(cursor: ^f32, cy: f32, color: rl.Color, shape: StatusIconShape, label: cstring, font: rl.Font) {
|
status_icon :: proc(cursor: ^f32, cy: f32, color: rl.Color, shape: StatusIconShape, label: cstring, font: rl.Font) {
|
||||||
size: f32 = 10
|
size: f32 = 10
|
||||||
ix := cursor^ + size * 0.5
|
ix := cursor^ + size * 0.5
|
||||||
@@ -48,15 +48,15 @@ status_icon :: proc(cursor: ^f32, cy: f32, color: rl.Color, shape: StatusIconSha
|
|||||||
|
|
||||||
cursor^ += size + 6
|
cursor^ += size + 6
|
||||||
rl.DrawTextEx(font, label, {cursor^, cy - f32(font.baseSize) * 0.5}, f32(font.baseSize), 1, rl.RAYWHITE)
|
rl.DrawTextEx(font, label, {cursor^, cy - f32(font.baseSize) * 0.5}, f32(font.baseSize), 1, rl.RAYWHITE)
|
||||||
cursor^ += rl.MeasureTextEx(font, label, f32(font.baseSize), 1).x + PADDING
|
cursor^ += rl.MeasureTextEx(font, label, f32(font.baseSize), 1).x + PADDING_X
|
||||||
}
|
}
|
||||||
|
|
||||||
status_divider :: proc(cursor: ^f32, cy: f32) {
|
status_divider :: proc(cursor: ^f32, cy: f32) {
|
||||||
rl.DrawLineV({cursor^, cy - 8}, {cursor^, cy + 8}, rl.DARKGRAY)
|
rl.DrawLineV({cursor^, cy - 8}, {cursor^, cy + 8}, rl.DARKGRAY)
|
||||||
cursor^ += PADDING
|
cursor^ += PADDING_X
|
||||||
}
|
}
|
||||||
|
|
||||||
status_text :: proc(cursor: ^f32, cy: f32, text: cstring, font: rl.Font) {
|
status_text :: proc(cursor: ^f32, cy: f32, text: cstring, font: rl.Font) {
|
||||||
rl.DrawTextEx(font, text, {cursor^, cy - f32(font.baseSize) * 0.5}, f32(font.baseSize), 1, rl.RAYWHITE)
|
rl.DrawTextEx(font, text, {cursor^, cy - f32(font.baseSize) * 0.5}, f32(font.baseSize), 1, rl.RAYWHITE)
|
||||||
cursor^ += rl.MeasureTextEx(font, text, f32(font.baseSize), 1).x + PADDING
|
cursor^ += rl.MeasureTextEx(font, text, f32(font.baseSize), 1).x + PADDING_X
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:strings"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
MEM_INDICATOR_W :: 14
|
||||||
|
MEM_ADDRESS_W :: 72
|
||||||
|
MEM_ROW_H :: 20
|
||||||
|
MEM_HEADER_H :: 24
|
||||||
|
MEM_BYTES_PER_ROW :: 16
|
||||||
|
MEM_TOTAL_ROWS :: 256
|
||||||
|
MEM_FONT_ROWS :: 5
|
||||||
|
MEM_ROM_START :: 512
|
||||||
|
MEM_VIRTUAL_ROWS :: MEM_FONT_ROWS + 1 + (256 - 32)
|
||||||
|
|
||||||
|
MEM_COL_LABELS := [16]string{"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}
|
||||||
|
|
||||||
|
byte_col_w :: proc(rect: rl.Rectangle) -> f32 {
|
||||||
|
used := f32(MEM_INDICATOR_W + MEM_ADDRESS_W + 12)
|
||||||
|
return (rect.width - used) / 16
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_tab_memory :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
|
rl.DrawRectangleRec(rect, rl.DARKGRAY)
|
||||||
|
|
||||||
|
// Header background
|
||||||
|
rl.DrawRectangle(i32(rect.x), i32(rect.y), i32(rect.width), MEM_HEADER_H, rl.BLACK)
|
||||||
|
|
||||||
|
// Header: Address label
|
||||||
|
rl.DrawTextEx(sim.font, "Address", {rect.x + MEM_INDICATOR_W, rect.y + 4}, 16, 1, rl.GRAY)
|
||||||
|
|
||||||
|
// Header: column labels 0-F
|
||||||
|
col_w := byte_col_w(rect)
|
||||||
|
for col in 0..<16 {
|
||||||
|
x := rect.x + MEM_INDICATOR_W + MEM_ADDRESS_W + f32(col) * col_w
|
||||||
|
label := strings.clone_to_cstring(MEM_COL_LABELS[col], context.temp_allocator)
|
||||||
|
rl.DrawTextEx(sim.font, label, {x, rect.y + 4}, 16, 1, rl.GRAY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header separator
|
||||||
|
rl.DrawLine(
|
||||||
|
i32(rect.x), i32(rect.y + MEM_HEADER_H),
|
||||||
|
i32(rect.x + rect.width), i32(rect.y + MEM_HEADER_H),
|
||||||
|
rl.GRAY,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scroll panel area (below header)
|
||||||
|
panel_rect := rl.Rectangle{
|
||||||
|
rect.x,
|
||||||
|
rect.y + MEM_HEADER_H,
|
||||||
|
rect.width,
|
||||||
|
rect.height - MEM_HEADER_H,
|
||||||
|
}
|
||||||
|
|
||||||
|
content_rect := rl.Rectangle{
|
||||||
|
0, 0,
|
||||||
|
rect.width - 12,
|
||||||
|
f32(MEM_VIRTUAL_ROWS) * MEM_ROW_H,
|
||||||
|
}
|
||||||
|
|
||||||
|
view : rl.Rectangle
|
||||||
|
rl.GuiScrollPanel(panel_rect, nil, content_rect, &sim.mem_scroll, &view)
|
||||||
|
|
||||||
|
rl.BeginScissorMode(i32(view.x), i32(view.y), i32(view.width), i32(view.height))
|
||||||
|
|
||||||
|
draw_row := 0
|
||||||
|
|
||||||
|
// --- Font rows (0x000 - 0x04F) ---
|
||||||
|
for row in 0..<MEM_FONT_ROWS {
|
||||||
|
addr := row * MEM_BYTES_PER_ROW
|
||||||
|
row_y := panel_rect.y + f32(draw_row) * MEM_ROW_H + sim.mem_scroll.y
|
||||||
|
draw_memory_row(rect, sim, draw_row, addr, row_y)
|
||||||
|
draw_row += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Divider ---
|
||||||
|
divider_y := panel_rect.y + f32(draw_row) * MEM_ROW_H + sim.mem_scroll.y
|
||||||
|
rl.DrawRectangle(i32(rect.x), i32(divider_y), i32(rect.width), MEM_ROW_H, rl.ColorAlpha(rl.BLACK, 0.4))
|
||||||
|
rl.DrawTextEx(
|
||||||
|
sim.font,
|
||||||
|
"---- reserved (0x0050 - 0x01FF) ----",
|
||||||
|
{rect.x + MEM_INDICATOR_W, divider_y + 2},
|
||||||
|
16, 1, rl.DARKGRAY,
|
||||||
|
)
|
||||||
|
draw_row += 1
|
||||||
|
|
||||||
|
// --- ROM rows (0x200 onwards) ---
|
||||||
|
for i := 0; MEM_ROM_START + i * MEM_BYTES_PER_ROW < 4096; i += 1 {
|
||||||
|
addr := MEM_ROM_START + i * MEM_BYTES_PER_ROW
|
||||||
|
row_y := panel_rect.y + f32(draw_row) * MEM_ROW_H + sim.mem_scroll.y
|
||||||
|
draw_memory_row(rect, sim, draw_row, addr, row_y)
|
||||||
|
draw_row += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.EndScissorMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_memory_row :: proc(rect: rl.Rectangle, sim: ^Simulator, visual_row: int, addr: int, row_y: f32) {
|
||||||
|
col_w := byte_col_w(rect)
|
||||||
|
|
||||||
|
if visual_row % 2 == 0 {
|
||||||
|
rl.DrawRectangle(i32(rect.x), i32(row_y), i32(rect.width), MEM_ROW_H, rl.ColorAlpha(rl.BLACK, 0.2))
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_str := fmt.tprintf("%04X", addr)
|
||||||
|
rl.DrawTextEx(
|
||||||
|
sim.font,
|
||||||
|
strings.clone_to_cstring(addr_str, context.temp_allocator),
|
||||||
|
{rect.x + MEM_INDICATOR_W, row_y + 2},
|
||||||
|
16, 1, rl.RAYWHITE,
|
||||||
|
)
|
||||||
|
|
||||||
|
for col in 0..<16 {
|
||||||
|
byte_val := sim.machine.memory[addr + col]
|
||||||
|
byte_str := fmt.tprintf("%02X", byte_val)
|
||||||
|
x := rect.x + MEM_INDICATOR_W + MEM_ADDRESS_W + f32(col) * col_w
|
||||||
|
color := rl.RAYWHITE if byte_val != 0 else rl.GRAY
|
||||||
|
rl.DrawTextEx(
|
||||||
|
sim.font,
|
||||||
|
strings.clone_to_cstring(byte_str, context.temp_allocator),
|
||||||
|
{x, row_y + 2},
|
||||||
|
16, 1, color,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
package simulator
|
|
||||||
|
|
||||||
import "core:log"
|
|
||||||
import "core:strings"
|
|
||||||
import rl "vendor:raylib"
|
|
||||||
|
|
||||||
import emu "../machine"
|
|
||||||
import tfd "../../external/tinyfiledialogs"
|
|
||||||
|
|
||||||
gui_left_panel :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|
||||||
// ── Top panel and components ──
|
|
||||||
top_panel := rl.Rectangle {
|
|
||||||
rect.x,
|
|
||||||
rect.y,
|
|
||||||
rect.width,
|
|
||||||
rect.height / 2,
|
|
||||||
}
|
|
||||||
rl.DrawRectangleLinesEx(top_panel, 1, rl.DARKGRAY)
|
|
||||||
|
|
||||||
// Dropzone/file loader
|
|
||||||
file_loader_rect := rl.Rectangle {
|
|
||||||
top_panel.x,
|
|
||||||
top_panel.y,
|
|
||||||
top_panel.width,
|
|
||||||
(top_panel.height / 3) - PANEL_HEADER - PANEL_PADDING * 2,
|
|
||||||
}
|
|
||||||
gui_file_loader(file_loader_rect, sim)
|
|
||||||
|
|
||||||
// ── Bottom panel and components ──
|
|
||||||
bottom_panel := rl.Rectangle {
|
|
||||||
rect.x,
|
|
||||||
rect.y + top_panel.height,
|
|
||||||
rect.width,
|
|
||||||
rect.height / 2,
|
|
||||||
}
|
|
||||||
rl.DrawRectangleLinesEx(bottom_panel, 1, rl.GREEN)
|
|
||||||
gui_key_pad(bottom_panel, sim.machine.keypad, sim.font)
|
|
||||||
}
|
|
||||||
|
|
||||||
gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|
||||||
rl.GuiPanel(rect, "Rom / File")
|
|
||||||
|
|
||||||
// drop-zone occupies the panel's content area, minus space for the button
|
|
||||||
drop_zone := rl.Rectangle {
|
|
||||||
rect.x + PANEL_PADDING,
|
|
||||||
rect.y + PANEL_HEADER + PANEL_PADDING,
|
|
||||||
rect.width - PANEL_PADDING * 2,
|
|
||||||
rect.height - PANEL_HEADER - PANEL_PADDING * 2 - BUTTON_HEIGHT - PANEL_PADDING,
|
|
||||||
}
|
|
||||||
rl.DrawRectangleLinesEx(drop_zone, 1, rl.GREEN)
|
|
||||||
|
|
||||||
// centered drop-zone text
|
|
||||||
text: cstring = "Drop a CHIP-8 ROM here"
|
|
||||||
text_width := rl.MeasureText(text, BIG_FONT_SIZE)
|
|
||||||
text_x := drop_zone.x + (drop_zone.width - f32(text_width)) / 2
|
|
||||||
text_y := drop_zone.y + (drop_zone.height - f32(BIG_FONT_SIZE)) / 2
|
|
||||||
rl.DrawTextEx(sim.font, text, {text_x, text_y}, BIG_FONT_SIZE, 1, rl.WHITE)
|
|
||||||
|
|
||||||
// open rom button below drop-zone
|
|
||||||
btn_rect := rl.Rectangle {
|
|
||||||
drop_zone.x,
|
|
||||||
drop_zone.y + drop_zone.height + PANEL_PADDING,
|
|
||||||
BUTTON_WIDTH,
|
|
||||||
BUTTON_HEIGHT,
|
|
||||||
}
|
|
||||||
|
|
||||||
if rl.GuiButton(btn_rect, "Open ROM") {
|
|
||||||
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
|
|
||||||
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.running = true
|
|
||||||
sim.paused = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle file drop
|
|
||||||
if rl.IsFileDropped() {
|
|
||||||
dropped_file := rl.LoadDroppedFiles()
|
|
||||||
if dropped_file.count > 0 {
|
|
||||||
mouse := rl.GetMousePosition()
|
|
||||||
|
|
||||||
if rl.CheckCollisionPointRec(mouse, drop_zone) {
|
|
||||||
path_str := string(dropped_file.paths[0])
|
|
||||||
log.info("file dropped: ", path_str)
|
|
||||||
// @TODO: Stop sim, reset mem etc, load new rom
|
|
||||||
} else {
|
|
||||||
log.info("File dropped outside drop zone, ignoring")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rl.UnloadDroppedFiles(dropped_file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gui_key_pad :: proc(rect: rl.Rectangle, display: [16]bool, font: rl.Font) {
|
|
||||||
rl.GuiPanel(rect, "Input / Keypad")
|
|
||||||
|
|
||||||
content := rl.Rectangle {
|
|
||||||
rect.x + PANEL_PADDING,
|
|
||||||
rect.y + PANEL_HEADER + PANEL_PADDING,
|
|
||||||
rect.width - PANEL_PADDING * 2,
|
|
||||||
rect.height - PANEL_HEADER - PANEL_PADDING * 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
Key :: struct {
|
|
||||||
label: string,
|
|
||||||
index: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
keys := [16]Key {
|
|
||||||
{"1", 1}, {"2", 2}, {"3", 3}, {"C", 12},
|
|
||||||
{"4", 4}, {"5", 5}, {"6", 6}, {"D", 13},
|
|
||||||
{"7", 7}, {"8", 8}, {"9", 9}, {"E", 14},
|
|
||||||
{"A", 10}, {"0", 0}, {"B", 11}, {"F", 15},
|
|
||||||
}
|
|
||||||
|
|
||||||
btn_width := content.width / 4
|
|
||||||
btn_height := content.height / 4
|
|
||||||
|
|
||||||
for val, idx in keys {
|
|
||||||
str := strings.clone_to_cstring(val.label)
|
|
||||||
defer delete(str)
|
|
||||||
|
|
||||||
ri := idx / 4
|
|
||||||
ci := idx % 4
|
|
||||||
irect := rl.Rectangle {
|
|
||||||
x = content.x + btn_width * f32(ci),
|
|
||||||
y = content.y + btn_height * f32(ri),
|
|
||||||
width = btn_width,
|
|
||||||
height = btn_height,
|
|
||||||
}
|
|
||||||
|
|
||||||
if display[val.index] { rl.DrawRectangleRec(irect, rl.BLACK) }
|
|
||||||
|
|
||||||
rl.DrawRectangleLinesEx(irect, 1, rl.GRAY)
|
|
||||||
rl.DrawTextEx(
|
|
||||||
font,
|
|
||||||
str,
|
|
||||||
rl.Vector2{irect.x + btn_width / 2, irect.y + btn_height / 2},
|
|
||||||
KEYPAD_FONT_SIZE,
|
|
||||||
1,
|
|
||||||
rl.WHITE,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package simulator
|
|
||||||
|
|
||||||
import m "../machine"
|
|
||||||
import rl "vendor:raylib"
|
|
||||||
|
|
||||||
gui_right_panel :: proc(rect: rl.Rectangle, s: ^m.System) {
|
|
||||||
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
|
||||||
}
|
|
||||||
@@ -4,12 +4,16 @@ import emu "../machine"
|
|||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
Simulator :: struct {
|
Simulator :: struct {
|
||||||
|
// Emulator
|
||||||
machine: ^emu.System,
|
machine: ^emu.System,
|
||||||
rom_loaded: bool,
|
rom_loaded: bool,
|
||||||
running: bool,
|
running: bool,
|
||||||
paused: bool,
|
paused: bool,
|
||||||
cycles_per_second: int,
|
cycles_per_second: int,
|
||||||
|
// GUI
|
||||||
font: rl.Font,
|
font: rl.Font,
|
||||||
|
active_tab: i32,
|
||||||
|
mem_scroll : rl.Vector2,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires an initilized emulatore System Struct
|
// Requires an initilized emulatore System Struct
|
||||||
|
|||||||
Reference in New Issue
Block a user