diff options
-rw-r--r-- | CMakeModules/CopyYuzuQt5Deps.cmake | 5 | ||||
-rw-r--r-- | src/yuzu/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/yuzu/bootmanager.cpp | 11 | ||||
-rw-r--r-- | src/yuzu/bootmanager.h | 3 | ||||
-rw-r--r-- | src/yuzu/loading_screen.cpp | 71 | ||||
-rw-r--r-- | src/yuzu/loading_screen.h | 50 | ||||
-rw-r--r-- | src/yuzu/loading_screen.ui | 79 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 26 | ||||
-rw-r--r-- | src/yuzu/main.h | 4 |
9 files changed, 243 insertions, 11 deletions
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index 4fef66659..1e9810bba 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake @@ -45,5 +45,8 @@ function(copy_yuzu_Qt5_deps target_dir) windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) - windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*) + windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} + qjpeg$<$<CONFIG:Debug>:d>.* + qgif$<$<CONFIG:Debug>:d>.* + ) endfunction(copy_yuzu_Qt5_deps) diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 1f852df4b..4cab599b4 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -68,6 +68,8 @@ add_executable(yuzu game_list_p.h game_list_worker.cpp game_list_worker.h + loading_screen.cpp + loading_screen.h hotkeys.cpp hotkeys.h main.cpp @@ -102,9 +104,10 @@ set(UIS configuration/configure_system.ui configuration/configure_touchscreen_advanced.ui configuration/configure_web.ui + compatdb.ui hotkeys.ui + loading_screen.ui main.ui - compatdb.ui ) file(GLOB COMPAT_LIST diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 40db7a5e9..f74cb693a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -3,9 +3,7 @@ #include <QKeyEvent> #include <QScreen> #include <QWindow> - #include <fmt/format.h> - #include "common/microprofile.h" #include "common/scm_rev.h" #include "core/core.h" @@ -17,6 +15,7 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" #include "yuzu/bootmanager.h" +#include "yuzu/main.h" EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {} @@ -114,6 +113,8 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) InputCommon::Init(); InputCommon::StartJoystickEventHandler(); + connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent), + &GMainWindow::OnLoadComplete); } GRenderWindow::~GRenderWindow() { @@ -141,6 +142,10 @@ void GRenderWindow::SwapBuffers() { child->makeCurrent(); child->swapBuffers(); + if (!first_frame) { + emit FirstFrameDisplayed(); + first_frame = true; + } } void GRenderWindow::MakeCurrent() { @@ -309,6 +314,8 @@ void GRenderWindow::InitRenderTarget() { delete layout(); } + first_frame = false; + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, // WA_DontShowOnScreen, WA_DeleteOnClose QGLFormat fmt; diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 4e3028215..d1f37e503 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -152,6 +152,7 @@ public slots: signals: /// Emitted when the window is closed void Closed(); + void FirstFrameDisplayed(); private: std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const; @@ -171,6 +172,8 @@ private: /// Temporary storage of the screenshot taken QImage screenshot_image; + bool first_frame = false; + protected: void showEvent(QShowEvent* event) override; }; diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp new file mode 100644 index 000000000..f2d3214f6 --- /dev/null +++ b/src/yuzu/loading_screen.cpp @@ -0,0 +1,71 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <QBuffer> +#include <QByteArray> +#include <QHBoxLayout> +#include <QIODevice> +#include <QImage> +#include <QLabel> +#include <QMovie> +#include <QPainter> +#include <QPalette> +#include <QPixmap> +#include <QProgressBar> +#include <QStyleOption> +#include <QWindow> +#include "common/logging/log.h" +#include "core/loader/loader.h" +#include "ui_loading_screen.h" +#include "yuzu/loading_screen.h" + +LoadingScreen::LoadingScreen(QWidget* parent) + : QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()) { + ui->setupUi(this); + // Progress bar is hidden until we have a use for it. + ui->progress_bar->hide(); +} + +LoadingScreen::~LoadingScreen() = default; + +void LoadingScreen::Prepare(Loader::AppLoader& loader) { + std::vector<u8> buffer; + if (loader.ReadBanner(buffer) == Loader::ResultStatus::Success) { + backing_mem = + std::make_unique<QByteArray>(reinterpret_cast<char*>(buffer.data()), buffer.size()); + backing_buf = std::make_unique<QBuffer>(backing_mem.get()); + backing_buf->open(QIODevice::ReadOnly); + animation = std::make_unique<QMovie>(backing_buf.get(), QByteArray("GIF")); + animation->start(); + ui->banner->setMovie(animation.get()); + buffer.clear(); + } + if (loader.ReadLogo(buffer) == Loader::ResultStatus::Success) { + QPixmap map; + map.loadFromData(buffer.data(), buffer.size()); + ui->logo->setPixmap(map); + } +} + +void LoadingScreen::OnLoadProgress(std::size_t value, std::size_t total) { + if (total != previous_total) { + ui->progress_bar->setMaximum(total); + previous_total = total; + } + ui->progress_bar->setValue(value); +} + +void LoadingScreen::paintEvent(QPaintEvent* event) { + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + QWidget::paintEvent(event); +} + +void LoadingScreen::Clear() { + animation.reset(); + backing_buf.reset(); + backing_mem.reset(); +} diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h new file mode 100644 index 000000000..ffcaa260d --- /dev/null +++ b/src/yuzu/loading_screen.h @@ -0,0 +1,50 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <QWidget> + +namespace Loader { +class AppLoader; +} + +namespace Ui { +class LoadingScreen; +} + +class QBuffer; +class QByteArray; +class QMovie; + +class LoadingScreen : public QWidget { + Q_OBJECT + +public: + explicit LoadingScreen(QWidget* parent = nullptr); + + ~LoadingScreen(); + + /// Call before showing the loading screen to load the widgets with the logo and banner for the + /// currently loaded application. + void Prepare(Loader::AppLoader& loader); + + /// After the loading screen is hidden, the owner of this class can call this to clean up any + /// used resources such as the logo and banner. + void Clear(); + + // In order to use a custom widget with a stylesheet, you need to override the paintEvent + // See https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget + void paintEvent(QPaintEvent* event) override; + + void OnLoadProgress(std::size_t value, std::size_t total); + +private: + std::unique_ptr<QMovie> animation; + std::unique_ptr<QBuffer> backing_buf; + std::unique_ptr<QByteArray> backing_mem; + std::unique_ptr<Ui::LoadingScreen> ui; + std::size_t previous_total = 0; +}; diff --git a/src/yuzu/loading_screen.ui b/src/yuzu/loading_screen.ui new file mode 100644 index 000000000..00579b670 --- /dev/null +++ b/src/yuzu/loading_screen.ui @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LoadingScreen</class> + <widget class="QWidget" name="LoadingScreen"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>746</width> + <height>495</height> + </rect> + </property> + <property name="styleSheet"> + <string notr="true">background-color: rgb(0, 0, 0);</string> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="logo"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="margin"> + <number>30</number> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QProgressBar" name="progress_bar"> + <property name="styleSheet"> + <string notr="true">font-size: 26px;</string> + </property> + <property name="value"> + <number>0</number> + </property> + <property name="format"> + <string>Loading Shaders %v out of %m</string> + </property> + </widget> + </item> + </layout> + </item> + <item alignment="Qt::AlignRight|Qt::AlignBottom"> + <widget class="QLabel" name="banner"> + <property name="styleSheet"> + <string notr="true">background-color: black;</string> + </property> + <property name="text"> + <string/> + </property> + <property name="margin"> + <number>30</number> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f564de994..68bfa23ab 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -92,6 +92,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/hotkeys.h" +#include "yuzu/loading_screen.h" #include "yuzu/main.h" #include "yuzu/ui_settings.h" @@ -411,6 +412,10 @@ void GMainWindow::InitializeWidgets() { game_list = new GameList(vfs, this); ui.horizontalLayout->addWidget(game_list); + loading_screen = new LoadingScreen(this); + loading_screen->hide(); + ui.horizontalLayout->addWidget(loading_screen); + // Create status bar message_label = new QLabel(); // Configured separately for left alignment @@ -897,8 +902,9 @@ void GMainWindow::BootGame(const QString& filename) { .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, QString::fromStdString(title_name))); - render_window->show(); - render_window->setFocus(); + loading_screen->Prepare(Core::System::GetInstance().GetAppLoader()); + loading_screen->show(); + loading_screen->setFocus(); emulation_running = true; if (ui.action_Fullscreen->isChecked()) { @@ -932,6 +938,8 @@ void GMainWindow::ShutdownGame() { ui.action_Load_Amiibo->setEnabled(false); ui.action_Capture_Screenshot->setEnabled(false); render_window->hide(); + loading_screen->hide(); + loading_screen->Clear(); game_list->show(); game_list->setFilterFocus(); setWindowTitle(QString("yuzu %1| %2-%3") @@ -1505,6 +1513,13 @@ void GMainWindow::OnStopGame() { ShutdownGame(); } +void GMainWindow::OnLoadComplete() { + loading_screen->hide(); + loading_screen->Clear(); + render_window->show(); + render_window->setFocus(); +} + void GMainWindow::OnMenuReportCompatibility() { if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { CompatDB compatdb{this}; @@ -1771,9 +1786,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { this, tr("Confirm Key Rederivation"), tr("You are about to force rederive all of your keys. \nIf you do not know what this " "means or what you are doing, \nthis is a potentially destructive action. \nPlease " - "make " - "sure this is what you want \nand optionally make backups.\n\nThis will delete your " - "autogenerated key files and re-run the key derivation module."), + "make sure this is what you want \nand optionally make backups.\n\nThis will delete " + "your autogenerated key files and re-run the key derivation module."), QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel}); if (res == QMessageBox::Cancel) @@ -1818,7 +1832,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { errors + tr("<br><br>You can get all of these and dump all of your games easily by " "following <a href='https://yuzu-emu.org/help/quickstart/'>the " - "quickstart guide</a>. Alternatively, you can use another method of dumping " + "quickstart guide</a>. Alternatively, you can use another method of dumping" "to obtain all of your keys.")); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 2d705ad54..e07c892cf 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -25,6 +25,7 @@ class GImageInfo; class GraphicsBreakPointsWidget; class GraphicsSurfaceWidget; class GRenderWindow; +class LoadingScreen; class MicroProfileDialog; class ProfilerWidget; class QLabel; @@ -109,10 +110,10 @@ signals: void WebBrowserFinishedBrowsing(); public slots: + void OnLoadComplete(); void ProfileSelectorSelectProfile(); void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); - void WebBrowserOpenPage(std::string_view filename, std::string_view arguments); private: @@ -212,6 +213,7 @@ private: GRenderWindow* render_window; GameList* game_list; + LoadingScreen* loading_screen; // Status bar elements QLabel* message_label = nullptr; |