diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java index 6ebaad86c9..c35d975d68 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.java @@ -10,6 +10,7 @@ public enum BooleanSetting implements AbstractBooleanSetting { // These entries have the same names and order as in C++, just for consistency. + MAIN_SKIP_IPL(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SkipIPL", true), MAIN_DSP_HLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DSPHLE", true), MAIN_FASTMEM(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "Fastmem", true), MAIN_CPU_THREAD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUThread", true), @@ -36,8 +37,15 @@ public enum BooleanSetting implements AbstractBooleanSetting MAIN_WIIMOTE_ENABLE_SPEAKER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "WiimoteEnableSpeaker", false), MAIN_MMU(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MMU", false), + MAIN_PAUSE_ON_PANIC(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "PauseOnPanic", false), + MAIN_ACCURATE_CPU_CACHE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AccurateCPUCache", + false), MAIN_SYNC_GPU(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SyncGPU", false), MAIN_OVERCLOCK_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "OverclockEnable", false), + MAIN_RAM_OVERRIDE_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "RAMOverrideEnable", + false), + MAIN_CUSTOM_RTC_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableCustomRTC", + false), MAIN_AUTO_DISC_CHANGE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AutoDiscChange", false), MAIN_ALLOW_SD_WRITES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "WiiSDCardAllowWrites", true), @@ -260,6 +268,10 @@ public enum BooleanSetting implements AbstractBooleanSetting MAIN_ENABLE_CHEATS, MAIN_OVERRIDE_REGION_SETTINGS, MAIN_MMU, + MAIN_PAUSE_ON_PANIC, + MAIN_ACCURATE_CPU_CACHE, + MAIN_RAM_OVERRIDE_ENABLE, + MAIN_CUSTOM_RTC_ENABLE, MAIN_DSP_JIT, }; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java index 69b422ce54..06e90a4234 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/IntSetting.java @@ -18,6 +18,8 @@ public enum IntSetting implements AbstractIntSetting MAIN_CPU_CORE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUCore", NativeLibrary.DefaultCPUCore()), MAIN_GC_LANGUAGE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SelectedLanguage", 0), + MAIN_MEM1_SIZE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MEM1Size", 0x01800000), + MAIN_MEM2_SIZE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MEM2Size", 0x04000000), MAIN_SLOT_A(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotA", 8), MAIN_SLOT_B(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotB", 255), MAIN_SERIAL_PORT_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SerialPort1", 255), @@ -54,11 +56,16 @@ public enum IntSetting implements AbstractIntSetting GFX_ASPECT_RATIO(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "AspectRatio", 0), GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "SafeTextureCacheColorSamples", 128), + GFX_PNG_COMPRESSION_LEVEL(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "PNGCompressionLevel", + 6), GFX_MSAA(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "MSAA", 1), GFX_EFB_SCALE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "InternalResolution", 1), GFX_SHADER_COMPILATION_MODE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShaderCompilationMode", 0), + GFX_ENHANCE_FORCE_TEXTURE_FILTERING(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS, + "ForceTextureFiltering", 0), + GFX_ENHANCE_MAX_ANISOTROPY(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS, "MaxAnisotropy", 0), @@ -80,6 +87,8 @@ public enum IntSetting implements AbstractIntSetting private static final IntSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new IntSetting[]{ MAIN_CPU_CORE, MAIN_GC_LANGUAGE, + MAIN_MEM1_SIZE, + MAIN_MEM2_SIZE, MAIN_SLOT_A, // Can actually be changed, but specific code is required MAIN_SLOT_B, // Can actually be changed, but specific code is required MAIN_SERIAL_PORT_1, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.java index d838f6879b..09af07ef76 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/StringSetting.java @@ -21,6 +21,9 @@ public enum StringSetting implements AbstractStringSetting MAIN_BBA_BUILTIN_DNS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "BBA_BUILTIN_DNS", "149.56.167.128"), + MAIN_CUSTOM_RTC_VALUE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CustomRTCValue", + "0x386d4380"), + MAIN_GFX_BACKEND(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "GFXBackend", NativeLibrary.GetDefaultGraphicsBackendName()), @@ -39,6 +42,7 @@ public enum StringSetting implements AbstractStringSetting "PostProcessingShader", ""); private static final StringSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new StringSetting[]{ + MAIN_CUSTOM_RTC_VALUE, MAIN_GFX_BACKEND, }; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/DateTimeChoiceSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/DateTimeChoiceSetting.kt new file mode 100644 index 0000000000..d37ea57a98 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/DateTimeChoiceSetting.kt @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.settings.model.view + +import android.content.Context +import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting +import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting +import org.dolphinemu.dolphinemu.features.settings.model.Settings + +class DateTimeChoiceSetting( + context: Context, + private val setting: AbstractStringSetting, + nameId: Int, + descriptionId: Int +) : SettingsItem(context, nameId, descriptionId) { + override fun getType(): Int { + return TYPE_DATETIME_CHOICE + } + + override fun getSetting(): AbstractSetting { + return setting + } + + fun setSelectedValue(settings: Settings?, selection: String) { + setting.setString(settings, selection) + } + + fun getSelectedValue(settings: Settings): String { + return setting.getString(settings) + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java index 21b782fcb3..7b41c8e3f8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java @@ -29,6 +29,7 @@ public abstract class SettingsItem public static final int TYPE_RUN_RUNNABLE = 10; public static final int TYPE_STRING = 11; public static final int TYPE_HYPERLINK_HEADER = 12; + public static final int TYPE_DATETIME_CHOICE = 13; private final CharSequence mName; private final CharSequence mDescription; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java index c15c0d4498..8339c93207 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java @@ -9,6 +9,7 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Build; import android.provider.DocumentsContract; +import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.TextView; @@ -20,10 +21,14 @@ import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.color.MaterialColors; +import com.google.android.material.datepicker.CalendarConstraints; +import com.google.android.material.datepicker.MaterialDatePicker; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.elevation.ElevationOverlayProvider; import com.google.android.material.slider.Slider; import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.timepicker.MaterialTimePicker; +import com.google.android.material.timepicker.TimeFormat; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.databinding.DialogInputStringBinding; @@ -34,6 +39,7 @@ import org.dolphinemu.dolphinemu.databinding.ListItemSettingSwitchBinding; import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding; import org.dolphinemu.dolphinemu.dialogs.MotionAlertDialog; import org.dolphinemu.dolphinemu.features.settings.model.Settings; +import org.dolphinemu.dolphinemu.features.settings.model.view.DateTimeChoiceSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SwitchSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker; import org.dolphinemu.dolphinemu.features.settings.model.view.FloatSliderSetting; @@ -47,6 +53,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.SliderSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting; +import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.DateTimeSettingViewHolder; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.FilePickerViewHolder; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderHyperLinkViewHolder; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderViewHolder; @@ -68,6 +75,8 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; +import java.util.Calendar; +import java.util.TimeZone; public final class SettingsAdapter extends RecyclerView.Adapter implements DialogInterface.OnClickListener, Slider.OnChangeListener @@ -135,6 +144,9 @@ public final class SettingsAdapter extends RecyclerView.Adapter datePicker = MaterialDatePicker.Builder.datePicker() + .setSelection(storedTime) + .setTitleText(R.string.select_rtc_date) + .setCalendarConstraints(calendarConstraints) + .build(); + MaterialTimePicker timePicker = new MaterialTimePicker.Builder() + .setTimeFormat(timeFormat) + .setHour(calendar.get(Calendar.HOUR_OF_DAY)) + .setMinute(calendar.get(Calendar.MINUTE)) + .setTitleText(R.string.select_rtc_time) + .build(); + + datePicker.addOnPositiveButtonClickListener( + selection -> timePicker.show(mView.getActivity().getSupportFragmentManager(), + "TimePicker")); + timePicker.addOnPositiveButtonClickListener(selection -> + { + long epochTime = datePicker.getSelection() / 1000; + epochTime += (long) timePicker.getHour() * 60 * 60; + epochTime += (long) timePicker.getMinute() * 60; + String rtcString = "0x" + Long.toHexString(epochTime); + if (!item.getSelectedValue(mView.getSettings()).equals(rtcString)) + { + notifyItemChanged(mClickedPosition); + mView.onSettingChanged(); + } + + item.setSelectedValue(mView.getSettings(), rtcString); + + mClickedItem = null; + }); + datePicker.show(mView.getActivity().getSupportFragmentManager(), "DatePicker"); + } + public void onFilePickerConfirmation(String selectedFile) { FilePicker filePicker = (FilePicker) mClickedItem; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java index 5e8c5bd912..3a0df485b3 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java @@ -25,6 +25,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.PostProcessing; import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; import org.dolphinemu.dolphinemu.features.settings.model.WiimoteProfileStringSetting; +import org.dolphinemu.dolphinemu.features.settings.model.view.DateTimeChoiceSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SwitchSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker; import org.dolphinemu.dolphinemu.features.settings.model.view.HeaderSetting; @@ -564,8 +565,13 @@ public final class SettingsFragmentPresenter private void addGameCubeSettings(ArrayList sl) { + sl.add(new HeaderSetting(mContext, R.string.ipl_settings, 0)); + sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_SKIP_IPL, R.string.skip_main_menu, + R.string.skip_main_menu_description)); sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_GC_LANGUAGE, R.string.system_language, 0, R.array.gameCubeSystemLanguageEntries, R.array.gameCubeSystemLanguageValues)); + + sl.add(new HeaderSetting(mContext, R.string.device_settings, 0)); sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_SLOT_A, R.string.slot_a_device, 0, R.array.slotDeviceEntries, R.array.slotDeviceValues)); sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_SLOT_B, R.string.slot_b_device, 0, @@ -715,17 +721,103 @@ public final class SettingsFragmentPresenter emuCoresEntries = R.array.emuCoresEntriesGeneric; emuCoresValues = R.array.emuCoresValuesGeneric; } + sl.add(new HeaderSetting(mContext, R.string.cpu_options, 0)); sl.add(new SingleChoiceSetting(mContext, IntSetting.MAIN_CPU_CORE, R.string.cpu_core, 0, emuCoresEntries, emuCoresValues)); sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_MMU, R.string.mmu_enable, R.string.mmu_enable_description)); + sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_PAUSE_ON_PANIC, R.string.pause_on_panic, + R.string.pause_on_panic_description)); + sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_ACCURATE_CPU_CACHE, + R.string.enable_cpu_cache, R.string.enable_cpu_cache_description)); + + sl.add(new HeaderSetting(mContext, R.string.clock_override, 0)); sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_OVERCLOCK_ENABLE, R.string.overclock_enable, R.string.overclock_enable_description)); sl.add(new PercentSliderSetting(mContext, FloatSetting.MAIN_OVERCLOCK, R.string.overclock_title, R.string.overclock_title_description, 0, 400, "%")); + + AbstractIntSetting mem1Setting = new AbstractIntSetting() + { + @Override + public int getInt(Settings settings) + { + return IntSetting.MAIN_MEM1_SIZE.getInt(settings) / 1024 / 1024; + } + + @Override + public void setInt(Settings settings, int newValue) + { + IntSetting.MAIN_MEM1_SIZE.setInt(settings, newValue * 1024 * 1024); + } + + @Override + public boolean isOverridden(Settings settings) + { + return IntSetting.MAIN_MEM1_SIZE.isOverridden(settings); + } + + @Override + public boolean isRuntimeEditable() + { + return IntSetting.MAIN_MEM1_SIZE.isRuntimeEditable(); + } + + @Override + public boolean delete(Settings settings) + { + return IntSetting.MAIN_MEM1_SIZE.delete(settings); + } + }; + AbstractIntSetting mem2Setting = new AbstractIntSetting() + { + @Override + public int getInt(Settings settings) + { + return IntSetting.MAIN_MEM2_SIZE.getInt(settings) / 1024 / 1024; + } + + @Override + public void setInt(Settings settings, int newValue) + { + IntSetting.MAIN_MEM2_SIZE.setInt(settings, newValue * 1024 * 1024); + } + + @Override + public boolean isOverridden(Settings settings) + { + return IntSetting.MAIN_MEM2_SIZE.isOverridden(settings); + } + + @Override + public boolean isRuntimeEditable() + { + return IntSetting.MAIN_MEM2_SIZE.isRuntimeEditable(); + } + + @Override + public boolean delete(Settings settings) + { + return IntSetting.MAIN_MEM2_SIZE.delete(settings); + } + }; + sl.add(new HeaderSetting(mContext, R.string.memory_override, 0)); + sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_RAM_OVERRIDE_ENABLE, + R.string.enable_memory_size_override, + R.string.enable_memory_size_override_description)); + sl.add(new IntSliderSetting(mContext, mem1Setting, R.string.main_mem1_size, 0, 24, 64, "MB")); + sl.add(new IntSliderSetting(mContext, mem2Setting, R.string.main_mem2_size, 0, 64, 128, "MB")); + + sl.add(new HeaderSetting(mContext, R.string.gpu_options, 0)); sl.add(new SingleChoiceSetting(mContext, synchronizeGpuThread, R.string.synchronize_gpu_thread, R.string.synchronize_gpu_thread_description, R.array.synchronizeGpuThreadEntries, R.array.synchronizeGpuThreadValues)); + + sl.add(new HeaderSetting(mContext, R.string.custom_rtc_options, 0)); + sl.add(new SwitchSetting(mContext, BooleanSetting.MAIN_CUSTOM_RTC_ENABLE, + R.string.custom_rtc_enable, R.string.custom_rtc_description)); + sl.add(new DateTimeChoiceSetting(mContext, StringSetting.MAIN_CUSTOM_RTC_VALUE, + R.string.set_custom_rtc, 0)); } private void addSerialPortSubSettings(ArrayList sl, int serialPort1Type) @@ -800,6 +892,37 @@ public final class SettingsFragmentPresenter sl.add(new SingleChoiceSetting(mContext, IntSetting.GFX_ENHANCE_MAX_ANISOTROPY, R.string.anisotropic_filtering, R.string.anisotropic_filtering_description, R.array.anisotropicFilteringEntries, R.array.anisotropicFilteringValues)); + AbstractIntSetting filteringSetting = new AbstractIntSetting() + { + @Override public int getInt(Settings settings) + { + return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.getInt(settings); + } + + @Override public void setInt(Settings settings, int newValue) + { + BooleanSetting.GFX_ENHANCE_FORCE_FILTERING.setBoolean(settings, (newValue > 0)); + IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.setInt(settings, newValue); + } + + @Override public boolean isOverridden(Settings settings) + { + return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.isOverridden(settings); + } + + @Override public boolean isRuntimeEditable() + { + return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.isRuntimeEditable(); + } + + @Override public boolean delete(Settings settings) + { + return IntSetting.GFX_ENHANCE_FORCE_TEXTURE_FILTERING.delete(settings); + } + }; + sl.add(new SingleChoiceSetting(mContext, filteringSetting, R.string.texture_filtering, + R.string.texture_filtering_description, R.array.textureFilteringEntries, + R.array.textureFilteringValues)); int stereoModeValue = IntSetting.GFX_STEREO_MODE.getInt(mSettings); final int anaglyphMode = 3; @@ -821,8 +944,6 @@ public final class SettingsFragmentPresenter R.string.scaled_efb_copy, R.string.scaled_efb_copy_description)); sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENABLE_PIXEL_LIGHTING, R.string.per_pixel_lighting, R.string.per_pixel_lighting_description)); - sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENHANCE_FORCE_FILTERING, - R.string.force_texture_filtering, R.string.force_texture_filtering_description)); sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENHANCE_FORCE_TRUE_COLOR, R.string.force_24bit_color, R.string.force_24bit_color_description)); sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_DISABLE_FOG, R.string.disable_fog, @@ -944,8 +1065,12 @@ public final class SettingsFragmentPresenter R.string.defer_efb_invalidation, R.string.defer_efb_invalidation_description)); sl.add(new InvertedSwitchSetting(mContext, BooleanSetting.GFX_HACK_FAST_TEXTURE_SAMPLING, R.string.manual_texture_sampling, R.string.manual_texture_sampling_description)); + + sl.add(new HeaderSetting(mContext, R.string.frame_dumping, 0)); sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_INTERNAL_RESOLUTION_FRAME_DUMPS, R.string.internal_resolution_dumps, R.string.internal_resolution_dumps_description)); + sl.add(new IntSliderSetting(mContext, IntSetting.GFX_PNG_COMPRESSION_LEVEL, + R.string.png_compression_level, 0, 0, 9, "")); sl.add(new HeaderSetting(mContext, R.string.debugging, 0)); sl.add(new SwitchSetting(mContext, BooleanSetting.GFX_ENABLE_WIREFRAME, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/DateTimeSettingViewHolder.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/DateTimeSettingViewHolder.kt new file mode 100644 index 0000000000..79693e9c64 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/DateTimeSettingViewHolder.kt @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.features.settings.ui.viewholder + +import android.text.TextUtils +import android.view.View +import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding +import org.dolphinemu.dolphinemu.features.settings.model.view.DateTimeChoiceSetting +import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem +import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter +import java.time.Instant +import java.time.ZoneId +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle + +class DateTimeSettingViewHolder( + private val binding: ListItemSettingBinding, + adapter: SettingsAdapter +) : SettingViewHolder(binding.root, adapter) { + private var mItem: DateTimeChoiceSetting? = null + + override fun bind(item: SettingsItem) { + mItem = item as DateTimeChoiceSetting + val inputTime = mItem!!.getSelectedValue(adapter.settings) + binding.textSettingName.text = item.getName() + + if (!TextUtils.isEmpty(inputTime)) { + val epochTime = inputTime.substring(2).toLong(16) + val instant = Instant.ofEpochMilli(epochTime * 1000) + val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")) + val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) + binding.textSettingDescription.text = dateFormatter.format(zonedTime) + } else { + binding.textSettingDescription.text = item.getDescription() + } + setStyle(binding.textSettingName, mItem) + } + + override fun onClick(clicked: View) { + if (!mItem!!.isEditable) { + showNotRuntimeEditableError() + return + } + adapter.onDateTimeClick(mItem, bindingAdapterPosition) + setStyle(binding.textSettingName, mItem) + } + + override fun getItem(): SettingsItem? { + return mItem + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java index 611a62ca13..d34e4a1536 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SettingViewHolder.java @@ -54,6 +54,12 @@ public abstract class SettingViewHolder extends RecyclerView.ViewHolder Toast.LENGTH_SHORT).show(); } + protected static void showIplNotAvailableError() + { + Toast.makeText(DolphinApplication.getAppContext(), R.string.ipl_not_found, Toast.LENGTH_SHORT) + .show(); + } + /** * Called by the adapter to set this ViewHolder's child views to display the list item * it must now represent. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SwitchSettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SwitchSettingViewHolder.java index ea7185b2ec..8e568baf32 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SwitchSettingViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/SwitchSettingViewHolder.java @@ -7,13 +7,20 @@ import android.view.View; import androidx.annotation.Nullable; import org.dolphinemu.dolphinemu.databinding.ListItemSettingSwitchBinding; +import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SwitchSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; +import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; public final class SwitchSettingViewHolder extends SettingViewHolder { private SwitchSetting mItem; + private boolean iplExists = false; private final ListItemSettingSwitchBinding mBinding; @@ -32,11 +39,43 @@ public final class SwitchSettingViewHolder extends SettingViewHolder mBinding.textSettingDescription.setText(item.getDescription()); mBinding.settingSwitch.setChecked(mItem.isChecked(getAdapter().getSettings())); + mBinding.settingSwitch.setEnabled(true); - mBinding.settingSwitch.setEnabled(mItem.isEditable()); + // Check for IPL to make sure user can skip. + if (mItem.getSetting() == BooleanSetting.MAIN_SKIP_IPL) + { + ArrayList iplDirs = new ArrayList<>(Arrays.asList("USA", "JAP", "EUR")); + for (String dir : iplDirs) + { + File iplFile = new File(DirectoryInitialization.getUserDirectory(), + File.separator + "GC" + File.separator + dir + File.separator + "IPL.bin"); + if (iplFile.exists()) + { + iplExists = true; + break; + } + } + + if (mItem.isChecked(getAdapter().getSettings())) + { + mBinding.settingSwitch.setEnabled(iplExists); + } + else + { + mBinding.settingSwitch.setEnabled(true); + } + } mBinding.settingSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + // If a user has skip IPL disabled previously and deleted their IPL file, we need to allow + // them to skip it or else their game will appear broken. However, once this is enabled, we + // need to disable the option again to prevent the same issue from occurring. + if (mItem.getSetting() == BooleanSetting.MAIN_SKIP_IPL && !iplExists && isChecked) + { + mBinding.settingSwitch.setEnabled(false); + } + getAdapter().onBooleanClick(mItem, mBinding.settingSwitch.isChecked()); setStyle(mBinding.textSettingName, mItem); @@ -54,6 +93,15 @@ public final class SwitchSettingViewHolder extends SettingViewHolder return; } + if (mItem.getSetting() == BooleanSetting.MAIN_SKIP_IPL && !iplExists) + { + if (mItem.isChecked(getAdapter().getSettings())) + { + showIplNotAvailableError(); + return; + } + } + mBinding.settingSwitch.toggle(); } diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml index af3b5e29b0..4e27b8ade3 100644 --- a/Source/Android/app/src/main/res/values/arrays.xml +++ b/Source/Android/app/src/main/res/values/arrays.xml @@ -293,7 +293,7 @@ - @string/multiple_one + @string/filtering_default @string/multiple_two @string/multiple_four @string/multiple_eight @@ -307,6 +307,18 @@ 4 + + + @string/filtering_default + @string/filtering_nearest + @string/filtering_linear + + + 0 + 1 + 2 + + @string/stereoscopy_off diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 093e67b7cc..dac5a3d800 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -128,6 +128,10 @@ Speed Limit (0% = Unlimited) WARNING: Changing this from the default (100%) WILL break games and cause glitches. Please do not report bugs that occur with a non-default clock. GameCube + IPL Settings + Skip Main Menu + Put IPL ROMs in User/GC/<region> + Device Settings System Language GameCube Slot A Device GameCube Slot B Device @@ -250,6 +254,8 @@ Reduces the amount of aliasing caused by rasterizing 3D graphics. This makes the rendered picture look less blocky. Heavily decreases emulation speed and sometimes causes issues. Anisotropic Filtering Enhances visual quality of textures that are at oblique viewing angles. Might cause issues in a small number of games. + Texture Filtering + Overrides the texture scaling filter selected by the game. Any option except \'Default\' will alter the look of the game\'s textures and might cause issues in a small number of games. Post-Processing Effect Apply a post-processing effect after finishing a frame Post Processing Shader @@ -368,7 +374,9 @@ Manual Texture Sampling Use a manual implementation of texture sampling instead of the graphics backend\'s built-in functionality. Dump Frames at Internal Resolution + Frame Dumping Creates frame dumps and screenshots at the internal resolution of the renderer, rather than the size of the window it is displayed within. If the aspect ratio is widescreen, the output image will be scaled horizontally to preserve the vertical resolution. + PNG Compression Level Debugging Enable Wireframe Show Statistics @@ -381,15 +389,33 @@ Advanced + CPU Options CPU Core Enable MMU Enables the Memory Management Unit. Needed for some games, but may reduce performance. + Pause on Panic + Pauses the emulation if a Read/Write or Unknown Instruction panic occurs. The performance impact is the same as having Enable MMU on. + Enable Write-Back Cache (slow) + Enables emulation of the CPU write-back cache. Enabling will have a significant impact on performance. This should be left disabled unless absolutely needed. + Clock Override Override Emulated CPU Clock Speed Higher values can make variable-framerate games run at a higher framerate, requiring a powerful device. Lower values make games run at a lower framerate, increasing emulation speed, but reducing the emulated console\'s performance. Emulated CPU Clock Speed Adjusts the emulated CPU\'s clock rate if \"Override Emulated CPU Clock Speed\" is enabled. + Memory Override + Enable Emulated Memory Size Override + Adjusts the amount of RAM in the emulated console.\n\nWARNING: Enabling this will completely break many games. Only a small number of games can benefit from this. + MEM1 Size + MEM2 Size + GPU Options Synchronize GPU Thread Synchronizing the GPU thread reduces the risk of games crashing or becoming unstable with dual core enabled, but can also reduce the performance gain of dual core. If unsure, select \"On Idle Skipping\". Selecting \"Never\" is risky and not recommended! + Custom RTC Options + Enable Custom RTC + This settings allows you to set a custom real time clock (RTC) separate from your current system time. + Set Custom RTC + Select RTC Date + Select RTC Time Log @@ -623,6 +649,7 @@ It can efficiently compress both junk data and encrypted Wii data. Due to the Scoped Storage policy in Android 11 and newer, you can\'t change this path. Loading Settingsā€¦ This setting can\'t be changed while a game is running. + IPL not found Long press a setting to clear it. Do you want to restore this setting to its default value? Setting cleared @@ -752,6 +779,11 @@ It can efficiently compress both junk data and encrypted Wii data. 8x 16x + + Default + Force Nearest + Force Linear + Off Side-by-Side