Compare commits
4 Commits
30a37f26c5
...
6140db0d8f
| Author | SHA1 | Date | |
|---|---|---|---|
| 6140db0d8f | |||
| cc1962ff79 | |||
| 8830331774 | |||
| eded8b60b7 |
@@ -1,5 +1,5 @@
|
|||||||
APP_NAME := my_app
|
APP_NAME := my_app
|
||||||
SRC := ./src
|
SRC := ./src/main_desktop
|
||||||
|
|
||||||
.PHONY: all dev release clean
|
.PHONY: all dev release clean
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package main
|
|||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
|
||||||
import emu "machine"
|
import emu "../machine"
|
||||||
import sim "simulator"
|
import sim "../simulator"
|
||||||
|
|
||||||
DEV :: #config(DEV, false)
|
DEV :: #config(DEV, false)
|
||||||
|
|
||||||
@@ -22,9 +22,22 @@ main :: proc() {
|
|||||||
|
|
||||||
// Init the emu 8 "cpu"
|
// Init the emu 8 "cpu"
|
||||||
system := emu.init()
|
system := emu.init()
|
||||||
|
s := sim.Simulator {
|
||||||
|
machine = &system,
|
||||||
|
rom_loaded = false,
|
||||||
|
paused = true,
|
||||||
|
step = false,
|
||||||
|
cpu_hz = 700,
|
||||||
|
disasm_follow = true,
|
||||||
|
}
|
||||||
|
|
||||||
// Initilize sim, gui etc
|
sim.init(&s)
|
||||||
sim.run_simulator(&system)
|
|
||||||
|
for sim.should_run() {
|
||||||
|
sim.update(&s)
|
||||||
|
}
|
||||||
|
|
||||||
|
sim.shutdown(&s)
|
||||||
|
|
||||||
when DEV {
|
when DEV {
|
||||||
if len(track.allocation_map) > 0 {
|
if len(track.allocation_map) > 0 {
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
This allocator uses the malloc, calloc, free and realloc procs that emscripten
|
||||||
|
exposes in order to allocate memory. Just like Odin's default heap allocator
|
||||||
|
this uses proper alignment, so that maps and simd works.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main_web
|
||||||
|
|
||||||
|
import "core:mem"
|
||||||
|
import "core:c"
|
||||||
|
import "base:intrinsics"
|
||||||
|
|
||||||
|
// This will create bindings to emscripten's implementation of libc
|
||||||
|
// memory allocation features.
|
||||||
|
@(default_calling_convention = "c")
|
||||||
|
foreign {
|
||||||
|
calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||||
|
free :: proc(ptr: rawptr) ---
|
||||||
|
malloc :: proc(size: c.size_t) -> rawptr ---
|
||||||
|
realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||||
|
}
|
||||||
|
|
||||||
|
emscripten_allocator :: proc "contextless" () -> mem.Allocator {
|
||||||
|
return mem.Allocator{emscripten_allocator_proc, nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
emscripten_allocator_proc :: proc(
|
||||||
|
allocator_data: rawptr,
|
||||||
|
mode: mem.Allocator_Mode,
|
||||||
|
size, alignment: int,
|
||||||
|
old_memory: rawptr,
|
||||||
|
old_size: int,
|
||||||
|
location := #caller_location
|
||||||
|
) -> (data: []byte, err: mem.Allocator_Error) {
|
||||||
|
// These aligned alloc procs are almost indentical those in
|
||||||
|
// `_heap_allocator_proc` in `core:os`. Without the proper alignment you
|
||||||
|
// cannot use maps and simd features.
|
||||||
|
|
||||||
|
aligned_alloc :: proc(size, alignment: int, zero_memory: bool, old_ptr: rawptr = nil) -> ([]byte, mem.Allocator_Error) {
|
||||||
|
a := max(alignment, align_of(rawptr))
|
||||||
|
space := size + a - 1
|
||||||
|
|
||||||
|
allocated_mem: rawptr
|
||||||
|
if old_ptr != nil {
|
||||||
|
original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
|
||||||
|
allocated_mem = realloc(original_old_ptr, c.size_t(space+size_of(rawptr)))
|
||||||
|
} else if zero_memory {
|
||||||
|
// calloc automatically zeros memory, but it takes a number + size
|
||||||
|
// instead of just size.
|
||||||
|
allocated_mem = calloc(c.size_t(space+size_of(rawptr)), 1)
|
||||||
|
} else {
|
||||||
|
allocated_mem = malloc(c.size_t(space+size_of(rawptr)))
|
||||||
|
}
|
||||||
|
aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
||||||
|
|
||||||
|
ptr := uintptr(aligned_mem)
|
||||||
|
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||||
|
diff := int(aligned_ptr - ptr)
|
||||||
|
if (size + diff) > space || allocated_mem == nil {
|
||||||
|
return nil, .Out_Of_Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
aligned_mem = rawptr(aligned_ptr)
|
||||||
|
mem.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem
|
||||||
|
|
||||||
|
return mem.byte_slice(aligned_mem, size), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
aligned_free :: proc(p: rawptr) {
|
||||||
|
if p != nil {
|
||||||
|
free(mem.ptr_offset((^rawptr)(p), -1)^)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, mem.Allocator_Error) {
|
||||||
|
if p == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return aligned_alloc(new_size, new_alignment, true, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch mode {
|
||||||
|
case .Alloc:
|
||||||
|
return aligned_alloc(size, alignment, true)
|
||||||
|
|
||||||
|
case .Alloc_Non_Zeroed:
|
||||||
|
return aligned_alloc(size, alignment, false)
|
||||||
|
|
||||||
|
case .Free:
|
||||||
|
aligned_free(old_memory)
|
||||||
|
return nil, nil
|
||||||
|
|
||||||
|
case .Resize:
|
||||||
|
if old_memory == nil {
|
||||||
|
return aligned_alloc(size, alignment, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes := aligned_resize(old_memory, old_size, size, alignment) or_return
|
||||||
|
|
||||||
|
// realloc doesn't zero the new bytes, so we do it manually.
|
||||||
|
if size > old_size {
|
||||||
|
new_region := raw_data(bytes[old_size:])
|
||||||
|
intrinsics.mem_zero(new_region, size - old_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes, nil
|
||||||
|
|
||||||
|
case .Resize_Non_Zeroed:
|
||||||
|
if old_memory == nil {
|
||||||
|
return aligned_alloc(size, alignment, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return aligned_resize(old_memory, old_size, size, alignment)
|
||||||
|
|
||||||
|
case .Query_Features:
|
||||||
|
set := (^mem.Allocator_Mode_Set)(old_memory)
|
||||||
|
if set != nil {
|
||||||
|
set^ = {.Alloc, .Free, .Resize, .Query_Features}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
|
||||||
|
case .Free_All, .Query_Info:
|
||||||
|
return nil, .Mode_Not_Implemented
|
||||||
|
}
|
||||||
|
return nil, .Mode_Not_Implemented
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
This logger is largely a copy of the console logger in `core:log`, but it uses
|
||||||
|
emscripten's `puts` proc to write into he console of the web browser.
|
||||||
|
|
||||||
|
This is more or less identical to the logger in Aronicu's repository:
|
||||||
|
https://github.com/Aronicu/Raylib-WASM/tree/main
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main_web
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:log"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
|
Emscripten_Logger_Opts :: log.Options{.Level, .Short_File_Path, .Line}
|
||||||
|
|
||||||
|
create_emscripten_logger :: proc (lowest := log.Level.Debug, opt := Emscripten_Logger_Opts) -> log.Logger {
|
||||||
|
return log.Logger{data = nil, procedure = logger_proc, lowest_level = lowest, options = opt}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This create's a binding to `puts` which will be linked in as part of the
|
||||||
|
// emscripten runtime.
|
||||||
|
@(default_calling_convention = "c")
|
||||||
|
foreign {
|
||||||
|
puts :: proc(buffer: cstring) -> c.int ---
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
logger_proc :: proc(
|
||||||
|
logger_data: rawptr,
|
||||||
|
level: log.Level,
|
||||||
|
text: string,
|
||||||
|
options: log.Options,
|
||||||
|
location := #caller_location
|
||||||
|
) {
|
||||||
|
b := strings.builder_make(context.temp_allocator)
|
||||||
|
strings.write_string(&b, Level_Headers[level])
|
||||||
|
do_location_header(options, &b, location)
|
||||||
|
fmt.sbprint(&b, text)
|
||||||
|
|
||||||
|
if bc, bc_err := strings.to_cstring(&b); bc_err == nil {
|
||||||
|
puts(bc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
Level_Headers := [?]string {
|
||||||
|
0 ..< 10 = "[DEBUG] --- ",
|
||||||
|
10 ..< 20 = "[INFO ] --- ",
|
||||||
|
20 ..< 30 = "[WARN ] --- ",
|
||||||
|
30 ..< 40 = "[ERROR] --- ",
|
||||||
|
40 ..< 50 = "[FATAL] --- ",
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
do_location_header :: proc(opts: log.Options, buf: ^strings.Builder, location := #caller_location) {
|
||||||
|
if log.Location_Header_Opts & opts == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.sbprint(buf, "[")
|
||||||
|
file := location.file_path
|
||||||
|
if .Short_File_Path in opts {
|
||||||
|
last := 0
|
||||||
|
for r, i in location.file_path {
|
||||||
|
if r == '/' {
|
||||||
|
last = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file = location.file_path[last:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.Location_File_Opts & opts != nil {
|
||||||
|
fmt.sbprint(buf, file)
|
||||||
|
}
|
||||||
|
if .Line in opts {
|
||||||
|
if log.Location_File_Opts & opts != nil {
|
||||||
|
fmt.sbprint(buf, ":")
|
||||||
|
}
|
||||||
|
fmt.sbprint(buf, location.line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if .Procedure in opts {
|
||||||
|
if (log.Location_File_Opts | {.Line}) & opts != nil {
|
||||||
|
fmt.sbprint(buf, ":")
|
||||||
|
}
|
||||||
|
fmt.sbprintf(buf, "%s()", location.procedure)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.sbprint(buf, "] ")
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en-us">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
|
||||||
|
<title>Odin + Raylib on the web</title>
|
||||||
|
<meta name="title" content="Odin + Raylib on the web">
|
||||||
|
<meta name="description" content="Make games using Odin + Raylib that work in the browser">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
canvas.game_canvas {
|
||||||
|
border: 0px none;
|
||||||
|
background-color: black;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas class="game_canvas" id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1" onmousedown="event.target.focus()" onkeydown="event.preventDefault()"></canvas>
|
||||||
|
<script type="text/javascript" src="odin.js"></script>
|
||||||
|
<script>
|
||||||
|
var odinMemoryInterface = new odin.WasmMemoryInterface();
|
||||||
|
odinMemoryInterface.setIntSize(4);
|
||||||
|
var odinImports = odin.setupDefaultImports(odinMemoryInterface);
|
||||||
|
|
||||||
|
// The Module is used as configuration for emscripten.
|
||||||
|
var Module = {
|
||||||
|
// This is called by emscripten when it starts up.
|
||||||
|
instantiateWasm: (imports, successCallback) => {
|
||||||
|
const newImports = {
|
||||||
|
...odinImports,
|
||||||
|
...imports
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebAssembly.instantiateStreaming(fetch("index.wasm"), newImports).then(function(output) {
|
||||||
|
var e = output.instance.exports;
|
||||||
|
odinMemoryInterface.setExports(e);
|
||||||
|
odinMemoryInterface.setMemory(e.memory);
|
||||||
|
return successCallback(output.instance);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// This happens a bit after `instantiateWasm`, when everything is
|
||||||
|
// done setting up. At that point we can run code.
|
||||||
|
onRuntimeInitialized: () => {
|
||||||
|
var e = wasmExports;
|
||||||
|
|
||||||
|
// Calls any procedure marked with @init
|
||||||
|
e._start();
|
||||||
|
|
||||||
|
// See source/main_web/main_web.odin for main_start,
|
||||||
|
// main_update and main_end.
|
||||||
|
e.main_start();
|
||||||
|
|
||||||
|
function send_resize() {
|
||||||
|
var canvas = document.getElementById('canvas');
|
||||||
|
e.web_window_size_changed(canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', function(event) {
|
||||||
|
send_resize();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
// This can probably be done better: Ideally we'd feed the
|
||||||
|
// initial size to `main_start`. But there seems to be a
|
||||||
|
// race condition. `canvas` doesn't have it's correct size yet.
|
||||||
|
send_resize();
|
||||||
|
|
||||||
|
// Runs the "main loop".
|
||||||
|
function do_main_update() {
|
||||||
|
if (!e.main_update()) {
|
||||||
|
e.main_end();
|
||||||
|
|
||||||
|
// Calls procedures marked with @fini
|
||||||
|
e._end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.requestAnimationFrame(do_main_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.requestAnimationFrame(do_main_update);
|
||||||
|
},
|
||||||
|
print: (function() {
|
||||||
|
var element = document.getElementById("output");
|
||||||
|
if (element) element.value = ''; // clear browser cache
|
||||||
|
return function(text) {
|
||||||
|
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||||
|
console.log(text);
|
||||||
|
if (element) {
|
||||||
|
element.value += text + "\n";
|
||||||
|
element.scrollTop = element.scrollHeight; // focus on bottom
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(),
|
||||||
|
canvas: (function() {
|
||||||
|
return document.getElementById("canvas");
|
||||||
|
})()
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Emscripten injects its javascript here -->
|
||||||
|
{{{ SCRIPT }}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// These procs are the ones that will be called from `index.html`, which is
|
||||||
|
// generated from `index_template.html`.
|
||||||
|
|
||||||
|
package main_web
|
||||||
|
|
||||||
|
import "base:runtime"
|
||||||
|
import "core:c"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
|
import emu "../machine"
|
||||||
|
import sim "../simulator"
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
web_context: runtime.Context
|
||||||
|
|
||||||
|
@export
|
||||||
|
main_start :: proc "c" () {
|
||||||
|
context = runtime.default_context()
|
||||||
|
|
||||||
|
// The WASM allocator doesn't seem to work properly in combination with
|
||||||
|
// emscripten. There is some kind of conflict with how the manage memory.
|
||||||
|
// So this sets up an allocator that uses emscripten's malloc.
|
||||||
|
context.allocator = emscripten_allocator()
|
||||||
|
runtime.init_global_temporary_allocator(1*mem.Megabyte)
|
||||||
|
|
||||||
|
// Since we now use js_wasm32 we should be able to remove this and use
|
||||||
|
// context.logger = log.create_console_logger(). However, that one produces
|
||||||
|
// extra newlines on web. So it's a bug in that core lib.
|
||||||
|
context.logger = create_emscripten_logger()
|
||||||
|
|
||||||
|
web_context = context
|
||||||
|
|
||||||
|
// Init the emu 8 "cpu"
|
||||||
|
system := emu.init()
|
||||||
|
s := sim.Simulator {
|
||||||
|
machine = &system,
|
||||||
|
rom_loaded = false,
|
||||||
|
paused = true,
|
||||||
|
step = false,
|
||||||
|
cpu_hz = 700,
|
||||||
|
disasm_follow = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
sim.init(&s)
|
||||||
|
}
|
||||||
|
|
||||||
|
@export
|
||||||
|
main_update :: proc "c" () -> bool {
|
||||||
|
context = web_context
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
sim.update()
|
||||||
|
return sim.should_run()
|
||||||
|
}
|
||||||
|
|
||||||
|
@export
|
||||||
|
main_end :: proc "c" () {
|
||||||
|
context = web_context
|
||||||
|
// TODO
|
||||||
|
sim.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
@export
|
||||||
|
web_window_size_changed :: proc "c" (w: c.int, h: c.int) {
|
||||||
|
context = web_context
|
||||||
|
// TODO
|
||||||
|
game.parent_window_size_changed(int(w), int(h))
|
||||||
|
}
|
||||||
+76
-56
@@ -3,6 +3,9 @@ package simulator
|
|||||||
import emu "../machine"
|
import emu "../machine"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
// Globals
|
||||||
|
run: bool
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
WINDOW_WIDTH :: 1920
|
WINDOW_WIDTH :: 1920
|
||||||
WINDOW_HEIGHT :: 1080
|
WINDOW_HEIGHT :: 1080
|
||||||
@@ -38,13 +41,17 @@ Layout :: struct {
|
|||||||
info_box : rl.Rectangle,
|
info_box : rl.Rectangle,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize main the gui 'window'
|
init :: proc(sim: ^Simulator) {
|
||||||
run_gui :: proc(sim: ^Simulator) {
|
run = true
|
||||||
|
|
||||||
rl.SetConfigFlags({.WINDOW_RESIZABLE})
|
rl.SetConfigFlags({.WINDOW_RESIZABLE})
|
||||||
rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Octal Cookie - Chip 8 Simulator")
|
rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Octal Cookie - Chip 8 Simulator")
|
||||||
rl.InitAudioDevice()
|
rl.InitAudioDevice()
|
||||||
rl.SetTargetFPS(60)
|
rl.SetTargetFPS(60)
|
||||||
|
|
||||||
|
// Load sound
|
||||||
beep := rl.LoadSound("./assets/sounds/beep.wav")
|
beep := rl.LoadSound("./assets/sounds/beep.wav")
|
||||||
|
sim.sound = beep
|
||||||
|
|
||||||
// Load fonts
|
// Load fonts
|
||||||
font := rl.LoadFontEx("./assets/fonts/Inter_18pt-Regular.ttf", 18, nil, 0)
|
font := rl.LoadFontEx("./assets/fonts/Inter_18pt-Regular.ttf", 18, nil, 0)
|
||||||
@@ -56,71 +63,84 @@ run_gui :: proc(sim: ^Simulator) {
|
|||||||
|
|
||||||
rl.GuiSetFont(font)
|
rl.GuiSetFont(font)
|
||||||
rl.GuiSetStyle(.DEFAULT, 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
|
update :: proc(sim: ^Simulator) {
|
||||||
for !rl.WindowShouldClose() {
|
// Recalculate layout each frame based on current window size
|
||||||
// Recalculate layout each frame based on current window size
|
// Pass these down to gui functions so they can setup their sizes?
|
||||||
// Pass these down to gui functions so they can setup their sizes?
|
screen_width := f32(rl.GetScreenWidth())
|
||||||
screen_width := f32(rl.GetScreenWidth())
|
screen_height := f32(rl.GetScreenHeight())
|
||||||
screen_height := f32(rl.GetScreenHeight())
|
sidebar_width := screen_width * 0.20
|
||||||
sidebar_width := screen_width * 0.20
|
|
||||||
|
|
||||||
// set all the layout structs dynamically with the screen size
|
// set all the layout structs dynamically with the screen size
|
||||||
layout := calc_layout(screen_width, screen_height)
|
layout := calc_layout(screen_width, screen_height)
|
||||||
|
|
||||||
rl.BeginDrawing()
|
rl.BeginDrawing()
|
||||||
rl.ClearBackground(rl.Color{0x18, 0x18, 0x18, 0xFF})
|
rl.ClearBackground(rl.Color{0x18, 0x18, 0x18, 0xFF})
|
||||||
|
|
||||||
cycles := int(sim.cpu_hz / SIM_FPS)
|
cycles := int(sim.cpu_hz / SIM_FPS)
|
||||||
if (!sim.paused) {
|
if (!sim.paused) {
|
||||||
// Cycle the machine to update memory etc
|
// Cycle the machine to update memory etc
|
||||||
emu.run_machine(sim.machine, cycles)
|
emu.run_machine(sim.machine, cycles)
|
||||||
tick_timers(sim, beep)
|
tick_timers(sim)
|
||||||
}
|
|
||||||
|
|
||||||
if(sim.paused && sim.step) {
|
|
||||||
// Cycle the machine to update memory etc
|
|
||||||
emu.run_machine(sim.machine, 1)
|
|
||||||
tick_timers(sim, beep)
|
|
||||||
sim.step = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top
|
|
||||||
// ------------------------------------------
|
|
||||||
gui_control_bar(layout.control_bar, 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_panel(layout.bottom_panel, sim)
|
|
||||||
gui_status_bar(layout.status_bar, sim)
|
|
||||||
|
|
||||||
// Info Box
|
|
||||||
// ------------------------------------------
|
|
||||||
gui_info_box(layout.info_box, sim, screen_width, screen_height)
|
|
||||||
|
|
||||||
rl.EndDrawing()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(sim.paused && sim.step) {
|
||||||
|
// Cycle the machine to update memory etc
|
||||||
|
emu.run_machine(sim.machine, 1)
|
||||||
|
tick_timers(sim)
|
||||||
|
sim.step = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top
|
||||||
|
// ------------------------------------------
|
||||||
|
gui_control_bar(layout.control_bar, 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_panel(layout.bottom_panel, sim)
|
||||||
|
gui_status_bar(layout.status_bar, sim)
|
||||||
|
|
||||||
|
// Info Box
|
||||||
|
// ------------------------------------------
|
||||||
|
gui_info_box(layout.info_box, sim, screen_width, screen_height)
|
||||||
|
|
||||||
|
rl.EndDrawing()
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown :: proc(sim: ^Simulator) {
|
||||||
rl.UnloadFont(sim.font)
|
rl.UnloadFont(sim.font)
|
||||||
rl.UnloadSound(beep)
|
rl.UnloadSound(sim.sound)
|
||||||
rl.CloseAudioDevice()
|
rl.CloseAudioDevice()
|
||||||
rl.CloseWindow()
|
rl.CloseWindow()
|
||||||
}
|
}
|
||||||
|
|
||||||
tick_timers :: proc(sim: ^Simulator, beep: rl.Sound) {
|
should_run :: proc() -> bool {
|
||||||
|
when ODIN_OS != .JS {
|
||||||
|
if rl.WindowShouldClose() {
|
||||||
|
run = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return run
|
||||||
|
}
|
||||||
|
|
||||||
|
tick_timers :: proc(sim: ^Simulator) {
|
||||||
|
beep := sim.sound
|
||||||
|
|
||||||
if sim.machine.delay_timer > 0 do sim.machine.delay_timer -= 1
|
if sim.machine.delay_timer > 0 do sim.machine.delay_timer -= 1
|
||||||
if sim.machine.sound_timer > 0 {
|
if sim.machine.sound_timer > 0 {
|
||||||
sim.machine.sound_timer -= 1
|
sim.machine.sound_timer -= 1
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ Simulator :: struct {
|
|||||||
cpu_hz: f32,
|
cpu_hz: f32,
|
||||||
info_box: bool,
|
info_box: bool,
|
||||||
// GUI
|
// GUI
|
||||||
|
sound: rl.Sound,
|
||||||
font: rl.Font,
|
font: rl.Font,
|
||||||
active_tab: i32,
|
active_tab: i32,
|
||||||
mem_scroll: rl.Vector2,
|
mem_scroll: rl.Vector2,
|
||||||
@@ -44,6 +45,7 @@ Simulator :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Requires an initilized emulatore System Struct
|
// Requires an initilized emulatore System Struct
|
||||||
|
/*
|
||||||
run_simulator :: proc(s: ^emu.System) {
|
run_simulator :: proc(s: ^emu.System) {
|
||||||
sim := Simulator {
|
sim := Simulator {
|
||||||
machine = s,
|
machine = s,
|
||||||
@@ -56,3 +58,4 @@ run_simulator :: proc(s: ^emu.System) {
|
|||||||
|
|
||||||
run_gui(&sim)
|
run_gui(&sim)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user