feat(android): add ASTC mode and CRT shader settings to Zep Zone

ASTC Settings:
- Add ANDROID_ASTC_MODE enum to IntSetting.kt
- Add setting to Zep Zone panel in SettingsFragmentPresenter.kt
- Add string resources for Auto/Native/Decompress options
- Add arrays for option names and values

CRT Shader Settings:
- Add 6 CRT float settings to FloatSetting.kt (scanline_strength, curvature, gamma, bloom, brightness, alpha)
- Add CRT_MASK_TYPE int setting for mask type selection
- Add scale factor support to SliderSetting.kt for float-to-percentage conversion
- Add conditional visibility for CRT settings (only shown when CRT filter is enabled)
- Add string resources and arrays for all CRT settings

The CRT settings section only appears in Zep Zone when the scaling filter is
set to CRTEasyMode or CRTRoyale.

Co-Authored-By: FDT <fdt@citron-emu.org>
This commit is contained in:
Zephyron
2026-02-03 18:41:22 +10:00
parent 82fd6778ab
commit 127d339de9
7 changed files with 168 additions and 5 deletions

View File

@@ -6,8 +6,13 @@ package org.citron.citron_emu.features.settings.model
import org.citron.citron_emu.utils.NativeConfig import org.citron.citron_emu.utils.NativeConfig
enum class FloatSetting(override val key: String) : AbstractFloatSetting { enum class FloatSetting(override val key: String) : AbstractFloatSetting {
// No float settings currently exist // CRT Shader Settings
EMPTY_SETTING(""); CRT_SCANLINE_STRENGTH("crt_scanline_strength"),
CRT_CURVATURE("crt_curvature"),
CRT_GAMMA("crt_gamma"),
CRT_BLOOM("crt_bloom"),
CRT_BRIGHTNESS("crt_brightness"),
CRT_ALPHA("crt_alpha");
override fun getFloat(needsGlobal: Boolean): Float = NativeConfig.getFloat(key, false) override fun getFloat(needsGlobal: Boolean): Float = NativeConfig.getFloat(key, false)

View File

@@ -39,6 +39,10 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
SHADER_BACKEND("shader_backend"), SHADER_BACKEND("shader_backend"),
VRAM_USAGE_MODE("vram_usage_mode"), VRAM_USAGE_MODE("vram_usage_mode"),
EXTENDED_DYNAMIC_STATE("extended_dynamic_state"), EXTENDED_DYNAMIC_STATE("extended_dynamic_state"),
ANDROID_ASTC_MODE("android_astc_mode"),
// CRT Shader Settings
CRT_MASK_TYPE("crt_mask_type"),
// VRAM Management settings (FIXED: VRAM leak prevention) // VRAM Management settings (FIXED: VRAM leak prevention)
VRAM_LIMIT_MB("vram_limit_mb"), VRAM_LIMIT_MB("vram_limit_mb"),

View File

@@ -14,6 +14,7 @@ import org.citron.citron_emu.features.settings.model.AbstractBooleanSetting
import org.citron.citron_emu.features.settings.model.AbstractSetting import org.citron.citron_emu.features.settings.model.AbstractSetting
import org.citron.citron_emu.features.settings.model.BooleanSetting import org.citron.citron_emu.features.settings.model.BooleanSetting
import org.citron.citron_emu.features.settings.model.ByteSetting import org.citron.citron_emu.features.settings.model.ByteSetting
import org.citron.citron_emu.features.settings.model.FloatSetting
import org.citron.citron_emu.features.settings.model.IntSetting import org.citron.citron_emu.features.settings.model.IntSetting
import org.citron.citron_emu.features.settings.model.LongSetting import org.citron.citron_emu.features.settings.model.LongSetting
import org.citron.citron_emu.features.settings.model.ShortSetting import org.citron.citron_emu.features.settings.model.ShortSetting
@@ -425,6 +426,15 @@ abstract class SettingsItem(
valuesId = R.array.astcRecompressionValues valuesId = R.array.astcRecompressionValues
) )
) )
put(
SingleChoiceSetting(
IntSetting.ANDROID_ASTC_MODE,
titleId = R.string.android_astc_mode,
descriptionId = R.string.android_astc_mode_description,
choicesId = R.array.androidAstcModeNames,
valuesId = R.array.androidAstcModeValues
)
)
put( put(
SingleChoiceSetting( SingleChoiceSetting(
IntSetting.SHADER_BACKEND, IntSetting.SHADER_BACKEND,
@@ -534,6 +544,83 @@ abstract class SettingsItem(
) )
) )
// CRT Shader Settings (shown conditionally in Zep Zone when CRT filter is selected)
put(
SliderSetting(
FloatSetting.CRT_SCANLINE_STRENGTH,
titleId = R.string.crt_scanline_strength,
descriptionId = R.string.crt_scanline_strength_description,
min = 0,
max = 200,
units = "%",
scale = 100.0f
)
)
put(
SliderSetting(
FloatSetting.CRT_CURVATURE,
titleId = R.string.crt_curvature,
descriptionId = R.string.crt_curvature_description,
min = 0,
max = 100,
units = "%",
scale = 100.0f
)
)
put(
SliderSetting(
FloatSetting.CRT_GAMMA,
titleId = R.string.crt_gamma,
descriptionId = R.string.crt_gamma_description,
min = 100,
max = 300,
units = "%",
scale = 100.0f
)
)
put(
SliderSetting(
FloatSetting.CRT_BLOOM,
titleId = R.string.crt_bloom,
descriptionId = R.string.crt_bloom_description,
min = 0,
max = 100,
units = "%",
scale = 100.0f
)
)
put(
SingleChoiceSetting(
IntSetting.CRT_MASK_TYPE,
titleId = R.string.crt_mask_type,
descriptionId = R.string.crt_mask_type_description,
choicesId = R.array.crtMaskTypeNames,
valuesId = R.array.crtMaskTypeValues
)
)
put(
SliderSetting(
FloatSetting.CRT_BRIGHTNESS,
titleId = R.string.crt_brightness,
descriptionId = R.string.crt_brightness_description,
min = 0,
max = 200,
units = "%",
scale = 100.0f
)
)
put(
SliderSetting(
FloatSetting.CRT_ALPHA,
titleId = R.string.crt_alpha,
descriptionId = R.string.crt_alpha_description,
min = 0,
max = 100,
units = "%",
scale = 100.0f
)
)
// Applet Mode Settings // Applet Mode Settings
put( put(
SingleChoiceSetting( SingleChoiceSetting(

View File

@@ -19,7 +19,8 @@ class SliderSetting(
descriptionString: String = "", descriptionString: String = "",
val min: Int = 0, val min: Int = 0,
val max: Int = 100, val max: Int = 100,
val units: String = "" val units: String = "",
val scale: Float = 1.0f // Scale factor for float settings (e.g., 100.0 means UI value 100 = C++ value 1.0)
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { ) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
override val type = TYPE_SLIDER override val type = TYPE_SLIDER
@@ -28,7 +29,7 @@ class SliderSetting(
is AbstractByteSetting -> setting.getByte(needsGlobal).toInt() is AbstractByteSetting -> setting.getByte(needsGlobal).toInt()
is AbstractShortSetting -> setting.getShort(needsGlobal).toInt() is AbstractShortSetting -> setting.getShort(needsGlobal).toInt()
is AbstractIntSetting -> setting.getInt(needsGlobal) is AbstractIntSetting -> setting.getInt(needsGlobal)
is AbstractFloatSetting -> setting.getFloat(needsGlobal).roundToInt() is AbstractFloatSetting -> (setting.getFloat(needsGlobal) * scale).roundToInt()
else -> -1 else -> -1
} }
@@ -36,7 +37,7 @@ class SliderSetting(
when (setting) { when (setting) {
is AbstractByteSetting -> setting.setByte(value.toByte()) is AbstractByteSetting -> setting.setByte(value.toByte())
is AbstractShortSetting -> setting.setShort(value.toShort()) is AbstractShortSetting -> setting.setShort(value.toShort())
is AbstractFloatSetting -> setting.setFloat(value.toFloat()) is AbstractFloatSetting -> setting.setFloat(value.toFloat() / scale)
else -> (setting as AbstractIntSetting).setInt(value) else -> (setting as AbstractIntSetting).setInt(value)
} }
} }

View File

@@ -19,6 +19,7 @@ import org.citron.citron_emu.features.settings.model.AbstractBooleanSetting
import org.citron.citron_emu.features.settings.model.AbstractIntSetting import org.citron.citron_emu.features.settings.model.AbstractIntSetting
import org.citron.citron_emu.features.settings.model.BooleanSetting import org.citron.citron_emu.features.settings.model.BooleanSetting
import org.citron.citron_emu.features.settings.model.ByteSetting import org.citron.citron_emu.features.settings.model.ByteSetting
import org.citron.citron_emu.features.settings.model.FloatSetting
import org.citron.citron_emu.features.settings.model.IntSetting import org.citron.citron_emu.features.settings.model.IntSetting
import org.citron.citron_emu.features.settings.model.LongSetting import org.citron.citron_emu.features.settings.model.LongSetting
import org.citron.citron_emu.features.settings.model.Settings import org.citron.citron_emu.features.settings.model.Settings
@@ -1026,6 +1027,7 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.astc_settings_header)) add(HeaderSetting(R.string.astc_settings_header))
add(IntSetting.ASTC_DECODE_MODE.key) add(IntSetting.ASTC_DECODE_MODE.key)
add(IntSetting.ASTC_RECOMPRESSION.key) add(IntSetting.ASTC_RECOMPRESSION.key)
add(IntSetting.ANDROID_ASTC_MODE.key)
add(HeaderSetting(R.string.advanced_graphics_header)) add(HeaderSetting(R.string.advanced_graphics_header))
add(IntSetting.SHADER_BACKEND.key) add(IntSetting.SHADER_BACKEND.key)
@@ -1045,6 +1047,20 @@ class SettingsFragmentPresenter(
add(IntSetting.BUFFER_EVICTION_FRAMES.key) add(IntSetting.BUFFER_EVICTION_FRAMES.key)
add(BooleanSetting.SPARSE_TEXTURE_PRIORITY_EVICTION.key) add(BooleanSetting.SPARSE_TEXTURE_PRIORITY_EVICTION.key)
add(BooleanSetting.LOG_VRAM_USAGE.key) add(BooleanSetting.LOG_VRAM_USAGE.key)
// CRT Shader Settings (only shown when CRT filter is enabled)
// CRTEasyMode = 9, CRTRoyale = 10
val scalingFilter = IntSetting.RENDERER_SCALING_FILTER.getInt(false)
if (scalingFilter == 9 || scalingFilter == 10) {
add(HeaderSetting(R.string.crt_shader_header))
add(FloatSetting.CRT_SCANLINE_STRENGTH.key)
add(FloatSetting.CRT_CURVATURE.key)
add(FloatSetting.CRT_GAMMA.key)
add(FloatSetting.CRT_BLOOM.key)
add(IntSetting.CRT_MASK_TYPE.key)
add(FloatSetting.CRT_BRIGHTNESS.key)
add(FloatSetting.CRT_ALPHA.key)
}
} }
} }

