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;
};