diff --git a/src/Pixi.zig b/src/Pixi.zig index 2ec47de..fda53e6 100644 --- a/src/Pixi.zig +++ b/src/Pixi.zig @@ -1,10 +1,12 @@ -// Imports const std = @import("std"); + const mach = @import("mach"); const gpu = mach.gpu; + const zstbi = @import("zstbi"); const zm = @import("zmath"); const nfd = @import("nfd"); + const imgui = @import("zig-imgui"); const imgui_mach = imgui.backends.mach; @@ -24,6 +26,7 @@ pub const mach_systems = .{ .main, .init, .lateInit, .tick, .deinit }; pub const main = mach.schedule(.{ .{ Core, .init }, .{ App, .init }, + .{ Editor, .init }, .{ Core, .main }, }); @@ -95,7 +98,14 @@ pub const Fonts = struct { fa_standard_solid: *imgui.Font = undefined, }; -pub fn init(_app: *App, _core: *Core, app_mod: mach.Mod(App), _editor: *Editor, editor_mod: mach.Mod(Editor)) !void { +/// This is a mach-called function, and the parameters are automatically injected. +pub fn init( + _app: *App, + _core: *Core, + _editor: *Editor, + app_mod: mach.Mod(App), +) !void { + // Store our global pointers so we can access them from non-mach functions for now app = _app; core = _core; editor = _editor; @@ -110,20 +120,19 @@ pub fn init(_app: *App, _core: *Core, app_mod: mach.Mod(App), _editor: *Editor, const path = std.fs.selfExeDirPath(buffer[0..]) catch "."; std.posix.chdir(path) catch {}; + // Here we have access to all the initial fields of the window const window = try core.windows.new(.{ .title = "Pixi", .vsync_mode = .double, }); - _app.* = .{ + app.* = .{ .allocator = allocator, .arena_allocator = std.heap.ArenaAllocator.init(allocator), .timer = try mach.time.Timer.start(), .window = window, .root_path = try allocator.dupeZ(u8, path), }; - - editor_mod.call(.init); } /// This is called from the event fired when the window is done being @@ -140,10 +149,12 @@ pub fn lateInit(editor_mod: mach.Mod(Editor)) !void { // Load assets app.loaded_assets = try LoadedAssets.init(app.allocator); + // Setup app.mouse = try input.Mouse.initDefault(app.allocator); app.packer = try Packer.init(app.allocator); app.batcher = try gfx.Batcher.init(app.allocator, 1000); + // Store information about the window in float format app.window_size = .{ @floatFromInt(window.width), @floatFromInt(window.height) }; app.framebuffer_size = .{ @floatFromInt(window.framebuffer_width), @floatFromInt(window.framebuffer_height) }; app.content_scale = .{ @@ -151,8 +162,8 @@ pub fn lateInit(editor_mod: mach.Mod(Editor)) !void { app.framebuffer_size[1] / app.window_size[1], }; + // Setup imgui imgui.setZigAllocator(&app.allocator); - _ = imgui.createContext(null); try imgui_mach.init(core, app.allocator, window.device, .{ .mag_filter = .nearest, @@ -161,6 +172,7 @@ pub fn lateInit(editor_mod: mach.Mod(Editor)) !void { .color_format = window.framebuffer_format, }); + // Setup fonts var io = imgui.getIO(); io.config_flags |= imgui.ConfigFlags_NavEnableKeyboard; io.display_framebuffer_scale = .{ .x = app.content_scale[0], .y = app.content_scale[1] }; @@ -191,10 +203,11 @@ pub fn lateInit(editor_mod: mach.Mod(Editor)) !void { app.fonts.fa_standard_solid = io.fonts.?.addFontFromFileTTF(assets.root ++ "fonts/fa-solid-900.ttf", editor.settings.font_size, &fa_config, @ptrCast(ranges.ptr)).?; app.fonts.fa_standard_regular = io.fonts.?.addFontFromFileTTF(assets.root ++ "fonts/fa-regular-400.ttf", editor.settings.font_size, &fa_config, @ptrCast(ranges.ptr)).?; - // Initialize the editor which loads our theme + // This will load our theme editor_mod.call(.lateInit); } +/// This is a mach-called function, and the parameters are automatically injected. pub fn tick(app_mod: mach.Mod(App), editor_mod: mach.Mod(Editor)) !void { // Process dialog requests editor_mod.call(.processDialogRequest); @@ -246,12 +259,6 @@ pub fn tick(app_mod: mach.Mod(App), editor_mod: mach.Mod(Editor)) !void { app.framebuffer_size[0] / app.window_size[0], app.framebuffer_size[1] / app.window_size[1], }; - - // TODO: - // Currently content scale is set to 1.0x1.0 because the scaling is handled by - // zig-imgui. Tested both on Windows (1.0 content scale) and macOS (2.0 content scale) - // If we can confirm that this is not needed, we can purge the use of content_scale from editor files - //app.content_scale = .{ 1.0, 1.0 }; }, else => {}, @@ -338,6 +345,7 @@ pub fn tick(app_mod: mach.Mod(App), editor_mod: mach.Mod(Editor)) !void { } } +/// This is a mach-called function, and the parameters are automatically injected. pub fn deinit(editor_mod: mach.Mod(Editor)) !void { editor_mod.call(.deinit); diff --git a/src/editor/Settings.zig b/src/editor/Settings.zig index e6c26ae..f12f0ba 100644 --- a/src/editor/Settings.zig +++ b/src/editor/Settings.zig @@ -4,53 +4,9 @@ const std = @import("std"); const Settings = @This(); -///Reads in default settings or reads from the settings file -pub fn init(allocator: std.mem.Allocator) !Settings { - const path = "settings.json"; - - // Attempt to read the file - const max_bytes = 10000; //maximum bytes in settings file - const settings_string = std.fs.cwd().readFileAlloc(allocator, path, max_bytes) catch null; - - // Check if the file was read, and if so, parse it - if (settings_string) |str| { - defer allocator.free(settings_string.?); - - const parsed_settings = std.json.parseFromSlice(@This(), allocator, str, .{}) catch null; - if (parsed_settings) |settings| { - // TODO: Fix this, we shouldnt have to allocate the theme name just because we need to free all later - var s: Settings = settings.value; - s.theme = try allocator.dupeZ(u8, s.theme); - return s; - } - } - // Return default if parsing failed or file does not exist - return @This(){ - .theme = try allocator.dupeZ(u8, "pixi_dark.json"), - }; -} - -pub fn save(self: *@This(), allocator: std.mem.Allocator) void { - const path = "settings.json"; - const stringified = std.json.stringifyAlloc(allocator, self, .{}) catch { - std.debug.print("ERROR: Failed to stringify settings\n", .{}); - return; - }; - defer allocator.free(stringified); - var file = std.fs.cwd().createFile(path, .{}) catch { - std.debug.print("ERROR: Failed to open settings file \"{s}\"\n", .{path}); - return; - }; - file.writeAll(stringified) catch { - std.debug.print("ERROR: Failed to write settings to file \"{s}\"\n", .{path}); - return; - }; -} - -/// Saves the current settings to a file and deinitializes the memory -pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void { - allocator.free(self.theme); -} +pub const InputScheme = enum { mouse, trackpad }; +pub const FlipbookView = enum { sequential, grid }; +pub const Compatibility = enum { none, ldtk }; /// Width of the explorer bar. explorer_width: f32 = 200.0, @@ -163,6 +119,49 @@ zoom_ctrl: bool = false, /// Setting to generate a compatiblity layer between pixi and level editors compatibility: Compatibility = .none, -pub const InputScheme = enum { mouse, trackpad }; -pub const FlipbookView = enum { sequential, grid }; -pub const Compatibility = enum { none, ldtk }; +///Reads in default settings or reads from the settings file +pub fn init(allocator: std.mem.Allocator) !Settings { + const path = "settings.json"; + + // Attempt to read the file + const max_bytes = 10000; //maximum bytes in settings file + const settings_string = std.fs.cwd().readFileAlloc(allocator, path, max_bytes) catch null; + + // Check if the file was read, and if so, parse it + if (settings_string) |str| { + defer allocator.free(settings_string.?); + + const parsed_settings = std.json.parseFromSlice(@This(), allocator, str, .{}) catch null; + if (parsed_settings) |settings| { + // TODO: Fix this, we shouldnt have to allocate the theme name just because we need to free all later + var s: Settings = settings.value; + s.theme = try allocator.dupeZ(u8, s.theme); + return s; + } + } + // Return default if parsing failed or file does not exist + return @This(){ + .theme = try allocator.dupeZ(u8, "pixi_dark.json"), + }; +} + +pub fn save(self: *@This(), allocator: std.mem.Allocator) void { + const path = "settings.json"; + const stringified = std.json.stringifyAlloc(allocator, self, .{}) catch { + std.debug.print("ERROR: Failed to stringify settings\n", .{}); + return; + }; + defer allocator.free(stringified); + var file = std.fs.cwd().createFile(path, .{}) catch { + std.debug.print("ERROR: Failed to open settings file \"{s}\"\n", .{path}); + return; + }; + file.writeAll(stringified) catch { + std.debug.print("ERROR: Failed to write settings to file \"{s}\"\n", .{path}); + return; + }; +} + +pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void { + allocator.free(self.theme); +}