Android: Add support for custom textures and texture dumping (#6144)
* Android: add app UI settings for custom textures and texture dumping. * Android: Bring lodepng_image_interface into jni directory, include it, and add lodepng to CMAKE for linker (Android version doesn't use the src/citra folder) * Android: Add custom texture and texture dumping config.ini settings * Register image interface line added. * Update src/android/app/src/main/res/values/strings.xml Co-authored-by: SachinVin <26602104+SachinVin@users.noreply.github.com> * Update src/android/app/src/main/jni/lodepng_image_interface.cpp Whoops Co-authored-by: SachinVin <26602104+SachinVin@users.noreply.github.com> * clang-format attempt #1 Co-authored-by: SachinVin <26602104+SachinVin@users.noreply.github.com>
This commit is contained in:
		| @@ -21,6 +21,7 @@ public class Settings { | |||||||
|     public static final String SECTION_CONTROLS = "Controls"; |     public static final String SECTION_CONTROLS = "Controls"; | ||||||
|     public static final String SECTION_RENDERER = "Renderer"; |     public static final String SECTION_RENDERER = "Renderer"; | ||||||
|     public static final String SECTION_LAYOUT = "Layout"; |     public static final String SECTION_LAYOUT = "Layout"; | ||||||
|  |     public static final String SECTION_UTILITY = "Utility"; | ||||||
|     public static final String SECTION_AUDIO = "Audio"; |     public static final String SECTION_AUDIO = "Audio"; | ||||||
|     public static final String SECTION_DEBUG = "Debug"; |     public static final String SECTION_DEBUG = "Debug"; | ||||||
|  |  | ||||||
| @@ -29,7 +30,7 @@ public class Settings { | |||||||
|     private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>(); |     private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>(); | ||||||
|  |  | ||||||
|     static { |     static { | ||||||
|         configFileSectionsMap.put(SettingsFile.FILE_NAME_CONFIG, Arrays.asList(SECTION_PREMIUM, SECTION_CORE, SECTION_SYSTEM, SECTION_CAMERA, SECTION_CONTROLS, SECTION_RENDERER, SECTION_LAYOUT, SECTION_AUDIO, SECTION_DEBUG)); |         configFileSectionsMap.put(SettingsFile.FILE_NAME_CONFIG, Arrays.asList(SECTION_PREMIUM, SECTION_CORE, SECTION_SYSTEM, SECTION_CAMERA, SECTION_CONTROLS, SECTION_RENDERER, SECTION_LAYOUT, SECTION_UTILITY, SECTION_AUDIO, SECTION_DEBUG)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -357,11 +357,14 @@ public final class SettingsFragmentPresenter { | |||||||
|         Setting render3dMode = rendererSection.getSetting(SettingsFile.KEY_RENDER_3D); |         Setting render3dMode = rendererSection.getSetting(SettingsFile.KEY_RENDER_3D); | ||||||
|         Setting factor3d = rendererSection.getSetting(SettingsFile.KEY_FACTOR_3D); |         Setting factor3d = rendererSection.getSetting(SettingsFile.KEY_FACTOR_3D); | ||||||
|         Setting useDiskShaderCache = rendererSection.getSetting(SettingsFile.KEY_USE_DISK_SHADER_CACHE); |         Setting useDiskShaderCache = rendererSection.getSetting(SettingsFile.KEY_USE_DISK_SHADER_CACHE); | ||||||
|  |  | ||||||
|         SettingSection layoutSection = mSettings.getSection(Settings.SECTION_LAYOUT); |         SettingSection layoutSection = mSettings.getSection(Settings.SECTION_LAYOUT); | ||||||
|         Setting cardboardScreenSize = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE); |         Setting cardboardScreenSize = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE); | ||||||
|         Setting cardboardXShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT); |         Setting cardboardXShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT); | ||||||
|         Setting cardboardYShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT); |         Setting cardboardYShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT); | ||||||
|  |         SettingSection utilitySection = mSettings.getSection(Settings.SECTION_UTILITY); | ||||||
|  |         Setting dumpTextures = utilitySection.getSetting(SettingsFile.KEY_DUMP_TEXTURES); | ||||||
|  |         Setting customTextures = utilitySection.getSetting(SettingsFile.KEY_CUSTOM_TEXTURES); | ||||||
|  |         //Setting preloadTextures = utilitySection.getSetting(SettingsFile.KEY_PRELOAD_TEXTURES); | ||||||
|  |  | ||||||
|         sl.add(new HeaderSetting(null, null, R.string.renderer, 0)); |         sl.add(new HeaderSetting(null, null, R.string.renderer, 0)); | ||||||
|         sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor)); |         sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor)); | ||||||
| @@ -377,6 +380,12 @@ public final class SettingsFragmentPresenter { | |||||||
|         sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE, Settings.SECTION_LAYOUT, R.string.cardboard_screen_size, R.string.cardboard_screen_size_description, 30, 100, "%", 85, cardboardScreenSize)); |         sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE, Settings.SECTION_LAYOUT, R.string.cardboard_screen_size, R.string.cardboard_screen_size_description, 30, 100, "%", 85, cardboardScreenSize)); | ||||||
|         sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_x_shift, R.string.cardboard_x_shift_description, -100, 100, "%", 0, cardboardXShift)); |         sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_x_shift, R.string.cardboard_x_shift_description, -100, 100, "%", 0, cardboardXShift)); | ||||||
|         sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_y_shift, R.string.cardboard_y_shift_description, -100, 100, "%", 0, cardboardYShift)); |         sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_y_shift, R.string.cardboard_y_shift_description, -100, 100, "%", 0, cardboardYShift)); | ||||||
|  |  | ||||||
|  |         sl.add(new HeaderSetting(null, null, R.string.utility, 0)); | ||||||
|  |         sl.add(new CheckBoxSetting(SettingsFile.KEY_DUMP_TEXTURES, Settings.SECTION_UTILITY, R.string.dump_textures, R.string.dump_textures_description, false, dumpTextures)); | ||||||
|  |         sl.add(new CheckBoxSetting(SettingsFile.KEY_CUSTOM_TEXTURES, Settings.SECTION_UTILITY, R.string.custom_textures, R.string.custom_textures_description, false, customTextures)); | ||||||
|  |         //Disabled until custom texture implementation gets rewrite, current one overloads RAM and crashes Citra. | ||||||
|  |         //sl.add(new CheckBoxSetting(SettingsFile.KEY_PRELOAD_TEXTURES, Settings.SECTION_UTILITY, R.string.preload_textures, R.string.preload_textures_description, false, preloadTextures)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void addAudioSettings(ArrayList<SettingsItem> sl) { |     private void addAudioSettings(ArrayList<SettingsItem> sl) { | ||||||
|   | |||||||
| @@ -64,6 +64,10 @@ public final class SettingsFile { | |||||||
|     public static final String KEY_CARDBOARD_X_SHIFT = "cardboard_x_shift"; |     public static final String KEY_CARDBOARD_X_SHIFT = "cardboard_x_shift"; | ||||||
|     public static final String KEY_CARDBOARD_Y_SHIFT = "cardboard_y_shift"; |     public static final String KEY_CARDBOARD_Y_SHIFT = "cardboard_y_shift"; | ||||||
|  |  | ||||||
|  |     public static final String KEY_DUMP_TEXTURES = "dump_textures"; | ||||||
|  |     public static final String KEY_CUSTOM_TEXTURES = "custom_textures"; | ||||||
|  |     public static final String KEY_PRELOAD_TEXTURES = "preload_textures"; | ||||||
|  |  | ||||||
|     public static final String KEY_AUDIO_OUTPUT_ENGINE = "output_engine"; |     public static final String KEY_AUDIO_OUTPUT_ENGINE = "output_engine"; | ||||||
|     public static final String KEY_ENABLE_AUDIO_STRETCHING = "enable_audio_stretching"; |     public static final String KEY_ENABLE_AUDIO_STRETCHING = "enable_audio_stretching"; | ||||||
|     public static final String KEY_VOLUME = "volume"; |     public static final String KEY_VOLUME = "volume"; | ||||||
|   | |||||||
| @@ -25,6 +25,8 @@ add_library(citra-android SHARED | |||||||
|     game_settings.h |     game_settings.h | ||||||
|     id_cache.cpp |     id_cache.cpp | ||||||
|     id_cache.h |     id_cache.h | ||||||
|  |     lodepng_image_interface.cpp | ||||||
|  |     lodepng_image_interface.h | ||||||
|     mic.cpp |     mic.cpp | ||||||
|     mic.h |     mic.h | ||||||
|     native.cpp |     native.cpp | ||||||
| @@ -34,6 +36,6 @@ add_library(citra-android SHARED | |||||||
| ) | ) | ||||||
|  |  | ||||||
| target_link_libraries(citra-android PRIVATE audio_core common core input_common network) | target_link_libraries(citra-android PRIVATE audio_core common core input_common network) | ||||||
| target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics log mediandk yuv) | target_link_libraries(citra-android PRIVATE android camera2ndk EGL glad inih jnigraphics lodepng log mediandk yuv) | ||||||
|  |  | ||||||
| set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android) | set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} citra-android) | ||||||
|   | |||||||
| @@ -179,6 +179,12 @@ void Config::ReadValues() { | |||||||
|     Settings::values.cardboard_y_shift = |     Settings::values.cardboard_y_shift = | ||||||
|         static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_y_shift", 0)); |         static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_y_shift", 0)); | ||||||
|  |  | ||||||
|  |     // Utility | ||||||
|  |     Settings::values.dump_textures = sdl2_config->GetBoolean("Utility", "dump_textures", false); | ||||||
|  |     Settings::values.custom_textures = sdl2_config->GetBoolean("Utility", "custom_textures", false); | ||||||
|  |     Settings::values.preload_textures = | ||||||
|  |         sdl2_config->GetBoolean("Utility", "preload_textures", false); | ||||||
|  |  | ||||||
|     // Audio |     // Audio | ||||||
|     Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false); |     Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false); | ||||||
|     Settings::values.enable_dsp_lle_multithread = |     Settings::values.enable_dsp_lle_multithread = | ||||||
|   | |||||||
| @@ -209,6 +209,19 @@ cardboard_x_shift = | |||||||
| # -100 - 100: Screen Y-Coordinate shift as a percentage of empty space. 0 (default) | # -100 - 100: Screen Y-Coordinate shift as a percentage of empty space. 0 (default) | ||||||
| cardboard_y_shift = | cardboard_y_shift = | ||||||
|  |  | ||||||
|  | [Utility] | ||||||
|  | # Dumps textures as PNG to dump/textures/[Title ID]/. | ||||||
|  | # 0 (default): Off, 1: On | ||||||
|  | dump_textures = | ||||||
|  |  | ||||||
|  | # Reads PNG files from load/textures/[Title ID]/ and replaces textures. | ||||||
|  | # 0 (default): Off, 1: On | ||||||
|  | custom_textures = | ||||||
|  |  | ||||||
|  | # Loads all custom textures into memory before booting. | ||||||
|  | # 0 (default): Off, 1: On | ||||||
|  | preload_textures = | ||||||
|  |  | ||||||
| [Audio] | [Audio] | ||||||
| # Whether or not to enable DSP LLE | # Whether or not to enable DSP LLE | ||||||
| # 0 (default): No, 1: Yes | # 0 (default): No, 1: Yes | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								src/android/app/src/main/jni/lodepng_image_interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/android/app/src/main/jni/lodepng_image_interface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // Copyright 2019 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <lodepng.h> | ||||||
|  | #include "common/logging/log.h" | ||||||
|  | #include "jni/lodepng_image_interface.h" | ||||||
|  |  | ||||||
|  | bool LodePNGImageInterface::DecodePNG(std::vector<u8>& dst, u32& width, u32& height, | ||||||
|  |                                       const std::string& path) { | ||||||
|  |     u32 lodepng_ret = lodepng::decode(dst, width, height, path); | ||||||
|  |     if (lodepng_ret) { | ||||||
|  |         LOG_CRITICAL(Frontend, "Failed to decode {} because {}", path, | ||||||
|  |                      lodepng_error_text(lodepng_ret)); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool LodePNGImageInterface::EncodePNG(const std::string& path, const std::vector<u8>& src, | ||||||
|  |                                       u32 width, u32 height) { | ||||||
|  |     u32 lodepng_ret = lodepng::encode(path, src, width, height); | ||||||
|  |     if (lodepng_ret) { | ||||||
|  |         LOG_CRITICAL(Frontend, "Failed to encode {} because {}", path, | ||||||
|  |                      lodepng_error_text(lodepng_ret)); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								src/android/app/src/main/jni/lodepng_image_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/android/app/src/main/jni/lodepng_image_interface.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | // Copyright 2019 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "core/frontend/image_interface.h" | ||||||
|  |  | ||||||
|  | class LodePNGImageInterface final : public Frontend::ImageInterface { | ||||||
|  | public: | ||||||
|  |     bool DecodePNG(std::vector<u8>& dst, u32& width, u32& height, const std::string& path) override; | ||||||
|  |     bool EncodePNG(const std::string& path, const std::vector<u8>& src, u32 width, | ||||||
|  |                    u32 height) override; | ||||||
|  | }; | ||||||
| @@ -38,6 +38,7 @@ | |||||||
| #include "jni/game_settings.h" | #include "jni/game_settings.h" | ||||||
| #include "jni/id_cache.h" | #include "jni/id_cache.h" | ||||||
| #include "jni/input_manager.h" | #include "jni/input_manager.h" | ||||||
|  | #include "jni/lodepng_image_interface.h" | ||||||
| #include "jni/mic.h" | #include "jni/mic.h" | ||||||
| #include "jni/native.h" | #include "jni/native.h" | ||||||
| #include "jni/ndk_motion.h" | #include "jni/ndk_motion.h" | ||||||
| @@ -174,6 +175,9 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { | |||||||
|     system.RegisterMiiSelector(std::make_shared<MiiSelector::AndroidMiiSelector>()); |     system.RegisterMiiSelector(std::make_shared<MiiSelector::AndroidMiiSelector>()); | ||||||
|     system.RegisterSoftwareKeyboard(std::make_shared<SoftwareKeyboard::AndroidKeyboard>()); |     system.RegisterSoftwareKeyboard(std::make_shared<SoftwareKeyboard::AndroidKeyboard>()); | ||||||
|  |  | ||||||
|  |     // Register generic image interface | ||||||
|  |     Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>()); | ||||||
|  |  | ||||||
|     // Register real Mic factory |     // Register real Mic factory | ||||||
|     Frontend::Mic::RegisterRealMicFactory(std::make_unique<Mic::AndroidFactory>()); |     Frontend::Mic::RegisterRealMicFactory(std::make_unique<Mic::AndroidFactory>()); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -103,7 +103,13 @@ | |||||||
|     <string name="use_shader_jit">Use shader JIT</string> |     <string name="use_shader_jit">Use shader JIT</string> | ||||||
|     <string name="use_disk_shader_cache">Use disk shader cache</string> |     <string name="use_disk_shader_cache">Use disk shader cache</string> | ||||||
|     <string name="use_disk_shader_cache_description">Reduce stuttering by storing and loading generated shaders to disk. It cannot be used without Enabling Hardware Shader.</string> |     <string name="use_disk_shader_cache_description">Reduce stuttering by storing and loading generated shaders to disk. It cannot be used without Enabling Hardware Shader.</string> | ||||||
|  |     <string name="utility">Utility</string> | ||||||
|  |     <string name="dump_textures">Dump textures</string> | ||||||
|  |     <string name="dump_textures_description">Dumps textures to dump/textures/[GAME ID]</string> | ||||||
|  |     <string name="custom_textures">Use custom textures</string> | ||||||
|  |     <string name="custom_textures_description">Uses custom textures found in load/textures/[GAME ID]</string> | ||||||
|  |     <string name="preload_textures">Preload custom textures</string> | ||||||
|  |     <string name="preload_textures_description">Loads all custom textures into memory. This feature can use a lot of memory.</string> | ||||||
|     <!-- Premium strings --> |     <!-- Premium strings --> | ||||||
|     <string name="premium_text">Premium</string> |     <string name="premium_text">Premium</string> | ||||||
|     <string name="premium_settings_upsell">Upgrade to Premium and support Citra!</string> |     <string name="premium_settings_upsell">Upgrade to Premium and support Citra!</string> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user