diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameHost.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameHost.kt index 730b484f0..77ff6e52b 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameHost.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/GameHost.kt @@ -137,6 +137,10 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su } } catch (_: Throwable) {} + val qs = org.kenjinx.android.viewmodels.QuickSettings(mainViewModel.activity) + try { + KenjinxNative.graphicsSetFullscreenStretch(qs.stretchToFullscreen) + } catch (_: Throwable) {} _guestThread = thread(start = true, name = "KenjinxGuest") { runGame() } @@ -280,6 +284,7 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su // If rotation is known: Force plausibility (Landscape ↔ Portrait) expectedRotation?.let { rot -> + // ROTATION_90 (1) / ROTATION_270 (3) => Landscape val landscape = (rot == 1 || rot == 3) if (landscape && h > w) { val t = w; w = h; h = t diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/KenjinxNative.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/KenjinxNative.kt index 8a7fdc3ac..29753acb6 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/KenjinxNative.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/KenjinxNative.kt @@ -53,6 +53,7 @@ interface KenjinxNativeJna : Library { fun graphicsRendererSetSize(width: Int, height: Int) fun graphicsRendererSetVsync(vSyncMode: Int) fun graphicsRendererRunLoop() + fun graphicsSetFullscreenStretch(enable: Boolean) fun deviceReloadFilesystem() fun inputInitialize(width: Int, height: Int) fun inputSetClientSize(width: Int, height: Int) @@ -119,10 +120,10 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance { @JvmStatic fun updateProgress(infoPtr: Long, progress: Float) { + // Get string from native pointer and push into progress overlay val text = NativeHelpers.instance.getStringJava(infoPtr) MainActivity.mainViewModel?.gameHost?.setProgress(text, progress) } - @JvmStatic fun onSurfaceSizeChanged(width: Int, height: Int) { // No-Op: Placeholder – Hook if needed. @@ -187,6 +188,7 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance { /** * Variant B (strings directly). Used by newer JNI/interop paths. + * Signature exactly matches the C# call in AndroidUIHandler.cs / Interop.UpdateUiHandler(...). */ @JvmStatic fun uiHandlerUpdate( diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/QuickSettings.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/QuickSettings.kt index d1eadd051..d1ac6b446 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/QuickSettings.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/QuickSettings.kt @@ -36,6 +36,7 @@ class QuickSettings(val activity: Activity) { var enableShaderCache: Boolean var enableTextureRecompression: Boolean var enableMacroHLE: Boolean + var stretchToFullscreen: Boolean var resScale: Float var maxAnisotropy: Float var isGrid: Boolean @@ -74,6 +75,7 @@ class QuickSettings(val activity: Activity) { enableShaderCache = sharedPref.getBoolean("enableShaderCache", true) enableTextureRecompression = sharedPref.getBoolean("enableTextureRecompression", false) enableMacroHLE = sharedPref.getBoolean("enableMacroHLE", true) + stretchToFullscreen = sharedPref.getBoolean("stretchToFullscreen", false) resScale = sharedPref.getFloat("resScale", 1f) maxAnisotropy = sharedPref.getFloat("maxAnisotropy", 0f) useVirtualController = sharedPref.getBoolean("useVirtualController", true) @@ -112,6 +114,7 @@ class QuickSettings(val activity: Activity) { putBoolean("enableShaderCache", enableShaderCache) putBoolean("enableTextureRecompression", enableTextureRecompression) putBoolean("enableMacroHLE", enableMacroHLE) + putBoolean("stretchToFullscreen", stretchToFullscreen) putFloat("resScale", resScale) putFloat("maxAnisotropy", maxAnisotropy) putBoolean("useVirtualController", useVirtualController) diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt index fc804aa9f..e453afac2 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt @@ -57,6 +57,7 @@ class SettingsViewModel(val activity: MainActivity) { enableShaderCache: MutableState, enableTextureRecompression: MutableState, enableMacroHLE: MutableState, + stretchToFullscreen: MutableState, resScale: MutableState, maxAnisotropy: MutableState, useVirtualController: MutableState, @@ -91,6 +92,7 @@ class SettingsViewModel(val activity: MainActivity) { enableShaderCache.value = sharedPref.getBoolean("enableShaderCache", true) enableTextureRecompression.value = sharedPref.getBoolean("enableTextureRecompression", false) enableMacroHLE.value = sharedPref.getBoolean("enableMacroHLE", false) + stretchToFullscreen.value = sharedPref.getBoolean("stretchToFullscreen", false) resScale.value = sharedPref.getFloat("resScale", 1f) maxAnisotropy.value = sharedPref.getFloat("maxAnisotropy", 0f) useVirtualController.value = sharedPref.getBoolean("useVirtualController", true) @@ -131,6 +133,7 @@ class SettingsViewModel(val activity: MainActivity) { enableShaderCache: MutableState, enableTextureRecompression: MutableState, enableMacroHLE: MutableState, + stretchToFullscreen: MutableState, resScale: MutableState, maxAnisotropy: MutableState, useVirtualController: MutableState, @@ -167,6 +170,7 @@ class SettingsViewModel(val activity: MainActivity) { putBoolean("enableShaderCache", enableShaderCache.value) putBoolean("enableTextureRecompression", enableTextureRecompression.value) putBoolean("enableMacroHLE", enableMacroHLE.value) + putBoolean("stretchToFullscreen", stretchToFullscreen.value) putFloat("resScale", resScale.value) putFloat("maxAnisotropy", maxAnisotropy.value) putBoolean("useVirtualController", useVirtualController.value) diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt index 56fb71601..212f2da11 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt @@ -111,6 +111,7 @@ class SettingViews { val enableShaderCache = remember { mutableStateOf(false) } val enableTextureRecompression = remember { mutableStateOf(false) } val enableMacroHLE = remember { mutableStateOf(false) } + val stretchToFullscreen = remember { mutableStateOf(false) } val resScale = remember { mutableFloatStateOf(1f) } val maxAnisotropy = remember { mutableFloatStateOf(0f) } val useVirtualController = remember { mutableStateOf(true) } @@ -165,6 +166,7 @@ class SettingViews { enableShaderCache, enableTextureRecompression, enableMacroHLE, + stretchToFullscreen, resScale, maxAnisotropy, useVirtualController, @@ -210,6 +212,7 @@ class SettingViews { enableShaderCache, enableTextureRecompression, enableMacroHLE, + stretchToFullscreen, resScale, maxAnisotropy, useVirtualController, @@ -259,6 +262,7 @@ class SettingViews { selectedOrientation = orientationPref.value, onOrientationSelected = { sel -> orientationPref.value = sel + // Save and use immediately val qs = QuickSettings(mainViewModel.activity) qs.orientationPreference = sel qs.save() @@ -1245,6 +1249,7 @@ class SettingViews { enableShaderCache.SwitchSelector(label = "Shader Cache") enableTextureRecompression.SwitchSelector(label = "Texture Recompression") enableMacroHLE.SwitchSelector(label = "Macro HLE") + stretchToFullscreen.SwitchSelector(label = "Stretch to Fullscreen") ResolutionScaleDropdown( selectedScale = resScale.floatValue, onScaleSelected = { scale -> diff --git a/src/LibKenjinx/LibKenjinx.Graphics.cs b/src/LibKenjinx/LibKenjinx.Graphics.cs index e97bbc560..657a7d12e 100644 --- a/src/LibKenjinx/LibKenjinx.Graphics.cs +++ b/src/LibKenjinx/LibKenjinx.Graphics.cs @@ -221,19 +221,29 @@ namespace LibKenjinx [StructLayout(LayoutKind.Sequential)] public struct GraphicsConfiguration { - public float ResScale = 1f; - public float MaxAnisotropy = -1; - public bool FastGpuTime = true; - public bool Fast2DCopy = true; - public bool EnableMacroJit = false; - public bool EnableMacroHLE = true; - public bool EnableShaderCache = true; - public bool EnableTextureRecompression = false; - public BackendThreading BackendThreading = BackendThreading.Auto; - public AspectRatio AspectRatio = AspectRatio.Fixed16x9; + public float ResScale; + public float MaxAnisotropy; + public bool FastGpuTime; + public bool Fast2DCopy; + public bool EnableMacroJit; + public bool EnableMacroHLE; + public bool EnableShaderCache; + public bool EnableTextureRecompression; + public BackendThreading BackendThreading; + public AspectRatio AspectRatio; // <- important public GraphicsConfiguration() { + ResScale = 1f; + MaxAnisotropy = -1; + FastGpuTime = true; + Fast2DCopy = true; + EnableMacroJit = false; + EnableMacroHLE = true; + EnableShaderCache = true; + EnableTextureRecompression = false; + BackendThreading = BackendThreading.Auto; + AspectRatio = AspectRatio.Fixed16x9; } } diff --git a/src/LibKenjinx/LibKenjinx.Native.cs b/src/LibKenjinx/LibKenjinx.Native.cs index f83b50725..356dd2e04 100644 --- a/src/LibKenjinx/LibKenjinx.Native.cs +++ b/src/LibKenjinx/LibKenjinx.Native.cs @@ -132,7 +132,6 @@ namespace LibKenjinx } List extensions = []; - var size = Marshal.SizeOf(); var extPtr = (IntPtr*)nativeGraphicsInterop.VkRequiredExtensions; for (int i = 0; i < nativeGraphicsInterop.VkRequiredExtensionsCount; i++) { @@ -274,6 +273,7 @@ namespace LibKenjinx return stats; } + [UnmanagedCallersOnly(EntryPoint = "device_launch_mii_editor")] public static bool LaunchMiiEditAppletNative() { @@ -468,5 +468,34 @@ namespace LibKenjinx CloseUser(userId); } + + // ---------------------- + // Stretch: Helper + Exports + // ---------------------- + + // central logic (managed) + private static void ApplyFullscreenStretch(bool enable) + { + var ar = enable ? AspectRatio.Stretched : AspectRatio.Fixed16x9; + + // Retrieve, modify, write back struct + var cfg = GraphicsConfiguration; + cfg.AspectRatio = ar; + GraphicsConfiguration = cfg; + + // Hot-Apply for running emulation + var dev = SwitchDevice?.EmulationContext; + if (dev != null) + { + try { dev.Configuration.AspectRatio = ar; } catch { } + } + } + + // CamelCase Export (JNA calls it here) + [UnmanagedCallersOnly(EntryPoint = "graphicsSetFullscreenStretch")] + public static void GraphicsSetFullscreenStretchNativeAlias(bool enable) + { + ApplyFullscreenStretch(enable); + } } }