Compare commits
No commits in common. "2629d15e2f63aee5ecd33fe180e3d072ddb7e482" and "85ec9a84c492be12154241870904d6f0f4b463b4" have entirely different histories.
2629d15e2f
...
85ec9a84c4
|
@ -15,13 +15,14 @@ This is a simple (read: incomplete) for-fun long-term project. I hope to get "mo
|
||||||
- [x] Affine Sprites
|
- [x] Affine Sprites
|
||||||
- [ ] Windowing (see [this branch](https://git.musuka.dev/paoda/zba/src/branch/window))
|
- [ ] Windowing (see [this branch](https://git.musuka.dev/paoda/zba/src/branch/window))
|
||||||
- [ ] Audio Resampler (Having issues with SDL2's)
|
- [ ] Audio Resampler (Having issues with SDL2's)
|
||||||
|
- [x] Immediate Mode GUI (see [this branch](https://git.musuka.dev/paoda/zba/src/branch/imgui))
|
||||||
- [ ] Refactoring for easy-ish perf boosts
|
- [ ] Refactoring for easy-ish perf boosts
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
As it currently exists, ZBA is run from the terminal. In your console of choice, type `./zba --help` to see what you can do.
|
As it currently exists, ZBA is run from the terminal. In your console of choice, type `./zba --help` to see what you can do.
|
||||||
|
|
||||||
I typically find myself typing `./zba -b ./bin/bios.bin` and then going to File -> Insert ROM to load the title of my choice.
|
I typically find myself typing `./zba -b ./bin/bios.bin ./bin/test/suite.gba` to see how badly my "cool new feature" broke everything else.
|
||||||
|
|
||||||
Need a BIOS? Why not try using the open-source [Cult-Of-GBA BIOS](https://github.com/Cult-of-GBA/BIOS) written by [fleroviux](https://github.com/fleroviux) and [DenSinH](https://github.com/DenSinH)?
|
Need a BIOS? Why not try using the open-source [Cult-Of-GBA BIOS](https://github.com/Cult-of-GBA/BIOS) written by [fleroviux](https://github.com/fleroviux) and [DenSinH](https://github.com/DenSinH)?
|
||||||
|
|
||||||
|
|
|
@ -179,30 +179,23 @@ pub fn write(self: *Self, comptime T: type, word_count: u16, address: u32, value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, cpu: *Arm7tdmi, maybe_rom: ?[]const u8, maybe_save: ?[]const u8) !Self {
|
pub fn init(allocator: Allocator, cpu: *Arm7tdmi, rom_path: []const u8, save_path: ?[]const u8) !Self {
|
||||||
const Device = Gpio.Device;
|
const file = try std.fs.cwd().openFile(rom_path, .{});
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
const items: struct { []u8, [12]u8, Backup.Kind, Device.Kind } = if (maybe_rom) |file_path| blk: {
|
const file_buf = try file.readToEndAlloc(allocator, try file.getEndPos());
|
||||||
const file = try std.fs.cwd().openFile(file_path, .{});
|
const title = file_buf[0xA0..0xAC].*;
|
||||||
defer file.close();
|
const kind = Backup.guess(file_buf);
|
||||||
|
const device = if (config.config().guest.force_rtc) .Rtc else guessDevice(file_buf);
|
||||||
|
|
||||||
const buffer = try file.readToEndAlloc(allocator, try file.getEndPos());
|
logHeader(file_buf, title);
|
||||||
const title = buffer[0xA0..0xAC];
|
|
||||||
logHeader(buffer, title);
|
|
||||||
|
|
||||||
const device_kind = if (config.config().guest.force_rtc) .Rtc else guessDevice(buffer);
|
|
||||||
|
|
||||||
break :blk .{ buffer, title.*, Backup.guess(buffer), device_kind };
|
|
||||||
} else .{ try allocator.alloc(u8, 0), [_]u8{0} ** 12, .None, .None };
|
|
||||||
|
|
||||||
const title = items[1];
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.buf = items[0],
|
.buf = file_buf,
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.title = title,
|
.title = title,
|
||||||
.backup = try Backup.init(allocator, items[2], title, maybe_save),
|
.backup = try Backup.init(allocator, kind, title, save_path),
|
||||||
.gpio = try Gpio.init(allocator, cpu, items[3]),
|
.gpio = try Gpio.init(allocator, cpu, device),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,11 +223,11 @@ fn guessDevice(buf: []const u8) Gpio.Device.Kind {
|
||||||
return .None;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logHeader(buf: []const u8, title: *const [12]u8) void {
|
fn logHeader(buf: []const u8, title: [12]u8) void {
|
||||||
const version = buf[0xBC];
|
const ver = buf[0xBC];
|
||||||
|
|
||||||
log.info("Title: {s}", .{title});
|
log.info("Title: {s}", .{title});
|
||||||
if (version != 0) log.info("Version: {}", .{version});
|
if (ver != 0) log.info("Version: {}", .{ver});
|
||||||
|
|
||||||
log.info("Game Code: {s}", .{buf[0xAC..0xB0]});
|
log.info("Game Code: {s}", .{buf[0xAC..0xB0]});
|
||||||
log.info("Maker Code: {s}", .{buf[0xB0..0xB2]});
|
log.info("Maker Code: {s}", .{buf[0xB0..0xB2]});
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub const Backup = struct {
|
||||||
flash: Flash,
|
flash: Flash,
|
||||||
eeprom: Eeprom,
|
eeprom: Eeprom,
|
||||||
|
|
||||||
pub const Kind = enum {
|
const Kind = enum {
|
||||||
Eeprom,
|
Eeprom,
|
||||||
Sram,
|
Sram,
|
||||||
Flash,
|
Flash,
|
||||||
|
|
|
@ -26,25 +26,25 @@ const histogram_len = 0x400;
|
||||||
|
|
||||||
/// Immediate-Mode GUI State
|
/// Immediate-Mode GUI State
|
||||||
pub const State = struct {
|
pub const State = struct {
|
||||||
title: [12:0]u8,
|
title: [:0]const u8,
|
||||||
|
|
||||||
fps_hist: RingBuffer(u32),
|
fps_hist: RingBuffer(u32),
|
||||||
should_quit: bool = false,
|
should_quit: bool = false,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) !@This() {
|
pub fn init(allocator: Allocator, title: [12]u8) !@This() {
|
||||||
const history = try allocator.alloc(u32, histogram_len);
|
const history = try allocator.alloc(u32, histogram_len);
|
||||||
|
const without_null = std.mem.sliceTo(&title, 0);
|
||||||
var title: [12:0]u8 = [_:0]u8{0} ** 12;
|
|
||||||
std.mem.copy(u8, &title, "[No Title]");
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.title = title,
|
.title = try allocator.dupeZ(u8, without_null),
|
||||||
.fps_hist = RingBuffer(u32).init(history),
|
.fps_hist = RingBuffer(u32).init(history),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
||||||
|
allocator.free(self.title);
|
||||||
allocator.free(self.fps_hist.buf);
|
allocator.free(self.fps_hist.buf);
|
||||||
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -60,10 +60,9 @@ pub fn draw(state: *State, tex_id: GLuint, cpu: *Arm7tdmi) void {
|
||||||
defer zgui.endMenu();
|
defer zgui.endMenu();
|
||||||
|
|
||||||
if (zgui.menuItem("Quit", .{})) state.should_quit = true;
|
if (zgui.menuItem("Quit", .{})) state.should_quit = true;
|
||||||
|
|
||||||
if (zgui.menuItem("Insert ROM", .{})) blk: {
|
if (zgui.menuItem("Insert ROM", .{})) blk: {
|
||||||
const maybe_path = nfd.openFileDialog("gba", null) catch |e| {
|
const maybe_path = nfd.openFileDialog("gba", null) catch |e| {
|
||||||
log.err("failed to open file dialog: {}", .{e});
|
log.err("failed to open file dialog: {?}", .{e});
|
||||||
break :blk;
|
break :blk;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,10 +74,6 @@ pub fn draw(state: *State, tex_id: GLuint, cpu: *Arm7tdmi) void {
|
||||||
log.err("failed to replace GamePak: {}", .{e});
|
log.err("failed to replace GamePak: {}", .{e});
|
||||||
break :blk;
|
break :blk;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ideally, state.title = cpu.bus.pak.title
|
|
||||||
// since state.title is a [12:0]u8 and cpu.bus.pak.title is a [12]u8
|
|
||||||
std.mem.copy(u8, &state.title, &cpu.bus.pak.title);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +91,7 @@ pub fn draw(state: *State, tex_id: GLuint, cpu: *Arm7tdmi) void {
|
||||||
const w = @intToFloat(f32, gba_width * win_scale);
|
const w = @intToFloat(f32, gba_width * win_scale);
|
||||||
const h = @intToFloat(f32, gba_height * win_scale);
|
const h = @intToFloat(f32, gba_height * win_scale);
|
||||||
|
|
||||||
const window_title = std.mem.sliceTo(&state.title, 0);
|
const window_title = if (state.title.len != 0) state.title else "[No Title]";
|
||||||
_ = zgui.begin(window_title, .{ .flags = .{ .no_resize = true, .always_auto_resize = true } });
|
_ = zgui.begin(window_title, .{ .flags = .{ .no_resize = true, .always_auto_resize = true } });
|
||||||
defer zgui.end();
|
defer zgui.end();
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ pub fn main() void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Just copy the title instead of grabbing a pointer to it
|
// TODO: Just copy the title instead of grabbing a pointer to it
|
||||||
var gui = Gui.init(allocator, &bus.apu) catch |e| exitln("failed to init gui: {}", .{e});
|
var gui = Gui.init(allocator, bus.pak.title, &bus.apu) catch |e| exitln("failed to init gui: {}", .{e});
|
||||||
defer gui.deinit();
|
defer gui.deinit();
|
||||||
|
|
||||||
var quit = std.atomic.Atomic(bool).init(false);
|
var quit = std.atomic.Atomic(bool).init(false);
|
||||||
|
@ -139,7 +139,7 @@ pub fn main() void {
|
||||||
|
|
||||||
fn handleArguments(allocator: Allocator, data_path: []const u8, result: *const clap.Result(clap.Help, ¶ms, clap.parsers.default)) !FilePaths {
|
fn handleArguments(allocator: Allocator, data_path: []const u8, result: *const clap.Result(clap.Help, ¶ms, clap.parsers.default)) !FilePaths {
|
||||||
const rom_path = romPath(result);
|
const rom_path = romPath(result);
|
||||||
log.info("ROM path: {?s}", .{rom_path});
|
log.info("ROM path: {s}", .{rom_path});
|
||||||
|
|
||||||
const bios_path = result.args.bios;
|
const bios_path = result.args.bios;
|
||||||
if (bios_path) |path| log.info("BIOS path: {s}", .{path}) else log.warn("No BIOS provided", .{});
|
if (bios_path) |path| log.info("BIOS path: {s}", .{path}) else log.warn("No BIOS provided", .{});
|
||||||
|
@ -188,10 +188,10 @@ fn ensureConfigDirExists(config_path: []const u8) !void {
|
||||||
try dir.makePath("zba");
|
try dir.makePath("zba");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn romPath(result: *const clap.Result(clap.Help, ¶ms, clap.parsers.default)) ?[]const u8 {
|
fn romPath(result: *const clap.Result(clap.Help, ¶ms, clap.parsers.default)) []const u8 {
|
||||||
return switch (result.positionals.len) {
|
return switch (result.positionals.len) {
|
||||||
0 => null,
|
|
||||||
1 => result.positionals[0],
|
1 => result.positionals[0],
|
||||||
|
0 => exitln("ZBA requires a path to a GamePak ROM", .{}),
|
||||||
else => exitln("ZBA received too many positional arguments.", .{}),
|
else => exitln("ZBA received too many positional arguments.", .{}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub const Gui = struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
program_id: gl.GLuint,
|
program_id: gl.GLuint,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, apu: *Apu) !Self {
|
pub fn init(allocator: Allocator, title: [12]u8, apu: *Apu) !Self {
|
||||||
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO | SDL.SDL_INIT_EVENTS | SDL.SDL_INIT_AUDIO) < 0) panic();
|
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO | SDL.SDL_INIT_EVENTS | SDL.SDL_INIT_AUDIO) < 0) panic();
|
||||||
if (SDL.SDL_GL_SetAttribute(SDL.SDL_GL_CONTEXT_PROFILE_MASK, SDL.SDL_GL_CONTEXT_PROFILE_CORE) < 0) panic();
|
if (SDL.SDL_GL_SetAttribute(SDL.SDL_GL_CONTEXT_PROFILE_MASK, SDL.SDL_GL_CONTEXT_PROFILE_CORE) < 0) panic();
|
||||||
if (SDL.SDL_GL_SetAttribute(SDL.SDL_GL_CONTEXT_MAJOR_VERSION, 3) < 0) panic();
|
if (SDL.SDL_GL_SetAttribute(SDL.SDL_GL_CONTEXT_MAJOR_VERSION, 3) < 0) panic();
|
||||||
|
@ -91,7 +91,7 @@ pub const Gui = struct {
|
||||||
.audio = Audio.init(apu),
|
.audio = Audio.init(apu),
|
||||||
|
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.state = try imgui.State.init(allocator),
|
.state = try imgui.State.init(allocator, title),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub fn escape(title: [12]u8) [12]u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const FilePaths = struct {
|
pub const FilePaths = struct {
|
||||||
rom: ?[]const u8,
|
rom: []const u8,
|
||||||
bios: ?[]const u8,
|
bios: ?[]const u8,
|
||||||
save: ?[]const u8,
|
save: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue