forked from MeloNX/MeloNX
Add new SwiftUI Emulation View
This commit is contained in:
parent
a2c3f6d624
commit
f57d24706b
@ -618,7 +618,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = 4TD3JXVDW7;
|
||||
DEVELOPMENT_TEAM = 95J8WZ4TN8;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_TESTABILITY = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -628,6 +628,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",
|
||||
);
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@ -659,9 +663,17 @@
|
||||
"$(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",
|
||||
"$(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 = xyz.belladev.MeloNX;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/App/Core/Headers/Ryujinx-Header.h";
|
||||
@ -679,7 +691,7 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = 4TD3JXVDW7;
|
||||
DEVELOPMENT_TEAM = 95J8WZ4TN8;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@ -689,6 +701,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",
|
||||
);
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@ -720,9 +736,17 @@
|
||||
"$(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",
|
||||
"$(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 = xyz.belladev.MeloNX;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/App/Core/Headers/Ryujinx-Header.h";
|
||||
|
Binary file not shown.
@ -12,12 +12,12 @@
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_syswm.h>
|
||||
#import "utils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1,70 +0,0 @@
|
||||
//
|
||||
// VirtualController.swift
|
||||
// MeloNX
|
||||
//
|
||||
// Created by Stossy11 on 28/11/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import GameController
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
var hostingController: UIHostingController<ControllerView>? // Store reference to prevent deallocation
|
||||
|
||||
// Swts up a timer that adds subview to the Window and Repeats until the ControllerView is found in the Window to ensure that the controller shows.
|
||||
func waitForController() {
|
||||
guard let window = theWindow else { return }
|
||||
|
||||
// Function to search for an existing UIHostingController with ControllerView
|
||||
func findGCControllerView(in view: UIView) -> UIHostingController<ControllerView>? {
|
||||
if let hostingVC = view.next as? UIHostingController<ControllerView> {
|
||||
return hostingVC
|
||||
}
|
||||
|
||||
for subview in view.subviews {
|
||||
if let found = findGCControllerView(in: subview) {
|
||||
return found
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
let controllerView = ControllerView()
|
||||
let newHostingController = UIHostingController(rootView: controllerView)
|
||||
|
||||
hostingController = newHostingController
|
||||
|
||||
let containerView = newHostingController.view!
|
||||
containerView.backgroundColor = .clear
|
||||
containerView.frame = window.bounds
|
||||
containerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
// Timer for controller
|
||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||
if findGCControllerView(in: window) == nil {
|
||||
// Adds Virtual Controller Subview
|
||||
window.addSubview(containerView)
|
||||
window.bringSubviewToFront(containerView)
|
||||
|
||||
if let sdlWindow = SDL_GetWindowFromID(1) {
|
||||
SDL_SetWindowPosition(sdlWindow, 0, 0)
|
||||
}
|
||||
|
||||
timer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TransparentHostingContainerView: UIView {
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
// Check if the point is within the subviews of this container
|
||||
let view = super.hitTest(point, with: event)
|
||||
print(view)
|
||||
|
||||
// Return nil if the touch is outside visible content (passes through to views below)
|
||||
return view === self ? nil : view
|
||||
}
|
||||
}
|
@ -17,17 +17,11 @@ extension UIWindow {
|
||||
// Also waits for the window to append the on-screen controller
|
||||
@objc func wdb_makeKeyAndVisible() {
|
||||
if #available(iOS 13.0, *) {
|
||||
self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene)
|
||||
// self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene)
|
||||
}
|
||||
self.wdb_makeKeyAndVisible()
|
||||
theWindow = self
|
||||
|
||||
|
||||
if UserDefaults.standard.bool(forKey: "isVirtualController") {
|
||||
if let window = theWindow {
|
||||
waitForController()
|
||||
}
|
||||
}
|
||||
Ryujinx.shared.repeatuntilfindLayer()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,12 @@ class Ryujinx {
|
||||
let virtualController = VirtualController()
|
||||
|
||||
@Published var controllerMap: [Controller] = []
|
||||
@State var firmwareversion = "0"
|
||||
@Published var metalLayer: CAMetalLayer? = nil
|
||||
@Published var firmwareversion = "0"
|
||||
|
||||
var shouldMetal: Bool {
|
||||
metalLayer == nil
|
||||
}
|
||||
|
||||
static let shared = Ryujinx()
|
||||
|
||||
@ -402,6 +407,63 @@ class Ryujinx {
|
||||
}
|
||||
|
||||
|
||||
func repeatuntilfindLayer() {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
while self.metalLayer == nil {
|
||||
let layer = self.getMetalLayer(nil)
|
||||
|
||||
if layer != nil {
|
||||
DispatchQueue.main.async {
|
||||
self.metalLayer = layer
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
Thread.sleep(forTimeInterval: 0.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func getMetalLayer(_ window: OpaquePointer?) -> CAMetalLayer? {
|
||||
var window = window
|
||||
if window == nil {
|
||||
window = SDL_GetWindowFromID(1)
|
||||
}
|
||||
|
||||
var windowInfo = SDL_SysWMinfo()
|
||||
SDL_GetWindowWMInfo(window, &windowInfo)
|
||||
|
||||
|
||||
guard let uiWindow = windowInfo.info.uikit.window,
|
||||
let rootView = uiWindow.takeUnretainedValue().rootViewController?.view else {
|
||||
print("Unable to get root view")
|
||||
return nil
|
||||
}
|
||||
|
||||
func findMetalLayer(in view: UIView) -> CAMetalLayer? {
|
||||
if let metalLayer = view.layer as? CAMetalLayer {
|
||||
return metalLayer
|
||||
}
|
||||
|
||||
for subview in view.subviews {
|
||||
if let metalLayer = findMetalLayer(in: subview) {
|
||||
return metalLayer
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if let existingLayer = findMetalLayer(in: rootView) {
|
||||
print("Found Metal Layer")
|
||||
return existingLayer
|
||||
}
|
||||
print("found nothing")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
static func log(_ message: String) {
|
||||
print("[Ryujinx] \(message)")
|
||||
|
@ -75,7 +75,7 @@ struct ContentView: View {
|
||||
// MARK: - Body
|
||||
var body: some View {
|
||||
if game != nil, quits == false {
|
||||
if isLoading {
|
||||
if Ryujinx.shared.metalLayer == nil {
|
||||
emulationView
|
||||
.onAppear() {
|
||||
// This is fro the old exiting game feature that didn't work properly. will look into it and figure out a better alternative
|
||||
@ -93,9 +93,7 @@ struct ContentView: View {
|
||||
}
|
||||
} else {
|
||||
// This is when the game starts to stop the animation
|
||||
VStack {
|
||||
|
||||
}
|
||||
EmulationView()
|
||||
.onAppear() {
|
||||
isAnimating = false
|
||||
}
|
||||
@ -234,7 +232,7 @@ struct ContentView: View {
|
||||
private func initializeSDL() {
|
||||
setMoltenVKSettings()
|
||||
SDL_SetMainReady() // Sets SDL Ready
|
||||
SDL_iPhoneSetEventPump(SDL_TRUE) // Allow iOS Set Event Pump (Check out SDL2 Documentation here)
|
||||
SDL_iPhoneSetEventPump(SDL_TRUE) // Set iOS Event Pump to true (Check out SDL2 Documentation here)
|
||||
SDL_Init(SdlInitFlags) // Initialises SDL2
|
||||
initialize()
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
//
|
||||
// EmulationView.swift
|
||||
// MeloNX
|
||||
//
|
||||
// Created by Stossy11 on 09/02/2025.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// Emulation View
|
||||
struct EmulationView: View {
|
||||
@AppStorage("isVirtualController") var isVCA: Bool = true
|
||||
var body: some View {
|
||||
ZStack {
|
||||
MetalView() // The Emulation View
|
||||
.ignoresSafeArea()
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
|
||||
// Above Emulation View
|
||||
|
||||
if isVCA {
|
||||
ControllerView() // Virtual Controller
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
//
|
||||
// MetalView.swift
|
||||
// MeloNX
|
||||
//
|
||||
// Created by Stossy11 on 09/02/2025.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import MetalKit
|
||||
|
||||
struct MetalView: UIViewRepresentable {
|
||||
|
||||
func makeUIView(context: Context) -> UIView {
|
||||
let view = UIView()
|
||||
|
||||
let metalLayer = Ryujinx.shared.metalLayer!
|
||||
metalLayer.frame = view.bounds
|
||||
view.contentScaleFactor = metalLayer.contentsScale // Right size and Fix Touch :3
|
||||
view.layer.addSublayer(metalLayer)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIView, context: Context) {
|
||||
// nothin
|
||||
}
|
||||
}
|
@ -9,15 +9,15 @@
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.nintendo.switch-package</string>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Nintendo Switch Package</string>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
<string>public.archive</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Nintendo Switch Package</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.nintendo.switch-package</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
@ -29,15 +29,15 @@
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.nintendo.switch-cartridge</string>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Nintendo Switch Cartridge</string>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
<string>public.archive</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Nintendo Switch Cartridge</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.nintendo.switch-cartridge</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
|
@ -21,7 +21,7 @@ struct MeloNXApp: App {
|
||||
if bool {
|
||||
print("Ryujinx Files Initialized Successfully")
|
||||
} else {
|
||||
exit(0)
|
||||
// exit(0)
|
||||
}
|
||||
|
||||
}
|
||||
@ -29,7 +29,7 @@ struct MeloNXApp: App {
|
||||
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
|
||||
InitializeRyujinx() { bool in
|
||||
if !bool {
|
||||
exit(0)
|
||||
// exit(0)
|
||||
}
|
||||
|
||||
}
|
||||
@ -144,8 +144,9 @@ func InitializeRyujinx(completion: @escaping (Bool) -> Void) {
|
||||
exit(0)
|
||||
}
|
||||
|
||||
let task = URLSession.shared.dataTask(with: URL(string: addFolders(path)!)!) { data, _, _ in
|
||||
let task = URLSession.shared.dataTask(with: URL(string: addFolders(path)!)!) { data, response, error in
|
||||
let text = String(data: data ?? Data(), encoding: .utf8) ?? ""
|
||||
print(text)
|
||||
completion(text.contains("true"))
|
||||
}
|
||||
task.resume()
|
||||
|
Loading…
x
Reference in New Issue
Block a user