From 398fb78a315ec3081eb571ce9eb45bb497f989fa Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Thu, 27 Jul 2023 20:24:33 +0000 Subject: [PATCH] refactor virtual pad composition --- .../app/src/main/AndroidManifest.xml | 1 + .../org/ryujinx/android/GameController.kt | 71 +++++++++++-------- .../main/java/org/ryujinx/android/GameHost.kt | 8 +-- .../android/viewmodels/MainViewModel.kt | 6 ++ .../org/ryujinx/android/views/MainView.kt | 55 ++++++++------ 5 files changed, 83 insertions(+), 58 deletions(-) diff --git a/src/RyujinxAndroid/app/src/main/AndroidManifest.xml b/src/RyujinxAndroid/app/src/main/AndroidManifest.xml index 5dc772de1..4501665de 100644 --- a/src/RyujinxAndroid/app/src/main/AndroidManifest.xml +++ b/src/RyujinxAndroid/app/src/main/AndroidManifest.xml @@ -28,6 +28,7 @@ diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt index 2266a2eb7..aaf97cd3e 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleCoroutineScope +import androidx.lifecycle.lifecycleScope import com.swordfish.radialgamepad.library.RadialGamePad import com.swordfish.radialgamepad.library.config.ButtonConfig import com.swordfish.radialgamepad.library.config.CrossConfig @@ -27,11 +28,47 @@ import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.launch +import org.ryujinx.android.viewmodels.MainViewModel typealias GamePad = RadialGamePad typealias GamePadConfig = RadialGamePadConfig -class GameController(var activity: Activity, var ryujinxNative: RyujinxNative = RyujinxNative()) { +class GameController(var activity: Activity) { + + companion object{ + private fun Create(context: Context, activity: Activity, controller: GameController) : View + { + val inflator = LayoutInflater.from(context) + val view = inflator.inflate(R.layout.game_layout, null) + view.findViewById(R.id.leftcontainer)!!.addView(controller.leftGamePad) + view.findViewById(R.id.rightcontainer)!!.addView(controller.rightGamePad) + + return view + } + @Composable + fun Compose(viewModel: MainViewModel) : Unit + { + AndroidView( + modifier = Modifier.fillMaxSize(), factory = { context -> + val controller = GameController(viewModel.activity) + val c = Create(context, viewModel.activity, controller) + viewModel.activity.lifecycleScope.apply { + viewModel.activity.lifecycleScope.launch { + val events = merge(controller.leftGamePad.events(),controller.rightGamePad.events()) + .shareIn(viewModel.activity.lifecycleScope, SharingStarted.Lazily) + events.safeCollect { + controller.handleEvent(it) + } + } + } + controller.controllerView = c + viewModel.setGameController(controller) + c + }) + } + } + + private var ryujinxNative: RyujinxNative private var controllerView: View? = null var leftGamePad: GamePad var rightGamePad: GamePad @@ -56,36 +93,8 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative = leftGamePad.gravityY = 1f rightGamePad.gravityX = 1f rightGamePad.gravityY = 1f - } - @Composable - fun Compose(lifecycleScope: LifecycleCoroutineScope, lifecycle:Lifecycle) : Unit - { - AndroidView( - modifier = Modifier.fillMaxSize(), factory = { context -> Create(context)}) - - lifecycleScope.apply { - lifecycleScope.launch { - val events = merge(leftGamePad.events(),rightGamePad.events()) - .shareIn(lifecycleScope, SharingStarted.Lazily) - - events.safeCollect { - handleEvent(it) - } - } - } - } - - private fun Create(context: Context) : View - { - val inflator = LayoutInflater.from(context) - val view = inflator.inflate(R.layout.game_layout, null) - view.findViewById(R.id.leftcontainer)!!.addView(leftGamePad) - view.findViewById(R.id.rightcontainer)!!.addView(rightGamePad) - - controllerView = view - - return controllerView as View + ryujinxNative = RyujinxNative() } fun setVisible(isVisible: Boolean){ @@ -99,7 +108,7 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative = fun connect(){ if(controllerId == -1) - controllerId = ryujinxNative.inputConnectGamepad(0) + controllerId = RyujinxNative().inputConnectGamepad(0) } private fun handleEvent(ev: Event) { diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt index a66096dbc..2bbb99804 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt @@ -11,7 +11,7 @@ import org.ryujinx.android.viewmodels.VulkanDriverViewModel import java.io.File import kotlin.concurrent.thread -class GameHost(context: Context?, val controller: GameController, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback { +class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback { private var _renderingThreadWatcher: Thread? = null private var _height: Int = 0 private var _width: Int = 0 @@ -142,16 +142,14 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo _nativeRyujinx.inputInitialize(width, height) if(!settings.useVirtualController){ - controller.setVisible(false) + mainViewModel.controller?.setVisible(false) } else{ - controller.connect() + mainViewModel.controller?.connect() } mainViewModel.activity.physicalControllerManager.connect() - // - _nativeRyujinx.graphicsRendererSetSize( surfaceHolder.surfaceFrame.width(), surfaceHolder.surfaceFrame.height() diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt index 1c1e34399..2c1641787 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/viewmodels/MainViewModel.kt @@ -6,12 +6,14 @@ import android.os.Build import android.os.PerformanceHintManager import androidx.compose.runtime.MutableState import androidx.navigation.NavHostController +import org.ryujinx.android.GameController import org.ryujinx.android.GameHost import org.ryujinx.android.MainActivity import org.ryujinx.android.PerformanceManager @SuppressLint("WrongConstant") class MainViewModel(val activity: MainActivity) { + var controller: GameController? = null var performanceManager: PerformanceManager? = null var selected: GameModel? = null private var gameTimeState: MutableState? = null @@ -65,4 +67,8 @@ class MainViewModel(val activity: MainActivity) { this.value = gameTime } } + + fun setGameController(controller: GameController) { + this.controller = controller + } } \ No newline at end of file diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt index 8ec1d5650..752b2c193 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt @@ -40,35 +40,39 @@ import kotlin.math.roundToInt class MainView { companion object { @Composable - fun Main(mainViewModel: MainViewModel){ + fun Main(mainViewModel: MainViewModel) { val navController = rememberNavController() mainViewModel.setNavController(navController) NavHost(navController = navController, startDestination = "home") { composable("home") { HomeViews.Home(mainViewModel.homeViewModel, navController) } composable("game") { GameView(mainViewModel) } - composable("settings") { SettingViews.Main(SettingsViewModel(navController, mainViewModel.activity)) } + composable("settings") { + SettingViews.Main( + SettingsViewModel( + navController, + mainViewModel.activity + ) + ) + } } } @Composable - fun GameView(mainViewModel: MainViewModel){ + fun GameView(mainViewModel: MainViewModel) { Box(modifier = Modifier.fillMaxSize()) { - val controller = remember { - GameController(mainViewModel.activity) - } AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> - GameHost(context, controller, mainViewModel) + GameHost(context, mainViewModel) } ) - GameOverlay(mainViewModel, controller) + GameOverlay(mainViewModel) } } @Composable - fun GameOverlay(mainViewModel: MainViewModel, controller: GameController){ + fun GameOverlay(mainViewModel: MainViewModel) { Box(modifier = Modifier.fillMaxSize()) { GameStats(mainViewModel) @@ -84,9 +88,6 @@ class MainView { Thread.sleep(2) val event = awaitPointerEvent() - if(controller.isVisible) - continue - val change = event .component1() .firstOrNull() @@ -100,10 +101,12 @@ class MainView { position.y.roundToInt() ) } + PointerEventType.Release -> { ryujinxNative.inputReleaseTouchPoint() } + PointerEventType.Move -> { ryujinxNative.inputSetTouchPoint( position.x.roundToInt(), @@ -117,18 +120,24 @@ class MainView { } }) { } - controller.Compose(mainViewModel.activity.lifecycleScope, mainViewModel.activity.lifecycle) - Row(modifier = Modifier - .align(Alignment.BottomCenter) - .padding(8.dp)) { - IconButton(modifier = Modifier.padding(4.dp),onClick = { - controller.setVisible(!controller.isVisible) + GameController.Compose(mainViewModel) + Row( + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(8.dp) + ) { + IconButton(modifier = Modifier.padding(4.dp), onClick = { + mainViewModel.controller?.setVisible(!mainViewModel.controller!!.isVisible) }) { - Icon(imageVector = rememberVideogameAsset(), contentDescription = "Toggle Virtual Pad") + Icon( + imageVector = rememberVideogameAsset(), + contentDescription = "Toggle Virtual Pad" + ) } } } } + @Composable fun rememberVideogameAsset(): ImageVector { val primaryColor = MaterialTheme.colorScheme.primary @@ -226,7 +235,7 @@ class MainView { } @Composable - fun GameStats(mainViewModel: MainViewModel){ + fun GameStats(mainViewModel: MainViewModel) { val fifo = remember { mutableStateOf(0.0) } @@ -237,8 +246,10 @@ class MainView { mutableStateOf(0.0) } - Surface(modifier = Modifier.padding(16.dp), - color = MaterialTheme.colorScheme.surface.copy(0.4f)) { + Surface( + modifier = Modifier.padding(16.dp), + color = MaterialTheme.colorScheme.surface.copy(0.4f) + ) { Column { var gameTimeVal = 0.0 if (!gameTime.value.isInfinite())