From 1ee3bdd159e3cf0b22d3a77680e441b0326b01e3 Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Sun, 5 Oct 2025 14:27:35 +0300 Subject: [PATCH] working SwiftUI mac example --- .gitignore | 1 + NesKit/NesSystem.h | 2 +- NesKit/NesSystem.mm | 4 +++ NesKitSwift/NesSystemSwift.swift | 16 ++++----- .../UserInterfaceState.xcuserstate | Bin 17708 -> 0 bytes examples/NesApp/NesApp/ContentView.swift | 34 ++++++++++++++---- .../NesApp/NesApp/NesView/NesSystemView.swift | 23 ++++++++++++ examples/NesApp/NesApp/NesView/NesView.swift | 21 ++++------- 8 files changed, 69 insertions(+), 32 deletions(-) delete mode 100644 examples/NesApp/NesApp.xcodeproj/project.xcworkspace/xcuserdata/selim.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 examples/NesApp/NesApp/NesView/NesSystemView.swift diff --git a/.gitignore b/.gitignore index 9970017..be36e49 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ out/ build/ CMakeLists.txt.user **/.DS_Store +xcuserdata/ .swiftpm/ diff --git a/NesKit/NesSystem.h b/NesKit/NesSystem.h index 3a025d9..8f9f5e5 100644 --- a/NesKit/NesSystem.h +++ b/NesKit/NesSystem.h @@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN @property CGImageRef frame; - (instancetype)init; -- (void)runRom:(NSString*)path; +- (void)runRom:(NSURL*)url; - (void)stepToNextFrame; @end diff --git a/NesKit/NesSystem.mm b/NesKit/NesSystem.mm index 98a3988..2b15c9a 100644 --- a/NesKit/NesSystem.mm +++ b/NesKit/NesSystem.mm @@ -30,7 +30,11 @@ } - (void)runRom:(NSURL*)url { + + [url startAccessingSecurityScopedResource]; _system->insertCartridge([url fileSystemRepresentation]); + [url stopAccessingSecurityScopedResource]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while(TRUE) { [_condition lock]; diff --git a/NesKitSwift/NesSystemSwift.swift b/NesKitSwift/NesSystemSwift.swift index 5bda4a7..4fa4cd1 100644 --- a/NesKitSwift/NesSystemSwift.swift +++ b/NesKitSwift/NesSystemSwift.swift @@ -10,14 +10,10 @@ import NesKitCpp class NesSystemSwift { - var nesSystem: nes.System? - - init() { - - let frameBufferSize = nes.Ppu.SCREEN_WIDTH * nes.Ppu.SCREEN_HEIGHT * MemoryLayout.stride - - nesSystem?.setNewFrameCallback({ frameBuffer in - - }) - } +// var nesSystem: nes.System? +// +// init() { +// +// let frameBufferSize = nes.Ppu.SCREEN_WIDTH * nes.Ppu.SCREEN_HEIGHT * MemoryLayout.stride +// } } diff --git a/examples/NesApp/NesApp.xcodeproj/project.xcworkspace/xcuserdata/selim.xcuserdatad/UserInterfaceState.xcuserstate b/examples/NesApp/NesApp.xcodeproj/project.xcworkspace/xcuserdata/selim.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 59f273ee0b15b97f08fef81326f381d8d1142600..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17708 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 NesSystemView { - self.layer.addSublayer(self.nesLayer) + NesSystemView(system: system) } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() + func updateNSView(_ nsView: NesSystemView, context: Context) { - self.nesLayer.frame = self.layer.frame } }