mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-09 21:47:56 +00:00
More adjustments to UI
This commit is contained in:
@@ -298,6 +298,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
steps: Int,
|
steps: Int,
|
||||||
selectedStep: Int,
|
selectedStep: Int,
|
||||||
describe: (Int) -> String,
|
describe: (Int) -> String,
|
||||||
|
onCommitted: (Int) -> Unit,
|
||||||
onChanged: (Int) -> Unit
|
onChanged: (Int) -> Unit
|
||||||
) {
|
) {
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||||
@@ -327,14 +328,20 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pressedValue = slider.value
|
||||||
|
|
||||||
slider.setOnTouchListener { _, event ->
|
slider.setOnTouchListener { _, event ->
|
||||||
val drawer = emulationFragment.view?.findViewById<DrawerLayout>(R.id.drawer_layout)
|
val drawer = emulationFragment.view?.findViewById<DrawerLayout>(R.id.drawer_layout)
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
drawer?.requestDisallowInterceptTouchEvent(true)
|
drawer?.requestDisallowInterceptTouchEvent(true)
|
||||||
|
pressedValue = slider.value
|
||||||
}
|
}
|
||||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||||
drawer?.requestDisallowInterceptTouchEvent(false)
|
drawer?.requestDisallowInterceptTouchEvent(false)
|
||||||
|
if (slider.value != pressedValue) {
|
||||||
|
onCommitted(slider.value.toInt())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
@@ -389,6 +396,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
fun addEffectPicker(
|
fun addEffectPicker(
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
choices: List<String>,
|
choices: List<String>,
|
||||||
|
hasEffects: Boolean,
|
||||||
|
onRemoveAll: () -> Unit,
|
||||||
onPicked: (Int) -> Unit
|
onPicked: (Int) -> Unit
|
||||||
) {
|
) {
|
||||||
val context = emulationFragment.requireContext()
|
val context = emulationFragment.requireContext()
|
||||||
@@ -398,6 +407,10 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
val button = itemView.findViewById<com.google.android.material.button.MaterialButton>(
|
val button = itemView.findViewById<com.google.android.material.button.MaterialButton>(
|
||||||
R.id.add_button
|
R.id.add_button
|
||||||
)
|
)
|
||||||
|
val removeButton =
|
||||||
|
itemView.findViewById<com.google.android.material.button.MaterialButton>(
|
||||||
|
R.id.remove_all_button
|
||||||
|
)
|
||||||
val choiceGroup = itemView.findViewById<RadioGroup>(R.id.add_choices)
|
val choiceGroup = itemView.findViewById<RadioGroup>(R.id.add_choices)
|
||||||
|
|
||||||
choices.forEachIndexed { index, name ->
|
choices.forEachIndexed { index, name ->
|
||||||
@@ -413,22 +426,27 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
choiceGroup.addView(radioButton)
|
choiceGroup.addView(radioButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
val closedBackground = MaterialColors.getColor(
|
var closedLabel = R.string.post_processing_add
|
||||||
button,
|
if (hasEffects) {
|
||||||
com.google.android.material.R.attr.colorSecondaryContainer
|
closedLabel = R.string.post_processing_open_list
|
||||||
)
|
removeButton.visibility = View.VISIBLE
|
||||||
val closedForeground = MaterialColors.getColor(
|
}
|
||||||
button,
|
button.setText(closedLabel)
|
||||||
com.google.android.material.R.attr.colorOnSecondaryContainer
|
|
||||||
)
|
val removeBackground = MaterialColors.getColor(
|
||||||
val openBackground = MaterialColors.getColor(
|
removeButton,
|
||||||
button,
|
|
||||||
com.google.android.material.R.attr.colorErrorContainer
|
com.google.android.material.R.attr.colorErrorContainer
|
||||||
)
|
)
|
||||||
val openForeground = MaterialColors.getColor(
|
val removeForeground = MaterialColors.getColor(
|
||||||
button,
|
removeButton,
|
||||||
com.google.android.material.R.attr.colorOnErrorContainer
|
com.google.android.material.R.attr.colorOnErrorContainer
|
||||||
)
|
)
|
||||||
|
removeButton.backgroundTintList = ColorStateList.valueOf(removeBackground)
|
||||||
|
removeButton.setTextColor(removeForeground)
|
||||||
|
removeButton.iconTint = ColorStateList.valueOf(removeForeground)
|
||||||
|
removeButton.setOnClickListener {
|
||||||
|
onRemoveAll()
|
||||||
|
}
|
||||||
|
|
||||||
val slide = context.resources.displayMetrics.density * 24.0f
|
val slide = context.resources.displayMetrics.density * 24.0f
|
||||||
|
|
||||||
@@ -451,11 +469,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
.start()
|
.start()
|
||||||
|
|
||||||
button.text = context.getString(R.string.post_processing_hide_effects)
|
button.setText(R.string.post_processing_close_list)
|
||||||
button.setIconResource(R.drawable.ic_clear)
|
button.setIconResource(R.drawable.ic_clear)
|
||||||
button.backgroundTintList = ColorStateList.valueOf(openBackground)
|
|
||||||
button.setTextColor(openForeground)
|
|
||||||
button.iconTint = ColorStateList.valueOf(openForeground)
|
|
||||||
} else {
|
} else {
|
||||||
choiceGroup.animate()
|
choiceGroup.animate()
|
||||||
.alpha(0.0f)
|
.alpha(0.0f)
|
||||||
@@ -466,11 +481,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
.start()
|
.start()
|
||||||
|
|
||||||
button.text = context.getString(R.string.post_processing_add)
|
button.setText(closedLabel)
|
||||||
button.setIconResource(R.drawable.ic_add)
|
button.setIconResource(R.drawable.ic_add)
|
||||||
button.backgroundTintList = ColorStateList.valueOf(closedBackground)
|
|
||||||
button.setTextColor(closedForeground)
|
|
||||||
button.iconTint = ColorStateList.valueOf(closedForeground)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,8 +506,9 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
|
|
||||||
switchView.isChecked = NativePostProcessing.isEnabled()
|
switchView.isChecked = NativePostProcessing.isEnabled()
|
||||||
switchView.setOnCheckedChangeListener { _, checked ->
|
switchView.setOnCheckedChangeListener { _, checked ->
|
||||||
NativePostProcessing.setEnabled(checked)
|
emulationFragment.editPostProcessing {
|
||||||
saveSettings()
|
NativePostProcessing.setEnabled(checked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container.addView(itemView)
|
container.addView(itemView)
|
||||||
@@ -510,12 +523,21 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
val preset = NativePostProcessing.getActivePreset()
|
val preset = NativePostProcessing.getActivePreset()
|
||||||
if (preset.isNotEmpty()) {
|
if (preset.isNotEmpty()) {
|
||||||
addDivider(container)
|
addDivider(container)
|
||||||
var summary =
|
|
||||||
YuzuApplication.appContext.getString(R.string.post_processing_preset_locked)
|
var summary = ""
|
||||||
|
val described = NativePostProcessing.presets().firstOrNull { it.name == preset }
|
||||||
|
if (described != null) {
|
||||||
|
summary = described.description
|
||||||
|
}
|
||||||
|
if (summary.isEmpty()) {
|
||||||
|
summary =
|
||||||
|
YuzuApplication.appContext.getString(R.string.post_processing_preset_locked)
|
||||||
|
}
|
||||||
if (NativePostProcessing.isPresetModified()) {
|
if (NativePostProcessing.isPresetModified()) {
|
||||||
summary =
|
summary =
|
||||||
YuzuApplication.appContext.getString(R.string.post_processing_preset_modified)
|
YuzuApplication.appContext.getString(R.string.post_processing_preset_modified)
|
||||||
}
|
}
|
||||||
|
|
||||||
addPresetBand(container, preset, summary)
|
addPresetBand(container, preset, summary)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -553,8 +575,9 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val body = addShaderCard(title, summary, container) {
|
val body = addShaderCard(title, summary, container) {
|
||||||
NativePostProcessing.remove(index)
|
emulationFragment.editPostProcessing {
|
||||||
NativePostProcessing.persistFor(emulationFragment.shouldUseCustom)
|
NativePostProcessing.remove(index)
|
||||||
|
}
|
||||||
onStructureChanged()
|
onStructureChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,9 +588,20 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addEffectPicker(container, labels) { picked ->
|
addEffectPicker(
|
||||||
NativePostProcessing.append(files[picked], techniques[picked])
|
container,
|
||||||
NativePostProcessing.persistFor(emulationFragment.shouldUseCustom)
|
labels,
|
||||||
|
chain.isNotEmpty(),
|
||||||
|
{
|
||||||
|
emulationFragment.editPostProcessing {
|
||||||
|
NativePostProcessing.clearChain()
|
||||||
|
}
|
||||||
|
onStructureChanged()
|
||||||
|
}
|
||||||
|
) { picked ->
|
||||||
|
emulationFragment.editPostProcessing {
|
||||||
|
NativePostProcessing.append(files[picked], techniques[picked])
|
||||||
|
}
|
||||||
onStructureChanged()
|
onStructureChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -600,7 +634,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
container,
|
container,
|
||||||
steps,
|
steps,
|
||||||
step,
|
step,
|
||||||
{ position -> describeUniform(uniform, position) }
|
{ position -> describeUniform(uniform, position) },
|
||||||
|
{ emulationFragment.persistPostProcessing() }
|
||||||
) { position ->
|
) { position ->
|
||||||
NativePostProcessing.setValue(
|
NativePostProcessing.setValue(
|
||||||
index,
|
index,
|
||||||
@@ -608,7 +643,6 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
component,
|
component,
|
||||||
uniform.min + position * uniform.step
|
uniform.min + position * uniform.step
|
||||||
)
|
)
|
||||||
NativePostProcessing.persistFor(emulationFragment.shouldUseCustom)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.model
|
||||||
|
|
||||||
|
class FxPresetNameSetting(private val onNamed: (String) -> Unit) : AbstractStringSetting {
|
||||||
|
override val key: String
|
||||||
|
get() = "fx_preset_name"
|
||||||
|
|
||||||
|
override val defaultValue: Any
|
||||||
|
get() = ""
|
||||||
|
|
||||||
|
override val isRuntimeModifiable: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override val pairedSettingKey: String
|
||||||
|
get() = ""
|
||||||
|
|
||||||
|
override val isSwitchable: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
override val isSaveable: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override var global: Boolean
|
||||||
|
get() = true
|
||||||
|
set(_) {}
|
||||||
|
|
||||||
|
override fun getString(needsGlobal: Boolean): String = ""
|
||||||
|
|
||||||
|
override fun setString(value: String) = onNamed(value)
|
||||||
|
|
||||||
|
override fun getValueAsString(needsGlobal: Boolean): String = ""
|
||||||
|
|
||||||
|
override fun reset() {}
|
||||||
|
}
|
||||||
+4
-4
@@ -39,7 +39,7 @@ abstract class FxUniformSetting(
|
|||||||
|
|
||||||
protected fun commit(value: Float) {
|
protected fun commit(value: Float) {
|
||||||
NativePostProcessing.setValue(index, uniform.name, component, value)
|
NativePostProcessing.setValue(index, uniform.name, component, value)
|
||||||
NativePostProcessing.persist()
|
NativePostProcessing.store()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reset() = commit(uniform.defaultAt(component))
|
override fun reset() = commit(uniform.defaultAt(component))
|
||||||
@@ -92,11 +92,11 @@ class FxUniformBooleanSetting(
|
|||||||
override fun getBoolean(needsGlobal: Boolean): Boolean = currentValue() != 0f
|
override fun getBoolean(needsGlobal: Boolean): Boolean = currentValue() != 0f
|
||||||
|
|
||||||
override fun setBoolean(value: Boolean) {
|
override fun setBoolean(value: Boolean) {
|
||||||
|
var scalar = 0f
|
||||||
if (value) {
|
if (value) {
|
||||||
commit(1f)
|
scalar = 1f
|
||||||
return
|
|
||||||
}
|
}
|
||||||
commit(0f)
|
commit(scalar)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = getBoolean().toString()
|
override fun getValueAsString(needsGlobal: Boolean): String = getBoolean().toString()
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||||
|
|
||||||
|
class FxPresetSetting(
|
||||||
|
titleString: String,
|
||||||
|
descriptionString: String = "",
|
||||||
|
val deletable: Boolean = false,
|
||||||
|
val onApply: () -> Unit,
|
||||||
|
val onDelete: () -> Unit = {}
|
||||||
|
) : SettingsItem(emptySetting, 0, titleString, 0, descriptionString) {
|
||||||
|
override val type = TYPE_FX_PRESET
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
|
||||||
|
class FxToolbarSetting(
|
||||||
|
@StringRes val addLabelId: Int,
|
||||||
|
val listOpen: Boolean,
|
||||||
|
val presetLabel: String,
|
||||||
|
val hasEffects: Boolean,
|
||||||
|
val createPreset: StringInputSetting,
|
||||||
|
val onAdd: () -> Unit,
|
||||||
|
val onPresets: () -> Unit,
|
||||||
|
val onRemoveAll: () -> Unit
|
||||||
|
) : SettingsItem(emptySetting, 0, "", 0, "") {
|
||||||
|
override val type = TYPE_FX_TOOLBAR
|
||||||
|
}
|
||||||
+2
@@ -145,6 +145,8 @@ abstract class SettingsItem(
|
|||||||
const val TYPE_PATH = 14
|
const val TYPE_PATH = 14
|
||||||
const val TYPE_GPU_UNSWIZZLE = 15
|
const val TYPE_GPU_UNSWIZZLE = 15
|
||||||
const val TYPE_CARD = 16
|
const val TYPE_CARD = 16
|
||||||
|
const val TYPE_FX_TOOLBAR = 17
|
||||||
|
const val TYPE_FX_PRESET = 18
|
||||||
|
|
||||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||||
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
|
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
|
||||||
|
|||||||
+17
-1
@@ -24,6 +24,8 @@ import org.yuzu.yuzu_emu.R
|
|||||||
import org.yuzu.yuzu_emu.SettingsNavigationDirections
|
import org.yuzu.yuzu_emu.SettingsNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingCardBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingCardBinding
|
||||||
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxPresetBinding
|
||||||
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxToolbarBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
|
||||||
@@ -108,7 +110,21 @@ class SettingsAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingsItem.TYPE_CARD -> {
|
SettingsItem.TYPE_CARD -> {
|
||||||
CardViewHolder(ListItemSettingCardBinding.inflate(inflater), this)
|
CardViewHolder(ListItemSettingCardBinding.inflate(inflater, parent, false), this)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsItem.TYPE_FX_TOOLBAR -> {
|
||||||
|
FxToolbarViewHolder(
|
||||||
|
ListItemSettingFxToolbarBinding.inflate(inflater, parent, false),
|
||||||
|
this
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsItem.TYPE_FX_PRESET -> {
|
||||||
|
FxPresetViewHolder(
|
||||||
|
ListItemSettingFxPresetBinding.inflate(inflater, parent, false),
|
||||||
|
this
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
+126
-89
@@ -18,6 +18,7 @@ import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.FxPresetNameSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformBooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.FxUniformBooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformChoiceSetting
|
import org.yuzu.yuzu_emu.features.settings.model.FxUniformChoiceSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformSliderSetting
|
import org.yuzu.yuzu_emu.features.settings.model.FxUniformSliderSetting
|
||||||
@@ -54,6 +55,8 @@ class SettingsFragmentPresenter(
|
|||||||
|
|
||||||
private var presetPickerOpen = false
|
private var presetPickerOpen = false
|
||||||
|
|
||||||
|
private var postProcessingSynced = false
|
||||||
|
|
||||||
private val context get() = YuzuApplication.appContext
|
private val context get() = YuzuApplication.appContext
|
||||||
|
|
||||||
// Extension for altering settings list based on each setting's properties
|
// Extension for altering settings list based on each setting's properties
|
||||||
@@ -202,6 +205,11 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addPostProcessingSettings(sl: ArrayList<SettingsItem>) {
|
private fun addPostProcessingSettings(sl: ArrayList<SettingsItem>) {
|
||||||
|
if (!postProcessingSynced) {
|
||||||
|
postProcessingSynced = true
|
||||||
|
NativePostProcessing.reload()
|
||||||
|
}
|
||||||
|
|
||||||
val usable = NativePostProcessing.catalog().filter { it.valid }
|
val usable = NativePostProcessing.catalog().filter { it.valid }
|
||||||
|
|
||||||
sl.apply {
|
sl.apply {
|
||||||
@@ -216,68 +224,6 @@ class SettingsFragmentPresenter(
|
|||||||
return@apply
|
return@apply
|
||||||
}
|
}
|
||||||
|
|
||||||
val active = NativePostProcessing.getActivePreset()
|
|
||||||
var presetSummary = context.getString(R.string.post_processing_preset_none)
|
|
||||||
if (active.isNotEmpty()) {
|
|
||||||
presetSummary = active
|
|
||||||
if (NativePostProcessing.isPresetModified()) {
|
|
||||||
presetSummary = context.getString(R.string.post_processing_preset_modified)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add(
|
|
||||||
CardSetting(
|
|
||||||
titleId = R.string.post_processing_preset,
|
|
||||||
descriptionString = presetSummary,
|
|
||||||
expanded = presetPickerOpen
|
|
||||||
) {
|
|
||||||
presetPickerOpen = !presetPickerOpen
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (presetPickerOpen) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_preset_none,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.clearPreset()
|
|
||||||
presetPickerOpen = false
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
for (preset in NativePostProcessing.presets()) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleString = preset.name,
|
|
||||||
descriptionString = preset.description,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.applyPreset(preset.name)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
presetPickerOpen = false
|
|
||||||
expandedShaderSlots.clear()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (active.isNotEmpty()) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_preset_reset,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.applyPreset(active)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
expandedShaderSlots.clear()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val labels = mutableListOf<String>()
|
val labels = mutableListOf<String>()
|
||||||
val summaries = mutableListOf<String>()
|
val summaries = mutableListOf<String>()
|
||||||
val files = mutableListOf<String>()
|
val files = mutableListOf<String>()
|
||||||
@@ -296,6 +242,124 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val chain = NativePostProcessing.chain()
|
val chain = NativePostProcessing.chain()
|
||||||
|
val active = NativePostProcessing.getActivePreset()
|
||||||
|
|
||||||
|
var addLabel = R.string.post_processing_add
|
||||||
|
if (chain.isNotEmpty()) {
|
||||||
|
addLabel = R.string.post_processing_open_list
|
||||||
|
}
|
||||||
|
if (shaderPickerOpen) {
|
||||||
|
addLabel = R.string.post_processing_close_list
|
||||||
|
}
|
||||||
|
|
||||||
|
var presetLabel = context.getString(R.string.post_processing_presets)
|
||||||
|
if (active.isNotEmpty()) {
|
||||||
|
presetLabel = active
|
||||||
|
}
|
||||||
|
|
||||||
|
val createPreset = StringInputSetting(
|
||||||
|
setting = FxPresetNameSetting { name ->
|
||||||
|
NativePostProcessing.savePreset(name, "")
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
},
|
||||||
|
titleId = R.string.post_processing_preset_new,
|
||||||
|
descriptionId = R.string.post_processing_preset_new_description,
|
||||||
|
validator = { it != null && it.isNotBlank() && !it.contains('=') },
|
||||||
|
errorId = R.string.post_processing_preset_name_invalid
|
||||||
|
)
|
||||||
|
|
||||||
|
add(
|
||||||
|
FxToolbarSetting(
|
||||||
|
addLabelId = addLabel,
|
||||||
|
listOpen = shaderPickerOpen,
|
||||||
|
presetLabel = presetLabel,
|
||||||
|
hasEffects = chain.isNotEmpty(),
|
||||||
|
createPreset = createPreset,
|
||||||
|
onAdd = {
|
||||||
|
shaderPickerOpen = !shaderPickerOpen
|
||||||
|
presetPickerOpen = false
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
},
|
||||||
|
onPresets = {
|
||||||
|
presetPickerOpen = !presetPickerOpen
|
||||||
|
shaderPickerOpen = false
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
},
|
||||||
|
onRemoveAll = {
|
||||||
|
NativePostProcessing.clearChain()
|
||||||
|
NativePostProcessing.clearPreset()
|
||||||
|
NativePostProcessing.store()
|
||||||
|
expandedShaderSlots.clear()
|
||||||
|
shaderPickerOpen = false
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (shaderPickerOpen) {
|
||||||
|
for (choice in labels.indices) {
|
||||||
|
add(
|
||||||
|
RunnableSetting(
|
||||||
|
titleString = labels[choice],
|
||||||
|
descriptionString = summaries[choice],
|
||||||
|
isRunnable = true
|
||||||
|
) {
|
||||||
|
NativePostProcessing.append(files[choice], techniques[choice])
|
||||||
|
NativePostProcessing.store()
|
||||||
|
shaderPickerOpen = false
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presetPickerOpen) {
|
||||||
|
add(
|
||||||
|
FxPresetSetting(
|
||||||
|
titleString = context.getString(R.string.post_processing_preset_none),
|
||||||
|
onApply = {
|
||||||
|
NativePostProcessing.clearPreset()
|
||||||
|
presetPickerOpen = false
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for (preset in NativePostProcessing.presets()) {
|
||||||
|
add(
|
||||||
|
FxPresetSetting(
|
||||||
|
titleString = preset.name,
|
||||||
|
descriptionString = preset.description,
|
||||||
|
deletable = !preset.bundled,
|
||||||
|
onApply = {
|
||||||
|
NativePostProcessing.applyPreset(preset.name)
|
||||||
|
NativePostProcessing.store()
|
||||||
|
presetPickerOpen = false
|
||||||
|
expandedShaderSlots.clear()
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
},
|
||||||
|
onDelete = {
|
||||||
|
NativePostProcessing.deletePreset(preset.name)
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active.isNotEmpty()) {
|
||||||
|
add(
|
||||||
|
RunnableSetting(
|
||||||
|
titleId = R.string.post_processing_preset_reset,
|
||||||
|
isRunnable = true
|
||||||
|
) {
|
||||||
|
NativePostProcessing.applyPreset(active)
|
||||||
|
NativePostProcessing.store()
|
||||||
|
expandedShaderSlots.clear()
|
||||||
|
settingsViewModel.setReloadListAndNotifyDataset(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
for (index in chain.indices) {
|
for (index in chain.indices) {
|
||||||
val entry = chain[index]
|
val entry = chain[index]
|
||||||
val effect = usable.firstOrNull { it.file == entry.file }
|
val effect = usable.firstOrNull { it.file == entry.file }
|
||||||
@@ -385,33 +449,6 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
add(
|
|
||||||
CardSetting(
|
|
||||||
titleId = R.string.post_processing_add,
|
|
||||||
expanded = shaderPickerOpen
|
|
||||||
) {
|
|
||||||
shaderPickerOpen = !shaderPickerOpen
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (shaderPickerOpen) {
|
|
||||||
for (choice in labels.indices) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleString = labels[choice],
|
|
||||||
descriptionString = summaries[choice],
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.append(files[choice], techniques[choice])
|
|
||||||
NativePostProcessing.store()
|
|
||||||
shaderPickerOpen = false
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxPresetBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.FxPresetSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
|
|
||||||
|
class FxPresetViewHolder(
|
||||||
|
val binding: ListItemSettingFxPresetBinding,
|
||||||
|
adapter: SettingsAdapter
|
||||||
|
) : SettingViewHolder(binding.root, adapter) {
|
||||||
|
private lateinit var setting: FxPresetSetting
|
||||||
|
|
||||||
|
override fun bind(item: SettingsItem) {
|
||||||
|
setting = item as FxPresetSetting
|
||||||
|
|
||||||
|
binding.presetName.text = item.title
|
||||||
|
binding.presetDescription.text = item.description
|
||||||
|
binding.presetDescription.setVisible(item.description.isNotEmpty())
|
||||||
|
|
||||||
|
binding.presetRow.setOnClickListener { setting.onApply.invoke() }
|
||||||
|
|
||||||
|
binding.presetDelete.setVisible(setting.deletable)
|
||||||
|
binding.presetDelete.setOnClickListener { setting.onDelete.invoke() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(clicked: View) {}
|
||||||
|
|
||||||
|
override fun onLongClick(clicked: View): Boolean = true
|
||||||
|
}
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.view.View
|
||||||
|
import com.google.android.material.color.MaterialColors
|
||||||
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxToolbarBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.FxToolbarSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||||
|
|
||||||
|
class FxToolbarViewHolder(
|
||||||
|
val binding: ListItemSettingFxToolbarBinding,
|
||||||
|
adapter: SettingsAdapter
|
||||||
|
) : SettingViewHolder(binding.root, adapter) {
|
||||||
|
private lateinit var setting: FxToolbarSetting
|
||||||
|
|
||||||
|
override fun bind(item: SettingsItem) {
|
||||||
|
setting = item as FxToolbarSetting
|
||||||
|
|
||||||
|
binding.fxAdd.setText(setting.addLabelId)
|
||||||
|
var addIcon = R.drawable.ic_add
|
||||||
|
if (setting.listOpen) {
|
||||||
|
addIcon = R.drawable.ic_clear
|
||||||
|
}
|
||||||
|
binding.fxAdd.setIconResource(addIcon)
|
||||||
|
binding.fxAdd.setOnClickListener { setting.onAdd.invoke() }
|
||||||
|
|
||||||
|
binding.fxPresets.text = setting.presetLabel
|
||||||
|
binding.fxPresets.setOnClickListener { setting.onPresets.invoke() }
|
||||||
|
|
||||||
|
binding.fxCreatePreset.isEnabled = setting.hasEffects
|
||||||
|
binding.fxCreatePreset.setOnClickListener {
|
||||||
|
adapter.onStringInputClick(setting.createPreset, bindingAdapterPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
val removeBackground = MaterialColors.getColor(
|
||||||
|
binding.fxRemoveAll,
|
||||||
|
com.google.android.material.R.attr.colorErrorContainer
|
||||||
|
)
|
||||||
|
val removeForeground = MaterialColors.getColor(
|
||||||
|
binding.fxRemoveAll,
|
||||||
|
com.google.android.material.R.attr.colorOnErrorContainer
|
||||||
|
)
|
||||||
|
binding.fxRemoveAll.backgroundTintList = ColorStateList.valueOf(removeBackground)
|
||||||
|
binding.fxRemoveAll.iconTint = ColorStateList.valueOf(removeForeground)
|
||||||
|
binding.fxRemoveAll.isEnabled = setting.hasEffects
|
||||||
|
binding.fxRemoveAll.setOnClickListener { setting.onRemoveAll.invoke() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(clicked: View) {}
|
||||||
|
|
||||||
|
override fun onLongClick(clicked: View): Boolean = true
|
||||||
|
}
|
||||||
@@ -94,6 +94,7 @@ import org.yuzu.yuzu_emu.utils.InputHandler
|
|||||||
import org.yuzu.yuzu_emu.utils.Log
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
||||||
|
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils
|
import org.yuzu.yuzu_emu.utils.ViewUtils
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
import org.yuzu.yuzu_emu.utils.collect
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
@@ -883,6 +884,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
if (shouldUseCustom) {
|
if (shouldUseCustom) {
|
||||||
SettingsFile.loadCustomConfig(game!!)
|
SettingsFile.loadCustomConfig(game!!)
|
||||||
}
|
}
|
||||||
|
refreshPostProcessing()
|
||||||
|
addQuickSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1087,6 +1090,34 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun withPerGameConfig(create: Boolean, action: () -> Unit) {
|
||||||
|
val target = game
|
||||||
|
var owned = false
|
||||||
|
if (target != null && !NativeConfig.isPerGameConfigLoaded()) {
|
||||||
|
if (create || SettingsFile.getCustomSettingsFile(target).exists()) {
|
||||||
|
SettingsFile.loadCustomConfig(target)
|
||||||
|
owned = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action()
|
||||||
|
if (owned) {
|
||||||
|
NativeConfig.unloadPerGameConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshPostProcessing() = withPerGameConfig(false) {
|
||||||
|
NativePostProcessing.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun persistPostProcessing() = withPerGameConfig(true) {
|
||||||
|
NativePostProcessing.persist()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun editPostProcessing(action: () -> Unit) = withPerGameConfig(true) {
|
||||||
|
action()
|
||||||
|
NativePostProcessing.persist()
|
||||||
|
}
|
||||||
|
|
||||||
private fun addQuickSettings() {
|
private fun addQuickSettings() {
|
||||||
binding.quickSettingsSheet.apply {
|
binding.quickSettingsSheet.apply {
|
||||||
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
|
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ object NativePostProcessing {
|
|||||||
|
|
||||||
external fun store()
|
external fun store()
|
||||||
|
|
||||||
|
external fun reload()
|
||||||
|
|
||||||
|
external fun clearChain()
|
||||||
|
|
||||||
external fun getPresetsJson(): String
|
external fun getPresetsJson(): String
|
||||||
|
|
||||||
external fun getActivePreset(): String
|
external fun getActivePreset(): String
|
||||||
@@ -63,11 +67,7 @@ object NativePostProcessing {
|
|||||||
external fun getPresetDirectory(): String
|
external fun getPresetDirectory(): String
|
||||||
|
|
||||||
fun persist() {
|
fun persist() {
|
||||||
store()
|
val perGame = NativeConfig.isPerGameConfigLoaded()
|
||||||
NativeConfig.saveGlobalConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun persistFor(perGame: Boolean) {
|
|
||||||
store()
|
store()
|
||||||
if (perGame) {
|
if (perGame) {
|
||||||
NativeConfig.savePerGameConfig()
|
NativeConfig.savePerGameConfig()
|
||||||
|
|||||||
@@ -15,10 +15,22 @@
|
|||||||
#include "frontend_common/config.h"
|
#include "frontend_common/config.h"
|
||||||
#include "frontend_common/settings_generator.h"
|
#include "frontend_common/settings_generator.h"
|
||||||
#include "native.h"
|
#include "native.h"
|
||||||
|
#ifdef HAS_RESHADE
|
||||||
|
#include "video_core/post_processing/fx_chain.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
std::unique_ptr<AndroidConfig> global_config;
|
std::unique_ptr<AndroidConfig> global_config;
|
||||||
std::unique_ptr<AndroidConfig> per_game_config;
|
std::unique_ptr<AndroidConfig> per_game_config;
|
||||||
|
|
||||||
|
#ifdef HAS_RESHADE
|
||||||
|
static void ResetFxChainToGlobal() {
|
||||||
|
VideoCore::UseGlobalFxSettings();
|
||||||
|
VideoCore::FxChain::Instance().LoadFromSettings();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void ResetFxChainToGlobal() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
|
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
|
||||||
auto key = Common::Android::GetJString(env, jkey);
|
auto key = Common::Android::GetJString(env, jkey);
|
||||||
@@ -39,6 +51,7 @@ extern "C" {
|
|||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
global_config = std::make_unique<AndroidConfig>();
|
global_config = std::make_unique<AndroidConfig>();
|
||||||
FrontendCommon::GenerateSettings();
|
FrontendCommon::GenerateSettings();
|
||||||
|
ResetFxChainToGlobal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
@@ -47,6 +60,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env,
|
|||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
global_config->AndroidConfig::ReloadAllValues();
|
global_config->AndroidConfig::ReloadAllValues();
|
||||||
|
ResetFxChainToGlobal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
@@ -9,15 +10,29 @@
|
|||||||
|
|
||||||
#include "common/android/android_common.h"
|
#include "common/android/android_common.h"
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
#include "android_config.h"
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
#include "video_core/post_processing/fx_chain.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
#include "video_core/post_processing/fx_effect.h"
|
||||||
#include "video_core/post_processing/fx_preset.h"
|
#include "video_core/post_processing/fx_preset.h"
|
||||||
|
|
||||||
|
extern std::unique_ptr<AndroidConfig> per_game_config;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
bool EditingPerGame() {
|
||||||
|
return per_game_config != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginFxEdit() {
|
||||||
|
if (!EditingPerGame()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VideoCore::UsePerGameFxSettings();
|
||||||
|
}
|
||||||
|
|
||||||
nlohmann::json SerializeUniform(const VideoCore::FxUniformDesc& uniform) {
|
nlohmann::json SerializeUniform(const VideoCore::FxUniformDesc& uniform) {
|
||||||
nlohmann::json out;
|
nlohmann::json out;
|
||||||
out["name"] = uniform.name;
|
out["name"] = uniform.name;
|
||||||
@@ -201,10 +216,26 @@ void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_setValue(JNIEnv* env, jo
|
|||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_store(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_store(JNIEnv* env, jobject obj) {
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
BeginFxEdit();
|
||||||
VideoCore::FxChain::Instance().StoreToSettings();
|
VideoCore::FxChain::Instance().StoreToSettings();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_reload(JNIEnv* env, jobject obj) {
|
||||||
|
#ifdef HAS_RESHADE
|
||||||
|
if (!EditingPerGame()) {
|
||||||
|
VideoCore::UseGlobalFxSettings();
|
||||||
|
}
|
||||||
|
VideoCore::FxChain::Instance().LoadFromSettings();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_clearChain(JNIEnv* env, jobject obj) {
|
||||||
|
#ifdef HAS_RESHADE
|
||||||
|
VideoCore::FxChain::Instance().Clear();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getShaderDirectory(JNIEnv* env,
|
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getShaderDirectory(JNIEnv* env,
|
||||||
jobject obj) {
|
jobject obj) {
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
@@ -252,6 +283,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_isPresetModified(JNI
|
|||||||
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_applyPreset(JNIEnv* env, jobject obj,
|
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_applyPreset(JNIEnv* env, jobject obj,
|
||||||
jstring jname) {
|
jstring jname) {
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
BeginFxEdit();
|
||||||
return static_cast<jboolean>(
|
return static_cast<jboolean>(
|
||||||
VideoCore::ApplyFxPreset(Common::Android::GetJString(env, jname)));
|
VideoCore::ApplyFxPreset(Common::Android::GetJString(env, jname)));
|
||||||
#else
|
#else
|
||||||
@@ -263,6 +295,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_savePreset(JNIEnv* e
|
|||||||
jstring jname,
|
jstring jname,
|
||||||
jstring jdescription) {
|
jstring jdescription) {
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
BeginFxEdit();
|
||||||
return static_cast<jboolean>(
|
return static_cast<jboolean>(
|
||||||
VideoCore::SaveFxPreset(Common::Android::GetJString(env, jname),
|
VideoCore::SaveFxPreset(Common::Android::GetJString(env, jname),
|
||||||
Common::Android::GetJString(env, jdescription)));
|
Common::Android::GetJString(env, jdescription)));
|
||||||
@@ -274,6 +307,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_savePreset(JNIEnv* e
|
|||||||
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_deletePreset(JNIEnv* env, jobject obj,
|
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_deletePreset(JNIEnv* env, jobject obj,
|
||||||
jstring jname) {
|
jstring jname) {
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
BeginFxEdit();
|
||||||
return static_cast<jboolean>(
|
return static_cast<jboolean>(
|
||||||
VideoCore::DeleteFxPreset(Common::Android::GetJString(env, jname)));
|
VideoCore::DeleteFxPreset(Common::Android::GetJString(env, jname)));
|
||||||
#else
|
#else
|
||||||
@@ -283,6 +317,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_deletePreset(JNIEnv*
|
|||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_clearPreset(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_clearPreset(JNIEnv* env, jobject obj) {
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
BeginFxEdit();
|
||||||
VideoCore::SetActiveFxPreset(std::string_view());
|
VideoCore::SetActiveFxPreset(std::string_view());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -298,6 +333,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_isEnabled(JNIEnv* en
|
|||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_setEnabled(JNIEnv* env, jobject obj,
|
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_setEnabled(JNIEnv* env, jobject obj,
|
||||||
jboolean enabled) {
|
jboolean enabled) {
|
||||||
#ifdef HAS_RESHADE
|
#ifdef HAS_RESHADE
|
||||||
|
BeginFxEdit();
|
||||||
Settings::values.post_shader_enabled.SetValue(enabled != JNI_FALSE);
|
Settings::values.post_shader_enabled.SetValue(enabled != JNI_FALSE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,35 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<LinearLayout
|
||||||
android:id="@+id/add_button"
|
|
||||||
style="@style/Widget.Material3.Button.TonalButton"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="@string/post_processing_add"
|
android:orientation="horizontal">
|
||||||
app:icon="@drawable/ic_add" />
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/add_button"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/post_processing_add"
|
||||||
|
app:icon="@drawable/ic_add" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/remove_all_button"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/post_processing_remove_all"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:icon="@drawable/ic_delete" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
android:id="@+id/add_choices"
|
android:id="@+id/add_choices"
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
android:background="@drawable/shader_card_background"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/preset_row"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="12dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/preset_name"
|
||||||
|
style="@style/TextAppearance.Material3.TitleSmall"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/preset_description"
|
||||||
|
style="@style/TextAppearance.Material3.BodySmall"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/preset_delete"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/post_processing_preset_delete"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_delete"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:tint="?attr/colorOnSurfaceVariant" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/fx_add"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@string/post_processing_add"
|
||||||
|
app:icon="@drawable/ic_add" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/fx_presets"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_weight="1.4"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@string/post_processing_presets"
|
||||||
|
app:icon="@drawable/ic_dropdown_arrow"
|
||||||
|
app:iconGravity="textEnd" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/fx_create_preset"
|
||||||
|
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:contentDescription="@string/post_processing_preset_new"
|
||||||
|
app:icon="@drawable/ic_add" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/fx_remove_all"
|
||||||
|
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:contentDescription="@string/post_processing_remove_all"
|
||||||
|
app:icon="@drawable/ic_delete" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -303,11 +303,17 @@
|
|||||||
<string name="post_processing_per_game_description">Configure the effect chain for this game</string>
|
<string name="post_processing_per_game_description">Configure the effect chain for this game</string>
|
||||||
<string name="post_processing_add">Add effect</string>
|
<string name="post_processing_add">Add effect</string>
|
||||||
<string name="post_processing_remove">Remove</string>
|
<string name="post_processing_remove">Remove</string>
|
||||||
<string name="post_processing_hide_effects">Remove effects</string>
|
<string name="post_processing_open_list">Open list</string>
|
||||||
|
<string name="post_processing_close_list">Close list</string>
|
||||||
|
<string name="post_processing_remove_all">Remove effects</string>
|
||||||
<string name="post_processing_preset_locked">Preset active. Edit it in Post-Processing Effects before starting a game.</string>
|
<string name="post_processing_preset_locked">Preset active. Edit it in Post-Processing Effects before starting a game.</string>
|
||||||
<string name="post_processing_preset_modified">Preset active, with your own changes.</string>
|
<string name="post_processing_preset_modified">Preset active, with your own changes.</string>
|
||||||
<string name="post_processing_preset">Preset</string>
|
<string name="post_processing_presets">Presets</string>
|
||||||
|
<string name="post_processing_preset_new">New preset</string>
|
||||||
|
<string name="post_processing_preset_new_description">Saves the effects you have loaded, with their current values, as a preset you can pick later.</string>
|
||||||
|
<string name="post_processing_preset_name_invalid">Give the preset a name without an equals sign.</string>
|
||||||
<string name="post_processing_preset_none">No preset</string>
|
<string name="post_processing_preset_none">No preset</string>
|
||||||
|
<string name="post_processing_preset_delete">Delete preset</string>
|
||||||
<string name="post_processing_preset_reset">Reset preset values</string>
|
<string name="post_processing_preset_reset">Reset preset values</string>
|
||||||
<string name="post_processing_move_up">Move up</string>
|
<string name="post_processing_move_up">Move up</string>
|
||||||
<string name="post_processing_move_down">Move down</string>
|
<string name="post_processing_move_down">Move down</string>
|
||||||
|
|||||||
@@ -119,6 +119,26 @@ std::string SerializeFxChain(std::span<const FxChainEntry> entries) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UseGlobalFxSettings() {
|
||||||
|
Settings::values.post_shader_chain.SetGlobal(true);
|
||||||
|
Settings::values.post_shader_preset.SetGlobal(true);
|
||||||
|
Settings::values.post_shader_enabled.SetGlobal(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsePerGameFxSettings() {
|
||||||
|
const std::string chain = Settings::values.post_shader_chain.GetValue();
|
||||||
|
const std::string preset = Settings::values.post_shader_preset.GetValue();
|
||||||
|
const bool enabled = Settings::values.post_shader_enabled.GetValue();
|
||||||
|
|
||||||
|
Settings::values.post_shader_chain.SetGlobal(false);
|
||||||
|
Settings::values.post_shader_preset.SetGlobal(false);
|
||||||
|
Settings::values.post_shader_enabled.SetGlobal(false);
|
||||||
|
|
||||||
|
Settings::values.post_shader_chain.SetValue(chain);
|
||||||
|
Settings::values.post_shader_preset.SetValue(preset);
|
||||||
|
Settings::values.post_shader_enabled.SetValue(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
FxChain& FxChain::Instance() {
|
FxChain& FxChain::Instance() {
|
||||||
static FxChain instance;
|
static FxChain instance;
|
||||||
return instance;
|
return instance;
|
||||||
@@ -260,19 +280,11 @@ void FxChain::LoadFromSettings() {
|
|||||||
auto parsed = ParseFxChain(Settings::values.post_shader_chain.GetValue());
|
auto parsed = ParseFxChain(Settings::values.post_shader_chain.GetValue());
|
||||||
|
|
||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
entries = std::move(parsed);
|
if (entries == parsed) {
|
||||||
loaded = true;
|
return;
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::EnsureLoadedFromSettings() {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LoadFromSettings();
|
entries = std::move(parsed);
|
||||||
|
generation.fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FxChain::StoreToSettings() const {
|
void FxChain::StoreToSettings() const {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ struct FxChainEntry {
|
|||||||
std::string file;
|
std::string file;
|
||||||
std::string technique;
|
std::string technique;
|
||||||
std::map<std::string, std::array<f32, 4>> values;
|
std::map<std::string, std::array<f32, 4>> values;
|
||||||
|
|
||||||
|
bool operator==(const FxChainEntry&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FxChainSnapshot {
|
struct FxChainSnapshot {
|
||||||
@@ -31,6 +33,10 @@ std::vector<FxChainEntry> ParseFxChain(std::string_view value);
|
|||||||
|
|
||||||
std::string SerializeFxChain(std::span<const FxChainEntry> entries);
|
std::string SerializeFxChain(std::span<const FxChainEntry> entries);
|
||||||
|
|
||||||
|
void UseGlobalFxSettings();
|
||||||
|
|
||||||
|
void UsePerGameFxSettings();
|
||||||
|
|
||||||
class FxChain {
|
class FxChain {
|
||||||
public:
|
public:
|
||||||
static FxChain& Instance();
|
static FxChain& Instance();
|
||||||
@@ -65,8 +71,6 @@ public:
|
|||||||
|
|
||||||
void LoadFromSettings();
|
void LoadFromSettings();
|
||||||
|
|
||||||
void EnsureLoadedFromSettings();
|
|
||||||
|
|
||||||
void StoreToSettings() const;
|
void StoreToSettings() const;
|
||||||
|
|
||||||
void DropUnknownEntries();
|
void DropUnknownEntries();
|
||||||
@@ -76,7 +80,6 @@ private:
|
|||||||
|
|
||||||
mutable std::mutex mutex;
|
mutable std::mutex mutex;
|
||||||
std::vector<FxChainEntry> entries;
|
std::vector<FxChainEntry> entries;
|
||||||
bool loaded{};
|
|
||||||
std::atomic<u64> generation{1};
|
std::atomic<u64> generation{1};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user