mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
228 lines
6.1 KiB
C++
228 lines
6.1 KiB
C++
#include "stdafx.h"
|
|
#include "game_list_base.h"
|
|
#include "localized.h"
|
|
|
|
#include <QDir>
|
|
|
|
#include <cmath>
|
|
#include <unordered_set>
|
|
|
|
LOG_CHANNEL(game_list_log, "GameList");
|
|
|
|
game_list_base::game_list_base()
|
|
{
|
|
}
|
|
|
|
void game_list_base::repaint_icons(QList<game_info>& game_data, const QColor& icon_color, const QSize& icon_size, qreal device_pixel_ratio)
|
|
{
|
|
m_icon_size = icon_size;
|
|
m_icon_color = icon_color;
|
|
|
|
QPixmap placeholder(icon_size * device_pixel_ratio);
|
|
placeholder.setDevicePixelRatio(device_pixel_ratio);
|
|
placeholder.fill(Qt::transparent);
|
|
|
|
for (game_info& game : game_data)
|
|
{
|
|
game->pxmap = placeholder;
|
|
|
|
if (movie_item_base* item = game->item)
|
|
{
|
|
item->set_icon_load_func([this, game, device_pixel_ratio, cancel = item->icon_loading_aborted()](int)
|
|
{
|
|
IconLoadFunction(game, device_pixel_ratio, cancel);
|
|
});
|
|
|
|
item->call_icon_func();
|
|
}
|
|
}
|
|
}
|
|
|
|
void game_list_base::IconLoadFunction(game_info game, qreal device_pixel_ratio, std::shared_ptr<atomic_t<bool>> cancel)
|
|
{
|
|
if (cancel && cancel->load())
|
|
{
|
|
return;
|
|
}
|
|
|
|
static std::unordered_set<std::string> warn_once_list;
|
|
static shared_mutex s_mtx;
|
|
|
|
if (game->icon.isNull() && (game->info.icon_path.empty() || !game->icon.load(QString::fromStdString(game->info.icon_path))))
|
|
{
|
|
if (game_list_log.warning)
|
|
{
|
|
bool logged = false;
|
|
{
|
|
std::lock_guard lock(s_mtx);
|
|
logged = !warn_once_list.emplace(game->info.icon_path).second;
|
|
}
|
|
|
|
if (!logged)
|
|
{
|
|
game_list_log.warning("Could not load image from path %s", QDir(QString::fromStdString(game->info.icon_path)).absolutePath());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!game->item || (cancel && cancel->load()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const QColor color = GetGridCompatibilityColor(game->compat.color);
|
|
{
|
|
std::lock_guard lock(game->item->pixmap_mutex);
|
|
game->pxmap = PaintedPixmap(game->icon, device_pixel_ratio, game->hasCustomConfig, game->hasCustomPadConfig, color);
|
|
}
|
|
|
|
if (!cancel || !cancel->load())
|
|
{
|
|
if (m_icon_ready_callback)
|
|
m_icon_ready_callback(game);
|
|
}
|
|
}
|
|
|
|
QPixmap game_list_base::PaintedPixmap(const QPixmap& icon, qreal device_pixel_ratio, bool paint_config_icon, bool paint_pad_config_icon, const QColor& compatibility_color) const
|
|
{
|
|
QSize canvas_size(320, 176);
|
|
QSize icon_size(icon.size());
|
|
QPoint target_pos;
|
|
|
|
if (!icon.isNull())
|
|
{
|
|
// Let's upscale the original icon to at least fit into the outer rect of the size of PS3's ICON0.PNG
|
|
if (icon_size.width() < 320 || icon_size.height() < 176)
|
|
{
|
|
icon_size.scale(320, 176, Qt::KeepAspectRatio);
|
|
}
|
|
|
|
canvas_size = icon_size;
|
|
|
|
// Calculate the centered size and position of the icon on our canvas.
|
|
if (icon_size.width() != 320 || icon_size.height() != 176)
|
|
{
|
|
ensure(icon_size.height() > 0);
|
|
constexpr double target_ratio = 320.0 / 176.0; // aspect ratio 20:11
|
|
|
|
if ((icon_size.width() / static_cast<double>(icon_size.height())) > target_ratio)
|
|
{
|
|
canvas_size.setHeight(std::ceil(icon_size.width() / target_ratio));
|
|
}
|
|
else
|
|
{
|
|
canvas_size.setWidth(std::ceil(icon_size.height() * target_ratio));
|
|
}
|
|
|
|
target_pos.setX(std::max<int>(0, (canvas_size.width() - icon_size.width()) / 2.0));
|
|
target_pos.setY(std::max<int>(0, (canvas_size.height() - icon_size.height()) / 2.0));
|
|
}
|
|
}
|
|
|
|
// Create a canvas large enough to fit our entire scaled icon
|
|
QPixmap canvas(canvas_size * device_pixel_ratio);
|
|
canvas.setDevicePixelRatio(device_pixel_ratio);
|
|
canvas.fill(m_icon_color);
|
|
|
|
// Create a painter for our canvas
|
|
QPainter painter(&canvas);
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
|
|
|
// Draw the icon onto our canvas
|
|
if (!icon.isNull())
|
|
{
|
|
painter.drawPixmap(target_pos.x(), target_pos.y(), icon_size.width(), icon_size.height(), icon);
|
|
}
|
|
|
|
// Draw config icons if necessary
|
|
if (!m_is_list_layout && (paint_config_icon || paint_pad_config_icon))
|
|
{
|
|
const int width = canvas_size.width() * 0.2;
|
|
const QPoint origin = QPoint(canvas_size.width() - width, 0);
|
|
QString icon_path;
|
|
|
|
if (paint_config_icon && paint_pad_config_icon)
|
|
{
|
|
icon_path = ":/Icons/combo_config_bordered.png";
|
|
}
|
|
else if (paint_config_icon)
|
|
{
|
|
icon_path = ":/Icons/custom_config.png";
|
|
}
|
|
else if (paint_pad_config_icon)
|
|
{
|
|
icon_path = ":/Icons/controllers.png";
|
|
}
|
|
|
|
QPixmap custom_config_icon(icon_path);
|
|
custom_config_icon.setDevicePixelRatio(device_pixel_ratio);
|
|
painter.drawPixmap(origin, custom_config_icon.scaled(QSize(width, width) * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation));
|
|
}
|
|
|
|
// Draw game compatibility icons if necessary
|
|
if (compatibility_color.isValid())
|
|
{
|
|
const int size = canvas_size.height() * 0.2;
|
|
const int spacing = canvas_size.height() * 0.05;
|
|
QColor copyColor = QColor(compatibility_color);
|
|
copyColor.setAlpha(215); // ~85% opacity
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
painter.setBrush(QBrush(copyColor));
|
|
painter.setPen(QPen(Qt::black, std::max(canvas_size.width() / 320, canvas_size.height() / 176)));
|
|
painter.drawEllipse(spacing, spacing, size, size);
|
|
}
|
|
|
|
// Finish the painting
|
|
painter.end();
|
|
|
|
// Scale and return our final image
|
|
return canvas.scaled(m_icon_size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation);
|
|
}
|
|
|
|
QColor game_list_base::GetGridCompatibilityColor(const QString& string) const
|
|
{
|
|
if (m_draw_compat_status_to_grid && !m_is_list_layout)
|
|
{
|
|
return QColor(string);
|
|
}
|
|
return QColor();
|
|
}
|
|
|
|
std::string game_list_base::GetGameVersion(const game_info& game)
|
|
{
|
|
if (game->info.app_ver == Localized().category.unknown.toStdString())
|
|
{
|
|
// Fall back to Disc/Pkg Revision
|
|
return game->info.version;
|
|
}
|
|
|
|
return game->info.app_ver;
|
|
}
|
|
|
|
QIcon game_list_base::GetCustomConfigIcon(const game_info& game)
|
|
{
|
|
if (!game)
|
|
return {};
|
|
|
|
static const QIcon icon_combo_config_bordered(":/Icons/combo_config_bordered.png");
|
|
static const QIcon icon_custom_config(":/Icons/custom_config.png");
|
|
static const QIcon icon_controllers(":/Icons/controllers.png");
|
|
|
|
if (game->hasCustomConfig && game->hasCustomPadConfig)
|
|
{
|
|
return icon_combo_config_bordered;
|
|
}
|
|
|
|
if (game->hasCustomConfig)
|
|
{
|
|
return icon_custom_config;
|
|
}
|
|
|
|
if (game->hasCustomPadConfig)
|
|
{
|
|
return icon_controllers;
|
|
}
|
|
|
|
return {};
|
|
}
|