1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Qt: implement hover pam in game list

This commit is contained in:
Megamouse 2023-11-23 00:38:40 +01:00
parent aae155e954
commit 4dfda3240c
7 changed files with 169 additions and 34 deletions

View File

@ -22,4 +22,13 @@ struct GameInfo
u32 resolution = 0; u32 resolution = 0;
u64 size_on_disk = umax; u64 size_on_disk = umax;
std::string get_pam_path() const
{
if (icon_path.empty())
{
return {};
}
return icon_path.substr(0, icon_path.find_last_of("/")) + "/ICON1.PAM";
}
}; };

View File

@ -19,6 +19,7 @@ struct gui_game_info
bool hasCustomConfig = false; bool hasCustomConfig = false;
bool hasCustomPadConfig = false; bool hasCustomPadConfig = false;
bool has_hover_gif = false; bool has_hover_gif = false;
bool has_hover_pam = false;
movie_item_base* item = nullptr; movie_item_base* item = nullptr;
}; };

View File

@ -614,6 +614,7 @@ void game_list_frame::OnParsingFinished()
info.hasCustomConfig = fs::is_file(rpcs3::utils::get_custom_config_path(info.info.serial)); info.hasCustomConfig = fs::is_file(rpcs3::utils::get_custom_config_path(info.info.serial));
info.hasCustomPadConfig = fs::is_file(rpcs3::utils::get_custom_input_config_path(info.info.serial)); info.hasCustomPadConfig = fs::is_file(rpcs3::utils::get_custom_input_config_path(info.info.serial));
info.has_hover_gif = fs::is_file(game_icon_path + info.info.serial + "/hover.gif"); info.has_hover_gif = fs::is_file(game_icon_path + info.info.serial + "/hover.gif");
info.has_hover_pam = fs::is_file(info.info.get_pam_path());
m_games.push(std::make_shared<gui_game_info>(std::move(info))); m_games.push(std::make_shared<gui_game_info>(std::move(info)));
}; };

View File