View File

@@ -400,6 +400,18 @@
<item>2</item> <item>2</item>
</integer-array> </integer-array>
<string-array name="androidAstcModeNames">
<item>@string/android_astc_mode_auto</item>
<item>@string/android_astc_mode_native</item>
<item>@string/android_astc_mode_decompress</item>
</string-array>
<integer-array name="androidAstcModeValues">
<item>0</item>
<item>1</item>
<item>2</item>
</integer-array>
<string-array name="shaderBackendNames"> <string-array name="shaderBackendNames">
<item>GLSL</item> <item>GLSL</item>
<item>GLASM</item> <item>GLASM</item>
@@ -458,4 +470,17 @@
<item>1</item> <item>1</item>
</integer-array> </integer-array>
<!-- CRT Shader setting arrays -->
<string-array name="crtMaskTypeNames">
<item>@string/crt_mask_none</item>
<item>@string/crt_mask_aperture</item>
<item>@string/crt_mask_shadow</item>
</string-array>
<integer-array name="crtMaskTypeValues">
<item>0</item>
<item>1</item>
<item>2</item>
</integer-array>
</resources> </resources>

View File

@@ -1259,6 +1259,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<string name="astc_decode_mode_description">Controls how ASTC textures are decoded. GPU decoding is faster but may cause issues on some devices.</string> <string name="astc_decode_mode_description">Controls how ASTC textures are decoded. GPU decoding is faster but may cause issues on some devices.</string>
<string name="astc_recompression">ASTC Recompression Method</string> <string name="astc_recompression">ASTC Recompression Method</string>
<string name="astc_recompression_description">Controls how ASTC textures are recompressed when GPU doesn\'t support them natively.</string> <string name="astc_recompression_description">Controls how ASTC textures are recompressed when GPU doesn\'t support them natively.</string>
<string name="android_astc_mode">Android ASTC Eviction</string>
<string name="android_astc_mode_description">Controls texture cache eviction on Android devices with native ASTC support (Adreno 740+). Native mode uses compressed sizes for eviction, allowing more textures to be cached.</string>
<string name="android_astc_mode_auto">Auto (Detect Hardware)</string>
<string name="android_astc_mode_native">Native (Adreno 740+ Optimized)</string>
<string name="android_astc_mode_decompress">Decompress (Legacy)</string>
<string name="shader_backend">Shader Backend</string> <string name="shader_backend">Shader Backend</string>
<string name="shader_backend_description">Controls which shader backend to use for rendering.</string> <string name="shader_backend_description">Controls which shader backend to use for rendering.</string>
<string name="vram_usage_mode">VRAM Usage Mode</string> <string name="vram_usage_mode">VRAM Usage Mode</string>
@@ -1293,4 +1298,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<string name="gc_aggressiveness_light">Light (Recommended)</string> <string name="gc_aggressiveness_light">Light (Recommended)</string>
<string name="frame_skipping_header">Frame Skipping</string> <string name="frame_skipping_header">Frame Skipping</string>
<!-- CRT Shader Settings -->
<string name="crt_shader_header">CRT Shader Settings</string>
<string name="crt_scanline_strength">Scanline Strength</string>
<string name="crt_scanline_strength_description">Controls the intensity of CRT scanlines. Higher values create darker, more visible scanlines.</string>
<string name="crt_curvature">Screen Curvature</string>
<string name="crt_curvature_description">Simulates the curved glass of old CRT monitors. 0 is flat, higher values add more curve.</string>
<string name="crt_gamma">Gamma</string>
<string name="crt_gamma_description">Adjusts the brightness curve of the image. Lower values make the image darker, higher values make it brighter.</string>
<string name="crt_bloom">Bloom</string>
<string name="crt_bloom_description">Adds a soft glow around bright areas. Creates a phosphor bloom effect typical of CRT displays.</string>
<string name="crt_mask_type">Mask Type</string>
<string name="crt_mask_type_description">Simulates the shadow mask or aperture grille of CRT displays. Affects how subpixels are rendered.</string>
<string name="crt_brightness">Brightness</string>
<string name="crt_brightness_description">Overall brightness adjustment. Values below 1.0 darken the image, above 1.0 brighten it.</string>
<string name="crt_alpha">Shader Intensity</string>
<string name="crt_alpha_description">Blends between the CRT effect and original image. 1.0 is full CRT effect, lower values show more of the original.</string>
<string name="crt_mask_none">None</string>
<string name="crt_mask_aperture">Aperture Grille</string>
<string name="crt_mask_shadow">Shadow Mask</string>
</resources> </resources>