feat: add imgui support using zgui
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -12,3 +12,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Any Custom Scripts for Debugging purposes
 | 
					# Any Custom Scripts for Debugging purposes
 | 
				
			||||||
*.sh
 | 
					*.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Dear ImGui
 | 
				
			||||||
 | 
					**/imgui.ini
 | 
				
			||||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -16,3 +16,6 @@
 | 
				
			|||||||
[submodule "lib/zba-gdbstub"]
 | 
					[submodule "lib/zba-gdbstub"]
 | 
				
			||||||
	path = lib/zba-gdbstub
 | 
						path = lib/zba-gdbstub
 | 
				
			||||||
	url = https://git.musuka.dev/paoda/zba-gdbstub
 | 
						url = https://git.musuka.dev/paoda/zba-gdbstub
 | 
				
			||||||
 | 
					[submodule "lib/zgui"]
 | 
				
			||||||
 | 
						path = lib/zgui
 | 
				
			||||||
 | 
						url = https://git.musuka.dev/paoda/zgui
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								build.zig
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								build.zig
									
									
									
									
									
								
							@@ -2,7 +2,8 @@ const std = @import("std");
 | 
				
			|||||||
const builtin = @import("builtin");
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Sdk = @import("lib/SDL.zig/Sdk.zig");
 | 
					const Sdk = @import("lib/SDL.zig/Sdk.zig");
 | 
				
			||||||
