forked from MeloNX/MeloNX
cool
This commit is contained in:
parent
ac3958a363
commit
b41251e360
@ -347,6 +347,7 @@
|
|||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
|
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@ -356,6 +357,8 @@
|
|||||||
"$(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",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
@ -385,6 +388,7 @@
|
|||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
|
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@ -394,6 +398,8 @@
|
|||||||
"$(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",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
|
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Bucket
|
||||||
|
uuid = "64A8AF27-6696-4D7A-8C62-06216A95ECF0"
|
||||||
|
type = "1"
|
||||||
|
version = "2.0">
|
||||||
|
</Bucket>
|
@ -12,24 +12,31 @@ import GameController
|
|||||||
var theWindow: UIWindow? = nil
|
var theWindow: UIWindow? = nil
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
|
@State var device: MTLDevice? = MTLCreateSystemDefaultDevice()
|
||||||
@State var gameUrl: URL?
|
@State var gameUrl: URL?
|
||||||
@State var showFileImporter: Bool = false
|
@State var showFileImporter: Bool = false
|
||||||
|
@State var emulationStarted: Bool = false
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
ZStack {
|
||||||
Button {
|
|
||||||
showFileImporter.toggle()
|
|
||||||
} label: {
|
VStack {
|
||||||
Text("Select Game")
|
Text("NX iOS")
|
||||||
}
|
|
||||||
if let gameUrl {
|
|
||||||
Button {
|
Button {
|
||||||
DispatchQueue.main.async {
|
showFileImporter.toggle()
|
||||||
showVirtualController(url: gameUrl)
|
|
||||||
}
|
|
||||||
} label: {
|
} label: {
|
||||||
Text("Go!")
|
Text("Select Game")
|
||||||
|
}
|
||||||
|
if let gameUrl {
|
||||||
|
Button {
|
||||||
|
emulationStarted = true
|
||||||
|
gameUrl.startAccessingSecurityScopedResource()
|
||||||
|
showVirtualController(url: gameUrl)
|
||||||
|
} label: {
|
||||||
|
Text("Go!")
|
||||||
|
}
|
||||||
|
.padding(8)
|
||||||
}
|
}
|
||||||
.padding(8)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
@ -55,11 +62,9 @@ func startEmulation(game: URL) {
|
|||||||
enableKeyboard: false,
|
enableKeyboard: false,
|
||||||
graphicsBackend: "Vulkan"
|
graphicsBackend: "Vulkan"
|
||||||
)
|
)
|
||||||
DispatchQueue.main.async {
|
patchMakeKeyAndVisible()
|
||||||
SDL_SetMainReady()
|
SDL_SetMainReady()
|
||||||
SDL_iPhoneSetEventPump(SDL_TRUE)
|
SDL_iPhoneSetEventPump(SDL_TRUE)
|
||||||
patchMakeKeyAndVisible()
|
|
||||||
}
|
|
||||||
let emulator = RyujinxEmulator()
|
let emulator = RyujinxEmulator()
|
||||||
do {
|
do {
|
||||||
try emulator.startWithRunLoop(config: config)
|
try emulator.startWithRunLoop(config: config)
|
||||||
@ -78,14 +83,10 @@ func patchMakeKeyAndVisible() {
|
|||||||
extension UIWindow {
|
extension UIWindow {
|
||||||
@objc func wdb_makeKeyAndVisible() {
|
@objc func wdb_makeKeyAndVisible() {
|
||||||
print("Making window key and visible...")
|
print("Making window key and visible...")
|
||||||
if #available(iOS 13.0, *) {
|
self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene)
|
||||||
self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene)
|
|
||||||
}
|
|
||||||
self.wdb_makeKeyAndVisible()
|
self.wdb_makeKeyAndVisible()
|
||||||
theWindow = self
|
theWindow = self
|
||||||
if #available(iOS 15.0, *) {
|
reconnectVirtualController()
|
||||||
reconnectVirtualController()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,13 +61,14 @@ class RyujinxEmulator {
|
|||||||
]
|
]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
args.append("ryujinx")
|
args.append(config.inputPath)
|
||||||
|
|
||||||
args.append("--graphics-backend")
|
args.append("--graphics-backend")
|
||||||
args.append(config.graphicsBackend)
|
args.append(config.graphicsBackend)
|
||||||
|
args.append(contentsOf: ["--memory-manager-mode", "SoftwarePageTable"])
|
||||||
|
// args.append(contentsOf: ["--fullscreen", "true"])
|
||||||
|
args.append(contentsOf: ["--enable-debug-logs", "true"])
|
||||||
|
args.append(contentsOf: ["--enable-trace-logs", "true"])
|
||||||
// args.append("--input-path")
|
// args.append("--input-path")
|
||||||
args.append(config.inputPath)
|
|
||||||
|
|
||||||
args.append(contentsOf: config.additionalArgs)
|
args.append(contentsOf: config.additionalArgs)
|
||||||
|
|
||||||
@ -82,6 +83,7 @@ class RyujinxEmulator {
|
|||||||
|
|
||||||
var argvPtrs = cArgs
|
var argvPtrs = cArgs
|
||||||
|
|
||||||
|
|
||||||
let result = ryujinxMain(Int32(args.count), &argvPtrs)
|
let result = ryujinxMain(Int32(args.count), &argvPtrs)
|
||||||
|
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
@ -102,16 +104,19 @@ class RyujinxEmulator {
|
|||||||
|
|
||||||
let port = Port()
|
let port = Port()
|
||||||
runLoop.add(port, forMode: .default)
|
runLoop.add(port, forMode: .default)
|
||||||
|
|
||||||
do {
|
DispatchQueue.main.async {
|
||||||
try Self.start(with: config)
|
do {
|
||||||
} catch {
|
try Self.start(with: config)
|
||||||
Self.log("Emulation failed to start: \(error)")
|
} catch {
|
||||||
self.isRunning = false
|
Self.log("Emulation failed to start: \(error)")
|
||||||
return
|
self.isRunning = false
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while self.isRunning && runLoop.run(mode: .default, before: .distantFuture) {
|
while self.isRunning && runLoop.run(mode: .default, before: .distantFuture) {
|
||||||
autoreleasepool {
|
autoreleasepool {
|
||||||
}
|
}
|
||||||
@ -122,6 +127,8 @@ class RyujinxEmulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emulationThread?.name = "RyujinxEmulationThread"
|
emulationThread?.name = "RyujinxEmulationThread"
|
||||||
|
emulationThread?.qualityOfService = .userInteractive
|
||||||
|
emulationThread?.threadPriority = 0.9
|
||||||
emulationThread?.start()
|
emulationThread?.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict/>
|
<dict>
|
||||||
|
<key>UIFileSharingEnabled</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
210
MeloNX-XC/MeloNX/MetalVIew.swift
Normal file
210
MeloNX-XC/MeloNX/MetalVIew.swift
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
//
|
||||||
|
// MetalVIew.swift
|
||||||
|
// MeloNX
|
||||||
|
//
|
||||||
|
// Created by Stossy11 on 27/10/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Metal
|
||||||
|
import MetalKit
|
||||||
|
|
||||||
|
struct MetalView: UIViewRepresentable {
|
||||||
|
let device: MTLDevice?
|
||||||
|
let configure: (UIView) -> Void
|
||||||
|
|
||||||
|
func makeUIView(context: Context) -> SudachiScreenView {
|
||||||
|
let view = SudachiScreenView()
|
||||||
|
configure(view.primaryScreen)
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIView(_ uiView: SudachiScreenView, context: Context) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SudachiScreenView: UIView {
|
||||||
|
var primaryScreen: UIView!
|
||||||
|
var portraitconstraints = [NSLayoutConstraint]()
|
||||||
|
var landscapeconstraints = [NSLayoutConstraint]()
|
||||||
|
var fullscreenconstraints = [NSLayoutConstraint]()
|
||||||
|
let userDefaults = UserDefaults.standard
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
if userDefaults.bool(forKey: "isfullscreen") {
|
||||||
|
// setupSudachiScreenforcools()
|
||||||
|
setupSudachiScreen2()
|
||||||
|
} else if userDefaults.bool(forKey: "isairplay") {
|
||||||
|
setupSudachiScreen2()
|
||||||
|
} else if userDefaults.bool(forKey: "169fullscreen") { // this is for the 16/9 aspect ratio full screen
|
||||||
|
setupSudachiScreenforcools()
|
||||||
|
} else if UIDevice.current.userInterfaceIdiom == .pad {
|
||||||
|
setupSudachiScreenforiPad()
|
||||||
|
} else {
|
||||||
|
setupSudachiScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
if userDefaults.bool(forKey: "isfullscreen") {
|
||||||
|
setupSudachiScreen2()
|
||||||
|
} else if userDefaults.bool(forKey: "isairplay") {
|
||||||
|
setupSudachiScreen2()
|
||||||
|
} else if UIDevice.current.userInterfaceIdiom == .pad {
|
||||||
|
setupSudachiScreenforiPad()
|
||||||
|
} else {
|
||||||
|
setupSudachiScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func setupSudachiScreen2() {
|
||||||
|
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
|
||||||
|
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
primaryScreen.clipsToBounds = true
|
||||||
|
addSubview(primaryScreen)
|
||||||
|
|
||||||
|
fullscreenconstraints = [
|
||||||
|
primaryScreen.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
primaryScreen.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||||
|
primaryScreen.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||||
|
primaryScreen.bottomAnchor.constraint(equalTo: bottomAnchor)
|
||||||
|
]
|
||||||
|
|
||||||
|
addConstraints(fullscreenconstraints)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupSudachiScreenforcools() { // oh god this took a long time, im going insane
|
||||||
|
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
|
||||||
|
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
primaryScreen.clipsToBounds = true
|
||||||
|
|
||||||
|
addSubview(primaryScreen)
|
||||||
|
|
||||||
|
primaryScreen.layer.cornerRadius = 5
|
||||||
|
primaryScreen.layer.masksToBounds = true
|
||||||
|
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
primaryScreen.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||||
|
primaryScreen.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||||
|
primaryScreen.widthAnchor.constraint(lessThanOrEqualTo: widthAnchor),
|
||||||
|
primaryScreen.heightAnchor.constraint(lessThanOrEqualTo: heightAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
let aspectRatio: CGFloat = 16.0/9.0
|
||||||
|
let aspectRatioConstraint = NSLayoutConstraint(
|
||||||
|
item: primaryScreen ?? UIView(),
|
||||||
|
attribute: .width,
|
||||||
|
relatedBy: .equal,
|
||||||
|
toItem: primaryScreen,
|
||||||
|
attribute: .height,
|
||||||
|
multiplier: aspectRatio,
|
||||||
|
constant: 0
|
||||||
|
)
|
||||||
|
aspectRatioConstraint.priority = .required - 1
|
||||||
|
primaryScreen.addConstraint(aspectRatioConstraint)
|
||||||
|
|
||||||
|
let heightConstraint = primaryScreen.heightAnchor.constraint(equalTo: heightAnchor)
|
||||||
|
heightConstraint.priority = .defaultHigh
|
||||||
|
let widthConstraint = primaryScreen.widthAnchor.constraint(equalTo: widthAnchor)
|
||||||
|
widthConstraint.priority = .defaultHigh
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([heightConstraint, widthConstraint])
|
||||||
|
|
||||||
|
// Make primaryScreen fill container
|
||||||
|
fullscreenconstraints = [
|
||||||
|
primaryScreen.topAnchor.constraint(equalTo: primaryScreen.topAnchor),
|
||||||
|
primaryScreen.bottomAnchor.constraint(equalTo: primaryScreen.bottomAnchor),
|
||||||
|
primaryScreen.leadingAnchor.constraint(equalTo: primaryScreen.leadingAnchor),
|
||||||
|
primaryScreen.trailingAnchor.constraint(equalTo: primaryScreen.trailingAnchor)
|
||||||
|
]
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate(fullscreenconstraints)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupSudachiScreenforiPad() {
|
||||||
|
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
|
||||||
|
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
primaryScreen.clipsToBounds = true
|
||||||
|
primaryScreen.layer.borderColor = UIColor.secondarySystemBackground.cgColor
|
||||||
|
primaryScreen.layer.borderWidth = 3
|
||||||
|
primaryScreen.layer.cornerCurve = .continuous
|
||||||
|
primaryScreen.layer.cornerRadius = 10
|
||||||
|
addSubview(primaryScreen)
|
||||||
|
|
||||||
|
|
||||||
|
portraitconstraints = [
|
||||||
|
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10),
|
||||||
|
primaryScreen.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 10),
|
||||||
|
primaryScreen.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -10),
|
||||||
|
primaryScreen.heightAnchor.constraint(equalTo: primaryScreen.widthAnchor, multiplier: 9 / 16),
|
||||||
|
]
|
||||||
|
|
||||||
|
landscapeconstraints = [
|
||||||
|
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 50),
|
||||||
|
primaryScreen.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -100),
|
||||||
|
primaryScreen.widthAnchor.constraint(equalTo: primaryScreen.heightAnchor, multiplier: 16 / 9),
|
||||||
|
primaryScreen.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
updateConstraintsForOrientation()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func setupSudachiScreen() {
|
||||||
|
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
|
||||||
|
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
primaryScreen.clipsToBounds = true
|
||||||
|
primaryScreen.layer.borderColor = UIColor.secondarySystemBackground.cgColor
|
||||||
|
primaryScreen.layer.borderWidth = 3
|
||||||
|
primaryScreen.layer.cornerCurve = .continuous
|
||||||
|
primaryScreen.layer.cornerRadius = 10
|
||||||
|
addSubview(primaryScreen)
|
||||||
|
|
||||||
|
|
||||||
|
portraitconstraints = [
|
||||||
|
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10),
|
||||||
|
primaryScreen.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 10),
|
||||||
|
primaryScreen.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -10),
|
||||||
|
primaryScreen.heightAnchor.constraint(equalTo: primaryScreen.widthAnchor, multiplier: 9 / 16),
|
||||||
|
]
|
||||||
|
|
||||||
|
landscapeconstraints = [
|
||||||
|
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10),
|
||||||
|
primaryScreen.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -10),
|
||||||
|
primaryScreen.widthAnchor.constraint(equalTo: primaryScreen.heightAnchor, multiplier: 16 / 9),
|
||||||
|
primaryScreen.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
|
||||||
|
]
|
||||||
|
|
||||||
|
updateConstraintsForOrientation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
updateConstraintsForOrientation()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateConstraintsForOrientation() {
|
||||||
|
|
||||||
|
if userDefaults.bool(forKey: "isfullscreen") {
|
||||||
|
removeConstraints(portraitconstraints)
|
||||||
|
removeConstraints(landscapeconstraints)
|
||||||
|
removeConstraints(fullscreenconstraints)
|
||||||
|
addConstraints(fullscreenconstraints)
|
||||||
|
} else {
|
||||||
|
removeConstraints(portraitconstraints)
|
||||||
|
removeConstraints(landscapeconstraints)
|
||||||
|
|
||||||
|
let isPortrait = UIApplication.shared.statusBarOrientation.isPortrait
|
||||||
|
addConstraints(isPortrait ? portraitconstraints : landscapeconstraints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,56 +5,63 @@ using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard;
|
|||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen;
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represent the shared memory shared between applications for input.
|
/// Represents the shared memory used for input, shared between applications.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 0x40000)]
|
[StructLayout(LayoutKind.Explicit, Size = 0x40000)]
|
||||||
struct SharedMemory
|
struct SharedMemory
|
||||||
{
|
{
|
||||||
|
// Ensure each struct has a defined size and is properly aligned in memory.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Debug controller.
|
/// Debug controller state (size: approximately 0x400).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public RingLifo<DebugPadState> DebugPad;
|
public RingLifo<DebugPadState> DebugPad;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Touchscreen.
|
/// Touchscreen state (size: approximately 0x3000).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FieldOffset(0x400)]
|
[FieldOffset(0x400)]
|
||||||
public RingLifo<TouchScreenState> TouchScreen;
|
public RingLifo<TouchScreenState> TouchScreen;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mouse.
|
/// Mouse state (size: approximately 0x400).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FieldOffset(0x3400)]
|
[FieldOffset(0x3400)]
|
||||||
public RingLifo<MouseState> Mouse;
|
public RingLifo<MouseState> Mouse;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keyboard.
|
/// Keyboard state (size: approximately 0x400).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FieldOffset(0x3800)]
|
[FieldOffset(0x3800)]
|
||||||
public RingLifo<KeyboardState> Keyboard;
|
public RingLifo<KeyboardState> Keyboard;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Nintendo Pads.
|
/// Nintendo Pads (size: approximately 0x800).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FieldOffset(0x9A00)]
|
[FieldOffset(0x3C00)]
|
||||||
public Array10<NpadState> Npads;
|
public Array10<NpadState> Npads;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a SharedMemory instance with each component initialized.
|
||||||
|
/// </summary>
|
||||||
public static SharedMemory Create()
|
public static SharedMemory Create()
|
||||||
{
|
{
|
||||||
SharedMemory result = new()
|
// Initialize each component separately to avoid potential layout issues.
|
||||||
{
|
SharedMemory result = new SharedMemory();
|
||||||
DebugPad = RingLifo<DebugPadState>.Create(),
|
|
||||||
TouchScreen = RingLifo<TouchScreenState>.Create(),
|
result.DebugPad = RingLifo<DebugPadState>.Create();
|
||||||
Mouse = RingLifo<MouseState>.Create(),
|
result.TouchScreen = RingLifo<TouchScreenState>.Create();
|
||||||
Keyboard = RingLifo<KeyboardState>.Create(),
|
result.Mouse = RingLifo<MouseState>.Create();
|
||||||
};
|
result.Keyboard = RingLifo<KeyboardState>.Create();
|
||||||
|
|
||||||
|
// Initialize each Npad state in a loop
|
||||||
for (int i = 0; i < result.Npads.Length; i++)
|
for (int i = 0; i < result.Npads.Length; i++)
|
||||||
{
|
{
|
||||||
result.Npads[i] = NpadState.Create();
|
result.Npads[i] = NpadState.Create();
|
||||||
|
@ -52,7 +52,6 @@ namespace Ryujinx.HLE
|
|||||||
Gpu = new GpuContext(Configuration.GpuRenderer);
|
Gpu = new GpuContext(Configuration.GpuRenderer);
|
||||||
System = new HOS.Horizon(this);
|
System = new HOS.Horizon(this);
|
||||||
Statistics = new PerformanceStatistics();
|
Statistics = new PerformanceStatistics();
|
||||||
Hid = new Hid(this, System.HidStorage);
|
|
||||||
Processes = new ProcessLoader(this);
|
Processes = new ProcessLoader(this);
|
||||||
TamperMachine = new TamperMachine();
|
TamperMachine = new TamperMachine();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user