/* 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 SCREEN_H #define SCREEN_H #include #include #include #include #include #include #include #include #include #include "glad/glad.h" #include "FrontendUtil.h" #include "duckstation/gl/context.h" class EmuThread; const struct { int id; float ratio; const char* label; } aspectRatios[] = { { 0, 1, "4:3 (native)" }, { 4, (5.f / 3) / (4.f / 3), "5:3 (3DS)"}, { 1, (16.f / 9) / (4.f / 3), "16:9" }, { 2, (21.f / 9) / (4.f / 3), "21:9" }, { 3, 0, "window" } }; constexpr int AspectRatiosNum = sizeof(aspectRatios) / sizeof(aspectRatios[0]); class ScreenPanel : public QWidget { Q_OBJECT public: explicit ScreenPanel(QWidget* parent); virtual ~ScreenPanel(); QTimer* setupMouseTimer(); void updateMouseTimer(); QTimer* mouseTimer; QSize screenGetMinSize(int factor); void osdSetEnabled(bool enabled); void osdAddMessage(unsigned int color, const char* msg); private slots: void onScreenLayoutChanged(); protected: struct OSDItem { unsigned int id; qint64 timestamp; char text[256]; unsigned int color; bool rendered; QImage bitmap; }; QMutex osdMutex; bool osdEnabled; unsigned int osdID; std::deque 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]; int screenKind[Frontend::MaxScreenTransforms]; int numScreens; bool touching = false; 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 ScreenPanel { Q_OBJECT public: explicit ScreenPanelNative(QWidget* parent); virtual ~ScreenPanelNative(); protected: void paintEvent(QPaintEvent* event) override; private: void setupScreenLayout() override; QImage screen[2]; QTransform screenTrans[Frontend::MaxScreenTransforms]; }; class ScreenPanelGL : public ScreenPanel { Q_OBJECT public: explicit ScreenPanelGL(QWidget* parent); virtual ~ScreenPanelGL(); std::optional getWindowInfo(); bool createContext(); void setSwapInterval(int intv); void initOpenGL(); void deinitOpenGL(); void drawScreenGL(); GL::Context* getContext() { return glContext.get(); } void transferLayout(); protected: qreal devicePixelRatioFromScreen() const; int scaledWindowWidth() const; int scaledWindowHeight() const; QPaintEngine* paintEngine() const override; private: void setupScreenLayout() override; std::unique_ptr glContext; GLuint screenVertexBuffer, screenVertexArray; GLuint screenTexture; GLuint screenShaderProgram[3]; GLuint screenShaderTransformULoc, screenShaderScreenSizeULoc; QMutex screenSettingsLock; WindowInfo windowInfo; bool filter; int lastScreenWidth = -1, lastScreenHeight = -1; GLuint osdShader[3]; GLint osdScreenSizeULoc, osdPosULoc, osdSizeULoc; GLfloat osdScaleFactorULoc; GLuint osdVertexArray; GLuint osdVertexBuffer; std::map osdTextures; void osdRenderItem(OSDItem* item) override; void osdDeleteItem(OSDItem* item) override; }; #endif // SCREEN_H