Compare commits

...

2 Commits

Author SHA1 Message Date
jasonhilder eb702890bb Added assets for gui to use. 2026-06-09 08:18:20 +02:00
jasonhilder f8ef6f030f Renamed gui to simulator as a better structure. 2026-06-09 08:17:47 +02:00
11 changed files with 153 additions and 34 deletions
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -61,9 +61,9 @@ init :: proc() -> System {
return s
}
run_machine :: proc(s: ^System) {
run_machine :: proc(s: ^System, cycles: int) {
// CPU cycles
for _ in 0..<12 {
for _ in 0..<cycles {
handle_input(s)
cycle(s)
}
+7 -9
View File
@@ -3,8 +3,8 @@ package main
import "core:log"
import "core:mem"
import chip "machine"
import gui "gui"
import emu "machine"
import sim "simulator"
DEV :: #config(DEV, false)
@@ -20,20 +20,18 @@ main :: proc() {
context.allocator = mem.tracking_allocator(&track)
}
// Init the Chip 8 "cpu"
system := chip.init()
// Init the emu 8 "cpu"
system := emu.init()
// TODO: move this into a gui component
// load rom, hardcoded for now, will eventually be cli or gui
err := chip.load_rom(&system, "./test_roms/7-beep.ch8")
err := emu.load_rom(&system, "./test_roms/7-beep.ch8")
if err != nil {
panic("failed to load rom!")
}
// gui will init the layout etc, it will require reference to
// the system as it will use its display buffer etc
// NOTE: may just need a few fields rather than whole struct check later
gui.init_gui(&system)
// Initilize sim, gui etc
sim.run_simulator(&system)
when DEV {
if len(track.allocation_map) > 0 {
@@ -1,14 +1,12 @@
package gui
package simulator
import "core:log"
import m "../machine"
import rl "vendor:raylib"
PADDING :: 10
gui_control_bar :: proc(rect: rl.Rectangle, s: ^m.System) {
gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
// Small text area
// Control bar buttons
@@ -17,10 +15,19 @@ gui_control_bar :: proc(rect: rl.Rectangle, s: ^m.System) {
gap : f32 = 6
cursor : f32 = rect.x + PADDING
if btn(&cursor, rect, btn_h, btn_w, gap, "RUN") { log.info("RUN clicked") }
if btn(&cursor, rect, btn_h, btn_w, gap, "PAUSE") { log.info("PAUSE clicked") }
if btn(&cursor, rect, btn_h, btn_w, gap, "RUN") {
log.info("RUN clicked")
sim.paused = false
sim.running = true
}
if btn(&cursor, rect, btn_h, btn_w, gap, "PAUSE") {
log.info("PAUSE clicked")
sim.paused = true
sim.running = false
}
if btn(&cursor, rect, btn_h, btn_w, gap, "STEP") { log.info("STEP clicked") }
if btn(&cursor, rect, btn_h, btn_w, gap, "STOP") { log.info("STOP clicked") }
}
btn :: proc(cursor: ^f32, rect: rl.Rectangle, h, w, gap: f32, label: cstring) -> bool {
+52 -9
View File
@@ -1,6 +1,6 @@
package gui
package simulator
import m "../machine"
import emu "../machine"
import rl "vendor:raylib"
// Initial window size
@@ -17,14 +17,29 @@ Layout :: struct {
left_panel : rl.Rectangle,
display : rl.Rectangle,
right_panel : rl.Rectangle,
status_bar : rl.Rectangle,
}
// Initialize main the gui 'window'
init_gui :: proc(s: ^m.System) {
run_gui :: proc(sim: ^Simulator) {
rl.SetConfigFlags({.WINDOW_RESIZABLE})
rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "raylib")
rl.InitAudioDevice()
rl.SetTargetFPS(60)
beep := rl.LoadSound("./beep.wav")
// Load fonts
font := rl.LoadFontEx("./assets/fonts/Inter_18pt-Regular.ttf", 18, nil, 0)
rl.SetTextureFilter(font.texture, .BILINEAR)
sim.font = font
// Initialize style system first
rl.GuiLoadStyleDefault()
// Then load dark theme
rl.GuiLoadStyle("./assets/raygui_styles/style_dark.rgs")
// Then override font AFTER (style load resets it)
rl.GuiSetFont(font)
rl.GuiSetStyle(.DEFAULT, cast(i32)rl.GuiDefaultProperty.TEXT_SIZE, 18)
// Draw each of the components in its own window within the main window
for !rl.WindowShouldClose() {
@@ -41,17 +56,39 @@ init_gui :: proc(s: ^m.System) {
rl.ClearBackground(rl.BLACK)
// Cycle the machine to update memory etc
m.run_machine(s)
// if (sim.is_running) else don't run machine, here we can start,pause etc
if (!sim.paused) {
emu.run_machine(sim.machine, 12)
// Now draw the update data
gui_left_panel(layout.left_panel, s)
gui_right_panel(layout.right_panel, s)
gui_screen(layout.display, s)
gui_control_bar(layout.control_bar, s)
// Handle delay timer
if sim.machine.delay_timer > 0 do sim.machine.delay_timer -= 1
// Current sound file is around 1s so stop
// immediately when timer is 0
if sim.machine.sound_timer > 0 {
sim.machine.sound_timer -= 1
if !rl.IsSoundPlaying(beep) do rl.PlaySound(beep)
} else {
rl.StopSound(beep)
}
}
gui_control_bar(layout.control_bar, sim)
// gui_left_panel(layout.left_panel, s.machine)
// gui_right_panel(layout.right_panel, s.machine)
// Screen is just drawing the display buffer just needs that as arg
// Not the whole sim struct
gui_screen(layout.display, sim.machine)
gui_status_bar(layout.status_bar, sim)
rl.EndDrawing()
}
rl.UnloadFont(sim.font)
rl.UnloadFont(font)
rl.UnloadSound(beep)
rl.CloseAudioDevice()
rl.CloseWindow()
}
@@ -88,5 +125,11 @@ calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout {
width = sidebar_width,
height = sidebar_height
},
status_bar = rl.Rectangle {
x = 0,
y = screen_height - control_bar_height,
width = screen_width,
height = control_bar_height
},
}
}
@@ -1,4 +1,4 @@
package gui
package simulator
import m "../machine"
import rl "vendor:raylib"
@@ -1,4 +1,4 @@
package gui
package simulator
import m "../machine"
import rl "vendor:raylib"
@@ -1,4 +1,4 @@
package gui
package simulator
import m "../machine"
import rl "vendor:raylib"
+25
View File
@@ -0,0 +1,25 @@
package simulator
import emu "../machine"
import rl "vendor:raylib"
Simulator :: struct {
font: rl.Font,
machine: ^emu.System,
running: bool,
paused: bool,
cycles_per_second: int
}
// Requires an initilized emulatore System Struct
run_simulator :: proc(s: ^emu.System) {
sim := Simulator {
machine = s,
running = true,
paused = false,
cycles_per_second = 12
}
run_gui(&sim)
}
+46
View File
@@ -0,0 +1,46 @@
package simulator
import "core:fmt"
import rl "vendor:raylib"
gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
cursor: f32 = rect.x + PADDING
cy := rect.y + rect.height * 0.5
if sim.running && !sim.paused {
status_icon(&cursor, cy, rl.GREEN, .CIRCLE, "Running", sim.font)
} else {
status_icon(&cursor, cy, rl.RED, .SQUARE, "Paused", sim.font)
}
status_divider(&cursor, cy)
status_text(&cursor, cy, fmt.ctprintf("FPS: %d", rl.GetFPS()), sim.font)
}
StatusIconShape :: enum { CIRCLE, SQUARE }
status_icon :: proc(cursor: ^f32, cy: f32, color: rl.Color, shape: StatusIconShape, label: cstring, font: rl.Font) {
size: f32 = 10
ix := cursor^ + size * 0.5
switch shape {
case .CIRCLE: rl.DrawCircleV({ix, cy}, size * 0.5, color)
case .SQUARE: rl.DrawRectangleV({ix - size*0.5, cy - size*0.5}, {size, size}, color)
}
cursor^ += size + 6
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
}
status_divider :: proc(cursor: ^f32, cy: f32) {
rl.DrawLineV({cursor^, cy - 8}, {cursor^, cy + 8}, rl.DARKGRAY)
cursor^ += PADDING
}
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)
cursor^ += rl.MeasureTextEx(font, text, f32(font.baseSize), 1).x + PADDING
}