Added/updated components to be isolated rectangles.
This commit is contained in:
+81
-47
@@ -3,29 +3,36 @@ package simulator
|
||||
import emu "../machine"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
// Initial window size
|
||||
// @ Window
|
||||
WINDOW_WIDTH :: 1920
|
||||
WINDOW_HEIGHT :: 1080
|
||||
|
||||
// @TODO: If this grows lets move it into its own file
|
||||
// ─── Layout constants ───────────────────────────────────────────────────
|
||||
SIDEBAR_PERCENT :: 0.20
|
||||
DISPLAY_PERCENT :: 0.30
|
||||
// @ Layout proportions
|
||||
// Sidebar takes 20% of screen width on each side; display takes the rest.
|
||||
// The center column splits vertically: 40% display, 60% debug panel.
|
||||
SIDEBAR_PERCENT :: f32(0.20)
|
||||
DISPLAY_V_RATIO :: f32(0.40)
|
||||
// @ Fixed heights
|
||||
CONTROL_BAR_H :: f32(50)
|
||||
STATUS_BAR_H :: f32(30)
|
||||
PANEL_PADDING :: 10
|
||||
PANEL_HEADER :: 24
|
||||
// @ Layout constants
|
||||
PADDING_X :: f32(10)
|
||||
PADDING_Y :: f32(8)
|
||||
PANEL_HEADER :: f32(24)
|
||||
// @ Buttons
|
||||
BUTTON_HEIGHT :: 30
|
||||
BUTTON_WIDTH :: 120
|
||||
// @ Fonts
|
||||
BIG_FONT_SIZE :: 20
|
||||
KEYPAD_FONT_SIZE :: 18
|
||||
|
||||
Layout :: struct {
|
||||
control_bar : rl.Rectangle,
|
||||
left_panel : rl.Rectangle,
|
||||
file_loader : rl.Rectangle,
|
||||
keypad : rl.Rectangle,
|
||||
display : rl.Rectangle,
|
||||
bottom_panel : rl.Rectangle,
|
||||
right_panel : rl.Rectangle,
|
||||
cpu : rl.Rectangle,
|
||||
status_bar : rl.Rectangle,
|
||||
}
|
||||
|
||||
@@ -46,7 +53,7 @@ run_gui :: proc(sim: ^Simulator) {
|
||||
rl.GuiLoadStyle("./assets/raygui_styles/style_dark.rgs")
|
||||
|
||||
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
|
||||
for !rl.WindowShouldClose() {
|
||||
@@ -79,9 +86,26 @@ run_gui :: proc(sim: ^Simulator) {
|
||||
}
|
||||
}
|
||||
|
||||
// Top
|
||||
// ------------------------------------------
|
||||
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)
|
||||
|
||||
// Right
|
||||
// ------------------------------------------
|
||||
gui_cpu(layout.cpu, sim)
|
||||
|
||||
// Bottom
|
||||
// ------------------------------------------
|
||||
gui_bottom_tabs(layout.bottom_panel, sim)
|
||||
gui_status_bar(layout.status_bar, sim)
|
||||
|
||||
rl.EndDrawing()
|
||||
@@ -95,64 +119,74 @@ run_gui :: proc(sim: ^Simulator) {
|
||||
|
||||
// @TODO: If this grows lets move it into its own file
|
||||
calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout {
|
||||
top_h := CONTROL_BAR_H
|
||||
bottom_h := STATUS_BAR_H
|
||||
content_h := screen_height - top_h - bottom_h
|
||||
content_y := top_h
|
||||
// Control bar is a fixed height frozen at top of gui, all items start below it.
|
||||
y_pos := CONTROL_BAR_H
|
||||
x_pos := f32(0)
|
||||
|
||||
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
|
||||
bottom_panel_h := content_h * f32(1.0 - screen_h_ratio)
|
||||
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
|
||||
x_center := sidebar_width
|
||||
y_center := screen_width - sidebar_width * 2
|
||||
|
||||
return Layout {
|
||||
// Left Area
|
||||
control_bar = rl.Rectangle{
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = screen_width,
|
||||
height = top_h,
|
||||
height = CONTROL_BAR_H,
|
||||
},
|
||||
|
||||
left_panel = rl.Rectangle{
|
||||
file_loader = rl.Rectangle{
|
||||
x = 0,
|
||||
y = top_h,
|
||||
width = sidebar_w,
|
||||
height = content_h,
|
||||
y = y_pos,
|
||||
width = sidebar_width,
|
||||
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{
|
||||
x = center_x,
|
||||
y = top_h,
|
||||
width = center_w,
|
||||
height = screen_h,
|
||||
x = sidebar_width,
|
||||
y = y_pos,
|
||||
width = display_width,
|
||||
height = display_height,
|
||||
},
|
||||
|
||||
// MEMORY / DEBUG panel (bottom center)
|
||||
// ------------------------------------------
|
||||
// Bottom Area
|
||||
bottom_panel = rl.Rectangle{
|
||||
x = center_x,
|
||||
y = top_h + screen_h,
|
||||
width = center_w,
|
||||
height = memory_h,
|
||||
x = sidebar_width,
|
||||
y = y_pos + display_height,
|
||||
width = screen_width - sidebar_width,
|
||||
height = visible_height - display_height,
|
||||
},
|
||||
|
||||
right_panel = rl.Rectangle{
|
||||
x = screen_width - sidebar_w,
|
||||
y = top_h,
|
||||
width = sidebar_w,
|
||||
height = content_h,
|
||||
// ------------------------------------------
|
||||
// Right Area
|
||||
cpu = rl.Rectangle {
|
||||
x = sidebar_width + display_width,
|
||||
y = y_pos,
|
||||
width = sidebar_width * 2,
|
||||
height = display_height
|
||||
},
|
||||
|
||||
// ------------------------------------------
|
||||
// Bottom Area
|
||||
status_bar = rl.Rectangle{
|
||||
x = 0,
|
||||
y = screen_height - bottom_h,
|
||||
x = x_pos,
|
||||
y = y_pos + visible_height,
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user