From 6c6cefad6c4add22cd01ca665301219fd6b2c0b0 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 31 Oct 2024 19:26:41 +0100 Subject: [PATCH] add splashscreen --- res/melon.qrc | 1 + src/frontend/qt_sdl/OSD_shaders.h | 5 +- src/frontend/qt_sdl/Screen.cpp | 185 +++++++++++++++++++++++++++++- src/frontend/qt_sdl/Screen.h | 16 ++- 4 files changed, 200 insertions(+), 7 deletions(-) diff --git a/res/melon.qrc b/res/melon.qrc index 38915bbf..3c5824d6 100644 --- a/res/melon.qrc +++ b/res/melon.qrc @@ -2,5 +2,6 @@ icon/melon_256x256.png + melon.svg diff --git a/src/frontend/qt_sdl/OSD_shaders.h b/src/frontend/qt_sdl/OSD_shaders.h index a2a6af70..253fcdc5 100644 --- a/src/frontend/qt_sdl/OSD_shaders.h +++ b/src/frontend/qt_sdl/OSD_shaders.h @@ -26,6 +26,7 @@ uniform vec2 uScreenSize; uniform ivec2 uOSDPos; uniform ivec2 uOSDSize; uniform float uScaleFactor; +uniform float uTexScale; in vec2 vPosition; @@ -35,8 +36,8 @@ void main() { vec4 fpos; - vec2 osdpos = (vPosition * vec2(uOSDSize * uScaleFactor)); - fTexcoord = osdpos; + vec2 osdpos = (vPosition * vec2(uOSDSize)); + fTexcoord = osdpos * uTexScale; osdpos += uOSDPos; fpos.xy = ((osdpos * 2.0) / uScreenSize * uScaleFactor) - 1.0; diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index 367d679d..0d05a065 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -46,11 +46,13 @@ #include "main_shaders.h" #include "OSD_shaders.h" #include "font.h" +#include "version.h" using namespace melonDS; const u32 kOSDMargin = 6; +const int kLogoWidth = 192; ScreenPanel::ScreenPanel(QWidget* parent) : QWidget(parent) @@ -80,6 +82,29 @@ ScreenPanel::ScreenPanel(QWidget* parent) : QWidget(parent) loadConfig(); setFilter(mainWindow->getWindowConfig().GetBool("ScreenFilter")); + + splashLogo = QPixmap(":/melon-logo"); + + strncpy(splashText[0].text, "File->Open ROM...", 256); + splashText[0].id = 0x80000000; + splashText[0].color = 0; + splashText[0].rendered = false; + splashText[0].rainbowstart = -1; + + strncpy(splashText[1].text, "to get started", 256); + splashText[1].id = 0x80000001; + splashText[1].color = 0; + splashText[1].rendered = false; + splashText[1].rainbowstart = -1; + + std::string url = MELONDS_URL; + int urlpos = url.find("://"); + urlpos = (urlpos == std::string::npos) ? 0 : urlpos+3; + strncpy(splashText[2].text, url.c_str() + urlpos, 256); + splashText[2].id = 0x80000002; + splashText[2].color = 0; + splashText[2].rendered = false; + splashText[2].rainbowstart = -1; } ScreenPanel::~ScreenPanel() @@ -150,6 +175,8 @@ void ScreenPanel::setupScreenLayout() aspectBot); numScreens = layout.GetScreenTransforms(screenMatrix[0], screenKind); + + calcSplashLayout(); } QSize ScreenPanel::screenGetMinSize(int factor = 1) @@ -483,8 +510,14 @@ void ScreenPanel::osdRenderItem(OSDItem* item) u32 color = item->color; bool rainbow = (color == 0); - u32 ticks = (u32)QDateTime::currentMSecsSinceEpoch(); - u32 rainbowinc = ((text[0] * 17) + (ticks * 13)) % 600; + u32 rainbowinc; + if (item->rainbowstart == -1) + { + u32 ticks = (u32) QDateTime::currentMSecsSinceEpoch(); + rainbowinc = ((text[0] * 17) + (ticks * 13)) % 600; + } + else + rainbowinc = (u32)item->rainbowstart; color |= 0xFF000000; const u32 shadow = 0xE0000000; @@ -582,6 +615,8 @@ void ScreenPanel::osdRenderItem(OSDItem* item) bitmap[(y * w) + x] = shadow; } } + + item->rainbowend = (int)rainbowinc; } void ScreenPanel::osdDeleteItem(OSDItem* item) @@ -603,11 +638,12 @@ void ScreenPanel::osdAddMessage(unsigned int color, const char* text) OSDItem item; - item.id = osdID++; + item.id = (osdID++) & 0x7FFFFFFF; item.timestamp = QDateTime::currentMSecsSinceEpoch(); strncpy(item.text, text, 255); item.text[255] = '\0'; item.color = color; item.rendered = false; + item.rainbowstart = -1; osdItems.push_back(item); @@ -641,6 +677,73 @@ void ScreenPanel::osdUpdate() it++; } + // render splashscreen text items if needed + + int rainbowinc = -1; + bool needrecalc = false; + + for (int i = 0; i < 3; i++) + { + if (!splashText[i].rendered) + { + splashText[i].rainbowstart = rainbowinc; + osdRenderItem(&splashText[i]); + splashText[i].rendered = true; + rainbowinc = splashText[i].rainbowend; + needrecalc = true; + } + } + + osdMutex.unlock(); + + if (needrecalc) + calcSplashLayout(); +} + +void ScreenPanel::calcSplashLayout() +{ + if (!splashText[0].rendered) + return; + + osdMutex.lock(); + + int w = width(); + int h = height(); + + int xlogo = (w - kLogoWidth) / 2; + int ylogo = (h - kLogoWidth) / 2; + + // top text + int totalwidth = splashText[0].bitmap.width() + 6 + splashText[1].bitmap.width(); + if (totalwidth >= w) + { + // stacked vertically + splashPos[0].setX((width() - splashText[0].bitmap.width()) / 2); + splashPos[1].setX((width() - splashText[1].bitmap.width()) / 2); + + int basey = ylogo / 2; + splashPos[0].setY(basey - splashText[0].bitmap.height() - 1); + splashPos[1].setY(basey + 1); + } + else + { + // horizontal + splashPos[0].setX((w - totalwidth) / 2); + splashPos[1].setX(splashPos[0].x() + splashText[0].bitmap.width() + 6); + + int basey = (ylogo - splashText[0].bitmap.height()) / 2; + splashPos[0].setY(basey); + splashPos[1].setY(basey); + } + + // bottom text + splashPos[2].setX((w - splashText[2].bitmap.width()) / 2); + splashPos[2].setY(ylogo + kLogoWidth + ((ylogo - splashText[2].bitmap.height()) / 2)); + + // logo + splashPos[3].setX(xlogo); + splashPos[3].setY(ylogo); + osdMutex.unlock(); } @@ -708,6 +811,20 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event) } osdUpdate(); + + if (!emuThread->emuIsActive()) + { + // splashscreen + osdMutex.lock(); + + painter.drawPixmap(QRect(splashPos[3], QSize(kLogoWidth, kLogoWidth)), splashLogo); + + for (int i = 0; i < 3; i++) + painter.drawImage(splashPos[i], splashText[i].bitmap); + + osdMutex.unlock(); + } + if (osdEnabled) { osdMutex.lock(); @@ -862,6 +979,7 @@ void ScreenPanelGL::initOpenGL() osdPosULoc = glGetUniformLocation(osdShader, "uOSDPos"); osdSizeULoc = glGetUniformLocation(osdShader, "uOSDSize"); osdScaleFactorULoc = glGetUniformLocation(osdShader, "uScaleFactor"); + osdTexScaleULoc = glGetUniformLocation(osdShader, "uTexScale"); const float osdvertices[6*2] = { @@ -882,6 +1000,18 @@ void ScreenPanelGL::initOpenGL() glEnableVertexAttribArray(0); // position glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0)); + // splash logo texture + QImage logo = splashLogo.scaled(kLogoWidth*2, kLogoWidth*2).toImage(); + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, logo.width(), logo.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, logo.bits()); + logoTexture = tex; + transferLayout(); glInited = true; } @@ -908,6 +1038,8 @@ void ScreenPanelGL::deinitOpenGL() glDeleteVertexArrays(1, &osdVertexArray); glDeleteBuffers(1, &osdVertexBuffer); + glDeleteTextures(1, &logoTexture); + glDeleteProgram(osdShader); @@ -1023,6 +1155,52 @@ void ScreenPanelGL::drawScreenGL() } osdUpdate(); + + if (!emuThread->emuIsActive()) + { + // splashscreen + osdMutex.lock(); + + glUseProgram(osdShader); + + glUniform2f(osdScreenSizeULoc, w, h); + glUniform1f(osdScaleFactorULoc, factor); + glUniform1f(osdTexScaleULoc, 2.0); + + glBindBuffer(GL_ARRAY_BUFFER, osdVertexBuffer); + glBindVertexArray(osdVertexArray); + + glActiveTexture(GL_TEXTURE0); + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, logoTexture); + glUniform2i(osdPosULoc, splashPos[3].x(), splashPos[3].y()); + glUniform2i(osdSizeULoc, kLogoWidth, kLogoWidth); + glDrawArrays(GL_TRIANGLES, 0, 2*3); + + glUniform1f(osdTexScaleULoc, 1.0); + + for (int i = 0; i < 3; i++) + { + OSDItem& item = splashText[i]; + + if (!osdTextures.count(item.id)) + continue; + + glBindTexture(GL_TEXTURE_2D, osdTextures[item.id]); + glUniform2i(osdPosULoc, splashPos[i].x(), splashPos[i].y()); + glUniform2i(osdSizeULoc, item.bitmap.width(), item.bitmap.height()); + glDrawArrays(GL_TRIANGLES, 0, 2*3); + } + + glDisable(GL_BLEND); + glUseProgram(0); + + osdMutex.unlock(); + } + if (osdEnabled) { osdMutex.lock(); @@ -1033,6 +1211,7 @@ void ScreenPanelGL::drawScreenGL() glUniform2f(osdScreenSizeULoc, w, h); glUniform1f(osdScaleFactorULoc, factor); + glUniform1f(osdTexScaleULoc, 1.0); glBindBuffer(GL_ARRAY_BUFFER, osdVertexBuffer); glBindVertexArray(osdVertexArray); diff --git a/src/frontend/qt_sdl/Screen.h b/src/frontend/qt_sdl/Screen.h index c17626bd..a988815e 100644 --- a/src/frontend/qt_sdl/Screen.h +++ b/src/frontend/qt_sdl/Screen.h @@ -110,6 +110,9 @@ protected: bool rendered; QImage bitmap; + + int rainbowstart; + int rainbowend; }; QMutex osdMutex; @@ -117,6 +120,10 @@ protected: unsigned int osdID; std::deque osdItems; + QPixmap splashLogo; + OSDItem splashText[3]; + QPoint splashPos[4]; + void loadConfig(); virtual void setupScreenLayout(); @@ -141,6 +148,8 @@ protected: virtual void osdDeleteItem(OSDItem* item); void osdUpdate(); + + void calcSplashLayout(); }; @@ -202,7 +211,7 @@ private: GLuint screenVertexBuffer, screenVertexArray; GLuint screenTexture; GLuint screenShaderProgram; - GLuint screenShaderTransformULoc, screenShaderScreenSizeULoc; + GLint screenShaderTransformULoc, screenShaderScreenSizeULoc; QMutex screenSettingsLock; WindowInfo windowInfo; @@ -211,11 +220,14 @@ private: GLuint osdShader; GLint osdScreenSizeULoc, osdPosULoc, osdSizeULoc; - GLfloat osdScaleFactorULoc; + GLint osdScaleFactorULoc; + GLint osdTexScaleULoc; GLuint osdVertexArray; GLuint osdVertexBuffer; std::map osdTextures; + GLuint logoTexture; + void osdRenderItem(OSDItem* item) override; void osdDeleteItem(OSDItem* item) override; };