Compare commits

...

5 Commits

Author SHA1 Message Date
jasonhilder 31cbcb38e8 Cleanup debug border, add test button. 2026-06-03 07:36:33 +02:00
jasonhilder 9f6d69227c Fixed incorrect layout for control bar. 2026-06-03 07:36:18 +02:00
jasonhilder 97cc324abb Updated .gitignore 2026-06-03 07:14:41 +02:00
jasonhilder 756fd07bb2 No need for display file in machine, gui handles it. 2026-06-03 07:13:52 +02:00
jasonhilder e6feabe2f1 Gui code neatened up for easy components.
Updated the gui init etc to use a layout struct to quickly setup new
rectangles for the gui. Each component can use its rect as its bounding
box for ui elements, each can set its own padding etc per panel
2026-06-03 07:04:04 +02:00
7 changed files with 103 additions and 123 deletions
+3
View File
@@ -1,3 +1,6 @@
# This ignore the build artifacts produced from running/building the Odin source code
*.bin
*.o
# Project management
todo
+11
View File
@@ -0,0 +1,11 @@
package gui
import m "../machine"
import rl "vendor:raylib"
CB_PADDING :: 20
gui_control_bar :: proc(rect: rl.Rectangle, s: ^m.System) {
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
rl.GuiButton(rl.Rectangle{rect.x, rect.y, 100, rect.height}, "test")
}
+53 -9
View File
@@ -7,6 +7,18 @@ import rl "vendor:raylib"
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 {
left_panel : rl.Rectangle,
right_panel : rl.Rectangle,
display : rl.Rectangle,
control_bar : rl.Rectangle,
}
// Initialize main the gui 'window'
init_gui :: proc(s: ^m.System) {
rl.SetConfigFlags({.WINDOW_RESIZABLE})
@@ -20,15 +32,9 @@ init_gui :: proc(s: ^m.System) {
// 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
display_rect := rl.Rectangle{
x = sidebar_width,
y = 0,
width = screen_width - (sidebar_width * 2),
height = screen_height * 0.30,
}
layout := calc_layout(screen_width, screen_height)
rl.BeginDrawing()
rl.ClearBackground(rl.BLACK)
@@ -42,8 +48,10 @@ init_gui :: proc(s: ^m.System) {
}
// --------------------------------------
// run each gui "component"
gui_screen(display_rect, s)
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)
rl.EndDrawing()
}
@@ -51,3 +59,39 @@ init_gui :: proc(s: ^m.System) {
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 {
sidebar_width := screen_width * SIDEBAR_PERCENT
display_height := screen_height * DISPLAY_PERCENT
return Layout {
left_panel = rl.Rectangle {
x = 0,
y = 0,
width = sidebar_width,
height = screen_height
},
right_panel = rl.Rectangle {
x = screen_width - sidebar_width,
y = 0,
width = sidebar_width,
height = screen_height
},
display = rl.Rectangle {
x = sidebar_width,
y = 0,
width = screen_width - (sidebar_width * 2),
height = display_height
},
control_bar = rl.Rectangle {
x = sidebar_width,
y = display_height,
width = screen_width - (sidebar_width * 2),
height = (screen_height * 0.05)
}
}
}
+8
View File
@@ -0,0 +1,8 @@
package gui
import m "../machine"
import rl "vendor:raylib"
gui_left_panel :: proc(rect: rl.Rectangle, s: ^m.System) {
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
}
+8
View File
@@ -0,0 +1,8 @@
package gui
import m "../machine"
import rl "vendor:raylib"
gui_right_panel :: proc(rect: rl.Rectangle, s: ^m.System) {
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
}
+19 -47
View File
@@ -3,56 +3,33 @@ package gui
import m "../machine"
import rl "vendor:raylib"
control_bar_height :: f32(20.0)
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
gui_screen :: proc(window_rect: rl.Rectangle, s: ^m.System) {
control_bar_rect := rl.Rectangle{
x = window_rect.x,
y = window_rect.y,
width = window_rect.width,
height = control_bar_height
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
}
content_rect := rl.Rectangle{
x = window_rect.x,
y = window_rect.y + control_bar_height,
width = window_rect.width,
height = window_rect.height - control_bar_height
}
chip8_aspect := f32(64.0 / 32.0)
available_aspect := content_rect.width / content_rect.height
screen_rect := content_rect
if available_aspect > chip8_aspect {
// Content area is too wide
screen_rect.height = content_rect.height
screen_rect.width = content_rect.height * chip8_aspect
screen_rect.x = content_rect.x + (content_rect.width - screen_rect.width) / 2
screen_rect.y = content_rect.y
} else {
// Content area is too tall
screen_rect.width = content_rect.width
screen_rect.height = content_rect.width / chip8_aspect
screen_rect.x = content_rect.x
screen_rect.y = content_rect.y + (content_rect.height - screen_rect.height) / 2
}
pixel_size := min(int(screen_rect.width / 64), int(screen_rect.height / 32))
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(int(screen_rect.x) + (int(screen_rect.width) - actual_width) / 2)
display_y := i32(int(screen_rect.y) + (int(screen_rect.height) - actual_height) / 2)
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(window_rect, 1, rl.DARKGRAY)
rl.DrawRectangleLinesEx(control_bar_rect, 1, rl.GREEN)
rl.DrawRectangleLinesEx(rect, 1, rl.DARKGRAY)
rl.DrawRectangleLinesEx(screen_rect, 2, rl.WHITE)
render_display(&s.display, display_x, display_y, i32(pixel_size))
@@ -60,17 +37,12 @@ gui_screen :: proc(window_rect: rl.Rectangle, s: ^m.System) {
@(private = "file")
render_display :: proc(display_buffer: ^[32][64]u8, offset_x, offset_y, scale: i32) {
// Fill display area with black background
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,
)
rl.DrawRectangle(i32(x) * scale + offset_x, i32(y) * scale + offset_y, scale, scale, rl.WHITE)
}
}
}
-66
View File
@@ -1,66 +0,0 @@
package machine
import rl "vendor:raylib"
// Handle the "display" and all of its required functions
// raylib window, rendering, scale constants
SCALE :: 20
SCREEN_WITDH :: 64 * SCALE
SCREEN_HEIGHT :: 32 * SCALE
CYCLES_PER_FRAME :: 12
// Display will handle all the screen drawing with raylib etc
run_system :: proc(s: ^System) {
rl.InitWindow(SCREEN_WITDH, SCREEN_HEIGHT, "raylib")
rl.InitAudioDevice()
rl.SetTargetFPS(60)
beep := rl.LoadSound("./beep.wav")
for !rl.WindowShouldClose() {
rl.BeginDrawing()
rl.ClearBackground(rl.BLACK)
// Do a cpu cycle
// Cap at 60hz/60fps
for _ in 0..<CYCLES_PER_FRAME {
handle_input(s)
cycle(s)
}
// Handle delay timer
if s.delay_timer > 0 do s.delay_timer -= 1
// Current sound file is around 1s so stop
// immediately when timer is 0
if s.sound_timer > 0 {
s.sound_timer -= 1
if !rl.IsSoundPlaying(beep) do rl.PlaySound(beep)
} else {
rl.StopSound(beep)
}
render_display_buffer(&s.display)
rl.EndDrawing()
}
rl.UnloadSound(beep)
rl.CloseAudioDevice()
rl.CloseWindow()
}
// update display with display buffer bits
render_display_buffer :: proc(display_buffer: ^[32][64]u8) {
// get row
for y in 0..<len(display_buffer) {
// get cols
for x in 0..<len(display_buffer[0]) {
if display_buffer[y][x] == 0x01 {
rl.DrawRectangle(i32(x * SCALE), i32(y * SCALE), SCALE, SCALE, rl.WHITE)
}
}
}
}