mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-23 07:56:52 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a21ca36cbb | |||
| 5fdc04be27 | |||
| 9e06060c5b | |||
| 41caecdca4 | |||
| f3fec9a307 | |||
| f8c300baa1 | |||
| 05e9fb6082 | |||
| 42a324d7cb | |||
| 463e8a4d0f | |||
| 2d77c43427 | |||
| a46f4be466 | |||
| 5b86242313 | |||
| d24e79c991 |
Vendored
+105
-51
@@ -37,7 +37,15 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR
|
||||
AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME))
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME)
|
||||
if (FFmpeg_SYSTEM_NAME STREQUAL "openorbis" OR FFmpeg_SYSTEM_NAME STREQUAL "managarm")
|
||||
# All of these platforms are supported by ffmpeg as native build OSes
|
||||
# anything else (like Redox or Managarm or PS4) is NOT natively supported
|
||||
# hence, assume the "unix like" is just "none" for the sake of OUR sanity.
|
||||
# If YOUR OS/platform has actual native support:
|
||||
# 1. congrats
|
||||
# 2. feel free to add it on the condition below
|
||||
if (NOT (NETBSD OR SOLARIS OR FREEBSD
|
||||
OR OPENBSD OR DRAGONFLYBSD OR HAIKU
|
||||
OR LINUX OR MSYS OR WIN32 OR ANDROID OR APPLE))
|
||||
set(FFmpeg_SYSTEM_NAME "none")
|
||||
endif()
|
||||
# TODO: Can we really do better? Auto-detection? Something clever?
|
||||
@@ -56,23 +64,26 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (OPENORBIS OR MANAGARM)
|
||||
if (OPENORBIS OR MANAGARM OR EMSCRIPTEN)
|
||||
# Doesn't support VA-API, don't go thru the embarrassment of trying to enable it
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
|
||||
elseif (ANDROID)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-mediacodec
|
||||
--enable-jni
|
||||
)
|
||||
elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
--disable-vaapi
|
||||
--disnable-cuvid
|
||||
--disnable-ffnvcodec
|
||||
--disnable-nvdec
|
||||
--disable-vulkan
|
||||
--disable-libdrm)
|
||||
elseif (UNIX)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBVA libva)
|
||||
pkg_check_modules(CUDA cuda)
|
||||
pkg_check_modules(FFNVCODEC ffnvcodec)
|
||||
pkg_check_modules(VDPAU vdpau)
|
||||
|
||||
# X11 is "optional", some distros may opt for a super-fully wayland install...
|
||||
find_package(X11)
|
||||
if(X11_FOUND)
|
||||
# Include X11 if possible, some APIs such as VDPAU heavily depend
|
||||
# upon it's existence!
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${X11_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${X11_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${X11_LDFLAGS})
|
||||
if (NOT APPLE)
|
||||
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
|
||||
if(SOLARIS)
|
||||
@@ -81,32 +92,37 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
"${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
|
||||
else()
|
||||
pkg_check_modules(LIBDRM libdrm REQUIRED)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${LIBDRM_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${LIBDRM_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBDRM_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBDRM_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBDRM_LDFLAGS})
|
||||
endif()
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-libdrm)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --enable-libdrm)
|
||||
endif()
|
||||
|
||||
pkg_check_modules(LIBVA libva)
|
||||
if(LIBVA_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA_LDFLAGS})
|
||||
|
||||
# Logically, they can only exist if libva itself exists
|
||||
pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
|
||||
pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${X11_LIBRARIES}
|
||||
${LIBVA-DRM_LIBRARIES}
|
||||
${LIBVA-X11_LIBRARIES}
|
||||
${LIBVA_LIBRARIES})
|
||||
if (LIBVA-DRM_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA-DRM_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA-DRM_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA-DRM_LDFLAGS})
|
||||
endif()
|
||||
if (LIBVA-X11_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${LIBVA-X11_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${LIBVA-X11_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${LIBVA-X11_LDFLAGS})
|
||||
endif()
|
||||
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-hwaccel=h264_vaapi
|
||||
--enable-hwaccel=vp8_vaapi
|
||||
--enable-hwaccel=vp9_vaapi)
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${X11_INCLUDE_DIRS}
|
||||
${LIBVA-DRM_INCLUDE_DIRS}
|
||||
${LIBVA-X11_INCLUDE_DIRS}
|
||||
${LIBVA_INCLUDE_DIRS}
|
||||
)
|
||||
message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found")
|
||||
else()
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
|
||||
@@ -117,6 +133,12 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
message(WARNING "ffmpeg: X11 libraries not found, disabling VA-API...")
|
||||
endif()
|
||||
|
||||
pkg_check_modules(CUDA cuda)
|
||||
pkg_check_modules(FFNVCODEC ffnvcodec)
|
||||
pkg_check_modules(VDPAU vdpau)
|
||||
pkg_check_modules(VULKAN vulkan)
|
||||
find_package(spirv-headers)
|
||||
|
||||
if (FFNVCODEC_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-cuvid
|
||||
@@ -124,8 +146,7 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
--enable-nvdec
|
||||
--enable-hwaccel=h264_nvdec
|
||||
--enable-hwaccel=vp8_nvdec
|
||||
--enable-hwaccel=vp9_nvdec
|
||||
)
|
||||
--enable-hwaccel=vp9_nvdec)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS})
|
||||
@@ -146,8 +167,7 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-vdpau
|
||||
--enable-hwaccel=h264_vdpau
|
||||
--enable-hwaccel=vp9_vdpau
|
||||
)
|
||||
--enable-hwaccel=vp9_vdpau)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS})
|
||||
@@ -156,6 +176,24 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau)
|
||||
message(WARNING "ffmpeg: libvdpau-dev not found, disabling Video Decode and Presentation API for Unix (VDPAU)...")
|
||||
endif()
|
||||
|
||||
if (VULKAN_FOUND AND NOT APPLE)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-vulkan
|
||||
--enable-hwaccel=h264_vulkan
|
||||
--enable-hwaccel=vp9_vulkan)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VULKAN_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VULKAN_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VULKAN_LDFLAGS})
|
||||
message(STATUS "ffmpeg: vulkan libraries version ${VULKAN_VERSION} found")
|
||||
endif()
|
||||
|
||||
if (SPIRV_HEADERS_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${SPIRV_HEADERS_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${SPIRV_HEADERS_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${SPIRV_HEADERS_LDFLAGS})
|
||||
message(STATUS "ffmpeg: spirv-headers libraries version ${SPIRV_HEADERS_VERSION} found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (OPENORBIS)
|
||||
@@ -164,20 +202,28 @@ if (OPENORBIS)
|
||||
-lSceUserService
|
||||
-lSceSysmodule
|
||||
-lSceNet
|
||||
-lSceLibcInternal
|
||||
)
|
||||
-lSceLibcInternal)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--disable-pthreads
|
||||
--extra-cflags=${CMAKE_SYSROOT}/usr/include
|
||||
--extra-cxxflags=${CMAKE_SYSROOT}/usr/include
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}"
|
||||
)
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}")
|
||||
elseif (MANAGARM)
|
||||
# Required for proper stuff
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--disable-pthreads
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}"
|
||||
)
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}")
|
||||
endif()
|
||||
|
||||
# Usually used by Emscripten
|
||||
if (DEFINED CMAKE_AR)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ar=${CMAKE_AR})
|
||||
endif()
|
||||
if (DEFINED CMAKE_NM)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --nm=${CMAKE_NM})
|
||||
endif()
|
||||
if (DEFINED CMAKE_RANLIB)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ranlib=${CMAKE_RANLIB})
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
@@ -252,8 +298,14 @@ else()
|
||||
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
# `--disable-vdpau` is needed to avoid linking issues
|
||||
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
|
||||
set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
|
||||
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
|
||||
set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
|
||||
if (FFmpeg_IS_CROSS_COMPILING)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ld=${CMAKE_LINKER})
|
||||
endif ()
|
||||
# TODO: This is a bit fragile, it depends on FFmpeg_HWACCEL_LDFLAGS being a list
|
||||
# whereas CMAKE_C_FLAGS (and likewise) is meant to NOT be a list, but rather
|
||||
# an elongated piece of string
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_MAKEFILE}
|
||||
@@ -267,6 +319,7 @@ else()
|
||||
--disable-ffprobe
|
||||
--disable-network
|
||||
--disable-swresample
|
||||
--disable-iconv
|
||||
--enable-decoder=h264
|
||||
--enable-decoder=vp8
|
||||
--enable-decoder=vp9
|
||||
@@ -274,10 +327,9 @@ else()
|
||||
--enable-pic
|
||||
--cc=${FFmpeg_CC}
|
||||
--cxx=${FFmpeg_CXX}
|
||||
--ld=${CMAKE_LINKER}
|
||||
--extra-cflags=${CMAKE_C_FLAGS}
|
||||
--extra-cxxflags=${CMAKE_CXX_FLAGS}
|
||||
--extra-ldflags=${CMAKE_C_LINK_FLAGS}
|
||||
--extra-ldflags="${FFmpeg_HWACCEL_LDFLAGS}"
|
||||
${FFmpeg_HWACCEL_FLAGS}
|
||||
${FFmpeg_CROSS_COMPILE_FLAGS}
|
||||
WORKING_DIRECTORY
|
||||
@@ -285,31 +337,33 @@ else()
|
||||
)
|
||||
unset(FFmpeg_CC)
|
||||
unset(FFmpeg_CXX)
|
||||
unset(FFmpeg_LD)
|
||||
unset(FFmpeg_HWACCEL_FLAGS)
|
||||
unset(FFmpeg_CROSS_COMPILE_FLAGS)
|
||||
|
||||
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
|
||||
# with context of the jobserver. Also helps ninja users.
|
||||
execute_process(
|
||||
COMMAND
|
||||
nproc
|
||||
OUTPUT_VARIABLE
|
||||
SYSTEM_THREADS)
|
||||
cmake_host_system_information(RESULT SYSTEM_THREADS QUERY NUMBER_OF_LOGICAL_CORES)
|
||||
|
||||
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
|
||||
|
||||
# BSD make or Solaris make don't support ffmpeg make-j8
|
||||
if (LINUX OR ANDROID OR APPLE OR WIN32 OR FREEBSD)
|
||||
if (DEFINED SYSTEM_THREADS AND (LINUX OR ANDROID OR APPLE OR WIN32))
|
||||
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
|
||||
else()
|
||||
set(FFmpeg_MAKE_ARGS "")
|
||||
endif()
|
||||
find_program(MAKE gmake)
|
||||
if (NOT MAKE_FOUND)
|
||||
# Arch famously names 'gmake' as 'make'
|
||||
find_program(MAKE make REQUIRED)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
gmake ${FFmpeg_MAKE_ARGS}
|
||||
${MAKE} ${FFmpeg_MAKE_ARGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
@@ -31,6 +31,7 @@ object GameHelper {
|
||||
|
||||
fun getGames(): List<Game> {
|
||||
val games = mutableListOf<Game>()
|
||||
val gamesByProgramId = mutableMapOf<String, Game>()
|
||||
val context = YuzuApplication.appContext
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@@ -63,6 +64,7 @@ object GameHelper {
|
||||
|
||||
addGamesRecursive(
|
||||
games,
|
||||
gamesByProgramId,
|
||||
FileUtil.listFiles(gameDirUri),
|
||||
scanDepth,
|
||||
mountedContainerUris
|
||||
@@ -136,6 +138,7 @@ object GameHelper {
|
||||
|
||||
private fun addGamesRecursive(
|
||||
games: MutableList<Game>,
|
||||
gamesByProgramId: MutableMap<String, Game>,
|
||||
files: Array<MinimalDocumentFile>,
|
||||
depth: Int,
|
||||
mountedContainerUris: MutableSet<String>
|
||||
@@ -148,6 +151,7 @@ object GameHelper {
|
||||
if (it.isDirectory) {
|
||||
addGamesRecursive(
|
||||
games,
|
||||
gamesByProgramId,
|
||||
FileUtil.listFiles(it.uri),
|
||||
depth - 1,
|
||||
mountedContainerUris
|
||||
@@ -156,8 +160,9 @@ object GameHelper {
|
||||
val extension = FileUtil.getExtension(it.uri).lowercase()
|
||||
val filePath = it.uri.toString()
|
||||
|
||||
if (externalContentExtensions.contains(extension) &&
|
||||
mountedContainerUris.add(filePath)) {
|
||||
val mountedContainer = externalContentExtensions.contains(extension) &&
|
||||
mountedContainerUris.add(filePath)
|
||||
if (mountedContainer) {
|
||||
NativeLibrary.addGameFolderFileToFilesystemProvider(filePath)
|
||||
}
|
||||
|
||||
@@ -165,6 +170,20 @@ object GameHelper {
|
||||
val game = getGame(it.uri, true, false)
|
||||
if (game != null) {
|
||||
games.add(game)
|
||||
if (game.programId != "0") {
|
||||
gamesByProgramId[game.programId] = game
|
||||
}
|
||||
} else if (mountedContainer) {
|
||||
GameMetadata.getProgramId(filePath).toLongOrNull()?.let { programId ->
|
||||
gamesByProgramId[(programId and 0x800L.inv()).toString()]
|
||||
}?.let { existingGame ->
|
||||
NativeLibrary.getPatchesForFile(existingGame.path, existingGame.programId)
|
||||
existingGame.version = GameMetadata.getVersion(
|
||||
existingGame.path,
|
||||
true
|
||||
)
|
||||
GameIconUtils.refreshGameIcon(existingGame)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -24,6 +27,15 @@ import coil.request.Options
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
import java.util.Collections
|
||||
import java.util.WeakHashMap
|
||||
|
||||
private val gameIconHashes = Collections.synchronizedMap(mutableMapOf<String, Int>())
|
||||
private val gameIconTargets = Collections.synchronizedMap(WeakHashMap<ImageView, GameIconTarget>())
|
||||
|
||||
private fun Game.iconCacheKey(): String = "$path|$version"
|
||||
|
||||
private data class GameIconTarget(val game: Game, var iconHash: Int? = null)
|
||||
|
||||
class GameIconFetcher(
|
||||
private val game: Game,
|
||||
@@ -31,14 +43,15 @@ class GameIconFetcher(
|
||||
) : Fetcher {
|
||||
override suspend fun fetch(): FetchResult {
|
||||
return DrawableResult(
|
||||
drawable = decodeGameIcon(game.path)!!.toDrawable(options.context.resources),
|
||||
drawable = decodeGameIcon(game)!!.toDrawable(options.context.resources),
|
||||
isSampled = false,
|
||||
dataSource = DataSource.DISK
|
||||
)
|
||||
}
|
||||
|
||||
private fun decodeGameIcon(uri: String): Bitmap? {
|
||||
val data = GameMetadata.getIcon(uri)
|
||||
private fun decodeGameIcon(game: Game): Bitmap? {
|
||||
val data = GameMetadata.getIcon(game.path)
|
||||
gameIconHashes[game.iconCacheKey()] = data.contentHashCode()
|
||||
return BitmapFactory.decodeByteArray(
|
||||
data,
|
||||
0,
|
||||
@@ -54,7 +67,7 @@ class GameIconFetcher(
|
||||
}
|
||||
|
||||
class GameIconKeyer : Keyer<Game> {
|
||||
override fun key(data: Game, options: Options): String = data.path
|
||||
override fun key(data: Game, options: Options): String = data.iconCacheKey()
|
||||
}
|
||||
|
||||
object GameIconUtils {
|
||||
@@ -71,14 +84,58 @@ object GameIconUtils {
|
||||
.build()
|
||||
|
||||
fun loadGameIcon(game: Game, imageView: ImageView) {
|
||||
gameIconTargets[imageView] = GameIconTarget(game)
|
||||
val request = ImageRequest.Builder(YuzuApplication.appContext)
|
||||
.data(game)
|
||||
.target(imageView)
|
||||
.error(R.drawable.default_icon)
|
||||
.listener(
|
||||
onSuccess = { _, _ ->
|
||||
val target = gameIconTargets[imageView]
|
||||
if (target?.game?.iconCacheKey() == game.iconCacheKey()) {
|
||||
gameIconHashes[game.iconCacheKey()]?.let {
|
||||
target.iconHash = it
|
||||
}
|
||||
}
|
||||
},
|
||||
onError = { _, _ ->
|
||||
gameIconTargets[imageView]?.iconHash = null
|
||||
}
|
||||
)
|
||||
.build()
|
||||
imageLoader.enqueue(request)
|
||||
}
|
||||
|
||||
fun refreshGameIcon(game: Game) {
|
||||
val targets = synchronized(gameIconTargets) {
|
||||
gameIconTargets
|
||||
.filterValues { it.game.path == game.path && it.game.programId == game.programId }
|
||||
.keys
|
||||
.toList()
|
||||
}
|
||||
if (targets.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val iconHash = GameMetadata.getIcon(game.path).contentHashCode()
|
||||
val targetsToRefresh = targets.filter { gameIconTargets[it]?.iconHash != iconHash }
|
||||
if (targetsToRefresh.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
imageLoader.memoryCache?.remove(MemoryCache.Key(game.iconCacheKey()))
|
||||
targetsToRefresh.forEach { imageView ->
|
||||
imageView.post {
|
||||
val target = gameIconTargets[imageView] ?: return@post
|
||||
if (target.game.path == game.path && target.game.programId == game.programId) {
|
||||
if (target.iconHash != iconHash) {
|
||||
loadGameIcon(game, imageView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap {
|
||||
val request = ImageRequest.Builder(YuzuApplication.appContext)
|
||||
.data(game)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:color="?attr/colorControlHighlight" />
|
||||
<item android:state_focused="true" android:color="@android:color/transparent" />
|
||||
<item android:state_selected="true" android:color="@android:color/transparent" />
|
||||
<item android:state_hovered="true" android:color="@android:color/transparent" />
|
||||
<item android:color="@android:color/transparent" />
|
||||
</selector>
|
||||
@@ -10,6 +10,7 @@
|
||||
android:clipChildren="true"
|
||||
android:layout_margin="0dp"
|
||||
app:cardBackgroundColor="@color/eden_card_background"
|
||||
app:rippleColor="@color/game_card_ripple"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="@color/eden_border">
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardPreventCornerOverlap="true"
|
||||
android:clipChildren="true"
|
||||
app:rippleColor="@color/game_card_ripple"
|
||||
android:layout_margin="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
android:focusable="true"
|
||||
android:transitionName="card_game"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:rippleColor="@color/game_card_ripple"
|
||||
android:foreground="@color/eden_border_gradient_start">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
android:focusable="true"
|
||||
android:transitionName="card_game_compact"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:rippleColor="@color/game_card_ripple"
|
||||
android:foreground="@color/eden_border_gradient_start">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:rippleColor="@color/game_card_ripple"
|
||||
app:strokeWidth="0dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
||||
Reference in New Issue
Block a user