diff --git a/src/android/app/src/main/cpp/NativeSettings.cpp b/src/android/app/src/main/cpp/NativeSettings.cpp index 492fe46..bff31c0 100644 --- a/src/android/app/src/main/cpp/NativeSettings.cpp +++ b/src/android/app/src/main/cpp/NativeSettings.cpp @@ -14,6 +14,19 @@ Java_info_cemu_Cemu_nativeinterface_NativeSettings_setOverlayPosition([[maybe_un g_config.Save(); } +extern "C" JNIEXPORT jint JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_getOverlayTextScalePercentage([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) +{ + return g_config.data().overlay.text_scale; +} + +extern "C" JNIEXPORT void JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_setOverlayTextScalePercentage([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint scalePercentage) +{ + g_config.data().overlay.text_scale = scalePercentage; + g_config.Save(); +} + extern "C" JNIEXPORT jboolean JNICALL Java_info_cemu_Cemu_nativeinterface_NativeSettings_isOverlayFPSEnabled([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) { @@ -118,6 +131,19 @@ Java_info_cemu_Cemu_nativeinterface_NativeSettings_setNotificationsPosition([[ma g_config.Save(); } +extern "C" JNIEXPORT jint JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_getNotificationsTextScalePercentage([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) +{ + return g_config.data().notification.text_scale; +} + +extern "C" JNIEXPORT void JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_setNotificationsTextScalePercentage([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint scalePercentage) +{ + g_config.data().notification.text_scale = scalePercentage; + g_config.Save(); +} + extern "C" JNIEXPORT jboolean JNICALL Java_info_cemu_Cemu_nativeinterface_NativeSettings_isNotificationControllerProfilesEnabled([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) { @@ -215,6 +241,45 @@ Java_info_cemu_Cemu_nativeinterface_NativeSettings_getAccurateBarriers([[maybe_u return g_config.data().vk_accurate_barriers; } +extern "C" [[maybe_unused]] JNIEXPORT void JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_setUpscalingFilter([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint upscaling_filter) +{ + g_config.data().upscale_filter = upscaling_filter; + g_config.Save(); +} + +extern "C" [[maybe_unused]] JNIEXPORT jboolean JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_getUpscalingFilter([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) +{ + return g_config.data().upscale_filter; +} + +extern "C" [[maybe_unused]] JNIEXPORT void JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_setDownscalingFilter([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint downscaling_filter) +{ + g_config.data().downscale_filter = downscaling_filter; + g_config.Save(); +} + +extern "C" [[maybe_unused]] JNIEXPORT jboolean JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_getDownscalingFilter([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) +{ + return g_config.data().downscale_filter; +} + +extern "C" [[maybe_unused]] JNIEXPORT void JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_setFullscreenScaling([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint fullscreen_scaling) +{ + g_config.data().fullscreen_scaling = fullscreen_scaling; + g_config.Save(); +} + +extern "C" [[maybe_unused]] JNIEXPORT jboolean JNICALL +Java_info_cemu_Cemu_nativeinterface_NativeSettings_getFullscreenScaling([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) +{ + return g_config.data().fullscreen_scaling; +} + extern "C" [[maybe_unused]] JNIEXPORT void JNICALL Java_info_cemu_Cemu_nativeinterface_NativeSettings_setAccurateBarriers([[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jboolean enabled) { diff --git a/src/android/app/src/main/java/info/cemu/Cemu/guibasecomponents/SliderRecyclerViewItem.java b/src/android/app/src/main/java/info/cemu/Cemu/guibasecomponents/SliderRecyclerViewItem.java index adb0cce..2049a66 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/guibasecomponents/SliderRecyclerViewItem.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/guibasecomponents/SliderRecyclerViewItem.java @@ -34,6 +34,7 @@ public class SliderRecyclerViewItem implements RecyclerViewItem { private float currentValue; private final OnChangeListener onChangeListener; private LabelFormatter labelFormatter; + private float stepSize = 1.0f; public SliderRecyclerViewItem(String label, float valueFrom, float valueTo, float currentValue, OnChangeListener onChangeListener, LabelFormatter labelFormatter) { this.label = label; @@ -44,6 +45,16 @@ public class SliderRecyclerViewItem implements RecyclerViewItem { this.labelFormatter = labelFormatter; } + public SliderRecyclerViewItem(String label, float valueFrom, float valueTo, float currentValue, float stepSize, OnChangeListener onChangeListener, LabelFormatter labelFormatter) { + this.label = label; + this.valueFrom = valueFrom; + this.valueTo = valueTo; + this.currentValue = currentValue; + this.stepSize = stepSize; + this.onChangeListener = onChangeListener; + this.labelFormatter = labelFormatter; + } + public SliderRecyclerViewItem(String label, float valueFrom, float valueTo, float currentValue, OnChangeListener onChangeListener) { this.label = label; this.valueFrom = valueFrom; @@ -64,7 +75,6 @@ public class SliderRecyclerViewItem implements RecyclerViewItem { if (labelFormatter != null) sliderViewHolder.slider.setLabelFormatter(labelFormatter); sliderViewHolder.slider.setValueFrom(valueFrom); sliderViewHolder.slider.setValueTo(valueTo); - float stepSize = 1.0f; sliderViewHolder.slider.setStepSize(stepSize); sliderViewHolder.slider.setValue(currentValue); sliderViewHolder.slider.addOnChangeListener((slider, value, fromUser) -> { diff --git a/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeSettings.java b/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeSettings.java index f8921ff..e3fe001 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeSettings.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/nativeinterface/NativeSettings.java @@ -21,6 +21,26 @@ public class NativeSettings { public static native void setVSyncMode(int vsyncMode); + public static final int FULLSCREEN_SCALING_KEEP_ASPECT_RATIO = 0; + public static final int FULLSCREEN_SCALING_STRETCH = 1; + + public static native int getFullscreenScaling(); + + public static native void setFullscreenScaling(int fullscreenScaling); + + public static final int SCALING_FILTER_BILINEAR_FILTER = 0; + public static final int SCALING_FILTER_BICUBIC_FILTER = 1; + public static final int SCALING_FILTER_BICUBIC_HERMITE_FILTER = 2; + public static final int SCALING_FILTER_NEAREST_NEIGHBOR_FILTER = 3; + + public static native int getUpscalingFilter(); + + public static native void setUpscalingFilter(int upscalingFilter); + + public static native int getDownscalingFilter(); + + public static native void setDownscalingFilter(int downscalingFilter); + public static native boolean getAccurateBarriers(); public static native void setAccurateBarriers(boolean enabled); @@ -56,6 +76,14 @@ public class NativeSettings { public static native void setOverlayPosition(int position); + public static final int OVERLAY_TEXT_SCALE_MIN = 50; + public static final int OVERLAY_TEXT_SCALE_MAX = 300; + + public static native int getOverlayTextScalePercentage(); + + public static native void setOverlayTextScalePercentage(int scalePercentage); + + public static native boolean isOverlayFPSEnabled(); public static native void setOverlayFPSEnabled(boolean enabled); @@ -84,6 +112,10 @@ public class NativeSettings { public static native void setNotificationsPosition(int position); + public static native int getNotificationsTextScalePercentage(); + + public static native void setNotificationsTextScalePercentage(int scalePercentage); + public static native boolean isNotificationControllerProfilesEnabled(); public static native void setNotificationControllerProfilesEnabled(boolean enabled); diff --git a/src/android/app/src/main/java/info/cemu/Cemu/settings/graphics/GraphicsSettingsFragment.java b/src/android/app/src/main/java/info/cemu/Cemu/settings/graphics/GraphicsSettingsFragment.java index 3f0e092..9185399 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/settings/graphics/GraphicsSettingsFragment.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/settings/graphics/GraphicsSettingsFragment.java @@ -29,6 +29,26 @@ public class GraphicsSettingsFragment extends Fragment { }; } + private static int fullscreenScalingModeToResourceNameId(int fullscreenScaling) { + return switch (fullscreenScaling) { + case NativeSettings.FULLSCREEN_SCALING_KEEP_ASPECT_RATIO -> R.string.keep_aspect_ratio; + case NativeSettings.FULLSCREEN_SCALING_STRETCH -> R.string.stretch; + default -> + throw new IllegalArgumentException("Invalid fullscreen scaling mode: " + fullscreenScaling); + }; + } + + private static int scalingFilterToResourceNameId(int fullscreenScaling) { + return switch (fullscreenScaling) { + case NativeSettings.SCALING_FILTER_BILINEAR_FILTER -> R.string.bilinear; + case NativeSettings.SCALING_FILTER_BICUBIC_FILTER -> R.string.bicubic; + case NativeSettings.SCALING_FILTER_BICUBIC_HERMITE_FILTER -> R.string.hermite; + case NativeSettings.SCALING_FILTER_NEAREST_NEIGHBOR_FILTER -> R.string.nearest_neighbor; + default -> + throw new IllegalArgumentException("Invalid fullscreen scaling mode: " + fullscreenScaling); + }; + } + @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { var binding = GenericRecyclerViewLayoutBinding.inflate(inflater, container, false); @@ -54,6 +74,47 @@ public class GraphicsSettingsFragment extends Fragment { CheckboxRecyclerViewItem accurateBarriersCheckbox = new CheckboxRecyclerViewItem(getString(R.string.accurate_barriers), getString(R.string.accurate_barriers_description), NativeSettings.getAccurateBarriers(), NativeSettings::setAccurateBarriers); genericRecyclerViewAdapter.addRecyclerViewItem(accurateBarriersCheckbox); + int fullscreenScalingMode = NativeSettings.getFullscreenScaling(); + var fullscreenScalingChoices = Stream.of(NativeSettings.FULLSCREEN_SCALING_KEEP_ASPECT_RATIO, NativeSettings.FULLSCREEN_SCALING_STRETCH) + .map(fullScreenScaling -> new SelectionAdapter.ChoiceItem<>(t -> t.setText(fullscreenScalingModeToResourceNameId(fullScreenScaling)), fullScreenScaling)) + .collect(Collectors.toList()); + SelectionAdapter fullscreenScalingSelectionAdapter = new SelectionAdapter<>(fullscreenScalingChoices, fullscreenScalingMode); + SingleSelectionRecyclerViewItem fullscreenScalingSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.fullscreen_scaling), + getString(fullscreenScalingModeToResourceNameId(fullscreenScalingMode)), fullscreenScalingSelectionAdapter, + (fullscreenScaling, selectionRecyclerViewItem) -> { + NativeSettings.setFullscreenScaling(fullscreenScaling); + selectionRecyclerViewItem.setDescription(getString(fullscreenScalingModeToResourceNameId(fullscreenScaling))); + }); + genericRecyclerViewAdapter.addRecyclerViewItem(fullscreenScalingSelection); + + var scalingFilterChoices = Stream.of( + NativeSettings.SCALING_FILTER_BILINEAR_FILTER, + NativeSettings.SCALING_FILTER_BICUBIC_FILTER, + NativeSettings.SCALING_FILTER_BICUBIC_HERMITE_FILTER, + NativeSettings.SCALING_FILTER_NEAREST_NEIGHBOR_FILTER + ).map(scalingFilter -> new SelectionAdapter.ChoiceItem<>(t -> t.setText(scalingFilterToResourceNameId(scalingFilter)), scalingFilter)) + .collect(Collectors.toList()); + + var upscaleFilterMode = NativeSettings.getUpscalingFilter(); + SelectionAdapter upscaleFilterSelectionAdapter = new SelectionAdapter<>(scalingFilterChoices, upscaleFilterMode); + SingleSelectionRecyclerViewItem upscaleFilterSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.upscale_filter), + getString(scalingFilterToResourceNameId(upscaleFilterMode)), upscaleFilterSelectionAdapter, + (upscaleFilter, selectionRecyclerViewItem) -> { + NativeSettings.setUpscalingFilter(upscaleFilter); + selectionRecyclerViewItem.setDescription(getString(scalingFilterToResourceNameId(upscaleFilter))); + }); + genericRecyclerViewAdapter.addRecyclerViewItem(upscaleFilterSelection); + + var downscaleFilterMode = NativeSettings.getDownscalingFilter() ; + SelectionAdapter downscaleFilterSelectionAdapter = new SelectionAdapter<>(scalingFilterChoices, downscaleFilterMode); + SingleSelectionRecyclerViewItem downscaleFilterSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.downscale_filter), + getString(scalingFilterToResourceNameId(downscaleFilterMode)), downscaleFilterSelectionAdapter, + (downscaleFilter, selectionRecyclerViewItem) -> { + NativeSettings.setDownscalingFilter(downscaleFilter); + selectionRecyclerViewItem.setDescription(getString(scalingFilterToResourceNameId(downscaleFilter))); + }); + genericRecyclerViewAdapter.addRecyclerViewItem(downscaleFilterSelection); + binding.recyclerView.setAdapter(genericRecyclerViewAdapter); return binding.getRoot(); } diff --git a/src/android/app/src/main/java/info/cemu/Cemu/settings/overlay/OverlaySettingsFragment.java b/src/android/app/src/main/java/info/cemu/Cemu/settings/overlay/OverlaySettingsFragment.java index 6c71755..571863a 100644 --- a/src/android/app/src/main/java/info/cemu/Cemu/settings/overlay/OverlaySettingsFragment.java +++ b/src/android/app/src/main/java/info/cemu/Cemu/settings/overlay/OverlaySettingsFragment.java @@ -18,9 +18,9 @@ import info.cemu.Cemu.guibasecomponents.GenericRecyclerViewAdapter; import info.cemu.Cemu.guibasecomponents.HeaderRecyclerViewItem; import info.cemu.Cemu.guibasecomponents.SelectionAdapter; import info.cemu.Cemu.guibasecomponents.SingleSelectionRecyclerViewItem; +import info.cemu.Cemu.guibasecomponents.SliderRecyclerViewItem; import info.cemu.Cemu.nativeinterface.NativeSettings; - public class OverlaySettingsFragment extends Fragment { private static int overlayScreenPositionToResourceNameId(int overlayScreenPosition) { return switch (overlayScreenPosition) { @@ -71,6 +71,15 @@ public class OverlaySettingsFragment extends Fragment { }); genericRecyclerViewAdapter.addRecyclerViewItem(overlayPositionSelection); + SliderRecyclerViewItem overlayTextScale = new SliderRecyclerViewItem(getString(R.string.overlay_text_scale), + NativeSettings.OVERLAY_TEXT_SCALE_MIN, + NativeSettings.OVERLAY_TEXT_SCALE_MAX, + NativeSettings.getOverlayTextScalePercentage(), + 25.0f, + value -> NativeSettings.setOverlayTextScalePercentage((int) value), + value -> (int) value + "%"); + genericRecyclerViewAdapter.addRecyclerViewItem(overlayTextScale); + CheckboxRecyclerViewItem overlayFps = new CheckboxRecyclerViewItem(getString(R.string.fps), getString(R.string.fps_overlay_description), NativeSettings.isOverlayFPSEnabled(), NativeSettings::setOverlayFPSEnabled); @@ -107,6 +116,15 @@ public class OverlaySettingsFragment extends Fragment { }); genericRecyclerViewAdapter.addRecyclerViewItem(notificationsPositionSelection); + SliderRecyclerViewItem notificationTextScale = new SliderRecyclerViewItem(getString(R.string.notifications_text_scale), + NativeSettings.OVERLAY_TEXT_SCALE_MIN, + NativeSettings.OVERLAY_TEXT_SCALE_MAX, + NativeSettings.getNotificationsTextScalePercentage(), + 25.0f, + value -> NativeSettings.setNotificationsTextScalePercentage((int) value), + value -> (int) value + "%"); + genericRecyclerViewAdapter.addRecyclerViewItem(notificationTextScale); + CheckboxRecyclerViewItem controllerProfiles = new CheckboxRecyclerViewItem(getString(R.string.controller_profiles), getString(R.string.controller_profiles_notification_description), NativeSettings.isNotificationControllerProfilesEnabled(), NativeSettings::setNotificationControllerProfilesEnabled); diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 9a5fb40..771c88e 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -178,4 +178,15 @@ Failed to initialize renderer: %1$s Open Cemu folder Could not open Cemu folder + Stretch + Keep aspect ratio + Bilinear + Bicubic + Hermite + Nearest neighbor + Fullscreen scaling + Upscale filter + Downscale filter + Overlay text scale + Notifications text scale \ No newline at end of file