integrate OSD into ScreenPanel and make it nicer
This commit is contained in:
parent
fa835ecf68
commit
345b7439e4
|
@ -32,7 +32,6 @@ set(SOURCES_QT_SDL
|
||||||
LAN_PCap.cpp
|
LAN_PCap.cpp
|
||||||
LAN_Socket.cpp
|
LAN_Socket.cpp
|
||||||
LocalMP.cpp
|
LocalMP.cpp
|
||||||
OSD.cpp
|
|
||||||
OSD_shaders.h
|
OSD_shaders.h
|
||||||
font.h
|
font.h
|
||||||
Platform.cpp
|
Platform.cpp
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#include "FrontendUtil.h"
|
#include "FrontendUtil.h"
|
||||||
#include "OSD.h"
|
|
||||||
|
|
||||||
#include "Args.h"
|
#include "Args.h"
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
|
@ -80,7 +79,7 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||||
EmuPauseStack = EmuPauseStackRunning;
|
EmuPauseStack = EmuPauseStackRunning;
|
||||||
RunningSomething = false;
|
RunningSomething = false;
|
||||||
|
|
||||||
connect(this, SIGNAL(windowUpdate()), mainWindow->panelWidget, SLOT(repaint()));
|
connect(this, SIGNAL(windowUpdate()), mainWindow->panel, SLOT(repaint()));
|
||||||
connect(this, SIGNAL(windowTitleChange(QString)), mainWindow, SLOT(onTitleUpdate(QString)));
|
connect(this, SIGNAL(windowTitleChange(QString)), mainWindow, SLOT(onTitleUpdate(QString)));
|
||||||
connect(this, SIGNAL(windowEmuStart()), mainWindow, SLOT(onEmuStart()));
|
connect(this, SIGNAL(windowEmuStart()), mainWindow, SLOT(onEmuStart()));
|
||||||
connect(this, SIGNAL(windowEmuStop()), mainWindow, SLOT(onEmuStop()));
|
connect(this, SIGNAL(windowEmuStop()), mainWindow, SLOT(onEmuStop()));
|
||||||
|
@ -88,7 +87,7 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||||
connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
|
connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(windowEmuFrameStep()), mainWindow->actFrameStep, SLOT(trigger()));
|
connect(this, SIGNAL(windowEmuFrameStep()), mainWindow->actFrameStep, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(windowLimitFPSChange()), mainWindow->actLimitFramerate, SLOT(trigger()));
|
connect(this, SIGNAL(windowLimitFPSChange()), mainWindow->actLimitFramerate, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(screenLayoutChange()), mainWindow->panelWidget, SLOT(onScreenLayoutChanged()));
|
connect(this, SIGNAL(screenLayoutChange()), mainWindow->panel, SLOT(onScreenLayoutChanged()));
|
||||||
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
|
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
|
||||||
connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger()));
|
connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger()));
|
||||||
connect(this, SIGNAL(screenEmphasisToggle()), mainWindow, SLOT(onScreenEmphasisToggled()));
|
connect(this, SIGNAL(screenEmphasisToggle()), mainWindow, SLOT(onScreenEmphasisToggled()));
|
||||||
|
@ -386,9 +385,7 @@ void EmuThread::run()
|
||||||
int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true);
|
int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true);
|
||||||
if (level != -1)
|
if (level != -1)
|
||||||
{
|
{
|
||||||
char msg[64];
|
mainWindow->osdAddMessage(0, "Solar sensor level: %d", level);
|
||||||
sprintf(msg, "Solar sensor level: %d", level);
|
|
||||||
OSD::AddMessage(0, msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Input::HotkeyPressed(HK_SolarSensorIncrease))
|
if (Input::HotkeyPressed(HK_SolarSensorIncrease))
|
||||||
|
@ -396,9 +393,7 @@ void EmuThread::run()
|
||||||
int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true);
|
int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true);
|
||||||
if (level != -1)
|
if (level != -1)
|
||||||
{
|
{
|
||||||
char msg[64];
|
mainWindow->osdAddMessage(0, "Solar sensor level: %d", level);
|
||||||
sprintf(msg, "Solar sensor level: %d", level);
|
|
||||||
OSD::AddMessage(0, msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,7 +475,7 @@ void EmuThread::run()
|
||||||
{
|
{
|
||||||
bool lid = !NDS->IsLidClosed();
|
bool lid = !NDS->IsLidClosed();
|
||||||
NDS->SetLidClosed(lid);
|
NDS->SetLidClosed(lid);
|
||||||
OSD::AddMessage(0, lid ? "Lid closed" : "Lid opened");
|
mainWindow->osdAddMessage(0, lid ? "Lid closed" : "Lid opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
// microphone input
|
// microphone input
|
||||||
|
|
|
@ -1,475 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2016-2023 melonDS team
|
|
||||||
|
|
||||||
This file is part of melonDS.
|
|
||||||
|
|
||||||
melonDS is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free
|
|
||||||
Software Foundation, either version 3 of the License, or (at your option)
|
|
||||||
any later version.
|
|
||||||
|
|
||||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <deque>
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
#include "../types.h"
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include "OpenGLSupport.h"
|
|
||||||
#include <QPainter>
|
|
||||||
|
|
||||||
#include "OSD.h"
|
|
||||||
#include "OSD_shaders.h"
|
|
||||||
#include "font.h"
|
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
using namespace melonDS;
|
|
||||||
|
|
||||||
extern MainWindow* mainWindow;
|
|
||||||
|
|
||||||
namespace OSD
|
|
||||||
{
|
|
||||||
|
|
||||||
const u32 kOSDMargin = 6;
|
|
||||||
|
|
||||||
struct Item
|
|
||||||
{
|
|
||||||
Uint32 Timestamp;
|
|
||||||
char Text[256];
|
|
||||||
u32 Color;
|
|
||||||
|
|
||||||
u32 Width, Height;
|
|
||||||
u32* Bitmap;
|
|
||||||
|
|
||||||
bool NativeBitmapLoaded;
|
|
||||||
QImage NativeBitmap;
|
|
||||||
|
|
||||||
bool GLTextureLoaded;
|
|
||||||
GLuint GLTexture;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::deque<Item> ItemQueue;
|
|
||||||
|
|
||||||
GLuint Shader[3];
|
|
||||||
GLint uScreenSize, uOSDPos, uOSDSize;
|
|
||||||
GLfloat uScaleFactor;
|
|
||||||
GLuint OSDVertexArray;
|
|
||||||
GLuint OSDVertexBuffer;
|
|
||||||
|
|
||||||
QMutex Rendering;
|
|
||||||
|
|
||||||
|
|
||||||
bool Init(bool openGL)
|
|
||||||
{
|
|
||||||
if (openGL)
|
|
||||||
{
|
|
||||||
OpenGL::BuildShaderProgram(kScreenVS_OSD, kScreenFS_OSD, Shader, "OSDShader");
|
|
||||||
|
|
||||||
GLuint pid = Shader[2];
|
|
||||||
glBindAttribLocation(pid, 0, "vPosition");
|
|
||||||
glBindFragDataLocation(pid, 0, "oColor");
|
|
||||||
|
|
||||||
OpenGL::LinkShaderProgram(Shader);
|
|
||||||
glUseProgram(pid);
|
|
||||||
glUniform1i(glGetUniformLocation(pid, "OSDTex"), 0);
|
|
||||||
|
|
||||||
uScreenSize = glGetUniformLocation(pid, "uScreenSize");
|
|
||||||
uOSDPos = glGetUniformLocation(pid, "uOSDPos");
|
|
||||||
uOSDSize = glGetUniformLocation(pid, "uOSDSize");
|
|
||||||
uScaleFactor = glGetUniformLocation(pid, "uScaleFactor");
|
|
||||||
|
|
||||||
float vertices[6*2] =
|
|
||||||
{
|
|
||||||
0, 0,
|
|
||||||
1, 1,
|
|
||||||
1, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 1,
|
|
||||||
1, 1
|
|
||||||
};
|
|
||||||
|
|
||||||
glGenBuffers(1, &OSDVertexBuffer);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
glGenVertexArrays(1, &OSDVertexArray);
|
|
||||||
glBindVertexArray(OSDVertexArray);
|
|
||||||
glEnableVertexAttribArray(0); // position
|
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeInit()
|
|
||||||
{
|
|
||||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
|
||||||
{
|
|
||||||
Item& item = *it;
|
|
||||||
|
|
||||||
if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
|
|
||||||
if (item.Bitmap) delete[] item.Bitmap;
|
|
||||||
|
|
||||||
it = ItemQueue.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int FindBreakPoint(const char* text, int i)
|
|
||||||
{
|
|
||||||
// i = character that went out of bounds
|
|
||||||
|
|
||||||
for (int j = i; j >= 0; j--)
|
|
||||||
{
|
|
||||||
if (text[j] == ' ')
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LayoutText(const char* text, u32* width, u32* height, int* breaks)
|
|
||||||
{
|
|
||||||
u32 w = 0;
|
|
||||||
u32 h = 14;
|
|
||||||
u32 totalw = 0;
|
|
||||||
u32 maxw = mainWindow->panelWidget->width() - (kOSDMargin*2);
|
|
||||||
int lastbreak = -1;
|
|
||||||
int numbrk = 0;
|
|
||||||
u16* ptr;
|
|
||||||
|
|
||||||
memset(breaks, 0, sizeof(int)*64);
|
|
||||||
|
|
||||||
for (int i = 0; text[i] != '\0'; )
|
|
||||||
{
|
|
||||||
int glyphsize;
|
|
||||||
if (text[i] == ' ')
|
|
||||||
{
|
|
||||||
glyphsize = 6;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u32 ch = text[i];
|
|
||||||
if (ch < 0x10 || ch > 0x7E) ch = 0x7F;
|
|
||||||
|
|
||||||
ptr = &font[(ch-0x10) << 4];
|
|
||||||
glyphsize = ptr[0];
|
|
||||||
if (!glyphsize) glyphsize = 6;
|
|
||||||
else glyphsize += 2; // space around the character
|
|
||||||
}
|
|
||||||
|
|
||||||
w += glyphsize;
|
|
||||||
if (w > maxw)
|
|
||||||
{
|
|
||||||
// wrap shit as needed
|
|
||||||
if (text[i] == ' ')
|
|
||||||
{
|
|
||||||
if (numbrk >= 64) break;
|
|
||||||
breaks[numbrk++] = i;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int brk = FindBreakPoint(text, i);
|
|
||||||
if (brk != lastbreak) i = brk;
|
|
||||||
|
|
||||||
if (numbrk >= 64) break;
|
|
||||||
breaks[numbrk++] = i;
|
|
||||||
|
|
||||||
lastbreak = brk;
|
|
||||||
}
|
|
||||||
|
|
||||||
w = 0;
|
|
||||||
h += 14;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (w > totalw) totalw = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
*width = totalw;
|
|
||||||
*height = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 RainbowColor(u32 inc)
|
|
||||||
{
|
|
||||||
// inspired from Acmlmboard
|
|
||||||
|
|
||||||
if (inc < 100) return 0xFFFF9B9B + (inc << 8);
|
|
||||||
else if (inc < 200) return 0xFFFFFF9B - ((inc-100) << 16);
|
|
||||||
else if (inc < 300) return 0xFF9BFF9B + (inc-200);
|
|
||||||
else if (inc < 400) return 0xFF9BFFFF - ((inc-300) << 8);
|
|
||||||
else if (inc < 500) return 0xFF9B9BFF + ((inc-400) << 16);
|
|
||||||
else return 0xFFFF9BFF - (inc-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderText(u32 color, const char* text, Item* item)
|
|
||||||
{
|
|
||||||
u32 w, h;
|
|
||||||
int breaks[64];
|
|
||||||
|
|
||||||
bool rainbow = (color == 0);
|
|
||||||
u32 rainbowinc = ((text[0] * 17) + (SDL_GetTicks() * 13)) % 600;
|
|
||||||
|
|
||||||
color |= 0xFF000000;
|
|
||||||
const u32 shadow = 0xE0000000;
|
|
||||||
|
|
||||||
LayoutText(text, &w, &h, breaks);
|
|
||||||
|
|
||||||
item->Width = w;
|
|
||||||
item->Height = h;
|
|
||||||
item->Bitmap = new u32[w*h];
|
|
||||||
memset(item->Bitmap, 0, w*h*sizeof(u32));
|
|
||||||
|
|
||||||
u32 x = 0, y = 1;
|
|
||||||
u32 maxw = mainWindow->panelWidget->width() - (kOSDMargin*2);
|
|
||||||
int curline = 0;
|
|
||||||
u16* ptr;
|
|
||||||
|
|
||||||
for (int i = 0; text[i] != '\0'; )
|
|
||||||
{
|
|
||||||
int glyphsize;
|
|
||||||
if (text[i] == ' ')
|
|
||||||
{
|
|
||||||
x += 6;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u32 ch = text[i];
|
|
||||||
if (ch < 0x10 || ch > 0x7E) ch = 0x7F;
|
|
||||||
|
|
||||||
ptr = &font[(ch-0x10) << 4];
|
|
||||||
int glyphsize = ptr[0];
|
|
||||||
if (!glyphsize) x += 6;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
x++;
|
|
||||||
|
|
||||||
if (rainbow)
|
|
||||||
{
|
|
||||||
color = RainbowColor(rainbowinc);
|
|
||||||
rainbowinc = (rainbowinc + 30) % 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw character
|
|
||||||
for (int cy = 0; cy < 12; cy++)
|
|
||||||
{
|
|
||||||
u16 val = ptr[4+cy];
|
|
||||||
|
|
||||||
for (int cx = 0; cx < glyphsize; cx++)
|
|
||||||
{
|
|
||||||
if (val & (1<<cx))
|
|
||||||
item->Bitmap[((y+cy) * w) + x+cx] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x += glyphsize;
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
if (breaks[curline] && i >= breaks[curline])
|
|
||||||
{
|
|
||||||
i = breaks[curline++];
|
|
||||||
if (text[i] == ' ') i++;
|
|
||||||
|
|
||||||
x = 0;
|
|
||||||
y += 14;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// shadow
|
|
||||||
for (y = 0; y < h; y++)
|
|
||||||
{
|
|
||||||
for (x = 0; x < w; x++)
|
|
||||||
{
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
val = item->Bitmap[(y * w) + x];
|
|
||||||
if ((val >> 24) == 0xFF) continue;
|
|
||||||
|
|
||||||
if (x > 0) val = item->Bitmap[(y * w) + x-1];
|
|
||||||
if (x < w-1) val |= item->Bitmap[(y * w) + x+1];
|
|
||||||
if (y > 0)
|
|
||||||
{
|
|
||||||
if (x > 0) val |= item->Bitmap[((y-1) * w) + x-1];
|
|
||||||
val |= item->Bitmap[((y-1) * w) + x];
|
|
||||||
if (x < w-1) val |= item->Bitmap[((y-1) * w) + x+1];
|
|
||||||
}
|
|
||||||
if (y < h-1)
|
|
||||||
{
|
|
||||||
if (x > 0) val |= item->Bitmap[((y+1) * w) + x-1];
|
|
||||||
val |= item->Bitmap[((y+1) * w) + x];
|
|
||||||
if (x < w-1) val |= item->Bitmap[((y+1) * w) + x+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((val >> 24) == 0xFF)
|
|
||||||
item->Bitmap[(y * w) + x] = shadow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AddMessage(u32 color, const char* text)
|
|
||||||
{
|
|
||||||
if (!Config::ShowOSD) return;
|
|
||||||
|
|
||||||
Rendering.lock();
|
|
||||||
|
|
||||||
Item item;
|
|
||||||
|
|
||||||
item.Timestamp = SDL_GetTicks();
|
|
||||||
strncpy(item.Text, text, 255); item.Text[255] = '\0';
|
|
||||||
item.Color = color;
|
|
||||||
item.Bitmap = nullptr;
|
|
||||||
|
|
||||||
item.NativeBitmapLoaded = false;
|
|
||||||
item.GLTextureLoaded = false;
|
|
||||||
|
|
||||||
ItemQueue.push_back(item);
|
|
||||||
|
|
||||||
Rendering.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update()
|
|
||||||
{
|
|
||||||
if (!Config::ShowOSD)
|
|
||||||
{
|
|
||||||
Rendering.lock();
|
|
||||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
|
||||||
{
|
|
||||||
Item& item = *it;
|
|
||||||
|
|
||||||
if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
|
|
||||||
if (item.Bitmap) delete[] item.Bitmap;
|
|
||||||
|
|
||||||
it = ItemQueue.erase(it);
|
|
||||||
}
|
|
||||||
Rendering.unlock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rendering.lock();
|
|
||||||
|
|
||||||
Uint32 tick_now = SDL_GetTicks();
|
|
||||||
Uint32 tick_min = tick_now - 2500;
|
|
||||||
|
|
||||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
|
||||||
{
|
|
||||||
Item& item = *it;
|
|
||||||
|
|
||||||
if (item.Timestamp < tick_min)
|
|
||||||
{
|
|
||||||
if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
|
|
||||||
if (item.Bitmap) delete[] item.Bitmap;
|
|
||||||
|
|
||||||
it = ItemQueue.erase(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item.Bitmap)
|
|
||||||
{
|
|
||||||
RenderText(item.Color, item.Text, &item);
|
|
||||||
}
|
|
||||||
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rendering.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawNative(QPainter& painter)
|
|
||||||
{
|
|
||||||
if (!Config::ShowOSD) return;
|
|
||||||
|
|
||||||
Rendering.lock();
|
|
||||||
|
|
||||||
u32 y = kOSDMargin;
|
|
||||||
|
|
||||||
painter.resetTransform();
|
|
||||||
|
|
||||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
|
||||||
{
|
|
||||||
Item& item = *it;
|
|
||||||
|
|
||||||
if (!item.NativeBitmapLoaded)
|
|
||||||
{
|
|
||||||
item.NativeBitmap = QImage((const uchar*)item.Bitmap, item.Width, item.Height, QImage::Format_ARGB32_Premultiplied);
|
|
||||||
item.NativeBitmapLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
painter.drawImage(kOSDMargin, y, item.NativeBitmap);
|
|
||||||
|
|
||||||
y += item.Height;
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rendering.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawGL(float w, float h, float factor)
|
|
||||||
{
|
|
||||||
if (!Config::ShowOSD) return;
|
|
||||||
if (!mainWindow || !mainWindow->panel) return;
|
|
||||||
|
|
||||||
Rendering.lock();
|
|
||||||
|
|
||||||
u32 y = kOSDMargin;
|
|
||||||
|
|
||||||
glUseProgram(Shader[2]);
|
|
||||||
|
|
||||||
glUniform2f(uScreenSize, w, h);
|
|
||||||
glUniform1f(uScaleFactor, factor);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
|
|
||||||
glBindVertexArray(OSDVertexArray);
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
|
||||||
{
|
|
||||||
Item& item = *it;
|
|
||||||
|
|
||||||
if (!item.GLTextureLoaded)
|
|
||||||
{
|
|
||||||
glGenTextures(1, &item.GLTexture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, item.GLTexture);
|
|
||||||
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, item.Width, item.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, item.Bitmap);
|
|
||||||
|
|
||||||
item.GLTextureLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, item.GLTexture);
|
|
||||||
glUniform2i(uOSDPos, kOSDMargin, y);
|
|
||||||
glUniform2i(uOSDSize, item.Width, item.Height);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 2*3);
|
|
||||||
|
|
||||||
y += item.Height;
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glUseProgram(0);
|
|
||||||
|
|
||||||
Rendering.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2016-2023 melonDS team
|
|
||||||
|
|
||||||
This file is part of melonDS.
|
|
||||||
|
|
||||||
melonDS is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free
|
|
||||||
Software Foundation, either version 3 of the License, or (at your option)
|
|
||||||
any later version.
|
|
||||||
|
|
||||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OSD_H
|
|
||||||
#define OSD_H
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
namespace OSD
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace melonDS;
|
|
||||||
bool Init(bool openGL);
|
|
||||||
void DeInit();
|
|
||||||
|
|
||||||
void AddMessage(u32 color, const char* text);
|
|
||||||
|
|
||||||
void Update();
|
|
||||||
void DrawNative(QPainter& painter);
|
|
||||||
void DrawGL(float w, float h, float factor);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // OSD_H
|
|
|
@ -39,7 +39,6 @@
|
||||||
#include "LAN_Socket.h"
|
#include "LAN_Socket.h"
|
||||||
#include "LAN_PCap.h"
|
#include "LAN_PCap.h"
|
||||||
#include "LocalMP.h"
|
#include "LocalMP.h"
|
||||||
#include "OSD.h"
|
|
||||||
#include "SPI_Firmware.h"
|
#include "SPI_Firmware.h"
|
||||||
|
|
||||||
#ifdef __WIN32__
|
#ifdef __WIN32__
|
||||||
|
@ -53,6 +52,10 @@ extern CameraManager* camManager[2];
|
||||||
|
|
||||||
void emuStop();
|
void emuStop();
|
||||||
|
|
||||||
|
// TEMP
|
||||||
|
//#include "main.h"
|
||||||
|
//extern MainWindow* mainWindow;
|
||||||
|
|
||||||
|
|
||||||
namespace melonDS::Platform
|
namespace melonDS::Platform
|
||||||
{
|
{
|
||||||
|
@ -177,14 +180,14 @@ void SignalStop(StopReason reason)
|
||||||
{
|
{
|
||||||
case StopReason::GBAModeNotSupported:
|
case StopReason::GBAModeNotSupported:
|
||||||
Log(LogLevel::Error, "!! GBA MODE NOT SUPPORTED\n");
|
Log(LogLevel::Error, "!! GBA MODE NOT SUPPORTED\n");
|
||||||
OSD::AddMessage(0xFFA0A0, "GBA mode not supported.");
|
//mainWindow->osdAddMessage(0xFFA0A0, "GBA mode not supported.");
|
||||||
break;
|
break;
|
||||||
case StopReason::BadExceptionRegion:
|
case StopReason::BadExceptionRegion:
|
||||||
OSD::AddMessage(0xFFA0A0, "Internal error.");
|
//mainWindow->osdAddMessage(0xFFA0A0, "Internal error.");
|
||||||
break;
|
break;
|
||||||
case StopReason::PowerOff:
|
case StopReason::PowerOff:
|
||||||
case StopReason::External:
|
case StopReason::External:
|
||||||
OSD::AddMessage(0xFFC040, "Shutdown");
|
//mainWindow->osdAddMessage(0xFFC040, "Shutdown");
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <qpa/qplatformnativeinterface.h>
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
#include "OpenGLSupport.h"
|
#include "OpenGLSupport.h"
|
||||||
#include "duckstation/gl/context.h"
|
#include "duckstation/gl/context.h"
|
||||||
|
@ -49,8 +50,8 @@
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "main_shaders.h"
|
#include "main_shaders.h"
|
||||||
|
#include "OSD_shaders.h"
|
||||||
#include "OSD.h"
|
#include "font.h"
|
||||||
|
|
||||||
using namespace melonDS;
|
using namespace melonDS;
|
||||||
|
|
||||||
|
@ -64,23 +65,31 @@ extern int autoScreenSizing;
|
||||||
extern int videoRenderer;
|
extern int videoRenderer;
|
||||||
extern bool videoSettingsDirty;
|
extern bool videoSettingsDirty;
|
||||||
|
|
||||||
|
const u32 kOSDMargin = 6;
|
||||||
|
|
||||||
ScreenHandler::ScreenHandler(QWidget* widget)
|
|
||||||
|
ScreenPanel::ScreenPanel(QWidget* parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
widget->setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
widget->setAttribute(Qt::WA_AcceptTouchEvents);
|
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||||
QTimer* mouseTimer = setupMouseTimer();
|
QTimer* mouseTimer = setupMouseTimer();
|
||||||
widget->connect(mouseTimer, &QTimer::timeout, [=] { if (Config::MouseHide) widget->setCursor(Qt::BlankCursor);});
|
connect(mouseTimer, &QTimer::timeout, [=] { if (Config::MouseHide) setCursor(Qt::BlankCursor);});
|
||||||
|
|
||||||
|
osdEnabled = false;
|
||||||
|
osdID = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenHandler::~ScreenHandler()
|
ScreenPanel::~ScreenPanel()
|
||||||
{
|
{
|
||||||
mouseTimer->stop();
|
mouseTimer->stop();
|
||||||
delete mouseTimer;
|
delete mouseTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::screenSetupLayout(int w, int h)
|
void ScreenPanel::setupScreenLayout()
|
||||||
{
|
{
|
||||||
|
int w = width();
|
||||||
|
int h = height();
|
||||||
|
|
||||||
int sizing = Config::ScreenSizing;
|
int sizing = Config::ScreenSizing;
|
||||||
if (sizing == 3) sizing = autoScreenSizing;
|
if (sizing == 3) sizing = autoScreenSizing;
|
||||||
|
|
||||||
|
@ -113,7 +122,7 @@ void ScreenHandler::screenSetupLayout(int w, int h)
|
||||||
numScreens = Frontend::GetScreenTransforms(screenMatrix[0], screenKind);
|
numScreens = Frontend::GetScreenTransforms(screenMatrix[0], screenKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize ScreenHandler::screenGetMinSize(int factor = 1)
|
QSize ScreenPanel::screenGetMinSize(int factor = 1)
|
||||||
{
|
{
|
||||||
bool isHori = (Config::ScreenRotation == Frontend::screenRot_90Deg
|
bool isHori = (Config::ScreenRotation == Frontend::screenRot_90Deg
|
||||||
|| Config::ScreenRotation == Frontend::screenRot_270Deg);
|
|| Config::ScreenRotation == Frontend::screenRot_270Deg);
|
||||||
|
@ -158,7 +167,19 @@ QSize ScreenHandler::screenGetMinSize(int factor = 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::screenOnMousePress(QMouseEvent* event)
|
void ScreenPanel::onScreenLayoutChanged()
|
||||||
|
{
|
||||||
|
setMinimumSize(screenGetMinSize());
|
||||||
|
setupScreenLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::resizeEvent(QResizeEvent* event)
|
||||||
|
{
|
||||||
|
setupScreenLayout();
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::mousePressEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
if (event->button() != Qt::LeftButton) return;
|
if (event->button() != Qt::LeftButton) return;
|
||||||
|
@ -174,7 +195,7 @@ void ScreenHandler::screenOnMousePress(QMouseEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::screenOnMouseRelease(QMouseEvent* event)
|
void ScreenPanel::mouseReleaseEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
if (event->button() != Qt::LeftButton) return;
|
if (event->button() != Qt::LeftButton) return;
|
||||||
|
@ -187,7 +208,7 @@ void ScreenHandler::screenOnMouseRelease(QMouseEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::screenOnMouseMove(QMouseEvent* event)
|
void ScreenPanel::mouseMoveEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
||||||
|
@ -206,7 +227,7 @@ void ScreenHandler::screenOnMouseMove(QMouseEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::screenHandleTablet(QTabletEvent* event)
|
void ScreenPanel::tabletEvent(QTabletEvent* event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
||||||
|
@ -239,7 +260,7 @@ void ScreenHandler::screenHandleTablet(QTabletEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::screenHandleTouch(QTouchEvent* event)
|
void ScreenPanel::touchEvent(QTouchEvent* event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
||||||
|
@ -274,13 +295,26 @@ void ScreenHandler::screenHandleTouch(QTouchEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::showCursor()
|
bool ScreenPanel::event(QEvent* event)
|
||||||
{
|
{
|
||||||
mainWindow->panelWidget->setCursor(Qt::ArrowCursor);
|
if (event->type() == QEvent::TouchBegin
|
||||||
|
|| event->type() == QEvent::TouchEnd
|
||||||
|
|| event->type() == QEvent::TouchUpdate)
|
||||||
|
{
|
||||||
|
touchEvent((QTouchEvent*)event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QWidget::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::showCursor()
|
||||||
|
{
|
||||||
|
mainWindow->panel->setCursor(Qt::ArrowCursor);
|
||||||
mouseTimer->start();
|
mouseTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
QTimer* ScreenHandler::setupMouseTimer()
|
QTimer* ScreenPanel::setupMouseTimer()
|
||||||
{
|
{
|
||||||
mouseTimer = new QTimer();
|
mouseTimer = new QTimer();
|
||||||
mouseTimer->setSingleShot(true);
|
mouseTimer->setSingleShot(true);
|
||||||
|
@ -290,35 +324,290 @@ QTimer* ScreenHandler::setupMouseTimer()
|
||||||
return mouseTimer;
|
return mouseTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenPanelNative::ScreenPanelNative(QWidget* parent) : QWidget(parent), ScreenHandler(this)
|
int ScreenPanel::osdFindBreakPoint(const char* text, int i)
|
||||||
|
{
|
||||||
|
// i = character that went out of bounds
|
||||||
|
|
||||||
|
for (int j = i; j >= 0; j--)
|
||||||
|
{
|
||||||
|
if (text[j] == ' ')
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::osdLayoutText(const char* text, int* width, int* height, int* breaks)
|
||||||
|
{
|
||||||
|
int w = 0;
|
||||||
|
int h = 14;
|
||||||
|
int totalw = 0;
|
||||||
|
int maxw = ((QWidget*)this)->width() - (kOSDMargin*2);
|
||||||
|
int lastbreak = -1;
|
||||||
|
int numbrk = 0;
|
||||||
|
u16* ptr;
|
||||||
|
|
||||||
|
memset(breaks, 0, sizeof(int)*64);
|
||||||
|
|
||||||
|
for (int i = 0; text[i] != '\0'; )
|
||||||
|
{
|
||||||
|
int glyphsize;
|
||||||
|
if (text[i] == ' ')
|
||||||
|
{
|
||||||
|
glyphsize = 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 ch = text[i];
|
||||||
|
if (ch < 0x10 || ch > 0x7E) ch = 0x7F;
|
||||||
|
|
||||||
|
ptr = &::font[(ch-0x10) << 4];
|
||||||
|
glyphsize = ptr[0];
|
||||||
|
if (!glyphsize) glyphsize = 6;
|
||||||
|
else glyphsize += 2; // space around the character
|
||||||
|
}
|
||||||
|
|
||||||
|
w += glyphsize;
|
||||||
|
if (w > maxw)
|
||||||
|
{
|
||||||
|
// wrap shit as needed
|
||||||
|
if (text[i] == ' ')
|
||||||
|
{
|
||||||
|
if (numbrk >= 64) break;
|
||||||
|
breaks[numbrk++] = i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int brk = osdFindBreakPoint(text, i);
|
||||||
|
if (brk != lastbreak) i = brk;
|
||||||
|
|
||||||
|
if (numbrk >= 64) break;
|
||||||
|
breaks[numbrk++] = i;
|
||||||
|
|
||||||
|
lastbreak = brk;
|
||||||
|
}
|
||||||
|
|
||||||
|
w = 0;
|
||||||
|
h += 14;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (w > totalw) totalw = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
*width = totalw;
|
||||||
|
*height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ScreenPanel::osdRainbowColor(int inc)
|
||||||
|
{
|
||||||
|
// inspired from Acmlmboard
|
||||||
|
|
||||||
|
if (inc < 100) return 0xFFFF9B9B + (inc << 8);
|
||||||
|
else if (inc < 200) return 0xFFFFFF9B - ((inc-100) << 16);
|
||||||
|
else if (inc < 300) return 0xFF9BFF9B + (inc-200);
|
||||||
|
else if (inc < 400) return 0xFF9BFFFF - ((inc-300) << 8);
|
||||||
|
else if (inc < 500) return 0xFF9B9BFF + ((inc-400) << 16);
|
||||||
|
else return 0xFFFF9BFF - (inc-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::osdRenderItem(OSDItem* item)
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
int breaks[64];
|
||||||
|
|
||||||
|
char* text = item->text;
|
||||||
|
u32 color = item->color;
|
||||||
|
|
||||||
|
bool rainbow = (color == 0);
|
||||||
|
u32 ticks = (u32)QDateTime::currentMSecsSinceEpoch();
|
||||||
|
u32 rainbowinc = ((text[0] * 17) + (ticks * 13)) % 600;
|
||||||
|
|
||||||
|
color |= 0xFF000000;
|
||||||
|
const u32 shadow = 0xE0000000;
|
||||||
|
|
||||||
|
osdLayoutText(text, &w, &h, breaks);
|
||||||
|
|
||||||
|
item->bitmap = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
u32* bitmap = (u32*)item->bitmap.bits();
|
||||||
|
memset(bitmap, 0, w*h*sizeof(u32));
|
||||||
|
|
||||||
|
int x = 0, y = 1;
|
||||||
|
u32 maxw = ((QWidget*)this)->width() - (kOSDMargin*2);
|
||||||
|
int curline = 0;
|
||||||
|
u16* ptr;
|
||||||
|
|
||||||
|
for (int i = 0; text[i] != '\0'; )
|
||||||
|
{
|
||||||
|
int glyphsize;
|
||||||
|
if (text[i] == ' ')
|
||||||
|
{
|
||||||
|
x += 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 ch = text[i];
|
||||||
|
if (ch < 0x10 || ch > 0x7E) ch = 0x7F;
|
||||||
|
|
||||||
|
ptr = &::font[(ch-0x10) << 4];
|
||||||
|
int glyphsize = ptr[0];
|
||||||
|
if (!glyphsize) x += 6;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x++;
|
||||||
|
|
||||||
|
if (rainbow)
|
||||||
|
{
|
||||||
|
color = osdRainbowColor(rainbowinc);
|
||||||
|
rainbowinc = (rainbowinc + 30) % 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw character
|
||||||
|
for (int cy = 0; cy < 12; cy++)
|
||||||
|
{
|
||||||
|
u16 val = ptr[4+cy];
|
||||||
|
|
||||||
|
for (int cx = 0; cx < glyphsize; cx++)
|
||||||
|
{
|
||||||
|
if (val & (1<<cx))
|
||||||
|
bitmap[((y+cy) * w) + x+cx] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x += glyphsize;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (breaks[curline] && i >= breaks[curline])
|
||||||
|
{
|
||||||
|
i = breaks[curline++];
|
||||||
|
if (text[i] == ' ') i++;
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
y += 14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
for (y = 0; y < h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < w; x++)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = bitmap[(y * w) + x];
|
||||||
|
if ((val >> 24) == 0xFF) continue;
|
||||||
|
|
||||||
|
if (x > 0) val = bitmap[(y * w) + x-1];
|
||||||
|
if (x < w-1) val |= bitmap[(y * w) + x+1];
|
||||||
|
if (y > 0)
|
||||||
|
{
|
||||||
|
if (x > 0) val |= bitmap[((y-1) * w) + x-1];
|
||||||
|
val |= bitmap[((y-1) * w) + x];
|
||||||
|
if (x < w-1) val |= bitmap[((y-1) * w) + x+1];
|
||||||
|
}
|
||||||
|
if (y < h-1)
|
||||||
|
{
|
||||||
|
if (x > 0) val |= bitmap[((y+1) * w) + x-1];
|
||||||
|
val |= bitmap[((y+1) * w) + x];
|
||||||
|
if (x < w-1) val |= bitmap[((y+1) * w) + x+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val >> 24) == 0xFF)
|
||||||
|
bitmap[(y * w) + x] = shadow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::osdDeleteItem(OSDItem* item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::osdSetEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
osdMutex.lock();
|
||||||
|
osdEnabled = enabled;
|
||||||
|
osdMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::osdAddMessage(unsigned int color, const char* text)
|
||||||
|
{
|
||||||
|
if (!osdEnabled) return;
|
||||||
|
|
||||||
|
osdMutex.lock();
|
||||||
|
|
||||||
|
OSDItem item;
|
||||||
|
|
||||||
|
item.id = osdID++;
|
||||||
|
item.timestamp = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
strncpy(item.text, text, 255); item.text[255] = '\0';
|
||||||
|
item.color = color;
|
||||||
|
item.rendered = false;
|
||||||
|
|
||||||
|
osdItems.push_back(item);
|
||||||
|
|
||||||
|
osdMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanel::osdUpdate()
|
||||||
|
{
|
||||||
|
osdMutex.lock();
|
||||||
|
|
||||||
|
qint64 tick_now = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
qint64 tick_min = tick_now - 2500;
|
||||||
|
|
||||||
|
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
||||||
|
{
|
||||||
|
OSDItem& item = *it;
|
||||||
|
|
||||||
|
if ((!osdEnabled) || (item.timestamp < tick_min))
|
||||||
|
{
|
||||||
|
osdDeleteItem(&item);
|
||||||
|
it = osdItems.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.rendered)
|
||||||
|
{
|
||||||
|
osdRenderItem(&item);
|
||||||
|
item.rendered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
osdMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ScreenPanelNative::ScreenPanelNative(QWidget* parent) : ScreenPanel(parent)
|
||||||
{
|
{
|
||||||
screen[0] = QImage(256, 192, QImage::Format_RGB32);
|
screen[0] = QImage(256, 192, QImage::Format_RGB32);
|
||||||
screen[1] = QImage(256, 192, QImage::Format_RGB32);
|
screen[1] = QImage(256, 192, QImage::Format_RGB32);
|
||||||
|
|
||||||
screenTrans[0].reset();
|
screenTrans[0].reset();
|
||||||
screenTrans[1].reset();
|
screenTrans[1].reset();
|
||||||
|
|
||||||
OSD::Init(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenPanelNative::~ScreenPanelNative()
|
ScreenPanelNative::~ScreenPanelNative()
|
||||||
{
|
{
|
||||||
OSD::DeInit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenPanelNative::setupScreenLayout()
|
void ScreenPanelNative::setupScreenLayout()
|
||||||
{
|
{
|
||||||
int w = width();
|
ScreenPanel::setupScreenLayout();
|
||||||
int h = height();
|
|
||||||
|
|
||||||
screenSetupLayout(w, h);
|
|
||||||
|
|
||||||
for (int i = 0; i < numScreens; i++)
|
for (int i = 0; i < numScreens; i++)
|
||||||
{
|
{
|
||||||
float* mtx = screenMatrix[i];
|
float* mtx = screenMatrix[i];
|
||||||
screenTrans[i].setMatrix(mtx[0], mtx[1], 0.f,
|
screenTrans[i].setMatrix(mtx[0], mtx[1], 0.f,
|
||||||
mtx[2], mtx[3], 0.f,
|
mtx[2], mtx[3], 0.f,
|
||||||
mtx[4], mtx[5], 1.f);
|
mtx[4], mtx[5], 1.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,55 +642,32 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OSD::Update();
|
osdUpdate();
|
||||||
OSD::DrawNative(painter);
|
if (osdEnabled)
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelNative::resizeEvent(QResizeEvent* event)
|
|
||||||
{
|
|
||||||
setupScreenLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelNative::mousePressEvent(QMouseEvent* event)
|
|
||||||
{
|
|
||||||
screenOnMousePress(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelNative::mouseReleaseEvent(QMouseEvent* event)
|
|
||||||
{
|
|
||||||
screenOnMouseRelease(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelNative::mouseMoveEvent(QMouseEvent* event)
|
|
||||||
{
|
|
||||||
screenOnMouseMove(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelNative::tabletEvent(QTabletEvent* event)
|
|
||||||
{
|
|
||||||
screenHandleTablet(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScreenPanelNative::event(QEvent* event)
|
|
||||||
{
|
|
||||||
if (event->type() == QEvent::TouchBegin
|
|
||||||
|| event->type() == QEvent::TouchEnd
|
|
||||||
|| event->type() == QEvent::TouchUpdate)
|
|
||||||
{
|
{
|
||||||
screenHandleTouch((QTouchEvent*)event);
|
osdMutex.lock();
|
||||||
return true;
|
|
||||||
|
u32 y = kOSDMargin;
|
||||||
|
|
||||||
|
painter.resetTransform();
|
||||||
|
|
||||||
|
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
||||||
|
{
|
||||||
|
OSDItem& item = *it;
|
||||||
|
|
||||||
|
painter.drawImage(kOSDMargin, y, item.bitmap);
|
||||||
|
|
||||||
|
y += item.bitmap.height();
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
osdMutex.unlock();
|
||||||
}
|
}
|
||||||
return QWidget::event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelNative::onScreenLayoutChanged()
|
|
||||||
{
|
|
||||||
setMinimumSize(screenGetMinSize());
|
|
||||||
setupScreenLayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ScreenPanelGL::ScreenPanelGL(QWidget* parent) : QWidget(parent), ScreenHandler(this)
|
|
||||||
|
ScreenPanelGL::ScreenPanelGL(QWidget* parent) : ScreenPanel(parent)
|
||||||
{
|
{
|
||||||
setAutoFillBackground(false);
|
setAutoFillBackground(false);
|
||||||
setAttribute(Qt::WA_NativeWindow, true);
|
setAttribute(Qt::WA_NativeWindow, true);
|
||||||
|
@ -503,7 +769,41 @@ void ScreenPanelGL::initOpenGL()
|
||||||
memset(zeroData, 0, sizeof(zeroData));
|
memset(zeroData, 0, sizeof(zeroData));
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData);
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData);
|
||||||
|
|
||||||
OSD::Init(true);
|
|
||||||
|
OpenGL::BuildShaderProgram(kScreenVS_OSD, kScreenFS_OSD, osdShader, "OSDShader");
|
||||||
|
|
||||||
|
pid = osdShader[2];
|
||||||
|
glBindAttribLocation(pid, 0, "vPosition");
|
||||||
|
glBindFragDataLocation(pid, 0, "oColor");
|
||||||
|
|
||||||
|
OpenGL::LinkShaderProgram(osdShader);
|
||||||
|
glUseProgram(pid);
|
||||||
|
glUniform1i(glGetUniformLocation(pid, "OSDTex"), 0);
|
||||||
|
|
||||||
|
osdScreenSizeULoc = glGetUniformLocation(pid, "uScreenSize");
|
||||||
|
osdPosULoc = glGetUniformLocation(pid, "uOSDPos");
|
||||||
|
osdSizeULoc = glGetUniformLocation(pid, "uOSDSize");
|
||||||
|
osdScaleFactorULoc = glGetUniformLocation(pid, "uScaleFactor");
|
||||||
|
|
||||||
|
const float osdvertices[6*2] =
|
||||||
|
{
|
||||||
|
0, 0,
|
||||||
|
1, 1,
|
||||||
|
1, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 1,
|
||||||
|
1, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
glGenBuffers(1, &osdVertexBuffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, osdVertexBuffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(osdvertices), osdvertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &osdVertexArray);
|
||||||
|
glBindVertexArray(osdVertexArray);
|
||||||
|
glEnableVertexAttribArray(0); // position
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
||||||
|
|
||||||
|
|
||||||
glContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0);
|
glContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0);
|
||||||
transferLayout();
|
transferLayout();
|
||||||
|
@ -520,13 +820,52 @@ void ScreenPanelGL::deinitOpenGL()
|
||||||
|
|
||||||
OpenGL::DeleteShaderProgram(screenShaderProgram);
|
OpenGL::DeleteShaderProgram(screenShaderProgram);
|
||||||
|
|
||||||
OSD::DeInit();
|
|
||||||
|
for (const auto& [key, tex] : osdTextures)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &tex);
|
||||||
|
}
|
||||||
|
osdTextures.clear();
|
||||||
|
|
||||||
|
glDeleteVertexArrays(1, &osdVertexArray);
|
||||||
|
glDeleteBuffers(1, &osdVertexBuffer);
|
||||||
|
|
||||||
|
OpenGL::DeleteShaderProgram(osdShader);
|
||||||
|
|
||||||
|
|
||||||
glContext->DoneCurrent();
|
glContext->DoneCurrent();
|
||||||
|
|
||||||
lastScreenWidth = lastScreenHeight = -1;
|
lastScreenWidth = lastScreenHeight = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenPanelGL::osdRenderItem(OSDItem* item)
|
||||||
|
{
|
||||||
|
ScreenPanel::osdRenderItem(item);
|
||||||
|
|
||||||
|
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, item->bitmap.width(), item->bitmap.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, item->bitmap.bits());
|
||||||
|
|
||||||
|
osdTextures[item->id] = tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenPanelGL::osdDeleteItem(OSDItem* item)
|
||||||
|
{
|
||||||
|
if (osdTextures.count(item->id))
|
||||||
|
{
|
||||||
|
GLuint tex = osdTextures[item->id];
|
||||||
|
glDeleteTextures(1, &tex);
|
||||||
|
osdTextures.erase(item->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenPanel::osdDeleteItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
void ScreenPanelGL::drawScreenGL()
|
void ScreenPanelGL::drawScreenGL()
|
||||||
{
|
{
|
||||||
if (!glContext) return;
|
if (!glContext) return;
|
||||||
|
@ -590,8 +929,47 @@ void ScreenPanelGL::drawScreenGL()
|
||||||
|
|
||||||
screenSettingsLock.unlock();
|
screenSettingsLock.unlock();
|
||||||
|
|
||||||
OSD::Update();
|
osdUpdate();
|
||||||
OSD::DrawGL(w, h, factor);
|
if (osdEnabled)
|
||||||
|
{
|
||||||
|
osdMutex.lock();
|
||||||
|
|
||||||
|
u32 y = kOSDMargin;
|
||||||
|
|
||||||
|
glUseProgram(osdShader[2]);
|
||||||
|
|
||||||
|
glUniform2f(osdScreenSizeULoc, w, h);
|
||||||
|
glUniform1f(osdScaleFactorULoc, factor);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, osdVertexBuffer);
|
||||||
|
glBindVertexArray(osdVertexArray);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
||||||
|
{
|
||||||
|
OSDItem& item = *it;
|
||||||
|
|
||||||
|
if (!osdTextures.count(item.id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, osdTextures[item.id]);
|
||||||
|
glUniform2i(osdPosULoc, kOSDMargin, y);
|
||||||
|
glUniform2i(osdSizeULoc, item.bitmap.width(), item.bitmap.height());
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 2*3);
|
||||||
|
|
||||||
|
y += item.bitmap.height();
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
|
osdMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
glContext->SwapBuffers();
|
glContext->SwapBuffers();
|
||||||
}
|
}
|
||||||
|
@ -667,52 +1045,10 @@ QPaintEngine* ScreenPanelGL::paintEngine() const
|
||||||
|
|
||||||
void ScreenPanelGL::setupScreenLayout()
|
void ScreenPanelGL::setupScreenLayout()
|
||||||
{
|
{
|
||||||
int w = width();
|
ScreenPanel::setupScreenLayout();
|
||||||
int h = height();
|
|
||||||
|
|
||||||
screenSetupLayout(w, h);
|
|
||||||
transferLayout();
|
transferLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenPanelGL::resizeEvent(QResizeEvent* event)
|
|
||||||
{
|
|
||||||
setupScreenLayout();
|
|
||||||
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelGL::mousePressEvent(QMouseEvent* event)
|
|
||||||
{
|
|
||||||
screenOnMousePress(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelGL::mouseReleaseEvent(QMouseEvent* event)
|
|
||||||
{
|
|
||||||
screenOnMouseRelease(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelGL::mouseMoveEvent(QMouseEvent* event)
|
|
||||||
{
|
|
||||||
screenOnMouseMove(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelGL::tabletEvent(QTabletEvent* event)
|
|
||||||
{
|
|
||||||
screenHandleTablet(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScreenPanelGL::event(QEvent* event)
|
|
||||||
{
|
|
||||||
if (event->type() == QEvent::TouchBegin
|
|
||||||
|| event->type() == QEvent::TouchEnd
|
|
||||||
|| event->type() == QEvent::TouchUpdate)
|
|
||||||
{
|
|
||||||
screenHandleTouch((QTouchEvent*)event);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return QWidget::event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenPanelGL::transferLayout()
|
void ScreenPanelGL::transferLayout()
|
||||||
{
|
{
|
||||||
std::optional<WindowInfo> windowInfo = getWindowInfo();
|
std::optional<WindowInfo> windowInfo = getWindowInfo();
|
||||||
|
@ -734,9 +1070,3 @@ void ScreenPanelGL::transferLayout()
|
||||||
screenSettingsLock.unlock();
|
screenSettingsLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenPanelGL::onScreenLayoutChanged()
|
|
||||||
{
|
|
||||||
setMinimumSize(screenGetMinSize());
|
|
||||||
setupScreenLayout();
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,21 +20,20 @@
|
||||||
#define SCREEN_H
|
#define SCREEN_H
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <deque>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
#include "FrontendUtil.h"
|
#include "FrontendUtil.h"
|
||||||
#include "duckstation/gl/context.h"
|
#include "duckstation/gl/context.h"
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QWindow>
|
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QActionGroup>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QScreen>
|
|
||||||
#include <QCloseEvent>
|
|
||||||
|
|
||||||
|
|
||||||
class EmuThread;
|
class EmuThread;
|
||||||
|
|
||||||
|
@ -50,27 +49,54 @@ const struct { int id; float ratio; const char* label; } aspectRatios[] =
|
||||||
constexpr int AspectRatiosNum = sizeof(aspectRatios) / sizeof(aspectRatios[0]);
|
constexpr int AspectRatiosNum = sizeof(aspectRatios) / sizeof(aspectRatios[0]);
|
||||||
|
|
||||||
|
|
||||||
class ScreenHandler
|
class ScreenPanel : public QWidget
|
||||||
{
|
{
|
||||||
Q_GADGET
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScreenHandler(QWidget* widget);
|
explicit ScreenPanel(QWidget* parent);
|
||||||
virtual ~ScreenHandler();
|
virtual ~ScreenPanel();
|
||||||
|
|
||||||
QTimer* setupMouseTimer();
|
QTimer* setupMouseTimer();
|
||||||
void updateMouseTimer();
|
void updateMouseTimer();
|
||||||
QTimer* mouseTimer;
|
QTimer* mouseTimer;
|
||||||
QSize screenGetMinSize(int factor);
|
QSize screenGetMinSize(int factor);
|
||||||
|
|
||||||
|
void osdSetEnabled(bool enabled);
|
||||||
|
void osdAddMessage(unsigned int color, const char* msg);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onScreenLayoutChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void screenSetupLayout(int w, int h);
|
struct OSDItem
|
||||||
|
{
|
||||||
|
unsigned int id;
|
||||||
|
qint64 timestamp;
|
||||||
|
|
||||||
void screenOnMousePress(QMouseEvent* event);
|
char text[256];
|
||||||
void screenOnMouseRelease(QMouseEvent* event);
|
unsigned int color;
|
||||||
void screenOnMouseMove(QMouseEvent* event);
|
|
||||||
|
|
||||||
void screenHandleTablet(QTabletEvent* event);
|
bool rendered;
|
||||||
void screenHandleTouch(QTouchEvent* event);
|
QImage bitmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
QMutex osdMutex;
|
||||||
|
bool osdEnabled;
|
||||||
|
unsigned int osdID;
|
||||||
|
std::deque<OSDItem> osdItems;
|
||||||
|
|
||||||
|
virtual void setupScreenLayout();
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
|
void tabletEvent(QTabletEvent* event) override;
|
||||||
|
void touchEvent(QTouchEvent* event);
|
||||||
|
bool event(QEvent* event) override;
|
||||||
|
|
||||||
float screenMatrix[Frontend::MaxScreenTransforms][6];
|
float screenMatrix[Frontend::MaxScreenTransforms][6];
|
||||||
int screenKind[Frontend::MaxScreenTransforms];
|
int screenKind[Frontend::MaxScreenTransforms];
|
||||||
|
@ -79,10 +105,19 @@ protected:
|
||||||
bool touching = false;
|
bool touching = false;
|
||||||
|
|
||||||
void showCursor();
|
void showCursor();
|
||||||
|
|
||||||
|
int osdFindBreakPoint(const char* text, int i);
|
||||||
|
void osdLayoutText(const char* text, int* width, int* height, int* breaks);
|
||||||
|
unsigned int osdRainbowColor(int inc);
|
||||||
|
|
||||||
|
virtual void osdRenderItem(OSDItem* item);
|
||||||
|
virtual void osdDeleteItem(OSDItem* item);
|
||||||
|
|
||||||
|
void osdUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ScreenPanelNative : public QWidget, public ScreenHandler
|
class ScreenPanelNative : public ScreenPanel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -93,26 +128,15 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent* event) override;
|
|
||||||
|
|
||||||
void tabletEvent(QTabletEvent* event) override;
|
|
||||||
bool event(QEvent* event) override;
|
|
||||||
private slots:
|
|
||||||
void onScreenLayoutChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupScreenLayout();
|
void setupScreenLayout() override;
|
||||||
|
|
||||||
QImage screen[2];
|
QImage screen[2];
|
||||||
QTransform screenTrans[Frontend::MaxScreenTransforms];
|
QTransform screenTrans[Frontend::MaxScreenTransforms];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ScreenPanelGL : public QWidget, public ScreenHandler
|
class ScreenPanelGL : public ScreenPanel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -141,20 +165,8 @@ protected:
|
||||||
|
|
||||||
QPaintEngine* paintEngine() const override;
|
QPaintEngine* paintEngine() const override;
|
||||||
|
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event) override;
|
|
||||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent* event) override;
|
|
||||||
|
|
||||||
void tabletEvent(QTabletEvent* event) override;
|
|
||||||
bool event(QEvent* event) override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onScreenLayoutChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupScreenLayout();
|
void setupScreenLayout() override;
|
||||||
|
|
||||||
std::unique_ptr<GL::Context> glContext;
|
std::unique_ptr<GL::Context> glContext;
|
||||||
|
|
||||||
|
@ -168,6 +180,16 @@ private:
|
||||||
bool filter;
|
bool filter;
|
||||||
|
|
||||||
int lastScreenWidth = -1, lastScreenHeight = -1;
|
int lastScreenWidth = -1, lastScreenHeight = -1;
|
||||||
|
|
||||||
|
GLuint osdShader[3];
|
||||||
|
GLint osdScreenSizeULoc, osdPosULoc, osdSizeULoc;
|
||||||
|
GLfloat osdScaleFactorULoc;
|
||||||
|
GLuint osdVertexArray;
|
||||||
|
GLuint osdVertexBuffer;
|
||||||
|
std::map<unsigned int, GLuint> osdTextures;
|
||||||
|
|
||||||
|
void osdRenderItem(OSDItem* item) override;
|
||||||
|
void osdDeleteItem(OSDItem* item) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SCREEN_H
|
#endif // SCREEN_H
|
||||||
|
|
|
@ -81,8 +81,6 @@
|
||||||
#include "ArchiveUtil.h"
|
#include "ArchiveUtil.h"
|
||||||
#include "CameraManager.h"
|
#include "CameraManager.h"
|
||||||
|
|
||||||
#include "OSD.h"
|
|
||||||
|
|
||||||
using namespace melonDS;
|
using namespace melonDS;
|
||||||
|
|
||||||
// TEMP
|
// TEMP
|
||||||
|
@ -689,13 +687,13 @@ void MainWindow::osdAddMessage(unsigned int color, const char* fmt, ...)
|
||||||
if (fmt == nullptr)
|
if (fmt == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char msg[1024];
|
char msg[256];
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(msg, 1024, fmt, args);
|
vsnprintf(msg, 256, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
OSD::AddMessage(color, msg);
|
panel->osdAddMessage(color, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent* event)
|
void MainWindow::closeEvent(QCloseEvent* event)
|
||||||
|
@ -720,7 +718,6 @@ void MainWindow::createScreenPanel()
|
||||||
panelGL->show();
|
panelGL->show();
|
||||||
|
|
||||||
panel = panelGL;
|
panel = panelGL;
|
||||||
panelWidget = panelGL;
|
|
||||||
|
|
||||||
panelGL->createContext();
|
panelGL->createContext();
|
||||||
}
|
}
|
||||||
|
@ -729,14 +726,14 @@ void MainWindow::createScreenPanel()
|
||||||
{
|
{
|
||||||
ScreenPanelNative* panelNative = new ScreenPanelNative(this);
|
ScreenPanelNative* panelNative = new ScreenPanelNative(this);
|
||||||
panel = panelNative;
|
panel = panelNative;
|
||||||
panelWidget = panelNative;
|
panel->show();
|
||||||
panelWidget->show();
|
|
||||||
}
|
}
|
||||||
setCentralWidget(panelWidget);
|
setCentralWidget(panel);
|
||||||
|
|
||||||
actScreenFiltering->setEnabled(hasOGL);
|
actScreenFiltering->setEnabled(hasOGL);
|
||||||
|
panel->osdSetEnabled(Config::ShowOSD);
|
||||||
|
|
||||||
connect(this, SIGNAL(screenLayoutChange()), panelWidget, SLOT(onScreenLayoutChanged()));
|
connect(this, SIGNAL(screenLayoutChange()), panel, SLOT(onScreenLayoutChanged()));
|
||||||
emit screenLayoutChange();
|
emit screenLayoutChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1866,7 +1863,7 @@ void MainWindow::onChangeSavestateSRAMReloc(bool checked)
|
||||||
void MainWindow::onChangeScreenSize()
|
void MainWindow::onChangeScreenSize()
|
||||||
{
|
{
|
||||||
int factor = ((QAction*)sender())->data().toInt();
|
int factor = ((QAction*)sender())->data().toInt();
|
||||||
QSize diff = size() - panelWidget->size();
|
QSize diff = size() - panel->size();
|
||||||
resize(panel->screenGetMinSize(factor) + diff);
|
resize(panel->screenGetMinSize(factor) + diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1959,7 +1956,9 @@ void MainWindow::onChangeScreenFiltering(bool checked)
|
||||||
void MainWindow::onChangeShowOSD(bool checked)
|
void MainWindow::onChangeShowOSD(bool checked)
|
||||||
{
|
{
|
||||||
Config::ShowOSD = checked?1:0;
|
Config::ShowOSD = checked?1:0;
|
||||||
|
panel->osdSetEnabled(Config::ShowOSD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onChangeLimitFramerate(bool checked)
|
void MainWindow::onChangeLimitFramerate(bool checked)
|
||||||
{
|
{
|
||||||
Config::LimitFPS = checked?1:0;
|
Config::LimitFPS = checked?1:0;
|
||||||
|
@ -2065,7 +2064,7 @@ void MainWindow::onUpdateVideoSettings(bool glchange)
|
||||||
|
|
||||||
delete panel;
|
delete panel;
|
||||||
createScreenPanel();
|
createScreenPanel();
|
||||||
connect(emuThread, SIGNAL(windowUpdate()), panelWidget, SLOT(repaint()));
|
connect(emuThread, SIGNAL(windowUpdate()), panel, SLOT(repaint()));
|
||||||
}
|
}
|
||||||
|
|
||||||
videoSettingsDirty = true;
|
videoSettingsDirty = true;
|
||||||
|
|
|
@ -92,8 +92,7 @@ private:
|
||||||
bool oldMax;
|
bool oldMax;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScreenHandler* panel;
|
ScreenPanel* panel;
|
||||||
QWidget* panelWidget;
|
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
|
@ -230,8 +229,7 @@ private:
|
||||||
bool oldMax;
|
bool oldMax;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScreenHandler* panel;
|
ScreenPanel* panel;
|
||||||
QWidget* panelWidget;
|
|
||||||
|
|
||||||
QAction* actOpenROM;
|
QAction* actOpenROM;
|
||||||
QAction* actBootFirmware;
|
QAction* actBootFirmware;
|
||||||
|
|
|
@ -79,7 +79,6 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#include "FrontendUtil.h"
|
#include "FrontendUtil.h"
|
||||||
#include "OSD.h"
|
|
||||||
|
|
||||||
#include "Args.h"
|
#include "Args.h"
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
|
|
Loading…
Reference in New Issue