feat: add imgui support using zgui
This commit is contained in:
parent
59baa14bde
commit
93258ca511
|
@ -11,4 +11,8 @@
|
||||||
/lib/SDL2
|
/lib/SDL2
|
||||||
|
|
||||||
# Any Custom Scripts for Debugging purposes
|
# Any Custom Scripts for Debugging purposes
|
||||||
*.sh
|
*.sh
|
||||||
|
|
||||||
|
|
||||||
|
# Dear ImGui
|
||||||
|
**/imgui.ini
|
|
@ -13,3 +13,6 @@
|
||||||
[submodule "lib/zig-toml"]
|
[submodule "lib/zig-toml"]
|
||||||
path = lib/zig-toml
|
path = lib/zig-toml
|
||||||
url = https://github.com/aeronavery/zig-toml
|
url = https://github.com/aeronavery/zig-toml
|
||||||
|
[submodule "lib/zgui"]
|
||||||
|
path = lib/zgui
|
||||||
|
url = ssh://git@musuka.dev:2222/paoda/zgui.git
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
const std = @import("std");
|
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 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
|
||||||
|
@ -48,6 +50,12 @@ pub fn build(b: *std.build.Builder) void {
|
||||||
sdk.link(exe, .dynamic);
|
sdk.link(exe, .dynamic);
|
||||||
exe.addPackage(sdk.getNativePackage("sdl2"));
|
exe.addPackage(sdk.getNativePackage("sdl2"));
|
||||||
|
|
||||||
|
// 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.setBuildMode(mode);
|
||||||
exe.install();
|
exe.install();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7b01afc274db7231853dfd65c94dcd32f3f36b74
|
|
@ -13,8 +13,6 @@ const FilePaths = @import("util.zig").FilePaths;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
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
|
||||||
|
@ -87,7 +85,8 @@ pub fn main() void {
|
||||||
cpu.fastBoot();
|
cpu.fastBoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
var gui = Gui.init(&bus.pak.title, &bus.apu, width, height) catch |e| exitln("failed to init gui: {}", .{e});
|
// TODO: Just copy the title instead of grabbing a pointer to it
|
||||||
|
var gui = Gui.init(allocator, &bus.pak.title, &bus.apu) catch |e| exitln("failed to init gui: {}", .{e});
|
||||||
defer gui.deinit();
|
defer gui.deinit();
|
||||||
|
|
||||||
gui.run(&cpu, &scheduler) catch |e| exitln("failed to run gui thread: {}", .{e});
|
gui.run(&cpu, &scheduler) catch |e| exitln("failed to run gui thread: {}", .{e});
|
||||||
|
|
174
src/platform.zig
174
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 {
|
||||||
try gl.load(ctx, Self.glGetProcAddress);
|
try gl.load(ctx, Self.glGetProcAddress);
|
||||||
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,38 +171,86 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(self: *Self, cpu: *Arm7tdmi, scheduler: *Scheduler) !void {
|
pub fn run(self: *Self, cpu: *Arm7tdmi, scheduler: *Scheduler) !void {
|
||||||
|
const obj_ids = Self.genBufferObjects();
|
||||||
|
defer gl.deleteBuffers(3, @as(*const [3]c_uint, &obj_ids));
|
||||||
|
|
||||||
|
const emu_tex = Self.genGbaTexture(cpu.bus.ppu.framebuf.get(.Renderer));
|
||||||
|
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 quit = std.atomic.Atomic(bool).init(false);
|
||||||
var tracker = FpsTracker.init();
|
var tracker = FpsTracker.init();
|
||||||
|
|
||||||
var buffer_ids = Self.generateBuffers();
|
|
||||||
defer {
|
|
||||||
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));
|
|
||||||
defer gl.deleteTextures(1, &tex_id);
|
|
||||||
|
|
||||||
const thread = try std.Thread.spawn(.{}, emu.run, .{ &quit, scheduler, cpu, &tracker });
|
const thread = try std.Thread.spawn(.{}, emu.run, .{ &quit, scheduler, cpu, &tracker });
|
||||||
defer thread.join();
|
defer thread.join();
|
||||||
|
|
||||||
|
@ -177,6 +259,8 @@ pub const Gui = struct {
|
||||||
emu_loop: while (true) {
|
emu_loop: while (true) {
|
||||||
var event: SDL.SDL_Event = undefined;
|
var event: SDL.SDL_Event = undefined;
|
||||||
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 => {
|
||||||
|
@ -229,13 +313,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);
|
||||||
|
|
||||||
const dyn_title = std.fmt.bufPrintZ(&title_buf, "ZBA | {s} [Emu: {}fps] ", .{ self.title, tracker.value() }) catch unreachable;
|
const dyn_title = std.fmt.bufPrintZ(&title_buf, "ZBA | {s} [Emu: {}fps] ", .{ self.title, tracker.value() }) catch unreachable;
|
||||||
|
@ -247,6 +343,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);
|
||||||
|
|
Loading…
Reference in New Issue