Renamed gui to simulator as a better structure.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
package simulator
|
||||
|
||||
import "core:log"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
PADDING :: 10
|
||||
|
||||
gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
||||
// Small text area
|
||||
|
||||
// Control bar buttons
|
||||
btn_w : f32 = 80
|
||||
btn_h : f32 = rect.height - (PADDING * 2)
|
||||
gap : f32 = 6
|
||||
cursor : f32 = rect.x + PADDING
|
||||
|
||||
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") }
|
||||
}
|
||||
|
||||
btn :: proc(cursor: ^f32, rect: rl.Rectangle, h, w, gap: f32, label: cstring) -> bool {
|
||||
r := rl.Rectangle{cursor^, rect.y + PADDING, w, h}
|
||||
cursor^ += w + gap
|
||||
return rl.GuiButton(r, label)
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package simulator
|
||||
|
||||
import emu "../machine"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
// Initial window size
|
||||
WINDOW_WIDTH :: 1920
|
||||
WINDOW_HEIGHT :: 1080
|
||||
|
||||
// @TODO: If this grows lets move it into its own file
|
||||
SIDEBAR_PERCENT :: 0.20
|
||||
DISPLAY_PERCENT :: 0.30
|
||||
CONTROLBAR_PERCENT :: 0.05
|
||||
|
||||
Layout :: struct {
|
||||
control_bar : rl.Rectangle,
|
||||
left_panel : rl.Rectangle,
|
||||
display : rl.Rectangle,
|
||||
right_panel : rl.Rectangle,
|
||||
status_bar : rl.Rectangle,
|
||||
}
|
||||
|
||||
// Initialize main the gui 'window'
|
||||
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() {
|
||||
// Recalculate layout each frame based on current window size
|
||||
// Pass these down to gui functions so they can setup their sizes?
|
||||
screen_width := f32(rl.GetScreenWidth())
|
||||
screen_height := f32(rl.GetScreenHeight())
|
||||
sidebar_width := screen_width * 0.20
|
||||
|
||||
// set all the layout structs dynamically with the screen size
|
||||
layout := calc_layout(screen_width, screen_height)
|
||||
|
||||
rl.BeginDrawing()
|
||||
rl.ClearBackground(rl.BLACK)
|
||||
|
||||
// Cycle the machine to update memory etc
|
||||
// if (sim.is_running) else don't run machine, here we can start,pause etc
|
||||
if (!sim.paused) {
|
||||
emu.run_machine(sim.machine, 12)
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// @TODO: If this grows lets move it into its own file
|
||||
calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout {
|
||||
control_bar_height := screen_height * CONTROLBAR_PERCENT
|
||||
sidebar_width := screen_width * SIDEBAR_PERCENT
|
||||
sidebar_height := screen_height - control_bar_height
|
||||
display_height := screen_height * DISPLAY_PERCENT - control_bar_height
|
||||
|
||||
return Layout {
|
||||
control_bar = rl.Rectangle {
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = screen_width,
|
||||
height = control_bar_height
|
||||
},
|
||||
left_panel = rl.Rectangle {
|
||||
x = 0,
|
||||
y = control_bar_height,
|
||||
width = sidebar_width,
|
||||
height = sidebar_height
|
||||
},
|
||||
display = rl.Rectangle {
|
||||
x = sidebar_width,
|
||||
y = control_bar_height,
|
||||
width = screen_width - (sidebar_width * 2),
|
||||
height = display_height
|
||||
},
|
||||
right_panel = rl.Rectangle {
|
||||
x = screen_width - sidebar_width,
|
||||
y = control_bar_height,
|
||||
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
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package simulator
|
||||
|
||||
import m "../machine"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
gui_left_panel :: proc(rect: rl.Rectangle, s: ^m.System) {
|
||||
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package simulator
|
||||
|
||||
import m "../machine"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
gui_screen :: proc(rect: rl.Rectangle, s: ^m.System) {
|
||||
// Make sure screen is staying in its aspect ratio
|
||||
chip8_aspect := f32(64.0 / 32.0)
|
||||
available_aspect := rect.width / rect.height
|
||||
screen_rect := rect
|
||||
|
||||
if available_aspect > chip8_aspect {
|
||||
// Area is too wide
|
||||
screen_rect.width = rect.height * chip8_aspect
|
||||
screen_rect.x = rect.x + (rect.width - screen_rect.width) / 2
|
||||
} else {
|
||||
// Area is too tall
|
||||
screen_rect.height = rect.width / chip8_aspect
|
||||
screen_rect.y = rect.y + (rect.height - screen_rect.height) / 2
|
||||
}
|
||||
|
||||
pixel_size := min(int(screen_rect.width / 64), int(screen_rect.height / 32))
|
||||
pixel_size = max(pixel_size, 1)
|
||||
|
||||
actual_width := pixel_size * 64
|
||||
actual_height := pixel_size * 32
|
||||
|
||||
display_x := i32(screen_rect.x) + i32(int(screen_rect.width) - actual_width) / 2
|
||||
display_y := i32(screen_rect.y) + i32(int(screen_rect.height) - actual_height) / 2
|
||||
|
||||
// Debug borders
|
||||
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
|
||||
rl.DrawRectangleLinesEx(screen_rect, 2, rl.WHITE)
|
||||
|
||||
render_display(&s.display, display_x, display_y, i32(pixel_size))
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
render_display :: proc(display_buffer: ^[32][64]u8, offset_x, offset_y, scale: i32) {
|
||||
rl.DrawRectangle(offset_x, offset_y, 64 * scale, 32 * scale, rl.BLACK)
|
||||
|
||||
for y in 0..<len(display_buffer) {
|
||||
for x in 0..<len(display_buffer[0]) {
|
||||
if display_buffer[y][x] == 0x01 {
|
||||
rl.DrawRectangle(i32(x) * scale + offset_x, i32(y) * scale + offset_y, scale, scale, rl.WHITE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user