@ -75,16 +75,16 @@ void game_list_grid::populate(
item->setToolTip(tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(notes)); item->setToolTip(tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(notes));
} }
item->set_icon_func([this, item, game](int) item->set_icon_func([this, item, game](const QVideoFrame& frame)
{ {
if (!item || !game) if (!item || !game)
{ {
return; return;
} }
if (std::shared_ptr<QMovie> movie = item->movie(); movie && item->get_active()) if (const QPixmap pixmap = item->get_movie_image(frame); item->get_active() && !pixmap.isNull())
{ {
item->set_icon(gui::utils::get_centered_pixmap(movie->currentPixmap(), m_icon_size, 0, 0, 1.0, Qt::FastTransformation)); item->set_icon(gui::utils::get_centered_pixmap(pixmap, m_icon_size, 0, 0, 1.0, Qt::FastTransformation));
} }
else else
{ {
@ -92,21 +92,22 @@ void game_list_grid::populate(
item->set_icon(game->pxmap); item->set_icon(game->pxmap);
if (!game->has_hover_gif) if (!game->has_hover_gif && !game->has_hover_pam)
{ {
game->pxmap = {}; game->pxmap = {};
} }
if (movie) item->stop_movie();
{
movie->stop();
}
} }
}); });
if (play_hover_movies && game->has_hover_gif) if (play_hover_movies && game->has_hover_gif)
{ {
item->init_movie(game_icon_path % serial % "/hover.gif"); item->set_movie_path(game_icon_path % serial % "/hover.gif");
}
else if (play_hover_movies && game->has_hover_pam)
{
item->set_movie_path(QString::fromStdString(game->info.get_pam_path()));
} }
if (selected_item_id == game->info.path + game->info.icon_path) if (selected_item_id == game->info.path + game->info.icon_path)

View File

@ -235,16 +235,16 @@ void game_list_table::populate(
custom_table_widget_item* icon_item = new custom_table_widget_item; custom_table_widget_item* icon_item = new custom_table_widget_item;
game->item = icon_item; game->item = icon_item;
icon_item->set_icon_func([this, icon_item, game](int) icon_item->set_icon_func([this, icon_item, game](const QVideoFrame& frame)
{ {
if (!icon_item || !game) if (!icon_item || !game)
{ {
return; return;
} }
if (std::shared_ptr<QMovie> movie = icon_item->movie(); movie && icon_item->get_active()) if (const QPixmap pixmap = icon_item->get_movie_image(frame); icon_item->get_active() && !pixmap.isNull())
{ {
icon_item->setData(Qt::DecorationRole, movie->currentPixmap().scaled(m_icon_size, Qt::KeepAspectRatio)); icon_item->setData(Qt::DecorationRole, pixmap.scaled(m_icon_size, Qt::KeepAspectRatio));
} }
else else
{ {
@ -252,15 +252,12 @@ void game_list_table::populate(
icon_item->setData(Qt::DecorationRole, game->pxmap); icon_item->setData(Qt::DecorationRole, game->pxmap);
if (!game->has_hover_gif) if (!game->has_hover_gif && !game->has_hover_pam)
{ {
game->pxmap = {}; game->pxmap = {};
} }
if (movie) icon_item->stop_movie();
{
movie->stop();
}
} }
}); });
@ -288,7 +285,11 @@ void game_list_table::populate(
if (play_hover_movies && game->has_hover_gif) if (play_hover_movies && game->has_hover_gif)
{ {
icon_item->init_movie(game_icon_path % serial % "/hover.gif"); icon_item->set_movie_path(game_icon_path % serial % "/hover.gif");
}
else if (play_hover_movies && game->has_hover_pam)
{
icon_item->set_movie_path(QString::fromStdString(game->info.get_pam_path()));
} }
icon_item->setData(Qt::UserRole, index, true); icon_item->setData(Qt::UserRole, index, true);

View File

@ -1,6 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "movie_item_base.h" #include "movie_item_base.h"
#include <QFile>
movie_item_base::movie_item_base() movie_item_base::movie_item_base()
{ {
init_pointers(); init_pointers();
@ -13,6 +15,11 @@ movie_item_base::~movie_item_base()
m_movie->stop(); m_movie->stop();
} }
if (m_media_player)
{
m_media_player->stop();
}
wait_for_icon_loading(true); wait_for_icon_loading(true);
wait_for_size_on_disk_loading(true); wait_for_size_on_disk_loading(true);
} }
@ -25,33 +32,136 @@ void movie_item_base::init_pointers()
void movie_item_base::set_active(bool active) void movie_item_base::set_active(bool active)
{ {
if (!std::exchange(m_active, active) && active && m_movie) if (!std::exchange(m_active, active) && active)
{ {
m_movie->jumpToFrame(1); init_movie();
m_movie->start();
if (m_movie)
{
m_movie->jumpToFrame(1);
m_movie->start();
}
if (m_media_player)
{
m_media_player->play();
}
} }
} }
void movie_item_base::init_movie(const QString& path) void movie_item_base::init_movie()
{ {
if (path.isEmpty() || !m_icon_callback) return; if (m_movie || m_media_player)
m_movie.reset(new QMovie(path));
if (!m_movie->isValid())
{ {
m_movie.reset(); // Already initialized
return; return;
} }
QObject::connect(m_movie.get(), &QMovie::frameChanged, m_movie.get(), m_icon_callback); if (!m_icon_callback || m_movie_path.isEmpty() || !QFile::exists(m_movie_path))
{
m_movie_path.clear();
return;
}
const QString lower = m_movie_path.toLower();
if (lower.endsWith(".gif"))
{
m_movie.reset(new QMovie(m_movie_path));
m_movie_path.clear();
if (!m_movie->isValid())
{
m_movie.reset();
return;
}
QObject::connect(m_movie.get(), &QMovie::frameChanged, m_movie.get(), [this](int)
{
m_icon_callback({});
});
return;
}
if (lower.endsWith(".pam"))
{
// We can't set PAM files as source of the video player, so we have to feed them as raw data.
QFile file(m_movie_path);
if (!file.open(QFile::OpenModeFlag::ReadOnly))
{
return;
}
// TODO: Decode the pam properly before pushing it to the player
m_movie_data = file.readAll();
if (m_movie_data.isEmpty())
{
return;
}
m_movie_buffer.reset(new QBuffer(&m_movie_data));
m_movie_buffer->open(QIODevice::ReadOnly);
}
m_video_sink.reset(new QVideoSink());
QObject::connect(m_video_sink.get(), &QVideoSink::videoFrameChanged, m_video_sink.get(), [this](const QVideoFrame& frame)
{
m_icon_callback(frame);
});
m_media_player.reset(new QMediaPlayer());
m_media_player->setVideoSink(m_video_sink.get());
m_media_player->setLoops(QMediaPlayer::Infinite);
if (m_movie_buffer)
{
m_media_player->setSourceDevice(m_movie_buffer.get());
}
else
{
m_media_player->setSource(m_movie_path);
}
}
void movie_item_base::stop_movie()
{
if (m_movie)
{
m_movie->stop();
}
m_video_sink.reset();
m_media_player.reset();
m_movie_buffer.reset();
m_movie_data.clear();
}
QPixmap movie_item_base::get_movie_image(const QVideoFrame& frame) const
{
if (!m_active)
{
return {};
}
if (m_movie)
{
return m_movie->currentPixmap();
}
if (!frame.isValid())
{
return {};
}
// Get image. This usually also converts the image to ARGB32.
return QPixmap::fromImage(frame.toImage());
} }
void movie_item_base::call_icon_func() const void movie_item_base::call_icon_func() const
{ {
if (m_icon_callback) if (m_icon_callback)
{ {
m_icon_callback(0); m_icon_callback({});
} }
} }

View File

@ -6,11 +6,16 @@
#include <QMovie> #include <QMovie>
#include <QThread> #include <QThread>
#include <QBuffer>
#include <QMediaPlayer>
#include <QVideoSink>
#include <QVideoFrame>
#include <QPixmap>
#include <memory> #include <memory>
#include <functional> #include <functional>
using icon_callback_t = std::function<void(int)>; using icon_callback_t = std::function<void(const QVideoFrame&)>;
using icon_load_callback_t = std::function<void(int)>; using icon_load_callback_t = std::function<void(int)>;
using size_calc_callback_t = std::function<void()>; using size_calc_callback_t = std::function<void()>;
@ -29,12 +34,14 @@ public:
return m_active; return m_active;
} }
[[nodiscard]] std::shared_ptr<QMovie> movie() const void set_movie_path(QString path)
{ {
return m_movie; m_movie_path = std::move(path);
} }
void init_movie(const QString& path); void init_movie();
void stop_movie();
QPixmap get_movie_image(const QVideoFrame& frame) const;
void call_icon_func() const; void call_icon_func() const;
void set_icon_func(const icon_callback_t& func); void set_icon_func(const icon_callback_t& func);
@ -71,6 +78,11 @@ public:
shared_mutex pixmap_mutex; shared_mutex pixmap_mutex;
protected: protected:
QString m_movie_path;
QByteArray m_movie_data{};
std::unique_ptr<QBuffer> m_movie_buffer;
std::unique_ptr<QMediaPlayer> m_media_player;
std::shared_ptr<QVideoSink> m_video_sink;
std::shared_ptr<QMovie> m_movie; std::shared_ptr<QMovie> m_movie;
private: private: