diff --git a/src/Pixi.zig b/src/Pixi.zig index 630b170..956304e 100644 --- a/src/Pixi.zig +++ b/src/Pixi.zig @@ -15,10 +15,13 @@ const Core = mach.Core; pub const App = @This(); pub const Editor = @import("editor/Editor.zig"); +pub const Packer = @import("tools/Packer.zig"); + // Global pointers pub var core: *Core = undefined; pub var app: *App = undefined; pub var editor: *Editor = undefined; +pub var packer: *Packer = undefined; // Mach module, systems, and main pub const mach_module = .app; @@ -27,6 +30,7 @@ pub const main = mach.schedule(.{ .{ Core, .init }, .{ App, .init }, .{ Editor, .init }, + .{ Packer, .init }, .{ Core, .main }, }); @@ -43,7 +47,6 @@ total_time: f32 = 0.0, assets: Assets = undefined, fonts: Fonts = .{}, batcher: gfx.Batcher = undefined, -packer: Packer = undefined, pipeline_default: *gpu.RenderPipeline = undefined, pipeline_compute: *gpu.ComputePipeline = undefined, uniform_buffer_default: *gpu.Buffer = undefined, @@ -54,12 +57,14 @@ should_close: bool = false, pub const version: std.SemanticVersion = .{ .major = 0, .minor = 2, .patch = 0 }; -pub const Packer = @import("tools/Packer.zig"); - +// Generated files, these contain helpers for autocomplete +// So you can get a named index into assets.atlas.sprites pub const paths = @import("assets.zig"); pub const atlas = paths.pixi_atlas; +pub const animations = @import("animations.zig"); pub const shaders = @import("shaders.zig"); +// Other helpers and namespaces pub const fs = @import("tools/fs.zig"); pub const fa = @import("tools/font_awesome.zig"); pub const math = @import("math/math.zig"); @@ -97,12 +102,14 @@ pub fn init( _app: *App, _core: *Core, _editor: *Editor, + _packer: *Packer, 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; + packer = _packer; core.on_tick = app_mod.id.tick; core.on_exit = app_mod.id.deinit; @@ -145,7 +152,6 @@ pub fn lateInit(editor_mod: mach.Mod(Editor)) !void { // 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 @@ -345,7 +351,7 @@ pub fn deinit(editor_mod: mach.Mod(Editor)) !void { app.allocator.free(app.mouse.buttons); - app.packer.deinit(); + packer.deinit(); app.batcher.deinit(); app.pipeline_default.release(); diff --git a/src/editor/artboard/Artboard.zig b/src/editor/artboard/Artboard.zig index 7d24906..61babfb 100644 --- a/src/editor/artboard/Artboard.zig +++ b/src/editor/artboard/Artboard.zig @@ -3,6 +3,8 @@ const std = @import("std"); const Pixi = @import("../../Pixi.zig"); const Core = @import("mach").Core; const Editor = Pixi.Editor; +const Packer = Pixi.Packer; + const nfd = @import("nfd"); const imgui = @import("zig-imgui"); @@ -31,7 +33,7 @@ pub fn init(artboard: *Artboard) void { pub fn deinit() void {} -pub fn draw(artboard: *Artboard, core: *Core, app: *Pixi, editor: *Editor) !void { +pub fn draw(artboard: *Artboard, core: *Core, app: *Pixi, editor: *Editor, packer: *Packer) !void { imgui.pushStyleVar(imgui.StyleVar_WindowRounding, 0.0); defer imgui.popStyleVar(); imgui.setNextWindowPos(.{ @@ -124,7 +126,7 @@ pub fn draw(artboard: *Artboard, core: *Core, app: *Pixi, editor: *Editor) !void const mouse_clicked: bool = app.mouse.anyButtonDown(); if (editor.explorer.pane == .pack) { - drawCanvasPack(core, app, editor); + drawCanvasPack(editor, packer); } else if (editor.open_files.items.len > 0) { var files_flags: imgui.TabBarFlags = 0; files_flags |= imgui.TabBarFlags_Reorderable; @@ -386,7 +388,7 @@ pub fn drawGrip(window_width: f32, app: *Pixi, editor: *Editor) void { imgui.textColored(color, Pixi.fa.grip_lines_vertical); } -pub fn drawCanvasPack(core: *Core, app: *Pixi, editor: *Editor) void { +pub fn drawCanvasPack(editor: *Editor, packer: *Packer) void { var packed_textures_flags: imgui.TabBarFlags = 0; packed_textures_flags |= imgui.TabBarFlags_Reorderable; @@ -399,7 +401,7 @@ pub fn drawCanvasPack(core: *Core, app: *Pixi, editor: *Editor) void { imgui.TabItemFlags_None, )) { defer imgui.endTabItem(); - canvas_pack.draw(.diffusemap, app, core, editor); + canvas_pack.draw(.diffusemap, editor, packer); } if (imgui.beginTabItem( @@ -408,7 +410,7 @@ pub fn drawCanvasPack(core: *Core, app: *Pixi, editor: *Editor) void { imgui.TabItemFlags_None, )) { defer imgui.endTabItem(); - canvas_pack.draw(.heightmap, app, core, editor); + canvas_pack.draw(.heightmap, editor, packer); } } } diff --git a/src/editor/artboard/canvas_pack.zig b/src/editor/artboard/canvas_pack.zig index 3dc5af4..0f8ff3b 100644 --- a/src/editor/artboard/canvas_pack.zig +++ b/src/editor/artboard/canvas_pack.zig @@ -2,6 +2,7 @@ const std = @import("std"); const Pixi = @import("../../Pixi.zig"); const Core = @import("mach").Core; const Editor = Pixi.Editor; +const Packer = Pixi.Packer; const imgui = @import("zig-imgui"); pub const PackTexture = enum { @@ -9,7 +10,7 @@ pub const PackTexture = enum { heightmap, }; -pub fn draw(mode: PackTexture, app: *Pixi, _: *Core, editor: *Editor) void { +pub fn draw(mode: PackTexture, editor: *Editor, packer: *Packer) void { if (switch (mode) { .diffusemap => editor.atlas.diffusemap, .heightmap => editor.atlas.heightmap, @@ -27,7 +28,7 @@ pub fn draw(mode: PackTexture, app: *Pixi, _: *Core, editor: *Editor) void { const file_width = @as(f32, @floatFromInt(texture.image.width)); const file_height = @as(f32, @floatFromInt(texture.image.height)); - var camera = &app.packer.camera; + var camera = &packer.camera; // Handle zooming, panning and extents { diff --git a/src/editor/explorer/Explorer.zig b/src/editor/explorer/Explorer.zig index 1d1c40c..c09ed29 100644 --- a/src/editor/explorer/Explorer.zig +++ b/src/editor/explorer/Explorer.zig @@ -3,6 +3,7 @@ const std = @import("std"); const Pixi = @import("../../Pixi.zig"); const Core = @import("mach").Core; const Editor = Pixi.Editor; +const Packer = Pixi.Packer; const nfd = @import("nfd"); const imgui = @import("zig-imgui"); @@ -41,7 +42,7 @@ pub fn deinit() void { // TODO: Free memory } -pub fn draw(core: *Core, app: *Pixi, editor: *Editor, explorer: *Explorer) !void { +pub fn draw(core: *Core, app: *Pixi, editor: *Editor, explorer: *Explorer, packer: *Packer) !void { imgui.pushStyleVar(imgui.StyleVar_WindowRounding, 0.0); imgui.pushStyleVar(imgui.StyleVar_WindowBorderSize, 0.0); imgui.pushStyleVarImVec2(imgui.StyleVar_WindowPadding, .{ .x = 0.0, .y = 0.0 }); @@ -176,7 +177,7 @@ pub fn draw(core: *Core, app: *Pixi, editor: *Editor, explorer: *Explorer) !void } imgui.spacing(); imgui.spacing(); - try pack.draw(core, app, editor); + try pack.draw(app, editor, packer); }, .settings => { if (imgui.beginMenuBar()) { diff --git a/src/editor/explorer/pack.zig b/src/editor/explorer/pack.zig index 6974cd7..4a2b690 100644 --- a/src/editor/explorer/pack.zig +++ b/src/editor/explorer/pack.zig @@ -1,11 +1,14 @@ const std = @import("std"); + const Pixi = @import("../../Pixi.zig"); const Core = @import("mach").Core; const Editor = Pixi.Editor; +const Packer = Pixi.Packer; + const nfd = @import("nfd"); const imgui = @import("zig-imgui"); -pub fn draw(_: *Core, app: *Pixi, editor: *Editor) !void { +pub fn draw(app: *Pixi, editor: *Editor, packer: *Packer) !void { imgui.pushStyleVarImVec2(imgui.StyleVar_FramePadding, .{ .x = 6.0, .y = 5.0 }); defer imgui.popStyleVar(); imgui.pushStyleColorImVec4(imgui.Col_Button, editor.theme.highlight_secondary.toImguiVec4()); @@ -15,20 +18,20 @@ pub fn draw(_: *Core, app: *Pixi, editor: *Editor) !void { const window_size = imgui.getContentRegionAvail(); - switch (app.packer.target) { + switch (packer.target) { .all_open => { if (editor.open_files.items.len <= 1) { - app.packer.target = .project; + packer.target = .project; } }, .single_open => { if (editor.open_files.items.len == 0) - app.packer.target = .project; + packer.target = .project; }, else => {}, } - const preview_text = switch (app.packer.target) { + const preview_text = switch (packer.target) { .project => "Full Project", .all_open => "All Open Files", .single_open => "Current Open File", @@ -37,20 +40,20 @@ pub fn draw(_: *Core, app: *Pixi, editor: *Editor) !void { if (imgui.beginCombo("Files", preview_text.ptr, imgui.ComboFlags_None)) { defer imgui.endCombo(); if (imgui.menuItem("Full Project")) { - app.packer.target = .project; + packer.target = .project; } { const enabled = if (editor.getFile(editor.open_file_index)) |_| true else false; if (imgui.menuItemEx("Current Open File", null, false, enabled)) { - app.packer.target = .single_open; + packer.target = .single_open; } } { const enabled = if (editor.open_files.items.len > 1) true else false; if (imgui.menuItemEx("All Open Files", null, false, enabled)) { - app.packer.target = .all_open; + packer.target = .all_open; } } } @@ -65,8 +68,8 @@ pub fn draw(_: *Core, app: *Pixi, editor: *Editor) !void { { var packable: bool = true; - if (app.packer.target == .project and editor.project_folder == null) packable = false; - if (app.packer.target == .all_open and editor.open_files.items.len <= 1) packable = false; + if (packer.target == .project and editor.project_folder == null) packable = false; + if (packer.target == .all_open and editor.open_files.items.len <= 1) packable = false; if (editor.saving()) { imgui.pushStyleColorImVec4(imgui.Col_Text, editor.theme.text_background.toImguiVec4()); defer imgui.popStyleColor(); @@ -77,23 +80,23 @@ pub fn draw(_: *Core, app: *Pixi, editor: *Editor) !void { if (!packable) imgui.beginDisabled(true); if (imgui.buttonEx("Pack", .{ .x = window_size.x, .y = 0.0 })) { - switch (app.packer.target) { + switch (packer.target) { .project => { if (editor.project_folder) |folder| { - try Pixi.Packer.recurseFiles(app.allocator, folder); - try app.packer.packAndClear(); + try Pixi.Packer.recurseFiles(folder); + try packer.packAndClear(); } }, .all_open => { for (editor.open_files.items) |*file| { - try app.packer.append(file); + try packer.append(file); } - try app.packer.packAndClear(); + try packer.packAndClear(); }, .single_open => { if (editor.getFile(editor.open_file_index)) |file| { - try app.packer.append(file); - try app.packer.packAndClear(); + try packer.append(file); + try packer.packAndClear(); } }, } @@ -101,7 +104,7 @@ pub fn draw(_: *Core, app: *Pixi, editor: *Editor) !void { if (!packable) imgui.endDisabled(); - if (app.packer.target == .project and editor.project_folder == null) { + if (packer.target == .project and editor.project_folder == null) { imgui.pushStyleColorImVec4(imgui.Col_Text, editor.theme.text_background.toImguiVec4()); defer imgui.popStyleColor(); imgui.textWrapped("Select a project folder to pack."); diff --git a/src/main.zig b/src/main.zig index 2bd93d5..d0b12b8 100644 --- a/src/main.zig +++ b/src/main.zig @@ -10,6 +10,7 @@ const Modules = mach.Modules(.{ @import("editor/explorer/Explorer.zig"), @import("editor/artboard/Artboard.zig"), @import("editor/Sidebar.zig"), + @import("tools/Packer.zig"), }); // TODO: move this to a mach "entrypoint" zig module which handles nuances like WASM requires. diff --git a/src/storage/internal.zig b/src/storage/internal.zig index d1e5aa8..20dbe17 100644 --- a/src/storage/internal.zig +++ b/src/storage/internal.zig @@ -1803,9 +1803,9 @@ pub const PixiFile = struct { } } - Pixi.app.packer.ldtk = true; - defer Pixi.app.packer.ldtk = false; - try Pixi.app.packer.appendProject(); + Pixi.packer.ldtk = true; + defer Pixi.packer.ldtk = false; + try Pixi.packer.appendProject(); const ldtk_atlas_save_path = try std.fmt.allocPrintZ(Pixi.app.allocator, "{s}{c}pixi-ldtk.json", .{ project_folder_path, std.fs.path.sep }); defer Pixi.app.allocator.free(ldtk_atlas_save_path); @@ -1816,10 +1816,10 @@ pub const PixiFile = struct { const out_stream = handle.writer(); const options: std.json.StringifyOptions = .{}; - const output: Pixi.Packer.LDTKTileset.LDTKCompatibility = .{ .tilesets = Pixi.app.packer.ldtk_tilesets.items }; + const output: Pixi.Packer.LDTKTileset.LDTKCompatibility = .{ .tilesets = Pixi.packer.ldtk_tilesets.items }; try std.json.stringify(output, options, out_stream); - Pixi.app.packer.clearAndFree(); + Pixi.packer.clearAndFree(); } } diff --git a/src/tools/Packer.zig b/src/tools/Packer.zig index 6c16ef1..873fdc9 100644 --- a/src/tools/Packer.zig +++ b/src/tools/Packer.zig @@ -1,5 +1,6 @@ const std = @import("std"); const zstbi = @import("zstbi"); + const Pixi = @import("../Pixi.zig"); const Core = @import("mach").Core; @@ -7,6 +8,10 @@ pub const LDTKTileset = @import("LDTKTileset.zig"); const Packer = @This(); +// Mach module, systems, and main +pub const mach_module = .packer; +pub const mach_systems = .{ .init, .deinit }; + pub const Image = struct { width: usize, height: usize, @@ -43,7 +48,6 @@ contains_height: bool = false, open_files: std.ArrayList(Pixi.storage.Internal.PixiFile), target: PackTarget = .project, camera: Pixi.gfx.Camera = .{}, -allocator: std.mem.Allocator, ldtk: bool = false, ldtk_tilesets: std.ArrayList(LDTKTileset), @@ -54,20 +58,19 @@ pub const PackTarget = enum { single_open, }; -pub fn init(allocator: std.mem.Allocator) !Packer { - const pixels: [][4]u8 = try allocator.alloc([4]u8, 4); +pub fn init(packer: *Packer) !void { + const pixels: [][4]u8 = try Pixi.app.allocator.alloc([4]u8, 4); for (pixels) |*pixel| { pixel[3] = 0; } - return .{ - .sprites = std.ArrayList(Sprite).init(allocator), - .frames = std.ArrayList(zstbi.Rect).init(allocator), - .animations = std.ArrayList(Pixi.storage.External.Animation).init(allocator), - .open_files = std.ArrayList(Pixi.storage.Internal.PixiFile).init(allocator), + packer.* = .{ + .sprites = std.ArrayList(Sprite).init(Pixi.app.allocator), + .frames = std.ArrayList(zstbi.Rect).init(Pixi.app.allocator), + .animations = std.ArrayList(Pixi.storage.External.Animation).init(Pixi.app.allocator), + .open_files = std.ArrayList(Pixi.storage.Internal.PixiFile).init(Pixi.app.allocator), .placeholder = .{ .width = 2, .height = 2, .pixels = pixels }, - .allocator = allocator, - .ldtk_tilesets = std.ArrayList(LDTKTileset).init(allocator), + .ldtk_tilesets = std.ArrayList(LDTKTileset).init(Pixi.app.allocator), }; } @@ -78,7 +81,7 @@ pub fn newId(self: *Packer) u32 { } pub fn deinit(self: *Packer) void { - self.allocator.free(self.placeholder.pixels); + Pixi.app.allocator.free(self.placeholder.pixels); self.clearAndFree(); self.sprites.deinit(); self.frames.deinit(); @@ -88,21 +91,21 @@ pub fn deinit(self: *Packer) void { pub fn clearAndFree(self: *Packer) void { for (self.sprites.items) |*sprite| { - sprite.deinit(self.allocator); + sprite.deinit(Pixi.app.allocator); } for (self.animations.items) |*animation| { - self.allocator.free(animation.name); + Pixi.app.allocator.free(animation.name); } for (self.ldtk_tilesets.items) |*tileset| { for (tileset.layer_paths) |path| { - self.allocator.free(path); + Pixi.app.allocator.free(path); } for (tileset.sprites) |*sprite| { - self.allocator.free(sprite.name); + Pixi.app.allocator.free(sprite.name); } - self.allocator.free(tileset.sprites); - self.allocator.free(tileset.layer_paths); + Pixi.app.allocator.free(tileset.sprites); + Pixi.app.allocator.free(tileset.layer_paths); } self.frames.clearAndFree(); self.sprites.clearAndFree(); @@ -277,7 +280,7 @@ pub fn append(self: *Packer, file: *Pixi.storage.Internal.PixiFile) !void { } try self.sprites.append(.{ - .name = try std.fmt.allocPrintZ(self.allocator, "{s}_{s}", .{ sprite.name, layer.name }), + .name = try std.fmt.allocPrintZ(Pixi.app.allocator, "{s}_{s}", .{ sprite.name, layer.name }), .diffuse_image = image, .heightmap_image = heightmap_image, .origin = .{ @as(i32, @intFromFloat(sprite.origin_x)) - @as(i32, @intCast(offset[0])), @as(i32, @intFromFloat(sprite.origin_y)) - @as(i32, @intCast(offset[1])) }, @@ -292,7 +295,7 @@ pub fn append(self: *Packer, file: *Pixi.storage.Internal.PixiFile) !void { // Sprite contains no pixels but is part of an animation // To preserve the animation, add a blank pixel to the sprites list try self.sprites.append(.{ - .name = try std.fmt.allocPrintZ(self.allocator, "{s}_{s}", .{ sprite.name, layer.name }), + .name = try std.fmt.allocPrintZ(Pixi.app.allocator, "{s}_{s}", .{ sprite.name, layer.name }), .diffuse_image = null, .origin = .{ 0, 0 }, }); @@ -311,7 +314,7 @@ pub fn append(self: *Packer, file: *Pixi.storage.Internal.PixiFile) !void { const animation = file.animations.slice().get(animation_index); if (sprite_index == animation.start) { try self.animations.append(.{ - .name = try std.fmt.allocPrintZ(self.allocator, "{s}_{s}", .{ animation.name, layer.name }), + .name = try std.fmt.allocPrintZ(Pixi.app.allocator, "{s}_{s}", .{ animation.name, layer.name }), .start = self.sprites.items.len - 1, .length = animation.length, .fps = animation.fps, @@ -327,15 +330,15 @@ pub fn append(self: *Packer, file: *Pixi.storage.Internal.PixiFile) !void { } } -pub fn appendProject(self: Packer) !void { +pub fn appendProject(_: Packer) !void { if (Pixi.editor.project_folder) |root_directory| { - try recurseFiles(self.allocator, root_directory); + try recurseFiles(root_directory); } } -pub fn recurseFiles(allocator: std.mem.Allocator, root_directory: [:0]const u8) !void { +pub fn recurseFiles(root_directory: [:0]const u8) !void { const recursor = struct { - fn search(alloc: std.mem.Allocator, directory: [:0]const u8) !void { + fn search(directory: [:0]const u8) !void { var dir = try std.fs.cwd().openDir(directory, .{ .access_sub_paths = true, .iterate = true }); defer dir.close(); @@ -344,30 +347,30 @@ pub fn recurseFiles(allocator: std.mem.Allocator, root_directory: [:0]const u8) if (entry.kind == .file) { const ext = std.fs.path.extension(entry.name); if (std.mem.eql(u8, ext, ".pixi")) { - const abs_path = try std.fs.path.joinZ(alloc, &.{ directory, entry.name }); - defer alloc.free(abs_path); + const abs_path = try std.fs.path.joinZ(Pixi.app.allocator, &.{ directory, entry.name }); + defer Pixi.app.allocator.free(abs_path); if (Pixi.editor.getFileIndex(abs_path)) |index| { if (Pixi.editor.getFile(index)) |file| { - try Pixi.app.packer.append(file); + try Pixi.packer.append(file); } } else { if (try Pixi.storage.Internal.PixiFile.load(abs_path)) |file| { - try Pixi.app.packer.open_files.append(file); - try Pixi.app.packer.append(&Pixi.app.packer.open_files.items[Pixi.app.packer.open_files.items.len - 1]); + try Pixi.packer.open_files.append(file); + try Pixi.packer.append(&Pixi.packer.open_files.items[Pixi.packer.open_files.items.len - 1]); } } } } else if (entry.kind == .directory) { - const abs_path = try std.fs.path.joinZ(alloc, &[_][]const u8{ directory, entry.name }); - defer alloc.free(abs_path); - try search(alloc, abs_path); + const abs_path = try std.fs.path.joinZ(Pixi.app.allocator, &[_][]const u8{ directory, entry.name }); + defer Pixi.app.allocator.free(abs_path); + try search(abs_path); } } } }.search; - try recursor(allocator, root_directory); + try recursor(root_directory); return; } @@ -411,18 +414,18 @@ pub fn packAndClear(self: *Packer) !void { } const atlas: Pixi.storage.External.Atlas = .{ - .sprites = try self.allocator.alloc(Pixi.storage.External.Sprite, self.sprites.items.len), - .animations = try self.allocator.alloc(Pixi.storage.External.Animation, self.animations.items.len), + .sprites = try Pixi.app.allocator.alloc(Pixi.storage.External.Sprite, self.sprites.items.len), + .animations = try Pixi.app.allocator.alloc(Pixi.storage.External.Animation, self.animations.items.len), }; for (atlas.sprites, self.sprites.items, self.frames.items) |*dst, src, src_rect| { - dst.name = try self.allocator.dupeZ(u8, src.name); + dst.name = try Pixi.app.allocator.dupeZ(u8, src.name); dst.source = .{ src_rect.x, src_rect.y, src_rect.w, src_rect.h }; dst.origin = src.origin; } for (atlas.animations, self.animations.items) |*dst, src| { - dst.name = try self.allocator.dupeZ(u8, src.name); + dst.name = try Pixi.app.allocator.dupeZ(u8, src.name); dst.fps = src.fps; dst.length = src.length; dst.start = src.start; @@ -430,13 +433,13 @@ pub fn packAndClear(self: *Packer) !void { if (Pixi.editor.atlas.external) |*old_atlas| { for (old_atlas.sprites) |sprite| { - self.allocator.free(sprite.name); + Pixi.app.allocator.free(sprite.name); } for (old_atlas.animations) |animation| { - self.allocator.free(animation.name); + Pixi.app.allocator.free(animation.name); } - self.allocator.free(old_atlas.sprites); - self.allocator.free(old_atlas.animations); + Pixi.app.allocator.free(old_atlas.sprites); + Pixi.app.allocator.free(old_atlas.animations); Pixi.editor.atlas.external = atlas; } else {