diff --git a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj index e4e5a333e..fcf369e9f 100644 --- a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj +++ b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj @@ -634,6 +634,7 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -806,6 +807,10 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = 0.0.8; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; @@ -845,6 +850,7 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -1017,6 +1023,10 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = 0.0.8; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; diff --git a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index c300499fa..f5c700e80 100644 Binary files a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate and b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist b/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist index 62375ba69..8ff6cf524 100644 --- a/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist @@ -12,12 +12,12 @@ Ryujinx.xcscheme_^#shared#^_ orderHint - 1 + 2 com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_ orderHint - 2 + 1 SuppressBuildableAutocreation diff --git a/src/MeloNX/MeloNX/Core/Swift/Ryujinx.swift b/src/MeloNX/MeloNX/Core/Swift/Ryujinx.swift index 52e0ae7b7..204afd17f 100644 --- a/src/MeloNX/MeloNX/Core/Swift/Ryujinx.swift +++ b/src/MeloNX/MeloNX/Core/Swift/Ryujinx.swift @@ -152,9 +152,9 @@ class Ryujinx { args.append(contentsOf: ["--memory-manager-mode", config.memoryManagerMode]) - // args.append(contentsOf: ["--exclusive-fullscreen", String(config.fullscreen)]) - // args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"]) - // args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"]) + args.append(contentsOf: ["--exclusive-fullscreen", String(true)]) + args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"]) + args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"]) // We don't need this. Ryujinx should handle it fine :3 if config.fullscreen { @@ -174,10 +174,11 @@ class Ryujinx { args.append(contentsOf: ["--resolution-scale", String(config.resscale)]) } - if config.disableShaderCache { + if !config.disableShaderCache { // same with disableShaderCache args.append("--disable-shader-cache") } - if config.disableDockedMode { + + if !config.disableDockedMode { // disableDockedMode is actually enableDockedMode, i just have flipped it around in the settings page to make it easier to understand :3 args.append("--disable-docked-mode") } if config.enableTextureRecompression { diff --git a/src/MeloNX/MeloNX/Views/ContentView.swift b/src/MeloNX/MeloNX/Views/ContentView.swift index f91f38dd5..0fa635617 100644 --- a/src/MeloNX/MeloNX/Views/ContentView.swift +++ b/src/MeloNX/MeloNX/Views/ContentView.swift @@ -22,7 +22,6 @@ struct MoltenVKSettings: Codable, Hashable { struct ContentView: View { // MARK: - Properties @State private var theWindow: UIWindow? - @State private var virtualController: GCVirtualController? @State private var game: Game? @State private var controllersList: [Controller] = [] @State private var currentControllers: [Controller] = [] @@ -37,6 +36,11 @@ struct ContentView: View { @AppStorage("quit") var quit: Bool = false @State var quits: Bool = false + @State private var clumpOffset: CGFloat = -100 + private let clumpWidth: CGFloat = 100 + private let animationDuration: Double = 1.0 + @State private var isAnimating = false + @State var isLoading = true // MARK: - Initialization init() { @@ -58,18 +62,27 @@ struct ContentView: View { // MARK: - Body var body: some View { if let game, quits == false { - emulationView - .onAppear() { - Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in - timer.invalidate() - quits = quit - - if quits { - quit = false + if isLoading { + emulationView + .onAppear() { + Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in timer.invalidate() + quits = quit + + if quits { + quit = false + timer.invalidate() + } } } + } else { + VStack { + } + .onAppear() { + isAnimating = false + } + } } else { mainMenuView .onAppear() { @@ -81,15 +94,80 @@ struct ContentView: View { // MARK: - View Components private var emulationView: some View { - ZStack { - - } - .onAppear { - - setupEmulation() + GeometryReader { screenGeometry in + ZStack { + HStack(spacing: screenGeometry.size.width * 0.04) { + if let icon = game?.icon { + Image(uiImage: icon) + .resizable() + .frame( + width: min(screenGeometry.size.width * 0.25, 250), + height: min(screenGeometry.size.width * 0.25, 250) + ) + .clipShape(RoundedRectangle(cornerRadius: 16)) + .shadow(color: .black.opacity(0.5), radius: 10, x: 0, y: 5) + } + + VStack(alignment: .leading, spacing: screenGeometry.size.height * 0.015) { + Text("Loading \(game?.titleName ?? "Game")") + .font(.system(size: min(screenGeometry.size.width * 0.04, 32))) + .foregroundColor(.white) + + GeometryReader { geometry in + let containerWidth = min(screenGeometry.size.width * 0.35, 350) + + ZStack(alignment: .leading) { + // Background track + Rectangle() + .cornerRadius(10) + .frame(width: containerWidth, height: min(screenGeometry.size.height * 0.015, 12)) + .foregroundColor(.gray.opacity(0.3)) + .shadow(color: .black.opacity(0.2), radius: 4, x: 0, y: 2) + + // Animated loading bar + Rectangle() + .cornerRadius(10) + .frame(width: clumpWidth, height: min(screenGeometry.size.height * 0.015, 12)) + .foregroundColor(.blue) + .shadow(color: .blue.opacity(0.5), radius: 4, x: 0, y: 2) + .offset(x: isAnimating ? containerWidth : -clumpWidth) + .animation( + Animation.linear(duration: 1.0) + .repeatForever(autoreverses: false), + value: isAnimating + ) + } + .clipShape(RoundedRectangle(cornerRadius: 16)) + .onAppear { + isAnimating = true + + setupEmulation() + + + Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in + if get_current_fps() != 0 { + isLoading = false + isAnimating = false + timer.invalidate() + } + print(get_current_fps()) + } + } + } + .frame(height: min(screenGeometry.size.height * 0.015, 12)) + .frame(width: min(screenGeometry.size.width * 0.35, 350)) + } + } + .padding(.horizontal, screenGeometry.size.width * 0.06) + .padding(.vertical, screenGeometry.size.height * 0.05) + .position( + x: screenGeometry.size.width / 2, + y: screenGeometry.size.height * 0.5 + ) } + } } - + private var mainMenuView: some View { MainTabView(startemu: $game, config: $config, MVKconfig: $settings, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller) .onAppear() { @@ -116,7 +194,6 @@ struct ContentView: View { } private func setupEmulation() { - virtualController?.disconnect() patchMakeKeyAndVisible() if (currentControllers.first(where: { $0 == onscreencontroller }) != nil) { @@ -203,6 +280,8 @@ struct ContentView: View { print("Error: \(error.localizedDescription)") } } + + private func setMoltenVKSettings() { diff --git a/src/MeloNX/MeloNX/Views/GamesList/GameListView.swift b/src/MeloNX/MeloNX/Views/GamesList/GameListView.swift index 917a7ee9e..4d722d14d 100644 --- a/src/MeloNX/MeloNX/Views/GamesList/GameListView.swift +++ b/src/MeloNX/MeloNX/Views/GamesList/GameListView.swift @@ -140,7 +140,7 @@ struct GameLibraryView: View { Button { - var game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion) + let game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion) self.startemu = game } label: { @@ -165,7 +165,7 @@ struct GameLibraryView: View { Text("Show MeloNX Folder") } } label: { - Image(systemName: "ellipsis") + Image(systemName: "ellipsis.circle") .foregroundColor(.blue) } @@ -349,7 +349,6 @@ struct GameLibraryView: View { } } -// Make sure your Game model conforms to Codable extension Game: Codable { enum CodingKeys: String, CodingKey { case titleName, titleId, developer, version, fileURL diff --git a/src/MeloNX/MeloNX/Views/SettingsView/SettingsView.swift b/src/MeloNX/MeloNX/Views/SettingsView/SettingsView.swift index e016d8e88..838f227fc 100644 --- a/src/MeloNX/MeloNX/Views/SettingsView/SettingsView.swift +++ b/src/MeloNX/MeloNX/Views/SettingsView/SettingsView.swift @@ -52,7 +52,7 @@ struct SettingsView: View { .tint(.blue) Toggle(isOn: $config.disableShaderCache) { - labelWithIcon("Disable Shader Cache", iconName: "memorychip") + labelWithIcon("Shader Cache", iconName: "memorychip") } .tint(.blue) @@ -62,7 +62,7 @@ struct SettingsView: View { .tint(.blue) Toggle(isOn: $config.disableDockedMode) { - labelWithIcon("Disable Docked Mode", iconName: "dock.rectangle") + labelWithIcon("Docked Mode", iconName: "dock.rectangle") } .tint(.blue) diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index f6f9de017..585bc00ff 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -1306,7 +1306,7 @@ namespace Ryujinx.Headless.SDL2 options.IgnoreMissingServices, options.AspectRatio, options.AudioVolume, - options.UseHypervisor ?? true, + options.UseHypervisor ?? false, options.MultiplayerLanInterfaceId, Common.Configuration.Multiplayer.MultiplayerMode.LdnMitm); @@ -1499,75 +1499,75 @@ namespace Ryujinx.Headless.SDL2 return new FileStream(safeHandle, FileAccess.ReadWrite); } - public class GameInfo - { - public double FileSize; - public string? TitleName; - public string? TitleId; - public string? Developer; - public string? Version; - public byte[]? Icon; - } - -public unsafe struct GameInfoNative -{ - public ulong FileSize; - public fixed byte TitleName[512]; - public ulong TitleId; - public fixed byte Developer[256]; - public uint Version; - public byte* ImageData; // Changed to pointer - public uint ImageSize; // Actual size of image data - - public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version, byte[] imageData) - { - FileSize = fileSize; - TitleId = titleId; - Version = version; - - fixed (byte* developerPtr = Developer) - fixed (byte* titleNamePtr = TitleName) + public class GameInfo { - CopyStringToFixedArray(titleName, titleNamePtr, 512); - CopyStringToFixedArray(developer, developerPtr, 256); + public double FileSize; + public string? TitleName; + public string? TitleId; + public string? Developer; + public string? Version; + public byte[]? Icon; } - if (imageData == null || imageData.Length > 4096 * 4096) + public unsafe struct GameInfoNative { - // throw new ArgumentException("Image data must not exceed 4 MB."); - ImageSize = (uint)0; - ImageData = null; - } - else - { - ImageSize = (uint)imageData.Length; - - ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length); - - Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length); - } - } + public ulong FileSize; + public fixed byte TitleName[512]; + public ulong TitleId; + public fixed byte Developer[256]; + public uint Version; + public byte* ImageData; + public uint ImageSize; - // Don't forget to free the allocated memory - public void Dispose() - { - if (ImageData != null) - { - Marshal.FreeHGlobal((IntPtr)ImageData); - ImageData = null; - } - } - private static void CopyStringToFixedArray(string source, byte* destination, int length) - { - var span = new Span(destination, length); - Encoding.UTF8.GetBytes(source, span); - } + public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version, byte[] imageData) + { + FileSize = fileSize; + TitleId = titleId; + Version = version; - private static void CopyArrayToFixedArray(byte[] source, byte* destination, int maxLength) - { - var span = new Span(destination, maxLength); - source.AsSpan().CopyTo(span); + fixed (byte* developerPtr = Developer) + fixed (byte* titleNamePtr = TitleName) + { + CopyStringToFixedArray(titleName, titleNamePtr, 512); + CopyStringToFixedArray(developer, developerPtr, 256); + } + + if (imageData == null || imageData.Length > 4096 * 4096) + { + // throw new ArgumentException("Image data must not exceed 4 MB."); + ImageSize = (uint)0; + ImageData = null; + } + else + { + ImageSize = (uint)imageData.Length; + + ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length); + + Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length); + } + } + + // Don't forget to free the allocated memory + public void Dispose() + { + if (ImageData != null) + { + Marshal.FreeHGlobal((IntPtr)ImageData); + ImageData = null; + } + } + private static void CopyStringToFixedArray(string source, byte* destination, int length) + { + var span = new Span(destination, length); + Encoding.UTF8.GetBytes(source, span); + } + + private static void CopyArrayToFixedArray(byte[] source, byte* destination, int maxLength) + { + var span = new Span(destination, maxLength); + source.AsSpan().CopyTo(span); + } } } - } }