refactor virtual pad composition

This commit is contained in:
Emmanuel Hansen 2023-07-27 20:24:33 +00:00
parent 452d01f7bc
commit 35a85241c6
5 changed files with 83 additions and 58 deletions

View File

@ -28,6 +28,7 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:hardwareAccelerated="false"
android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
android:theme="@style/Theme.RyujinxAndroid">
<intent-filter>

View File

@ -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<FrameLayout>(R.id.leftcontainer)!!.addView(controller.leftGamePad)
view.findViewById<FrameLayout>(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<FrameLayout>(R.id.leftcontainer)!!.addView(leftGamePad)
view.findViewById<FrameLayout>(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) {

View File

@ -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()

View File

@ -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<Double>? = null
@ -65,4 +67,8 @@ class MainViewModel(val activity: MainActivity) {
this.value = gameTime
}
}
fun setGameController(controller: GameController) {
this.controller = controller
}
}

View File

@ -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())