const Gdbstub = @import("lib/zba-gdbstub/build.zig");
 | 
					const gdbstub = @import("lib/zba-gdbstub/build.zig");
 | 
				
			||||||
 | 
					const zgui = @import("lib/zgui/build.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn build(b: *std.build.Builder) void {
 | 
					pub fn build(b: *std.build.Builder) void {
 | 
				
			||||||
    // Minimum Zig Version
 | 
					    // Minimum Zig Version
 | 
				
			||||||
@@ -43,13 +44,20 @@ pub fn build(b: *std.build.Builder) void {
 | 
				
			|||||||
    exe.addAnonymousModule("gl", .{ .source_file = .{ .path = "lib/gl.zig" } });
 | 
					    exe.addAnonymousModule("gl", .{ .source_file = .{ .path = "lib/gl.zig" } });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // gdbstub
 | 
					    // gdbstub
 | 
				
			||||||
    Gdbstub.link(exe);
 | 
					    gdbstub.link(exe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Zig SDL Bindings: https://github.com/MasterQ32/SDL.zig
 | 
					    // Zig SDL Bindings: https://github.com/MasterQ32/SDL.zig
 | 
				
			||||||
    const sdk = Sdk.init(b, null);
 | 
					    const sdk = Sdk.init(b, null);
 | 
				
			||||||
    sdk.link(exe, .dynamic);
 | 
					    sdk.link(exe, .dynamic);
 | 
				
			||||||
    exe.addModule("sdl2", sdk.getNativeModule());
 | 
					    exe.addModule("sdl2", sdk.getNativeModule());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Dear ImGui bindings
 | 
				
			||||||
 | 
					    const zgui_options = zgui.BuildOptionsStep.init(b, .{ .backend = .sdl2_opengl3 });
 | 
				
			||||||
 | 
					    const zgui_pkg = zgui.getPkg(&.{zgui_options.getPkg()});
 | 
				
			||||||
 | 
					    exe.addPackage(zgui_pkg);
 | 
				
			||||||
 | 
					    zgui.link(exe, zgui_options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exe.setBuildMode(mode);
 | 
				
			||||||
    exe.install();
 | 
					    exe.install();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const run_cmd = exe.run();
 | 
					    const run_cmd = exe.run();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								lib/zgui
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								lib/zgui
									
									
									
									
									
										Submodule
									
								
							 Submodule lib/zgui added at 7b01afc274
									
								
							@@ -16,8 +16,6 @@ const Allocator = std.mem.Allocator;
 | 
				
			|||||||
const Atomic = std.atomic.Atomic;
 | 
					const Atomic = std.atomic.Atomic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const log = std.log.scoped(.Cli);
 | 
					const log = std.log.scoped(.Cli);
 | 
				
			||||||
const width = @import("core/ppu.zig").width;
 | 
					 | 
				
			||||||
const height = @import("core/ppu.zig").height;
 | 
					 | 
				
			||||||
pub const log_level = if (builtin.mode != .Debug) .info else std.log.default_level;
 | 
					pub const log_level = if (builtin.mode != .Debug) .info else std.log.default_level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CLI Arguments + Help Text
 | 
					// CLI Arguments + Help Text
 | 
				
			||||||
@@ -91,10 +89,12 @@ pub fn main() void {
 | 
				
			|||||||
        cpu.fastBoot();
 | 
					        cpu.fastBoot();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var quit = Atomic(bool).init(false);
 | 
					    // TODO: Just copy the title instead of grabbing a pointer to it
 | 
				
			||||||
    var gui = Gui.init(&bus.pak.title, &bus.apu, width, height) 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 = Atomic(bool).init(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (result.args.gdb) {
 | 
					    if (result.args.gdb) {
 | 
				
			||||||
        const Server = @import("gdbstub").Server;
 | 
					        const Server = @import("gdbstub").Server;
 | 
				
			||||||
        const EmuThing = @import("core/emu.zig").EmuThing;
 | 
					        const EmuThing = @import("core/emu.zig").EmuThing;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										173
									
								
								src/platform.zig
									
									
									
									
									
								
							
							
						
						
									
										173
									
								
								src/platform.zig
									
									
									
									
									
								
							@@ -1,6 +1,8 @@
 | 
				
			|||||||
const std = @import("std");
 | 
					const std = @import("std");
 | 
				
			||||||
const SDL = @import("sdl2");
 | 
					const SDL = @import("sdl2");
 | 
				
			||||||
const gl = @import("gl");
 | 
					const gl = @import("gl");
 | 
				
			||||||
 | 
					const zgui = @import("zgui");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emu = @import("core/emu.zig");
 | 
					const emu = @import("core/emu.zig");
 | 
				
			||||||
const config = @import("config.zig");
 | 
					const config = @import("config.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,6 +14,14 @@ const FpsTracker = @import("util.zig").FpsTracker;
 | 
				
			|||||||
const gba_width = @import("core/ppu.zig").width;
 | 
					const gba_width = @import("core/ppu.zig").width;
 | 
				
			||||||
const gba_height = @import("core/ppu.zig").height;
 | 
					const gba_height = @import("core/ppu.zig").height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const GLuint = gl.GLuint;
 | 
				
			||||||
 | 
					const GLsizei = gl.GLsizei;
 | 
				
			||||||
 | 
					const SDL_GLContext = *anyopaque;
 | 
				
			||||||
 | 
					const Allocator = std.mem.Allocator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const width = 1280;
 | 
				
			||||||
 | 
					const height = 720;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const sample_rate = 1 << 15;
 | 
					pub const sample_rate = 1 << 15;
 | 
				
			||||||
pub const sample_format = SDL.AUDIO_U16;
 | 
					pub const sample_format = SDL.AUDIO_U16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,7 +29,6 @@ const default_title = "ZBA";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub const Gui = struct {
 | 
					pub const Gui = struct {
 | 
				
			||||||
    const Self = @This();
 | 
					    const Self = @This();
 | 
				
			||||||
    const SDL_GLContext = *anyopaque; // SDL.SDL_GLContext is a ?*anyopaque
 | 
					 | 
				
			||||||
    const log = std.log.scoped(.Gui);
 | 
					    const log = std.log.scoped(.Gui);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // zig fmt: off
 | 
					    // zig fmt: off
 | 
				
			||||||
@@ -44,20 +53,20 @@ pub const Gui = struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    program_id: gl.GLuint,
 | 
					    program_id: gl.GLuint,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn init(title: *const [12]u8, apu: *Apu, width: i32, height: i32) !Self {
 | 
					    pub fn init(allocator: Allocator, title: *const [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();
 | 
				
			||||||
        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();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const win_scale = @intCast(c_int, config.config().host.win_scale);
 | 
					        // const win_scale = @intCast(c_int, config.config().host.win_scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const window = SDL.SDL_CreateWindow(
 | 
					        const window = SDL.SDL_CreateWindow(
 | 
				
			||||||
            default_title,
 | 
					            default_title,
 | 
				
			||||||
            SDL.SDL_WINDOWPOS_CENTERED,
 | 
					            SDL.SDL_WINDOWPOS_CENTERED,
 | 
				
			||||||
            SDL.SDL_WINDOWPOS_CENTERED,
 | 
					            SDL.SDL_WINDOWPOS_CENTERED,
 | 
				
			||||||
            @as(c_int, width * win_scale),
 | 
					            width,
 | 
				
			||||||
            @as(c_int, height * win_scale),
 | 
					            height,
 | 
				
			||||||
            SDL.SDL_WINDOW_OPENGL | SDL.SDL_WINDOW_SHOWN,
 | 
					            SDL.SDL_WINDOW_OPENGL | SDL.SDL_WINDOW_SHOWN,
 | 
				
			||||||
        ) orelse panic();
 | 
					        ) orelse panic();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -67,19 +76,39 @@ pub const Gui = struct {
 | 
				
			|||||||
        gl.load(ctx, Self.glGetProcAddress) catch {};
 | 
					        gl.load(ctx, Self.glGetProcAddress) catch {};
 | 
				
			||||||
        if (SDL.SDL_GL_SetSwapInterval(@boolToInt(config.config().host.vsync)) < 0) panic();
 | 
					        if (SDL.SDL_GL_SetSwapInterval(@boolToInt(config.config().host.vsync)) < 0) panic();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const program_id = try compileShaders();
 | 
					        zgui.init(allocator);
 | 
				
			||||||
 | 
					        zgui.backend.init(window, ctx, "#version 330 core");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Self{
 | 
					        return Self{
 | 
				
			||||||
            .window = window,
 | 
					            .window = window,
 | 
				
			||||||
            .title = std.mem.sliceTo(title, 0),
 | 
					            .title = std.mem.sliceTo(title, 0),
 | 
				
			||||||
            .ctx = ctx,
 | 
					            .ctx = ctx,
 | 
				
			||||||
            .program_id = program_id,
 | 
					            .program_id = try compileShaders(),
 | 
				
			||||||
            .audio = Audio.init(apu),
 | 
					            .audio = Audio.init(apu),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn compileShaders() !gl.GLuint {
 | 
					    fn drawGbaTexture(self: *const Self, obj_ids: struct { GLuint, GLuint, GLuint }, tex_id: GLuint, buf: []const u8) void {
 | 
				
			||||||
        // TODO: Panic on Shader Compiler Failure + Error Message
 | 
					        gl.bindTexture(gl.TEXTURE_2D, tex_id);
 | 
				
			||||||
 | 
					        defer gl.bindTexture(gl.TEXTURE_2D, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gba_width, gba_height, gl.RGBA, gl.UNSIGNED_INT_8_8_8_8, buf.ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Bind VAO, EBO. VBO not bound
 | 
				
			||||||
 | 
					        gl.bindVertexArray(obj_ids[0]); // VAO
 | 
				
			||||||
 | 
					        defer gl.bindVertexArray(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj_ids[2]); // EBO
 | 
				
			||||||
 | 
					        defer gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Use compiled frag + vertex shader
 | 
				
			||||||
 | 
					        gl.useProgram(self.program_id);
 | 
				
			||||||
 | 
					        defer gl.useProgram(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn compileShaders() !GLuint {
 | 
				
			||||||
        const vert_shader = @embedFile("shader/pixelbuf.vert");
 | 
					        const vert_shader = @embedFile("shader/pixelbuf.vert");
 | 
				
			||||||
        const frag_shader = @embedFile("shader/pixelbuf.frag");
 | 
					        const frag_shader = @embedFile("shader/pixelbuf.frag");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -108,20 +137,25 @@ pub const Gui = struct {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Returns the VAO ID since it's used in run()
 | 
					    // Returns the VAO ID since it's used in run()
 | 
				
			||||||
    fn generateBuffers() struct { c_uint, c_uint, c_uint } {
 | 
					    fn genBufferObjects() struct { GLuint, GLuint, GLuint } {
 | 
				
			||||||
        var vao_id: c_uint = undefined;
 | 
					        var vao_id: GLuint = undefined;
 | 
				
			||||||
        var vbo_id: c_uint = undefined;
 | 
					        var vbo_id: GLuint = undefined;
 | 
				
			||||||
        var ebo_id: c_uint = undefined;
 | 
					        var ebo_id: GLuint = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gl.genVertexArrays(1, &vao_id);
 | 
					        gl.genVertexArrays(1, &vao_id);
 | 
				
			||||||
        gl.genBuffers(1, &vbo_id);
 | 
					        gl.genBuffers(1, &vbo_id);
 | 
				
			||||||
        gl.genBuffers(1, &ebo_id);
 | 
					        gl.genBuffers(1, &ebo_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gl.bindVertexArray(vao_id);
 | 
					        gl.bindVertexArray(vao_id);
 | 
				
			||||||
 | 
					        defer gl.bindVertexArray(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo_id);
 | 
					        gl.bindBuffer(gl.ARRAY_BUFFER, vbo_id);
 | 
				
			||||||
        gl.bufferData(gl.ARRAY_BUFFER, @sizeOf(@TypeOf(vertices)), &vertices, gl.STATIC_DRAW);
 | 
					        defer gl.bindBuffer(gl.ARRAY_BUFFER, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo_id);
 | 
					        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo_id);
 | 
				
			||||||
 | 
					        defer gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.bufferData(gl.ARRAY_BUFFER, @sizeOf(@TypeOf(vertices)), &vertices, gl.STATIC_DRAW);
 | 
				
			||||||
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, @sizeOf(@TypeOf(indices)), &indices, gl.STATIC_DRAW);
 | 
					        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, @sizeOf(@TypeOf(indices)), &indices, gl.STATIC_DRAW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Position
 | 
					        // Position
 | 
				
			||||||
@@ -137,23 +171,72 @@ pub const Gui = struct {
 | 
				
			|||||||
        return .{ vao_id, vbo_id, ebo_id };
 | 
					        return .{ vao_id, vbo_id, ebo_id };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn generateTexture(buf: []const u8) c_uint {
 | 
					    fn genGbaTexture(buf: []const u8) GLuint {
 | 
				
			||||||
        var tex_id: c_uint = undefined;
 | 
					        var tex_id: GLuint = undefined;
 | 
				
			||||||
        gl.genTextures(1, &tex_id);
 | 
					        gl.genTextures(1, &tex_id);
 | 
				
			||||||
        gl.bindTexture(gl.TEXTURE_2D, tex_id);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
 | 
					        gl.bindTexture(gl.TEXTURE_2D, tex_id);
 | 
				
			||||||
        // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
 | 
					        defer gl.bindTexture(gl.TEXTURE_2D, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
 | 
					        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
 | 
				
			||||||
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
 | 
					        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gba_width, gba_height, 0, gl.RGBA, gl.UNSIGNED_INT_8_8_8_8, buf.ptr);
 | 
					        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gba_width, gba_height, 0, gl.RGBA, gl.UNSIGNED_INT_8_8_8_8, buf.ptr);
 | 
				
			||||||
        // gl.generateMipmap(gl.TEXTURE_2D); // TODO: Remove?
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return tex_id;
 | 
					        return tex_id;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn genOutTexture() GLuint {
 | 
				
			||||||
 | 
					        var tex_id: GLuint = undefined;
 | 
				
			||||||
 | 
					        gl.genTextures(1, &tex_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.bindTexture(gl.TEXTURE_2D, tex_id);
 | 
				
			||||||
 | 
					        defer gl.bindTexture(gl.TEXTURE_2D, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
 | 
				
			||||||
 | 
					        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gba_width, gba_height, 0, gl.RGBA, gl.UNSIGNED_INT_8_8_8_8, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return tex_id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn genFrameBufObject(tex_id: c_uint) !GLuint {
 | 
				
			||||||
 | 
					        var fbo_id: GLuint = undefined;
 | 
				
			||||||
 | 
					        gl.genFramebuffers(1, &fbo_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo_id);
 | 
				
			||||||
 | 
					        defer gl.bindFramebuffer(gl.FRAMEBUFFER, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        gl.framebufferTexture(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex_id, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const draw_buffers: [1]GLuint = .{gl.COLOR_ATTACHMENT0};
 | 
				
			||||||
 | 
					        gl.drawBuffers(1, &draw_buffers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
 | 
				
			||||||
 | 
					            return error.FrameBufferObejctInitFailed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return fbo_id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn draw(self: *Self, tex_id: GLuint) void {
 | 
				
			||||||
 | 
					        _ = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _ = zgui.begin("Game Boy Advance Screen", .{ .flags = .{ .no_resize = true } });
 | 
				
			||||||
 | 
					            defer zgui.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const args = .{
 | 
				
			||||||
 | 
					                .w = gba_width,
 | 
				
			||||||
 | 
					                .h = gba_height,
 | 
				
			||||||
 | 
					                .uv0 = .{ 0.0, 1.0 },
 | 
				
			||||||
 | 
					                .uv1 = .{ 1.0, 0.0 },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            zgui.image(@intToPtr(*anyopaque, tex_id), args);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const RunOptions = struct {
 | 
					    const RunOptions = struct {
 | 
				
			||||||
        quit: *std.atomic.Atomic(bool),
 | 
					        quit: *std.atomic.Atomic(bool),
 | 
				
			||||||
        tracker: ?*FpsTracker = null,
 | 
					        tracker: ?*FpsTracker = null,
 | 
				
			||||||
@@ -166,16 +249,18 @@ pub const Gui = struct {
 | 
				
			|||||||
        const tracker = opt.tracker;
 | 
					        const tracker = opt.tracker;
 | 
				
			||||||
        const quit = opt.quit;
 | 
					        const quit = opt.quit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var buffer_ids = Self.generateBuffers();
 | 
					        const obj_ids = Self.genBufferObjects();
 | 
				
			||||||
        defer {
 | 
					        defer gl.deleteBuffers(3, @as(*const [3]c_uint, &obj_ids));
 | 
				
			||||||
            gl.deleteBuffers(1, &buffer_ids[2]); // EBO
 | 
					 | 
				
			||||||
            gl.deleteBuffers(1, &buffer_ids[1]); // VBO
 | 
					 | 
				
			||||||
            gl.deleteVertexArrays(1, &buffer_ids[0]); // VAO
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        const vao_id = buffer_ids[0];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const tex_id = Self.generateTexture(cpu.bus.ppu.framebuf.get(.Renderer));
 | 
					        const emu_tex = Self.genGbaTexture(cpu.bus.ppu.framebuf.get(.Renderer));
 | 
				
			||||||
        defer gl.deleteTextures(1, &tex_id);
 | 
					        const out_tex = Self.genOutTexture();
 | 
				
			||||||
 | 
					        defer gl.deleteTextures(2, &[_]c_uint{ emu_tex, out_tex });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const fbo_id = try Self.genFrameBufObject(out_tex);
 | 
				
			||||||
 | 
					        defer gl.deleteFramebuffers(1, &fbo_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var quit = std.atomic.Atomic(bool).init(false);
 | 
				
			||||||
 | 
					        var tracker = FpsTracker.init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var title_buf: [0x100]u8 = undefined;
 | 
					        var title_buf: [0x100]u8 = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -187,6 +272,8 @@ pub const Gui = struct {
 | 
				
			|||||||
            if (quit.load(.Monotonic)) break :emu_loop;
 | 
					            if (quit.load(.Monotonic)) break :emu_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (SDL.SDL_PollEvent(&event) != 0) {
 | 
					            while (SDL.SDL_PollEvent(&event) != 0) {
 | 
				
			||||||
 | 
					                _ = zgui.backend.processEvent(&event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                switch (event.type) {
 | 
					                switch (event.type) {
 | 
				
			||||||
                    SDL.SDL_QUIT => break :emu_loop,
 | 
					                    SDL.SDL_QUIT => break :emu_loop,
 | 
				
			||||||
                    SDL.SDL_KEYDOWN => {
 | 
					                    SDL.SDL_KEYDOWN => {
 | 
				
			||||||
@@ -239,13 +326,25 @@ pub const Gui = struct {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Emulator has an internal Double Buffer
 | 
					            {
 | 
				
			||||||
            const framebuf = cpu.bus.ppu.framebuf.get(.Renderer);
 | 
					                gl.bindFramebuffer(gl.FRAMEBUFFER, fbo_id);
 | 
				
			||||||
            gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gba_width, gba_height, gl.RGBA, gl.UNSIGNED_INT_8_8_8_8, framebuf.ptr);
 | 
					                defer gl.bindFramebuffer(gl.FRAMEBUFFER, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const buf = cpu.bus.ppu.framebuf.get(.Renderer);
 | 
				
			||||||
 | 
					                gl.viewport(0, 0, gba_width, gba_height);
 | 
				
			||||||
 | 
					                self.drawGbaTexture(obj_ids, emu_tex, buf);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Background
 | 
				
			||||||
 | 
					            const size = zgui.io.getDisplaySize();
 | 
				
			||||||
 | 
					            gl.viewport(0, 0, @floatToInt(c_int, size[0]), @floatToInt(c_int, size[1]));
 | 
				
			||||||
 | 
					            gl.clearColor(0, 0, 0, 1.0);
 | 
				
			||||||
 | 
					            gl.clear(gl.COLOR_BUFFER_BIT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            zgui.backend.newFrame(width, height);
 | 
				
			||||||
 | 
					            self.draw(out_tex);
 | 
				
			||||||
 | 
					            zgui.backend.draw();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            gl.useProgram(self.program_id);
 | 
					 | 
				
			||||||
            gl.bindVertexArray(vao_id);
 | 
					 | 
				
			||||||
            gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, null);
 | 
					 | 
				
			||||||
            SDL.SDL_GL_SwapWindow(self.window);
 | 
					            SDL.SDL_GL_SwapWindow(self.window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (tracker) |t| {
 | 
					            if (tracker) |t| {
 | 
				
			||||||
@@ -259,6 +358,10 @@ pub const Gui = struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    pub fn deinit(self: *Self) void {
 | 
					    pub fn deinit(self: *Self) void {
 | 
				
			||||||
        self.audio.deinit();
 | 
					        self.audio.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        zgui.backend.deinit();
 | 
				
			||||||
 | 
					        zgui.deinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gl.deleteProgram(self.program_id);
 | 
					        gl.deleteProgram(self.program_id);
 | 
				
			||||||
        SDL.SDL_GL_DeleteContext(self.ctx);
 | 
					        SDL.SDL_GL_DeleteContext(self.ctx);
 | 
				
			||||||
        SDL.SDL_DestroyWindow(self.window);
 | 
					        SDL.SDL_DestroyWindow(self.window);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user