Refactored the rendering code into proper classes.

This commit is contained in:
Leon Styhre 2022-03-14 19:51:48 +01:00
parent 4f21d94aa5
commit f0c35d8509
66 changed files with 1614 additions and 1457 deletions

View file

@ -1163,7 +1163,7 @@ void FileData::launchGame()
// flickering and to avoid showing the game launch message briefly when returning // flickering and to avoid showing the game launch message briefly when returning
// from the game. // from the game.
if (!runInBackground) if (!runInBackground)
Renderer::swapBuffers(); Renderer::getInstance()->swapBuffers();
Scripting::fireEvent("game-start", romPath, getSourceFileData()->metadata.get("name"), Scripting::fireEvent("game-start", romPath, getSourceFileData()->metadata.get("name"),
getSourceFileData()->getSystem()->getName(), getSourceFileData()->getSystem()->getName(),

View file

@ -13,7 +13,8 @@
#include "views/ViewController.h" #include "views/ViewController.h"
MediaViewer::MediaViewer() MediaViewer::MediaViewer()
: mVideo {nullptr} : mRenderer {Renderer::getInstance()}
, mVideo {nullptr}
, mImage {nullptr} , mImage {nullptr}
{ {
Window::getInstance()->setMediaViewer(this); Window::getInstance()->setMediaViewer(this);
@ -77,10 +78,10 @@ void MediaViewer::update(int deltaTime)
void MediaViewer::render(const glm::mat4& /*parentTrans*/) void MediaViewer::render(const glm::mat4& /*parentTrans*/)
{ {
glm::mat4 trans {Renderer::getIdentity()}; glm::mat4 trans {Renderer::getIdentity()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
// Render a black background below the game media. // Render a black background below the game media.
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
0x000000FF, 0x000000FF); 0x000000FF, 0x000000FF);
if (mVideo && !mDisplayingImage) { if (mVideo && !mDisplayingImage) {
@ -112,17 +113,17 @@ void MediaViewer::render(const glm::mat4& /*parentTrans*/)
} }
if (shaders != 0) if (shaders != 0)
Renderer::shaderPostprocessing(shaders, videoParameters); mRenderer->shaderPostprocessing(shaders, videoParameters);
} }
else if (mImage && mImage->hasImage() && mImage->getSize() != glm::vec2 {}) { else if (mImage && mImage->hasImage() && mImage->getSize() != glm::vec2 {}) {
mImage->render(trans); mImage->render(trans);
if (mCurrentImageIndex == mScreenshotIndex && if (mCurrentImageIndex == mScreenshotIndex &&
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines")) Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"))
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); mRenderer->shaderPostprocessing(Renderer::SHADER_SCANLINES);
else if (mCurrentImageIndex == mTitleScreenIndex && else if (mCurrentImageIndex == mTitleScreenIndex &&
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines")) Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"))
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); mRenderer->shaderPostprocessing(Renderer::SHADER_SCANLINES);
// This is necessary so that the video loops if viewing an image when // This is necessary so that the video loops if viewing an image when
// the video ends. // the video ends.

View file

@ -36,6 +36,7 @@ private:
void showNext() override; void showNext() override;
void showPrevious() override; void showPrevious() override;
Renderer* mRenderer;
FileData* mGame; FileData* mGame;
bool mHasVideo; bool mHasVideo;

View file

@ -30,7 +30,8 @@
#define FADE_TIME 300.0f #define FADE_TIME 300.0f
Screensaver::Screensaver() Screensaver::Screensaver()
: mWindow {Window::getInstance()} : mRenderer {Renderer::getInstance()}
, mWindow {Window::getInstance()}
, mState {STATE_INACTIVE} , mState {STATE_INACTIVE}
, mImageScreensaver {nullptr} , mImageScreensaver {nullptr}
, mVideoScreensaver {nullptr} , mVideoScreensaver {nullptr}
@ -238,11 +239,11 @@ void Screensaver::renderScreensaver()
{ {
std::string screensaverType = Settings::getInstance()->getString("ScreensaverType"); std::string screensaverType = Settings::getInstance()->getString("ScreensaverType");
glm::mat4 trans {Renderer::getIdentity()}; glm::mat4 trans {Renderer::getIdentity()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (mVideoScreensaver && screensaverType == "video") { if (mVideoScreensaver && screensaverType == "video") {
// Render a black background below the video. // Render a black background below the video.
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
0x000000FF, 0x000000FF); 0x000000FF, 0x000000FF);
// Only render the video if the state requires it. // Only render the video if the state requires it.
@ -251,7 +252,7 @@ void Screensaver::renderScreensaver()
} }
else if (mImageScreensaver && screensaverType == "slideshow") { else if (mImageScreensaver && screensaverType == "slideshow") {
// Render a black background below the image. // Render a black background below the image.
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
0x000000FF, 0x000000FF); 0x000000FF, 0x000000FF);
// Only render the image if the state requires it. // Only render the image if the state requires it.
@ -268,11 +269,11 @@ void Screensaver::renderScreensaver()
if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") { if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") {
if (mHasMediaFiles) { if (mHasMediaFiles) {
if (Settings::getInstance()->getBool("ScreensaverSlideshowScanlines")) if (Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"))
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); mRenderer->shaderPostprocessing(Renderer::SHADER_SCANLINES);
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo") && if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo") &&
mGameOverlay) { mGameOverlay) {
if (mGameOverlayRectangleCoords.size() == 4) { if (mGameOverlayRectangleCoords.size() == 4) {
Renderer::drawRect( mRenderer->drawRect(
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3], mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn); 0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
@ -319,11 +320,11 @@ void Screensaver::renderScreensaver()
} }
if (shaders != 0) if (shaders != 0)
Renderer::shaderPostprocessing(shaders, videoParameters); mRenderer->shaderPostprocessing(shaders, videoParameters);
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) { if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) {
if (mGameOverlayRectangleCoords.size() == 4) { if (mGameOverlayRectangleCoords.size() == 4) {
Renderer::drawRect( mRenderer->drawRect(
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3], mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn); 0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
@ -347,7 +348,7 @@ void Screensaver::renderScreensaver()
Renderer::postProcessingParams dimParameters; Renderer::postProcessingParams dimParameters;
dimParameters.dimming = mDimValue; dimParameters.dimming = mDimValue;
dimParameters.saturation = mSaturationAmount; dimParameters.saturation = mSaturationAmount;
Renderer::shaderPostprocessing(Renderer::SHADER_CORE, dimParameters); mRenderer->shaderPostprocessing(Renderer::SHADER_CORE, dimParameters);
if (mDimValue > 0.63) if (mDimValue > 0.63)
mDimValue = glm::clamp(mDimValue - 0.015f, 0.68f, 1.0f); mDimValue = glm::clamp(mDimValue - 0.015f, 0.68f, 1.0f);
if (mSaturationAmount > 0.0) if (mSaturationAmount > 0.0)
@ -356,7 +357,7 @@ void Screensaver::renderScreensaver()
else if (Settings::getInstance()->getString("ScreensaverType") == "black") { else if (Settings::getInstance()->getString("ScreensaverType") == "black") {
Renderer::postProcessingParams blackParameters; Renderer::postProcessingParams blackParameters;
blackParameters.dimming = mDimValue; blackParameters.dimming = mDimValue;
Renderer::shaderPostprocessing(Renderer::SHADER_CORE, blackParameters); mRenderer->shaderPostprocessing(Renderer::SHADER_CORE, blackParameters);
if (mDimValue > 0.0) if (mDimValue > 0.0)
mDimValue = glm::clamp(mDimValue - 0.045f, 0.0f, 1.0f); mDimValue = glm::clamp(mDimValue - 0.045f, 0.0f, 1.0f);
} }
@ -567,8 +568,8 @@ void Screensaver::generateOverlayInfo()
if (mGameName == "" || mSystemName == "") if (mGameName == "" || mSystemName == "")
return; return;
float posX {Renderer::getWindowWidth() * 0.023f}; float posX {mRenderer->getWindowWidth() * 0.023f};
float posY {Renderer::getWindowHeight() * 0.02f}; float posY {mRenderer->getWindowHeight() * 0.02f};
std::string favoriteChar; std::string favoriteChar;
if (mCurrentGame && mCurrentGame->getFavorite()) if (mCurrentGame && mCurrentGame->getFavorite())
@ -595,7 +596,7 @@ void Screensaver::generateOverlayInfo()
else else
textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x; textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x;
float marginX {Renderer::getWindowWidth() * 0.01f}; float marginX {mRenderer->getWindowWidth() * 0.01f};
mGameOverlayRectangleCoords.clear(); mGameOverlayRectangleCoords.clear();
mGameOverlayRectangleCoords.push_back(posX - marginX); mGameOverlayRectangleCoords.push_back(posX - marginX);

View file

@ -58,6 +58,7 @@ private:
STATE_SCREENSAVER_ACTIVE STATE_SCREENSAVER_ACTIVE
}; };
Renderer* mRenderer;
Window* mWindow; Window* mWindow;
STATE mState; STATE mState;

View file

@ -24,6 +24,8 @@
#include "scrapers/Scraper.h" #include "scrapers/Scraper.h"
#include "views/ViewController.h" #include "views/ViewController.h"
#include <SDL2/SDL.h>
GuiGamelistOptions::GuiGamelistOptions(SystemData* system) GuiGamelistOptions::GuiGamelistOptions(SystemData* system)
: mMenu {"OPTIONS"} : mMenu {"OPTIONS"}
, mSystem {system} , mSystem {system}

View file

@ -15,7 +15,8 @@
#include "utils/StringUtil.h" #include "utils/StringUtil.h"
GuiLaunchScreen::GuiLaunchScreen() GuiLaunchScreen::GuiLaunchScreen()
: mBackground {":/graphics/frame.svg"} : mRenderer {Renderer::getInstance()}
, mBackground {":/graphics/frame.svg"}
, mGrid {nullptr} , mGrid {nullptr}
, mMarquee {nullptr} , mMarquee {nullptr}
{ {
@ -224,7 +225,7 @@ void GuiLaunchScreen::render(const glm::mat4& /*parentTrans*/)
setScale(mScaleUp); setScale(mScaleUp);
glm::mat4 trans {Renderer::getIdentity() * getTransform()}; glm::mat4 trans {Renderer::getIdentity() * getTransform()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
GuiComponent::renderChildren(trans); GuiComponent::renderChildren(trans);

View file

@ -33,6 +33,7 @@ public:
void render(const glm::mat4& parentTrans) override; void render(const glm::mat4& parentTrans) override;
private: private:
Renderer* mRenderer;
NinePatchComponent mBackground; NinePatchComponent mBackground;
ComponentGrid* mGrid; ComponentGrid* mGrid;

View file

@ -38,7 +38,8 @@
#define FAILED_VERIFICATION_RETRIES 8 #define FAILED_VERIFICATION_RETRIES 8
GuiScraperSearch::GuiScraperSearch(SearchType type, unsigned int scrapeCount) GuiScraperSearch::GuiScraperSearch(SearchType type, unsigned int scrapeCount)
: mGrid {glm::ivec2 {5, 3}} : mRenderer {Renderer::getInstance()}
, mGrid {glm::ivec2 {5, 3}}
, mSearchType {type} , mSearchType {type}
, mScrapeCount {scrapeCount} , mScrapeCount {scrapeCount}
, mRefinedSearch {false} , mRefinedSearch {false}
@ -630,10 +631,10 @@ void GuiScraperSearch::render(const glm::mat4& parentTrans)
glm::mat4 trans {parentTrans * getTransform()}; glm::mat4 trans {parentTrans * getTransform()};
renderChildren(trans); renderChildren(trans);
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x00000009, 0x00000009); mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x00000009, 0x00000009);
if (mBlockAccept) { if (mBlockAccept) {
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
mBusyAnim.render(trans); mBusyAnim.render(trans);
} }
} }

View file

@ -119,6 +119,7 @@ private:
// Resolve any metadata assets that need to be downloaded and return. // Resolve any metadata assets that need to be downloaded and return.
void returnResult(ScraperSearchResult result); void returnResult(ScraperSearchResult result);
Renderer* mRenderer;
ComponentGrid mGrid; ComponentGrid mGrid;
std::shared_ptr<TextComponent> mResultName; std::shared_ptr<TextComponent> mResultName;

View file

@ -21,6 +21,8 @@
#include "views/GamelistView.h" #include "views/GamelistView.h"
#include "views/ViewController.h" #include "views/ViewController.h"
#include <SDL2/SDL.h>
GuiSettings::GuiSettings(std::string title) GuiSettings::GuiSettings(std::string title)
: mMenu {title} : mMenu {title}
, mGoToSystem {nullptr} , mGoToSystem {nullptr}

View file

@ -57,6 +57,7 @@
namespace namespace
{ {
SDL_Event event {}; SDL_Event event {};
Renderer* renderer {nullptr};
Window* window {nullptr}; Window* window {nullptr};
int lastTime {0}; int lastTime {0};
@ -474,7 +475,7 @@ void applicationLoop()
window->update(deltaTime); window->update(deltaTime);
window->render(); window->render();
Renderer::swapBuffers(); renderer->swapBuffers();
Log::flush(); Log::flush();
#if !defined(__EMSCRIPTEN__) #if !defined(__EMSCRIPTEN__)
} }
@ -601,6 +602,7 @@ int main(int argc, char* argv[])
} }
} }
renderer = Renderer::getInstance();
window = Window::getInstance(); window = Window::getInstance();
ViewController::getInstance(); ViewController::getInstance();
CollectionSystemsManager::getInstance(); CollectionSystemsManager::getInstance();

View file

@ -18,8 +18,9 @@
GamelistView::GamelistView(FileData* root) GamelistView::GamelistView(FileData* root)
: GamelistBase {root} : GamelistBase {root}
, mLegacyMode {false} , mRenderer {Renderer::getInstance()}
, mViewStyle {ViewController::BASIC} , mViewStyle {ViewController::BASIC}
, mLegacyMode {false}
{ {
mViewStyle = ViewController::getInstance()->getState().viewstyle; mViewStyle = ViewController::getInstance()->getState().viewstyle;
@ -247,9 +248,9 @@ void GamelistView::render(const glm::mat4& parentTrans)
glm::ivec2 size {static_cast<int>(std::round(mSize.x * scaleX)), glm::ivec2 size {static_cast<int>(std::round(mSize.x * scaleX)),
static_cast<int>(std::round(mSize.y * scaleY))}; static_cast<int>(std::round(mSize.y * scaleY))};
Renderer::pushClipRect(pos, size); mRenderer->pushClipRect(pos, size);
renderChildren(trans); renderChildren(trans);
Renderer::popClipRect(); mRenderer->popClipRect();
} }
HelpStyle GamelistView::getHelpStyle() HelpStyle GamelistView::getHelpStyle()

View file

@ -102,8 +102,9 @@ private:
void legacyInitMDLabels(); void legacyInitMDLabels();
void legacyInitMDValues(); void legacyInitMDValues();
bool mLegacyMode; Renderer* mRenderer;
ViewController::GamelistViewStyle mViewStyle; ViewController::GamelistViewStyle mViewStyle;
bool mLegacyMode;
std::shared_ptr<ThemeData> mTheme; std::shared_ptr<ThemeData> mTheme;
std::vector<GuiComponent*> mThemeExtras; std::vector<GuiComponent*> mThemeExtras;

View file

@ -22,7 +22,8 @@
#endif #endif
SystemView::SystemView() SystemView::SystemView()
: mCamOffset {0.0f} : mRenderer {Renderer::getInstance()}
, mCamOffset {0.0f}
, mFadeOpacity {0.0f} , mFadeOpacity {0.0f}
, mPreviousScrollVelocity {0} , mPreviousScrollVelocity {0}
, mUpdatedGameCount {false} , mUpdatedGameCount {false}
@ -1048,7 +1049,7 @@ void SystemView::renderElements(const glm::mat4& parentTrans, bool abovePrimary)
elementTrans = glm::translate(elementTrans, elementTrans = glm::translate(elementTrans,
glm::vec3 {0.0f, (i - mCamOffset) * mSize.y, 0.0f}); glm::vec3 {0.0f, (i - mCamOffset) * mSize.y, 0.0f});
Renderer::pushClipRect( mRenderer->pushClipRect(
glm::ivec2 {static_cast<int>(glm::round(elementTrans[3].x)), glm::ivec2 {static_cast<int>(glm::round(elementTrans[3].x)),
static_cast<int>(glm::round(elementTrans[3].y))}, static_cast<int>(glm::round(elementTrans[3].y))},
glm::ivec2 {static_cast<int>(mSize.x), static_cast<int>(mSize.y)}); glm::ivec2 {static_cast<int>(mSize.x), static_cast<int>(mSize.y)});
@ -1081,7 +1082,7 @@ void SystemView::renderElements(const glm::mat4& parentTrans, bool abovePrimary)
mLegacySystemInfo->render(elementTrans); mLegacySystemInfo->render(elementTrans);
} }
Renderer::popClipRect(); mRenderer->popClipRect();
} }
} }
} }

View file

@ -108,6 +108,7 @@ private:
void legacyApplyTheme(const std::shared_ptr<ThemeData>& theme); void legacyApplyTheme(const std::shared_ptr<ThemeData>& theme);
void renderElements(const glm::mat4& parentTrans, bool abovePrimary); void renderElements(const glm::mat4& parentTrans, bool abovePrimary);
Renderer* mRenderer;
std::unique_ptr<CarouselComponent> mCarousel; std::unique_ptr<CarouselComponent> mCarousel;
std::unique_ptr<TextComponent> mLegacySystemInfo; std::unique_ptr<TextComponent> mLegacySystemInfo;
std::vector<SystemViewElements> mSystemElements; std::vector<SystemViewElements> mSystemElements;

View file

@ -31,7 +31,8 @@
#include "views/SystemView.h" #include "views/SystemView.h"
ViewController::ViewController() noexcept ViewController::ViewController() noexcept
: mNoGamesMessageBox {nullptr} : mRenderer {Renderer::getInstance()}
, mNoGamesMessageBox {nullptr}
, mCurrentView {nullptr} , mCurrentView {nullptr}
, mPreviousView {nullptr} , mPreviousView {nullptr}
, mSkipView {nullptr} , mSkipView {nullptr}
@ -201,7 +202,7 @@ void ViewController::invalidAlternativeEmulatorDialog()
void ViewController::goToStart(bool playTransition) void ViewController::goToStart(bool playTransition)
{ {
// Needed to avoid segfaults during emergency shutdown. // Needed to avoid segfaults during emergency shutdown.
if (Renderer::getSDLWindow() == nullptr) if (mRenderer->getSDLWindow() == nullptr)
return; return;
#if defined(__APPLE__) #if defined(__APPLE__)
@ -287,7 +288,7 @@ void ViewController::cancelViewTransitions()
void ViewController::stopScrolling() void ViewController::stopScrolling()
{ {
if (Renderer::getSDLWindow() == nullptr) if (mRenderer->getSDLWindow() == nullptr)
return; return;
mSystemListView->stopScrolling(); mSystemListView->stopScrolling();
@ -905,8 +906,8 @@ void ViewController::render(const glm::mat4& parentTrans)
// Fade out. // Fade out.
if (mFadeOpacity) { if (mFadeOpacity) {
unsigned int fadeColor = 0x00000000 | static_cast<unsigned char>(mFadeOpacity * 255); unsigned int fadeColor = 0x00000000 | static_cast<unsigned char>(mFadeOpacity * 255);
Renderer::setMatrix(parentTrans); mRenderer->setMatrix(parentTrans);
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
fadeColor, fadeColor); fadeColor, fadeColor);
} }
} }
@ -999,7 +1000,7 @@ void ViewController::reloadGamelistView(GamelistView* view, bool reloadTheme)
void ViewController::reloadAll() void ViewController::reloadAll()
{ {
if (Renderer::getSDLWindow() == nullptr) if (mRenderer->getSDLWindow() == nullptr)
return; return;
cancelViewTransitions(); cancelViewTransitions();

View file

@ -151,6 +151,7 @@ private:
void launch(FileData* game); void launch(FileData* game);
Renderer* mRenderer;
std::string mNoGamesErrorMessage; std::string mNoGamesErrorMessage;
std::string mRomDirectory; std::string mRomDirectory;
GuiMsgBox* mNoGamesMessageBox; GuiMsgBox* mNoGamesMessageBox;

View file

@ -74,6 +74,7 @@ set(CORE_HEADERS
# Renderers # Renderers
${CMAKE_CURRENT_SOURCE_DIR}/src/renderers/Renderer.h ${CMAKE_CURRENT_SOURCE_DIR}/src/renderers/Renderer.h
${CMAKE_CURRENT_SOURCE_DIR}/src/renderers/Renderer_GL21.h
${CMAKE_CURRENT_SOURCE_DIR}/src/renderers/Shader_GL21.h ${CMAKE_CURRENT_SOURCE_DIR}/src/renderers/Shader_GL21.h
# Resources # Resources

View file

@ -23,7 +23,8 @@
#define CLOCK_BACKGROUND_CREATION false #define CLOCK_BACKGROUND_CREATION false
Window::Window() noexcept Window::Window() noexcept
: mScreensaver {nullptr} : mRenderer {Renderer::getInstance()}
, mScreensaver {nullptr}
, mMediaViewer {nullptr} , mMediaViewer {nullptr}
, mLaunchScreen {nullptr} , mLaunchScreen {nullptr}
, mInfoPopup {nullptr} , mInfoPopup {nullptr}
@ -102,7 +103,7 @@ GuiComponent* Window::peekGui()
bool Window::init() bool Window::init()
{ {
if (!Renderer::init()) { if (!mRenderer->init()) {
LOG(LogError) << "Renderer failed to initialize."; LOG(LogError) << "Renderer failed to initialize.";
return false; return false;
} }
@ -146,7 +147,7 @@ void Window::deinit()
InputManager::getInstance().deinit(); InputManager::getInstance().deinit();
ResourceManager::getInstance().unloadAll(); ResourceManager::getInstance().unloadAll();
Renderer::deinit(); mRenderer->deinit();
} }
void Window::input(InputConfig* config, Input input) void Window::input(InputConfig* config, Input input)
@ -476,7 +477,7 @@ void Window::render()
// Also dim the background slightly. // Also dim the background slightly.
backgroundParameters.dimming = 0.60f; backgroundParameters.dimming = 0.60f;
Renderer::shaderPostprocessing(Renderer::SHADER_CORE | mRenderer->shaderPostprocessing(Renderer::SHADER_CORE |
Renderer::SHADER_BLUR_HORIZONTAL | Renderer::SHADER_BLUR_HORIZONTAL |
Renderer::SHADER_BLUR_VERTICAL, Renderer::SHADER_BLUR_VERTICAL,
backgroundParameters, &processedTexture[0]); backgroundParameters, &processedTexture[0]);
@ -484,7 +485,7 @@ void Window::render()
else { else {
// Dim the background slightly. // Dim the background slightly.
backgroundParameters.dimming = 0.60f; backgroundParameters.dimming = 0.60f;
Renderer::shaderPostprocessing(Renderer::SHADER_CORE, backgroundParameters, mRenderer->shaderPostprocessing(Renderer::SHADER_CORE, backgroundParameters,
&processedTexture[0]); &processedTexture[0]);
} }
@ -546,8 +547,8 @@ void Window::render()
// Render the quick list scrolling overlay, which is triggered in IList. // Render the quick list scrolling overlay, which is triggered in IList.
if (mListScrollOpacity != 0.0f) { if (mListScrollOpacity != 0.0f) {
Renderer::setMatrix(Renderer::getIdentity()); mRenderer->setMatrix(Renderer::getIdentity());
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
0x00000000 | static_cast<unsigned char>(mListScrollOpacity * 255.0f), 0x00000000 | static_cast<unsigned char>(mListScrollOpacity * 255.0f),
0x00000000 | static_cast<unsigned char>(mListScrollOpacity * 255.0f)); 0x00000000 | static_cast<unsigned char>(mListScrollOpacity * 255.0f));
@ -604,7 +605,7 @@ void Window::render()
mLaunchScreen->render(trans); mLaunchScreen->render(trans);
if (Settings::getInstance()->getBool("DisplayGPUStatistics") && mFrameDataText) { if (Settings::getInstance()->getBool("DisplayGPUStatistics") && mFrameDataText) {
Renderer::setMatrix(Renderer::getIdentity()); mRenderer->setMatrix(Renderer::getIdentity());
mDefaultFonts.at(1)->renderTextCache(mFrameDataText.get()); mDefaultFonts.at(1)->renderTextCache(mFrameDataText.get());
} }
} }
@ -612,8 +613,8 @@ void Window::render()
void Window::renderLoadingScreen(std::string text) void Window::renderLoadingScreen(std::string text)
{ {
glm::mat4 trans {Renderer::getIdentity()}; glm::mat4 trans {Renderer::getIdentity()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
0x000000FF, 0x000000FF); 0x000000FF, 0x000000FF);
ImageComponent splash(true); ImageComponent splash(true);
@ -629,11 +630,11 @@ void Window::renderLoadingScreen(std::string text)
float x {std::round((Renderer::getScreenWidth() - cache->metrics.size.x) / 2.0f)}; float x {std::round((Renderer::getScreenWidth() - cache->metrics.size.x) / 2.0f)};
float y {std::round(Renderer::getScreenHeight() * 0.835f)}; float y {std::round(Renderer::getScreenHeight() * 0.835f)};
trans = glm::translate(trans, glm::vec3 {x, y, 0.0f}); trans = glm::translate(trans, glm::vec3 {x, y, 0.0f});
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
font->renderTextCache(cache); font->renderTextCache(cache);
delete cache; delete cache;
Renderer::swapBuffers(); mRenderer->swapBuffers();
} }
void Window::renderListScrollOverlay(const float opacity, const std::string& text) void Window::renderListScrollOverlay(const float opacity, const std::string& text)

View file

@ -159,6 +159,7 @@ private:
// Returns true if at least one component on the stack is processing. // Returns true if at least one component on the stack is processing.
bool isProcessing(); bool isProcessing();
Renderer* mRenderer;
HelpComponent* mHelp; HelpComponent* mHelp;
ImageComponent* mBackgroundOverlay; ImageComponent* mBackgroundOverlay;
float mBackgroundOverlayOpacity; float mBackgroundOverlayOpacity;

View file

@ -17,7 +17,8 @@ ButtonComponent::ButtonComponent(const std::string& text,
const std::function<void()>& func, const std::function<void()>& func,
bool upperCase, bool upperCase,
bool flatStyle) bool flatStyle)
: mBox {":/graphics/button.svg"} : mRenderer {Renderer::getInstance()}
, mBox {":/graphics/button.svg"}
, mFont {Font::get(FONT_SIZE_MEDIUM)} , mFont {Font::get(FONT_SIZE_MEDIUM)}
, mPadding {0.0f, 0.0f, 0.0f, 0.0f} , mPadding {0.0f, 0.0f, 0.0f, 0.0f}
, mFocused {false} , mFocused {false}
@ -112,14 +113,14 @@ void ButtonComponent::render(const glm::mat4& parentTrans)
if (mFlatStyle) { if (mFlatStyle) {
if (mFocused) { if (mFocused) {
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
Renderer::drawRect(mPadding.x, mPadding.y, mSize.x - mPadding.x - mPadding.z, mRenderer->drawRect(mPadding.x, mPadding.y, mSize.x - mPadding.x - mPadding.z,
mSize.y - mPadding.y - mPadding.w, mFlatColorFocused, mSize.y - mPadding.y - mPadding.w, mFlatColorFocused,
mFlatColorFocused); mFlatColorFocused);
} }
else { else {
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
Renderer::drawRect(mPadding.x, mPadding.y, mSize.x - mPadding.x - mPadding.z, mRenderer->drawRect(mPadding.x, mPadding.y, mSize.x - mPadding.x - mPadding.z,
mSize.y - mPadding.y - mPadding.w, mFlatColorUnfocused, mSize.y - mPadding.y - mPadding.w, mFlatColorUnfocused,
mFlatColorUnfocused); mFlatColorUnfocused);
} }
@ -134,13 +135,13 @@ void ButtonComponent::render(const glm::mat4& parentTrans)
trans = glm::translate(trans, centerOffset); trans = glm::translate(trans, centerOffset);
if (Settings::getInstance()->getBool("DebugText")) { if (Settings::getInstance()->getBool("DebugText")) {
Renderer::drawRect(centerOffset.x, 0.0f, mTextCache->metrics.size.x, mSize.y, mRenderer->drawRect(centerOffset.x, 0.0f, mTextCache->metrics.size.x, mSize.y,
0x00000033, 0x00000033); 0x00000033, 0x00000033);
Renderer::drawRect(mBox.getPosition().x, 0.0f, mBox.getSize().x, mSize.y, 0x0000FF33, mRenderer->drawRect(mBox.getPosition().x, 0.0f, mBox.getSize().x, mSize.y, 0x0000FF33,
0x0000FF33); 0x0000FF33);
} }
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
mTextCache->setColor(getCurTextColor()); mTextCache->setColor(getCurTextColor());
mFont->renderTextCache(mTextCache.get()); mFont->renderTextCache(mTextCache.get());

View file

@ -50,6 +50,7 @@ private:
unsigned int getCurTextColor() const; unsigned int getCurTextColor() const;
void updateImage(); void updateImage();
Renderer* mRenderer;
NinePatchComponent mBox; NinePatchComponent mBox;
std::shared_ptr<Font> mFont; std::shared_ptr<Font> mFont;

View file

@ -21,6 +21,7 @@ namespace
CarouselComponent::CarouselComponent() CarouselComponent::CarouselComponent()
: IList<CarouselElement, SystemData*> {LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP} : IList<CarouselElement, SystemData*> {LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP}
, mRenderer {Renderer::getInstance()}
, mCamOffset {0.0f} , mCamOffset {0.0f}
, mPreviousScrollVelocity {0} , mPreviousScrollVelocity {0}
, mType {HORIZONTAL} , mType {HORIZONTAL}
@ -194,10 +195,10 @@ void CarouselComponent::render(const glm::mat4& parentTrans)
carouselTrans, glm::vec3 {mOrigin.x * mSize.x * -1.0f, mOrigin.y * mSize.y * -1.0f, 0.0f}); carouselTrans, glm::vec3 {mOrigin.x * mSize.x * -1.0f, mOrigin.y * mSize.y * -1.0f, 0.0f});
glm::vec2 clipPos {carouselTrans[3].x, carouselTrans[3].y}; glm::vec2 clipPos {carouselTrans[3].x, carouselTrans[3].y};
Renderer::setMatrix(carouselTrans); mRenderer->setMatrix(carouselTrans);
// Background box behind logos. // Background box behind logos.
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, mCarouselColor, mCarouselColorEnd, mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, mCarouselColor, mCarouselColorEnd,
mColorGradientHorizontal); mColorGradientHorizontal);
// Draw logos. // Draw logos.

View file

@ -68,6 +68,7 @@ protected:
} }
private: private:
Renderer* mRenderer;
std::function<void(CursorState state)> mCursorChangedCallback; std::function<void(CursorState state)> mCursorChangedCallback;
std::function<void()> mCancelTransitionsCallback; std::function<void()> mCancelTransitionsCallback;

View file

@ -13,7 +13,8 @@
using namespace GridFlags; using namespace GridFlags;
ComponentGrid::ComponentGrid(const glm::ivec2& gridDimensions) ComponentGrid::ComponentGrid(const glm::ivec2& gridDimensions)
: mGridSize {gridDimensions} : mRenderer {Renderer::getInstance()}
, mGridSize {gridDimensions}
, mCursor {0, 0} , mCursor {0, 0}
{ {
assert(gridDimensions.x > 0 && gridDimensions.y > 0); assert(gridDimensions.x > 0 && gridDimensions.y > 0);
@ -429,8 +430,8 @@ void ComponentGrid::render(const glm::mat4& parentTrans)
// Draw cell separators. // Draw cell separators.
for (size_t i = 0; i < mSeparators.size(); ++i) { for (size_t i = 0; i < mSeparators.size(); ++i) {
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
Renderer::drawRect(mSeparators[i][0], mSeparators[i][1], mSeparators[i][2], mRenderer->drawRect(mSeparators[i][0], mSeparators[i][1], mSeparators[i][2],
mSeparators[i][3], 0xC6C7C6FF, 0xC6C7C6FF); mSeparators[i][3], 0xC6C7C6FF, 0xC6C7C6FF);
} }
} }

View file

@ -128,6 +128,7 @@ private:
const GridEntry* getCellAt(int x, int y) const; const GridEntry* getCellAt(int x, int y) const;
const GridEntry* getCellAt(const glm::ivec2& pos) const { return getCellAt(pos.x, pos.y); } const GridEntry* getCellAt(const glm::ivec2& pos) const { return getCellAt(pos.x, pos.y); }
Renderer* mRenderer;
std::vector<std::vector<float>> mSeparators; std::vector<std::vector<float>> mSeparators;
glm::ivec2 mGridSize; glm::ivec2 mGridSize;
std::vector<GridEntry> mCells; std::vector<GridEntry> mCells;

View file

@ -14,6 +14,7 @@
ComponentList::ComponentList() ComponentList::ComponentList()
: IList<ComponentListRow, void*> {LIST_SCROLL_STYLE_SLOW, LIST_NEVER_LOOP} : IList<ComponentListRow, void*> {LIST_SCROLL_STYLE_SLOW, LIST_NEVER_LOOP}
, mRenderer {Renderer::getInstance()}
, mFocused {false} , mFocused {false}
, mSetupCompleted {false} , mSetupCompleted {false}
, mBottomCameraOffset {false} , mBottomCameraOffset {false}
@ -294,7 +295,7 @@ void ComponentList::render(const glm::mat4& parentTrans)
const int clipRectSizeX {static_cast<int>(std::round(dim.x))}; const int clipRectSizeX {static_cast<int>(std::round(dim.x))};
const int clipRectSizeY {static_cast<int>(std::round(dim.y))}; const int clipRectSizeY {static_cast<int>(std::round(dim.y))};
Renderer::pushClipRect(glm::ivec2 {clipRectPosX, clipRectPosY}, mRenderer->pushClipRect(glm::ivec2 {clipRectPosX, clipRectPosY},
glm::ivec2 {clipRectSizeX, clipRectSizeY}); glm::ivec2 {clipRectSizeX, clipRectSizeY});
// Scroll the camera. // Scroll the camera.
@ -374,20 +375,21 @@ void ComponentList::render(const glm::mat4& parentTrans)
} }
// Custom rendering. // Custom rendering.
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
// Draw selector bar. // Draw selector bar.
if (mFocused) { if (mFocused) {
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data); const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
if (mOpacity == 1.0f) { if (mOpacity == 1.0f) {
Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight, mRenderer->drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight,
0xFFFFFFFF, 0xFFFFFFFF, false, mOpacity, mDimming, 0xFFFFFFFF, 0xFFFFFFFF, false, mOpacity, mDimming,
Renderer::Blend::ONE_MINUS_DST_COLOR, Renderer::Blend::ZERO); Renderer::BlendFactor::ONE_MINUS_DST_COLOR,
Renderer::BlendFactor::ZERO);
Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight, mRenderer->drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight,
0x777777FF, 0x777777FF, false, mOpacity, mDimming, 0x777777FF, 0x777777FF, false, mOpacity, mDimming,
Renderer::Blend::ONE, Renderer::Blend::ONE); Renderer::BlendFactor::ONE, Renderer::BlendFactor::ONE);
} }
for (auto it = drawAfterCursor.cbegin(); it != drawAfterCursor.cend(); ++it) for (auto it = drawAfterCursor.cbegin(); it != drawAfterCursor.cend(); ++it)
@ -395,20 +397,20 @@ void ComponentList::render(const glm::mat4& parentTrans)
// Reset matrix if one of these components changed it. // Reset matrix if one of these components changed it.
if (drawAfterCursor.size()) if (drawAfterCursor.size())
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
} }
// Draw separators. // Draw separators.
float y = 0; float y = 0;
for (unsigned int i = 0; i < mEntries.size(); ++i) { for (unsigned int i = 0; i < mEntries.size(); ++i) {
Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(), mRenderer->drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(),
0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDimming); 0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDimming);
y += getRowHeight(mEntries.at(i).data); y += getRowHeight(mEntries.at(i).data);
} }
Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(), mRenderer->drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(),
0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDimming); 0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDimming);
Renderer::popClipRect(); mRenderer->popClipRect();
} }
float ComponentList::getRowHeight(const ComponentListRow& row) const float ComponentList::getRowHeight(const ComponentListRow& row) const

View file

@ -124,6 +124,7 @@ protected:
void onCursorChanged(const CursorState& state) override; void onCursorChanged(const CursorState& state) override;
private: private:
Renderer* mRenderer;
bool mFocused; bool mFocused;
bool mSetupCompleted; bool mSetupCompleted;
bool mBottomCameraOffset; bool mBottomCameraOffset;

View file

@ -16,7 +16,8 @@
#include "utils/StringUtil.h" #include "utils/StringUtil.h"
DateTimeEditComponent::DateTimeEditComponent(bool alignRight, DisplayMode dispMode) DateTimeEditComponent::DateTimeEditComponent(bool alignRight, DisplayMode dispMode)
: mEditing {false} : mRenderer {Renderer::getInstance()}
, mEditing {false}
, mEditIndex {0} , mEditIndex {0}
, mDisplayMode {dispMode} , mDisplayMode {dispMode}
, mKeyRepeatDir {0} , mKeyRepeatDir {0}
@ -181,15 +182,15 @@ void DateTimeEditComponent::render(const glm::mat4& parentTrans)
off.x += referenceSize - mTextCache->metrics.size.x; off.x += referenceSize - mTextCache->metrics.size.x;
trans = glm::translate(trans, off); trans = glm::translate(trans, off);
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (Settings::getInstance()->getBool("DebugText")) { if (Settings::getInstance()->getBool("DebugText")) {
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (mTextCache->metrics.size.x > 0.0f) { if (mTextCache->metrics.size.x > 0.0f) {
Renderer::drawRect(0.0f, 0.0f - off.y, mSize.x - off.x, mSize.y, 0x0000FF33, mRenderer->drawRect(0.0f, 0.0f - off.y, mSize.x - off.x, mSize.y, 0x0000FF33,
0x0000FF33); 0x0000FF33);
} }
Renderer::drawRect(0.0f, 0.0f, mTextCache->metrics.size.x, mTextCache->metrics.size.y, mRenderer->drawRect(0.0f, 0.0f, mTextCache->metrics.size.x, mTextCache->metrics.size.y,
0x00000033, 0x00000033); 0x00000033, 0x00000033);
} }
@ -198,7 +199,7 @@ void DateTimeEditComponent::render(const glm::mat4& parentTrans)
if (mEditing && mTime != 0) { if (mEditing && mTime != 0) {
if (mEditIndex >= 0 && static_cast<unsigned int>(mEditIndex) < mCursorBoxes.size()) if (mEditIndex >= 0 && static_cast<unsigned int>(mEditIndex) < mCursorBoxes.size())
Renderer::drawRect(mCursorBoxes[mEditIndex][0], mCursorBoxes[mEditIndex][1], mRenderer->drawRect(mCursorBoxes[mEditIndex][0], mCursorBoxes[mEditIndex][1],
mCursorBoxes[mEditIndex][2], mCursorBoxes[mEditIndex][3], mCursorBoxes[mEditIndex][2], mCursorBoxes[mEditIndex][3],
0x00000022, 0x00000022); 0x00000022, 0x00000022);
} }

View file

@ -10,6 +10,7 @@
#define ES_CORE_COMPONENTS_DATE_TIME_EDIT_COMPONENT_H #define ES_CORE_COMPONENTS_DATE_TIME_EDIT_COMPONENT_H
#include "GuiComponent.h" #include "GuiComponent.h"
#include "renderers/Renderer.h"
#include "utils/TimeUtil.h" #include "utils/TimeUtil.h"
class TextCache; class TextCache;
@ -66,6 +67,7 @@ private:
void changeDate(); void changeDate();
void updateTextCache(); void updateTextCache();
Renderer* mRenderer;
Utils::Time::DateTime mTime; Utils::Time::DateTime mTime;
Utils::Time::DateTime mTimeBeforeEdit; Utils::Time::DateTime mTimeBeforeEdit;

View file

@ -20,7 +20,8 @@
#include "ThemeData.h" #include "ThemeData.h"
FlexboxComponent::FlexboxComponent(std::vector<FlexboxItem>& items) FlexboxComponent::FlexboxComponent(std::vector<FlexboxItem>& items)
: mItems {items} : mRenderer {Renderer::getInstance()}
, mItems {items}
, mDirection {DEFAULT_DIRECTION} , mDirection {DEFAULT_DIRECTION}
, mAlignment {DEFAULT_ALIGNMENT} , mAlignment {DEFAULT_ALIGNMENT}
, mLines {DEFAULT_LINES} , mLines {DEFAULT_LINES}
@ -42,10 +43,10 @@ void FlexboxComponent::render(const glm::mat4& parentTrans)
computeLayout(); computeLayout();
glm::mat4 trans {parentTrans * getTransform()}; glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (Settings::getInstance()->getBool("DebugImage")) if (Settings::getInstance()->getBool("DebugImage"))
Renderer::drawRect(0.0f, 0.0f, ceilf(mSize.x), ceilf(mSize.y), 0xFF000033, 0xFF000033); mRenderer->drawRect(0.0f, 0.0f, ceilf(mSize.x), ceilf(mSize.y), 0xFF000033, 0xFF000033);
for (auto& item : mItems) { for (auto& item : mItems) {
if (!item.visible) if (!item.visible)

View file

@ -81,6 +81,7 @@ private:
// Calculate flexbox layout. // Calculate flexbox layout.
void computeLayout(); void computeLayout();
Renderer* mRenderer;
std::vector<FlexboxItem>& mItems; std::vector<FlexboxItem>& mItems;
// Layout options. // Layout options.

View file

@ -20,7 +20,8 @@
#include "utils/StringUtil.h" #include "utils/StringUtil.h"
GIFAnimComponent::GIFAnimComponent() GIFAnimComponent::GIFAnimComponent()
: mFrameSize {0} : mRenderer {Renderer::getInstance()}
, mFrameSize {0}
, mAnimFile {nullptr} , mAnimFile {nullptr}
, mAnimation {nullptr} , mAnimation {nullptr}
, mFrame {nullptr} , mFrame {nullptr}
@ -466,10 +467,10 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans)
} }
} }
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (Settings::getInstance()->getBool("DebugImage")) if (Settings::getInstance()->getBool("DebugImage"))
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0xFF000033, 0xFF000033); mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0xFF000033, 0xFF000033);
if (mTexture->getSize().x != 0.0f) { if (mTexture->getSize().x != 0.0f) {
mTexture->bind(); mTexture->bind();
@ -493,6 +494,6 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans)
vertices->convertBGRAToRGBA = true; vertices->convertBGRAToRGBA = true;
// Render it. // Render it.
Renderer::drawTriangleStrips(&vertices[0], 4); mRenderer->drawTriangleStrips(&vertices[0], 4);
} }
} }

View file

@ -69,6 +69,7 @@ private:
return ftell(reinterpret_cast<FILE*>(handle)); return ftell(reinterpret_cast<FILE*>(handle));
} }
Renderer* mRenderer;
std::shared_ptr<TextureResource> mTexture; std::shared_ptr<TextureResource> mTexture;
std::vector<uint8_t> mPictureRGBA; std::vector<uint8_t> mPictureRGBA;
size_t mFrameSize; size_t mFrameSize;

View file

@ -30,7 +30,8 @@ glm::vec2 ImageComponent::getSize() const
} }
ImageComponent::ImageComponent(bool forceLoad, bool dynamic) ImageComponent::ImageComponent(bool forceLoad, bool dynamic)
: mTargetSize {0, 0} : mRenderer {Renderer::getInstance()}
, mTargetSize {0, 0}
, mFlipX {false} , mFlipX {false}
, mFlipY {false} , mFlipY {false}
, mTargetIsMax {false} , mTargetIsMax {false}
@ -396,14 +397,14 @@ void ImageComponent::render(const glm::mat4& parentTrans)
return; return;
glm::mat4 trans {parentTrans * getTransform()}; glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (mTexture && mOpacity > 0.0f) { if (mTexture && mOpacity > 0.0f) {
if (Settings::getInstance()->getBool("DebugImage")) { if (Settings::getInstance()->getBool("DebugImage")) {
glm::vec2 targetSizePos {(mTargetSize - mSize) * mOrigin * glm::vec2 {-1.0f}}; glm::vec2 targetSizePos {(mTargetSize - mSize) * mOrigin * glm::vec2 {-1.0f}};
Renderer::drawRect(targetSizePos.x, targetSizePos.y, mTargetSize.x, mTargetSize.y, mRenderer->drawRect(targetSizePos.x, targetSizePos.y, mTargetSize.x, mTargetSize.y,
0xFF000033, 0xFF000033); 0xFF000033, 0xFF000033);
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0xFF000033, 0xFF000033); mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0xFF000033, 0xFF000033);
} }
// An image with zero size would normally indicate a corrupt image file. // An image with zero size would normally indicate a corrupt image file.
if (mTexture->getSize() != glm::ivec2 {}) { if (mTexture->getSize() != glm::ivec2 {}) {
@ -422,7 +423,7 @@ void ImageComponent::render(const glm::mat4& parentTrans)
mVertices->opacity = mThemeOpacity; mVertices->opacity = mThemeOpacity;
mVertices->dimming = mDimming; mVertices->dimming = mDimming;
Renderer::drawTriangleStrips(&mVertices[0], 4); mRenderer->drawTriangleStrips(&mVertices[0], 4);
} }
else { else {
if (!mTexture) { if (!mTexture) {

View file

@ -102,6 +102,7 @@ public:
std::vector<HelpPrompt> getHelpPrompts() override; std::vector<HelpPrompt> getHelpPrompts() override;
private: private:
Renderer* mRenderer;
glm::vec2 mTargetSize; glm::vec2 mTargetSize;
bool mFlipX; bool mFlipX;

View file

@ -16,7 +16,8 @@
#include "resources/ResourceManager.h" #include "resources/ResourceManager.h"
LottieAnimComponent::LottieAnimComponent() LottieAnimComponent::LottieAnimComponent()
: mCacheFrames {true} : mRenderer {Renderer::getInstance()}
, mCacheFrames {true}
, mMaxCacheSize {0} , mMaxCacheSize {0}
, mCacheSize {0} , mCacheSize {0}
, mFrameSize {0} , mFrameSize {0}
@ -53,8 +54,8 @@ LottieAnimComponent::LottieAnimComponent()
// Set component defaults. // Set component defaults.
setOrigin(0.5f, 0.5f); setOrigin(0.5f, 0.5f);
setSize(Renderer::getScreenWidth() * 0.2f, Renderer::getScreenHeight() * 0.2f); setSize(mRenderer->getScreenWidth() * 0.2f, mRenderer->getScreenHeight() * 0.2f);
setPosition(Renderer::getScreenWidth() * 0.3f, Renderer::getScreenHeight() * 0.3f); setPosition(mRenderer->getScreenWidth() * 0.3f, mRenderer->getScreenHeight() * 0.3f);
setDefaultZIndex(10.0f); setDefaultZIndex(10.0f);
setZIndex(10.0f); setZIndex(10.0f);
} }
@ -455,10 +456,10 @@ void LottieAnimComponent::render(const glm::mat4& parentTrans)
} }
} }
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (Settings::getInstance()->getBool("DebugImage")) if (Settings::getInstance()->getBool("DebugImage"))
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0xFF000033, 0xFF000033); mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0xFF000033, 0xFF000033);
if (mTexture->getSize().x != 0.0f) { if (mTexture->getSize().x != 0.0f) {
mTexture->bind(); mTexture->bind();
@ -482,6 +483,6 @@ void LottieAnimComponent::render(const glm::mat4& parentTrans)
vertices->convertBGRAToRGBA = true; vertices->convertBGRAToRGBA = true;
// Render it. // Render it.
Renderer::drawTriangleStrips(&vertices[0], 4); mRenderer->drawTriangleStrips(&vertices[0], 4);
} }
} }

View file

@ -48,6 +48,7 @@ public:
private: private:
void render(const glm::mat4& parentTrans) override; void render(const glm::mat4& parentTrans) override;
Renderer* mRenderer;
std::shared_ptr<TextureResource> mTexture; std::shared_ptr<TextureResource> mTexture;
std::vector<uint8_t> mPictureRGBA; std::vector<uint8_t> mPictureRGBA;
std::unordered_map<size_t, std::vector<uint8_t>> mFrameCache; std::unordered_map<size_t, std::vector<uint8_t>> mFrameCache;

View file

@ -16,7 +16,8 @@
NinePatchComponent::NinePatchComponent(const std::string& path, NinePatchComponent::NinePatchComponent(const std::string& path,
unsigned int edgeColor, unsigned int edgeColor,
unsigned int centerColor) unsigned int centerColor)
: mVertices {nullptr} : mRenderer {Renderer::getInstance()}
, mVertices {nullptr}
, mPath {path} , mPath {path}
, mCornerSize {16.0f, 16.0f} , mCornerSize {16.0f, 16.0f}
, mSharpCorners {false} , mSharpCorners {false}
@ -131,10 +132,10 @@ void NinePatchComponent::render(const glm::mat4& parentTrans)
glm::mat4 trans {parentTrans * getTransform()}; glm::mat4 trans {parentTrans * getTransform()};
if (mTexture && mVertices != nullptr) { if (mTexture && mVertices != nullptr) {
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
mVertices->opacity = mOpacity; mVertices->opacity = mOpacity;
mTexture->bind(); mTexture->bind();
Renderer::drawTriangleStrips(&mVertices[0], 6 * 9); mRenderer->drawTriangleStrips(&mVertices[0], 6 * 9);
} }
renderChildren(trans); renderChildren(trans);

View file

@ -62,6 +62,7 @@ private:
void buildVertices(); void buildVertices();
void updateColors(); void updateColors();
Renderer* mRenderer;
Renderer::Vertex* mVertices; Renderer::Vertex* mVertices;
std::string mPath; std::string mPath;

View file

@ -14,7 +14,8 @@
#include "resources/TextureResource.h" #include "resources/TextureResource.h"
RatingComponent::RatingComponent(bool colorizeChanges) RatingComponent::RatingComponent(bool colorizeChanges)
: mColorOriginalValue {DEFAULT_COLORSHIFT} : mRenderer {Renderer::getInstance()}
, mColorOriginalValue {DEFAULT_COLORSHIFT}
, mColorChangedValue {DEFAULT_COLORSHIFT} , mColorChangedValue {DEFAULT_COLORSHIFT}
, mColorShift {DEFAULT_COLORSHIFT} , mColorShift {DEFAULT_COLORSHIFT}
, mColorShiftEnd {DEFAULT_COLORSHIFT} , mColorShiftEnd {DEFAULT_COLORSHIFT}
@ -152,11 +153,11 @@ void RatingComponent::render(const glm::mat4& parentTrans)
glm::mat4 trans {parentTrans * getTransform()}; glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (mOpacity > 0.0f) { if (mOpacity > 0.0f) {
if (Settings::getInstance()->getBool("DebugImage")) { if (Settings::getInstance()->getBool("DebugImage")) {
Renderer::drawRect(0.0f, 0.0f, mSize.y * NUM_RATING_STARS, mSize.y, 0xFF000033, mRenderer->drawRect(0.0f, 0.0f, mSize.y * NUM_RATING_STARS, mSize.y, 0xFF000033,
0xFF000033); 0xFF000033);
} }
@ -167,16 +168,16 @@ void RatingComponent::render(const glm::mat4& parentTrans)
(mUnfilledColor & 0xFFFFFF00) + (mVertices[i].color & 0x000000FF); (mUnfilledColor & 0xFFFFFF00) + (mVertices[i].color & 0x000000FF);
} }
Renderer::drawTriangleStrips(&mVertices[4], 4); mRenderer->drawTriangleStrips(&mVertices[4], 4);
Renderer::bindTexture(0); mRenderer->bindTexture(0);
if (mUnfilledColor != mColorShift) if (mUnfilledColor != mColorShift)
updateColors(); updateColors();
} }
if (mFilledTexture->bind()) { if (mFilledTexture->bind()) {
Renderer::drawTriangleStrips(&mVertices[0], 4); mRenderer->drawTriangleStrips(&mVertices[0], 4);
Renderer::bindTexture(0); mRenderer->bindTexture(0);
} }
} }

View file

@ -52,6 +52,7 @@ private:
void updateVertices(); void updateVertices();
void updateColors(); void updateColors();
Renderer* mRenderer;
float mValue; float mValue;
int mOriginalValue; int mOriginalValue;
unsigned int mColorOriginalValue; unsigned int mColorOriginalValue;

View file

@ -15,7 +15,8 @@
#include "resources/Font.h" #include "resources/Font.h"
ScrollableContainer::ScrollableContainer() ScrollableContainer::ScrollableContainer()
: mScrollPos {0.0f, 0.0f} : mRenderer {Renderer::getInstance()}
, mScrollPos {0.0f, 0.0f}
, mScrollDir {0.0f, 0.0f} , mScrollDir {0.0f, 0.0f}
, mClipSpacing {0.0f} , mClipSpacing {0.0f}
, mAutoScrollDelay {0} , mAutoScrollDelay {0}
@ -233,11 +234,11 @@ void ScrollableContainer::render(const glm::mat4& parentTrans)
clipPos.y += static_cast<int>(mClipSpacing); clipPos.y += static_cast<int>(mClipSpacing);
clipDim.y -= static_cast<int>(mClipSpacing); clipDim.y -= static_cast<int>(mClipSpacing);
Renderer::pushClipRect(clipPos, clipDim); mRenderer->pushClipRect(clipPos, clipDim);
trans = glm::translate(trans, -glm::vec3 {mScrollPos.x, mScrollPos.y, 0.0f}); trans = glm::translate(trans, -glm::vec3 {mScrollPos.x, mScrollPos.y, 0.0f});
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
GuiComponent::renderChildren(trans); GuiComponent::renderChildren(trans);
Renderer::popClipRect(); mRenderer->popClipRect();
} }

View file

@ -18,6 +18,7 @@
#define AUTO_SCROLL_SPEED 4.0f #define AUTO_SCROLL_SPEED 4.0f
#include "GuiComponent.h" #include "GuiComponent.h"
#include "renderers/Renderer.h"
class ScrollableContainer : public GuiComponent class ScrollableContainer : public GuiComponent
{ {
@ -42,6 +43,7 @@ public:
void render(const glm::mat4& parentTrans) override; void render(const glm::mat4& parentTrans) override;
private: private:
Renderer* mRenderer;
glm::vec2 mScrollPos; glm::vec2 mScrollPos;
glm::vec2 mScrollDir; glm::vec2 mScrollDir;

View file

@ -15,7 +15,8 @@
#define MOVE_REPEAT_RATE 40 #define MOVE_REPEAT_RATE 40
SliderComponent::SliderComponent(float min, float max, float increment, const std::string& suffix) SliderComponent::SliderComponent(float min, float max, float increment, const std::string& suffix)
: mMin {min} : mRenderer {Renderer::getInstance()}
, mMin {min}
, mMax {max} , mMax {max}
, mSingleIncrement {increment} , mSingleIncrement {increment}
, mMoveRate {0.0f} , mMoveRate {0.0f}
@ -77,13 +78,13 @@ void SliderComponent::update(int deltaTime)
void SliderComponent::render(const glm::mat4& parentTrans) void SliderComponent::render(const glm::mat4& parentTrans)
{ {
glm::mat4 trans {parentTrans * getTransform()}; glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (Settings::getInstance()->getBool("DebugText")) { if (Settings::getInstance()->getBool("DebugText")) {
Renderer::drawRect( mRenderer->drawRect(
mSize.x - mTextCache->metrics.size.x, (mSize.y - mTextCache->metrics.size.y) / 2.0f, mSize.x - mTextCache->metrics.size.x, (mSize.y - mTextCache->metrics.size.y) / 2.0f,
mTextCache->metrics.size.x, mTextCache->metrics.size.y, 0x0000FF33, 0x0000FF33); mTextCache->metrics.size.x, mTextCache->metrics.size.y, 0x0000FF33, 0x0000FF33);
Renderer::drawRect(mSize.x - mTextCache->metrics.size.x, 0.0f, mTextCache->metrics.size.x, mRenderer->drawRect(mSize.x - mTextCache->metrics.size.x, 0.0f, mTextCache->metrics.size.x,
mSize.y, 0x00000033, 0x00000033); mSize.y, 0x00000033, 0x00000033);
} }
@ -97,7 +98,7 @@ void SliderComponent::render(const glm::mat4& parentTrans)
mFont->renderTextCache(mTextCache.get()); mFont->renderTextCache(mTextCache.get());
// Render bar. // Render bar.
Renderer::drawRect(mKnob.getSize().x / 2.0f, mSize.y / 2.0f - mBarHeight / 2.0f, width, mRenderer->drawRect(mKnob.getSize().x / 2.0f, mSize.y / 2.0f - mBarHeight / 2.0f, width,
mBarHeight, 0x777777FF, 0x777777FF); mBarHeight, 0x777777FF, 0x777777FF);
// Render knob. // Render knob.

View file

@ -40,6 +40,7 @@ public:
private: private:
void onValueChanged(); void onValueChanged();
Renderer* mRenderer;
float mMin, mMax; float mMin, mMax;
float mValue; float mValue;
float mSingleIncrement; float mSingleIncrement;

View file

@ -14,6 +14,7 @@
TextComponent::TextComponent() TextComponent::TextComponent()
: mFont {Font::get(FONT_SIZE_MEDIUM)} : mFont {Font::get(FONT_SIZE_MEDIUM)}
, mRenderer {Renderer::getInstance()}
, mColor {0x000000FF} , mColor {0x000000FF}
, mBgColor {0x00000000} , mBgColor {0x00000000}
, mColorOpacity {1.0f} , mColorOpacity {1.0f}
@ -39,6 +40,7 @@ TextComponent::TextComponent(const std::string& text,
glm::vec2 size, glm::vec2 size,
unsigned int bgcolor) unsigned int bgcolor)
: mFont {nullptr} : mFont {nullptr}
, mRenderer {Renderer::getInstance()}
, mColor {0x000000FF} , mColor {0x000000FF}
, mBgColor {0x00000000} , mBgColor {0x00000000}
, mColorOpacity {1.0f} , mColorOpacity {1.0f}
@ -161,10 +163,10 @@ void TextComponent::render(const glm::mat4& parentTrans)
return; return;
glm::mat4 trans {parentTrans * getTransform()}; glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (mRenderBackground) if (mRenderBackground)
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, mBgColor, mBgColor, false, mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, mBgColor, mBgColor, false,
mOpacity * mThemeOpacity, mDimming); mOpacity * mThemeOpacity, mDimming);
if (mTextCache) { if (mTextCache) {
@ -191,27 +193,27 @@ void TextComponent::render(const glm::mat4& parentTrans)
// Draw the "textbox" area, what we are aligned within. // Draw the "textbox" area, what we are aligned within.
if (Settings::getInstance()->getBool("DebugText")) if (Settings::getInstance()->getBool("DebugText"))
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x0000FF33, 0x0000FF33); mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x0000FF33, 0x0000FF33);
trans = glm::translate(trans, off); trans = glm::translate(trans, off);
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
// Draw the text area, where the text actually is located. // Draw the text area, where the text actually is located.
if (Settings::getInstance()->getBool("DebugText")) { if (Settings::getInstance()->getBool("DebugText")) {
switch (mHorizontalAlignment) { switch (mHorizontalAlignment) {
case ALIGN_LEFT: { case ALIGN_LEFT: {
Renderer::drawRect(0.0f, 0.0f, mTextCache->metrics.size.x, mRenderer->drawRect(0.0f, 0.0f, mTextCache->metrics.size.x,
mTextCache->metrics.size.y, 0x00000033, 0x00000033); mTextCache->metrics.size.y, 0x00000033, 0x00000033);
break; break;
} }
case ALIGN_CENTER: { case ALIGN_CENTER: {
Renderer::drawRect((mSize.x - mTextCache->metrics.size.x) / 2.0f, 0.0f, mRenderer->drawRect((mSize.x - mTextCache->metrics.size.x) / 2.0f, 0.0f,
mTextCache->metrics.size.x, mTextCache->metrics.size.y, mTextCache->metrics.size.x, mTextCache->metrics.size.y,
0x00000033, 0x00000033); 0x00000033, 0x00000033);
break; break;
} }
case ALIGN_RIGHT: { case ALIGN_RIGHT: {
Renderer::drawRect(mSize.x - mTextCache->metrics.size.x, 0.0f, mRenderer->drawRect(mSize.x - mTextCache->metrics.size.x, 0.0f,
mTextCache->metrics.size.x, mTextCache->metrics.size.y, mTextCache->metrics.size.x, mTextCache->metrics.size.y,
0x00000033, 0x00000033); 0x00000033, 0x00000033);
break; break;

View file

@ -89,6 +89,7 @@ private:
void calculateExtent(); void calculateExtent();
void onColorChanged(); void onColorChanged();
Renderer* mRenderer;
unsigned int mColor; unsigned int mColor;
unsigned int mBgColor; unsigned int mBgColor;
float mColorOpacity; float mColorOpacity;

View file

@ -19,7 +19,8 @@
#define BLINKTIME 1000 #define BLINKTIME 1000
TextEditComponent::TextEditComponent() TextEditComponent::TextEditComponent()
: mFocused {false} : mRenderer {Renderer::getInstance()}
, mFocused {false}
, mEditing {false} , mEditing {false}
, mCursor {0} , mCursor {0}
, mBlinkTime {0} , mBlinkTime {0}
@ -304,16 +305,16 @@ void TextEditComponent::render(const glm::mat4& parentTrans)
glm::ivec2 clipDim {static_cast<int>(dimScaled.x - trans[3].x), glm::ivec2 clipDim {static_cast<int>(dimScaled.x - trans[3].x),
static_cast<int>(dimScaled.y - trans[3].y)}; static_cast<int>(dimScaled.y - trans[3].y)};
Renderer::pushClipRect(clipPos, clipDim); mRenderer->pushClipRect(clipPos, clipDim);
trans = glm::translate(trans, glm::vec3 {-mScrollOffset.x, -mScrollOffset.y, 0.0f}); trans = glm::translate(trans, glm::vec3 {-mScrollOffset.x, -mScrollOffset.y, 0.0f});
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
if (mTextCache) if (mTextCache)
mFont->renderTextCache(mTextCache.get()); mFont->renderTextCache(mTextCache.get());
// Pop the clip early to allow the cursor to be drawn outside of the "text area". // Pop the clip early to allow the cursor to be drawn outside of the "text area".
Renderer::popClipRect(); mRenderer->popClipRect();
// Draw cursor. // Draw cursor.
glm::vec2 cursorPos; glm::vec2 cursorPos;
@ -328,13 +329,13 @@ void TextEditComponent::render(const glm::mat4& parentTrans)
float cursorHeight = mFont->getHeight() * 0.8f; float cursorHeight = mFont->getHeight() * 0.8f;
if (!mEditing) { if (!mEditing) {
Renderer::drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f, mRenderer->drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0xC7C7C7FF, 2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0xC7C7C7FF,
0xC7C7C7FF); 0xC7C7C7FF);
} }
if (mEditing && mBlinkTime < BLINKTIME / 2) { if (mEditing && mBlinkTime < BLINKTIME / 2) {
Renderer::drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f, mRenderer->drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0x777777FF, 2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0x777777FF,
0x777777FF); 0x777777FF);
} }

View file

@ -56,6 +56,7 @@ private:
glm::vec2 getTextAreaPos() const; glm::vec2 getTextAreaPos() const;
glm::vec2 getTextAreaSize() const; glm::vec2 getTextAreaSize() const;
Renderer* mRenderer;
std::string mText; std::string mText;
std::string mTextOrig; std::string mTextOrig;
bool mFocused; bool mFocused;

View file

@ -135,6 +135,7 @@ protected:
void onCursorChanged(const CursorState& state) override; void onCursorChanged(const CursorState& state) override;
private: private:
Renderer* mRenderer;
int mLoopOffset; int mLoopOffset;
int mLoopOffset2; int mLoopOffset2;
int mLoopTime; int mLoopTime;
@ -164,6 +165,7 @@ private:
template <typename T> TextListComponent<T>::TextListComponent() template <typename T> TextListComponent<T>::TextListComponent()
{ {
mRenderer = Renderer::getInstance();
mLoopOffset = 0; mLoopOffset = 0;
mLoopOffset2 = 0; mLoopOffset2 = 0;
mLoopTime = 0; mLoopTime = 0;
@ -232,17 +234,17 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
mSelectorImage.render(trans); mSelectorImage.render(trans);
} }
else { else {
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
Renderer::drawRect(0.0f, (mCursor - startEntry) * entrySize + mSelectorOffsetY, mSize.x, mRenderer->drawRect(0.0f, (mCursor - startEntry) * entrySize + mSelectorOffsetY,
mSelectorHeight, mSelectorColor, mSelectorColorEnd, mSize.x, mSelectorHeight, mSelectorColor, mSelectorColorEnd,
mSelectorColorGradientHorizontal); mSelectorColorGradientHorizontal);
} }
} }
if (Settings::getInstance()->getBool("DebugText")) { if (Settings::getInstance()->getBool("DebugText")) {
Renderer::drawRect(mHorizontalMargin, 0.0f, mSize.x - mHorizontalMargin * 2.0f, mSize.y, mRenderer->drawRect(mHorizontalMargin, 0.0f, mSize.x - mHorizontalMargin * 2.0f, mSize.y,
0x00000033, 0x00000033); 0x00000033, 0x00000033);
Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x0000FF33, 0x0000FF33); mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x0000FF33, 0x0000FF33);
} }
// Clip to inside margins. // Clip to inside margins.
@ -250,7 +252,7 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x; dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x;
dim.y = (trans[1].y * dim.y + trans[3].y) - trans[3].y; dim.y = (trans[1].y * dim.y + trans[3].y) - trans[3].y;
Renderer::pushClipRect( mRenderer->pushClipRect(
glm::ivec2 {static_cast<int>(std::round(trans[3].x + mHorizontalMargin)), glm::ivec2 {static_cast<int>(std::round(trans[3].x + mHorizontalMargin)),
static_cast<int>(std::round(trans[3].y))}, static_cast<int>(std::round(trans[3].y))},
glm::ivec2 {static_cast<int>(std::round(dim.x - mHorizontalMargin * 2.0f)), glm::ivec2 {static_cast<int>(std::round(dim.x - mHorizontalMargin * 2.0f)),
@ -323,7 +325,7 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
if (mLoopOffset == 0 && mLoopOffset2 == 0) if (mLoopOffset == 0 && mLoopOffset2 == 0)
mLoopScroll = false; mLoopScroll = false;
Renderer::setMatrix(drawTrans); mRenderer->setMatrix(drawTrans);
font->renderTextCache(entry.data.textCache.get()); font->renderTextCache(entry.data.textCache.get());
// Render currently selected row again if text is moved far enough for it to repeat. // Render currently selected row again if text is moved far enough for it to repeat.
@ -332,12 +334,12 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
drawTrans = trans; drawTrans = trans;
drawTrans = glm::translate( drawTrans = glm::translate(
drawTrans, offset - glm::vec3 {static_cast<float>(mLoopOffset2), 0.0f, 0.0f}); drawTrans, offset - glm::vec3 {static_cast<float>(mLoopOffset2), 0.0f, 0.0f});
Renderer::setMatrix(drawTrans); mRenderer->setMatrix(drawTrans);
font->renderTextCache(entry.data.textCache.get()); font->renderTextCache(entry.data.textCache.get());
} }
y += entrySize; y += entrySize;
} }
Renderer::popClipRect(); mRenderer->popClipRect();
List::listRenderTitleOverlay(trans); List::listRenderTitleOverlay(trans);
GuiComponent::renderChildren(trans); GuiComponent::renderChildren(trans);
} }

View file

@ -15,6 +15,8 @@
#include "Window.h" #include "Window.h"
#include "resources/TextureResource.h" #include "resources/TextureResource.h"
#include <SDL2/SDL.h>
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
@ -24,7 +26,8 @@ std::vector<std::string> VideoFFmpegComponent::sHWDecodedVideos;
std::vector<std::string> VideoFFmpegComponent::sSWDecodedVideos; std::vector<std::string> VideoFFmpegComponent::sSWDecodedVideos;
VideoFFmpegComponent::VideoFFmpegComponent() VideoFFmpegComponent::VideoFFmpegComponent()
: mRectangleOffset {0.0f, 0.0f} : mRenderer {Renderer::getInstance()}
, mRectangleOffset {0.0f, 0.0f}
, mFrameProcessingThread {nullptr} , mFrameProcessingThread {nullptr}
, mFormatContext {nullptr} , mFormatContext {nullptr}
, mVideoStream {nullptr} , mVideoStream {nullptr}
@ -133,7 +136,7 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
if (mIsPlaying && mFormatContext) { if (mIsPlaying && mFormatContext) {
Renderer::Vertex vertices[4]; Renderer::Vertex vertices[4];
Renderer::setMatrix(parentTrans); mRenderer->setMatrix(parentTrans);
unsigned int rectColor {0x000000FF}; unsigned int rectColor {0x000000FF};
@ -142,7 +145,7 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
// Render the black rectangle behind the video. // Render the black rectangle behind the video.
if (mVideoRectangleCoords.size() == 4) { if (mVideoRectangleCoords.size() == 4) {
Renderer::drawRect(mVideoRectangleCoords[0], mVideoRectangleCoords[1], mRenderer->drawRect(mVideoRectangleCoords[0], mVideoRectangleCoords[1],
mVideoRectangleCoords[2], mVideoRectangleCoords[3], // Line break. mVideoRectangleCoords[2], mVideoRectangleCoords[3], // Line break.
rectColor, rectColor); rectColor, rectColor);
} }
@ -219,8 +222,8 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
} }
// Render it. // Render it.
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
Renderer::drawTriangleStrips(&vertices[0], 4); mRenderer->drawTriangleStrips(&vertices[0], 4);
} }
else { else {
if (mVisible) if (mVisible)

View file

@ -84,6 +84,7 @@ private:
static void detectHWDecoder(); static void detectHWDecoder();
bool decoderInitHW(); bool decoderInitHW();
Renderer* mRenderer;
static enum AVHWDeviceType sDeviceType; static enum AVHWDeviceType sDeviceType;
static enum AVPixelFormat sPixelFormat; static enum AVPixelFormat sPixelFormat;
static std::vector<std::string> sSWDecodedVideos; static std::vector<std::string> sSWDecodedVideos;

View file

@ -15,7 +15,8 @@
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
GuiInfoPopup::GuiInfoPopup(std::string message, int duration) GuiInfoPopup::GuiInfoPopup(std::string message, int duration)
: mMessage {message} : mRenderer {Renderer::getInstance()}
, mMessage {message}
, mDuration {duration} , mDuration {duration}
, mAlpha {1.0f} , mAlpha {1.0f}
, mRunning {true} , mRunning {true}
@ -78,7 +79,7 @@ void GuiInfoPopup::render(const glm::mat4& /*parentTrans*/)
glm::mat4 trans {getTransform() * Renderer::getIdentity()}; glm::mat4 trans {getTransform() * Renderer::getIdentity()};
if (mRunning && updateState()) { if (mRunning && updateState()) {
// If we're still supposed to be rendering it. // If we're still supposed to be rendering it.
Renderer::setMatrix(trans); mRenderer->setMatrix(trans);
renderChildren(trans); renderChildren(trans);
} }
} }

View file

@ -10,6 +10,7 @@
#define ES_APP_GUIS_GUI_INFO_POPUP_H #define ES_APP_GUIS_GUI_INFO_POPUP_H
#include "GuiComponent.h" #include "GuiComponent.h"
#include "renderers/Renderer.h"
class ComponentGrid; class ComponentGrid;
class NinePatchComponent; class NinePatchComponent;
@ -27,6 +28,7 @@ public:
private: private:
bool updateState(); bool updateState();
Renderer* mRenderer;
ComponentGrid* mGrid; ComponentGrid* mGrid;
NinePatchComponent* mFrame; NinePatchComponent* mFrame;

View file

@ -3,7 +3,7 @@
// EmulationStation Desktop Edition // EmulationStation Desktop Edition
// Renderer.cpp // Renderer.cpp
// //
// General rendering functions. // Generic rendering functions.
// //
#include "renderers/Renderer.h" #include "renderers/Renderer.h"
@ -12,35 +12,20 @@
#include "Log.h" #include "Log.h"
#include "Settings.h" #include "Settings.h"
#include "Shader_GL21.h" #include "Shader_GL21.h"
#include "renderers/Renderer_GL21.h"
#include "resources/ResourceManager.h" #include "resources/ResourceManager.h"
#include <SDL2/SDL.h>
#include <stack>
#if defined(_WIN64) #if defined(_WIN64)
#include <windows.h> #include <windows.h>
#endif #endif
namespace Renderer Renderer* Renderer::getInstance()
{ {
static std::stack<Rect> clipStack; static RendererOpenGL instance;
static SDL_Window* sdlWindow {nullptr}; return &instance;
static glm::mat4 mProjectionMatrix {}; }
static glm::mat4 mProjectionMatrixRotated {};
static int windowWidth {0};
static int windowHeight {0};
static int screenWidth {0};
static int screenHeight {0};
static int screenOffsetX {0};
static int screenOffsetY {0};
static bool screenRotated {0};
static bool initialCursorState {1};
// Screen resolution modifiers relative to the 1920x1080 reference.
static float screenHeightModifier {0.0f};
static float screenWidthModifier {0.0f};
static float screenAspectRatio {0.0f};
static void setIcon() void Renderer::setIcon()
{ {
size_t width {0}; size_t width {0};
size_t height {0}; size_t height {0};
@ -66,18 +51,17 @@ namespace Renderer
// Try creating SDL surface from logo data. // Try creating SDL surface from logo data.
SDL_Surface* logoSurface {SDL_CreateRGBSurfaceFrom( SDL_Surface* logoSurface {SDL_CreateRGBSurfaceFrom(
static_cast<void*>(rawData.data()), static_cast<int>(width), static_cast<void*>(rawData.data()), static_cast<int>(width), static_cast<int>(height),
static_cast<int>(height), 32, static_cast<int>((width * 4)), rmask, gmask, bmask, 32, static_cast<int>((width * 4)), rmask, gmask, bmask, amask)};
amask)};
if (logoSurface != nullptr) { if (logoSurface != nullptr) {
SDL_SetWindowIcon(sdlWindow, logoSurface); SDL_SetWindowIcon(mSDLWindow, logoSurface);
SDL_FreeSurface(logoSurface); SDL_FreeSurface(logoSurface);
} }
} }
} }
static bool createWindow() bool Renderer::createWindow()
{ {
LOG(LogInfo) << "Creating window..."; LOG(LogInfo) << "Creating window...";
@ -86,7 +70,7 @@ namespace Renderer
return false; return false;
} }
initialCursorState = (SDL_ShowCursor(0) != 0); mInitialCursorState = (SDL_ShowCursor(0) != 0);
int displayIndex {Settings::getInstance()->getInt("DisplayIndex")}; int displayIndex {Settings::getInstance()->getInt("DisplayIndex")};
// Check that an invalid value has not been manually entered in the es_settings.xml file. // Check that an invalid value has not been manually entered in the es_settings.xml file.
@ -124,25 +108,25 @@ namespace Renderer
displayMode.h = displayBounds.h; displayMode.h = displayBounds.h;
#endif #endif
windowWidth = Settings::getInstance()->getInt("WindowWidth") ? mWindowWidth = Settings::getInstance()->getInt("WindowWidth") ?
Settings::getInstance()->getInt("WindowWidth") : Settings::getInstance()->getInt("WindowWidth") :
displayMode.w; displayMode.w;
windowHeight = Settings::getInstance()->getInt("WindowHeight") ? mWindowHeight = Settings::getInstance()->getInt("WindowHeight") ?
Settings::getInstance()->getInt("WindowHeight") : Settings::getInstance()->getInt("WindowHeight") :
displayMode.h; displayMode.h;
screenWidth = Settings::getInstance()->getInt("ScreenWidth") ? sScreenWidth = Settings::getInstance()->getInt("ScreenWidth") ?
Settings::getInstance()->getInt("ScreenWidth") : Settings::getInstance()->getInt("ScreenWidth") :
windowWidth; mWindowWidth;
screenHeight = Settings::getInstance()->getInt("ScreenHeight") ? sScreenHeight = Settings::getInstance()->getInt("ScreenHeight") ?
Settings::getInstance()->getInt("ScreenHeight") : Settings::getInstance()->getInt("ScreenHeight") :
windowHeight; mWindowHeight;
screenOffsetX = Settings::getInstance()->getInt("ScreenOffsetX") ? mScreenOffsetX = Settings::getInstance()->getInt("ScreenOffsetX") ?
Settings::getInstance()->getInt("ScreenOffsetX") : Settings::getInstance()->getInt("ScreenOffsetX") :
0; 0;
screenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ? mScreenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ?
Settings::getInstance()->getInt("ScreenOffsetY") : Settings::getInstance()->getInt("ScreenOffsetY") :
0; 0;
screenRotated = Settings::getInstance()->getBool("ScreenRotate"); mScreenRotated = Settings::getInstance()->getBool("ScreenRotate");
// Prevent the application window from minimizing when switching windows (when launching // Prevent the application window from minimizing when switching windows (when launching
// games or when manually switching windows using the task switcher). // games or when manually switching windows using the task switcher).
@ -160,11 +144,11 @@ namespace Renderer
bool userResolution = false; bool userResolution = false;
// Check if the user has changed the resolution from the command line. // Check if the user has changed the resolution from the command line.
if (windowWidth != displayMode.w || windowHeight != displayMode.h) if (mWindowWidth != displayMode.w || mWindowHeight != displayMode.h)
userResolution = true; userResolution = true;
unsigned int windowFlags; unsigned int windowFlags;
setupWindow(); setup();
#if defined(_WIN64) #if defined(_WIN64)
// For Windows we use SDL_WINDOW_BORDERLESS as "real" full screen doesn't work properly. // For Windows we use SDL_WINDOW_BORDERLESS as "real" full screen doesn't work properly.
@ -197,10 +181,10 @@ namespace Renderer
windowFlags = SDL_WINDOW_OPENGL; windowFlags = SDL_WINDOW_OPENGL;
#endif #endif
if ((sdlWindow = if ((mSDLWindow =
SDL_CreateWindow("EmulationStation", SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), SDL_CreateWindow("EmulationStation", SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex),
SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), windowWidth, SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), mWindowWidth,
windowHeight, windowFlags)) == nullptr) { mWindowHeight, windowFlags)) == nullptr) {
LOG(LogError) << "Couldn't create SDL window. " << SDL_GetError(); LOG(LogError) << "Couldn't create SDL window. " << SDL_GetError();
return false; return false;
} }
@ -218,36 +202,34 @@ namespace Renderer
// file and make sure to double the window and screen sizes in case of a high DPI // file and make sure to double the window and screen sizes in case of a high DPI
// display so that the full application window is used for rendering. // display so that the full application window is used for rendering.
int width = 0; int width = 0;
SDL_GL_GetDrawableSize(sdlWindow, &width, nullptr); SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr);
int scaleFactor = static_cast<int>(width / windowWidth); int scaleFactor = static_cast<int>(width / mWindowWidth);
LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x"
<< std::to_string(displayMode.h) << " (physical resolution " << std::to_string(displayMode.h) << " (physical resolution "
<< std::to_string(displayMode.w * scaleFactor) << "x" << std::to_string(displayMode.w * scaleFactor) << "x"
<< std::to_string(displayMode.h * scaleFactor) << ")"; << std::to_string(displayMode.h * scaleFactor) << ")";
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz";
<< " Hz"; LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x"
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(windowWidth) << "x" << std::to_string(mWindowHeight) << " (physical resolution "
<< std::to_string(windowHeight) << " (physical resolution " << std::to_string(mWindowWidth * scaleFactor) << "x"
<< std::to_string(windowWidth * scaleFactor) << "x" << std::to_string(mWindowHeight * scaleFactor) << ")";
<< std::to_string(windowHeight * scaleFactor) << ")";
windowWidth *= scaleFactor; mWindowWidth *= scaleFactor;
windowHeight *= scaleFactor; mWindowHeight *= scaleFactor;
screenWidth *= scaleFactor; sScreenWidth *= scaleFactor;
screenHeight *= scaleFactor; sScreenHeight *= scaleFactor;
#else #else
LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x"
<< std::to_string(displayMode.h); << std::to_string(displayMode.h);
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz";
<< " Hz"; LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x"
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(windowWidth) << "x" << std::to_string(mWindowHeight);
<< std::to_string(windowHeight);
#endif #endif
screenHeightModifier = static_cast<float>(screenHeight) / 1080.0f; sScreenHeightModifier = static_cast<float>(sScreenHeight) / 1080.0f;
screenWidthModifier = static_cast<float>(screenWidth) / 1920.0f; sScreenWidthModifier = static_cast<float>(sScreenWidth) / 1920.0f;
screenAspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight); sScreenAspectRatio = static_cast<float>(sScreenWidth) / static_cast<float>(sScreenHeight);
LOG(LogInfo) << "Setting up OpenGL..."; LOG(LogInfo) << "Setting up OpenGL...";
@ -264,46 +246,21 @@ namespace Renderer
swapBuffers(); swapBuffers();
#endif #endif
LOG(LogInfo) << "Loading shaders..."; return loadShaders();
std::vector<std::string> shaderFiles;
shaderFiles.push_back(":/shaders/glsl/core.glsl");
shaderFiles.push_back(":/shaders/glsl/blur_horizontal.glsl");
shaderFiles.push_back(":/shaders/glsl/blur_vertical.glsl");
shaderFiles.push_back(":/shaders/glsl/scanlines.glsl");
for (auto it = shaderFiles.cbegin(); it != shaderFiles.cend(); ++it) {
Shader* loadShader = new Shader();
loadShader->loadShaderFile(*it, GL_VERTEX_SHADER);
loadShader->loadShaderFile(*it, GL_FRAGMENT_SHADER);
if (!loadShader->createProgram()) {
LOG(LogError) << "Could not create shader program.";
return false;
} }
sShaderProgramVector.push_back(loadShader); void Renderer::destroyWindow()
}
return true;
}
static void destroyWindow()
{ {
for (auto it = sShaderProgramVector.cbegin(); it != sShaderProgramVector.cend(); ++it)
delete *it;
destroyContext(); destroyContext();
SDL_DestroyWindow(sdlWindow); SDL_DestroyWindow(mSDLWindow);
sdlWindow = nullptr; mSDLWindow = nullptr;
SDL_ShowCursor(initialCursorState); SDL_ShowCursor(mInitialCursorState);
SDL_Quit(); SDL_Quit();
} }
bool init() bool Renderer::init()
{ {
if (!createWindow()) if (!createWindow())
return false; return false;
@ -311,57 +268,57 @@ namespace Renderer
glm::mat4 projection {getIdentity()}; glm::mat4 projection {getIdentity()};
Rect viewport {0, 0, 0, 0}; Rect viewport {0, 0, 0, 0};
viewport.x = windowWidth - screenOffsetX - screenWidth; viewport.x = mWindowWidth - mScreenOffsetX - sScreenWidth;
viewport.y = windowHeight - screenOffsetY - screenHeight; viewport.y = mWindowHeight - mScreenOffsetY - sScreenHeight;
viewport.w = screenWidth; viewport.w = sScreenWidth;
viewport.h = screenHeight; viewport.h = sScreenHeight;
projection = glm::ortho(0.0f, static_cast<float>(screenWidth), projection = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(screenHeight), 0.0f, -1.0f, 1.0f); static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f}); projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f});
mProjectionMatrixRotated = mProjectionMatrixRotated =
glm::translate(projection, {screenWidth * -1.0f, screenHeight * -1.0f, 0.0f}); glm::translate(projection, {sScreenWidth * -1.0f, sScreenHeight * -1.0f, 0.0f});
viewport.x = screenOffsetX; viewport.x = mScreenOffsetX;
viewport.y = screenOffsetY; viewport.y = mScreenOffsetY;
viewport.w = screenWidth; viewport.w = sScreenWidth;
viewport.h = screenHeight; viewport.h = sScreenHeight;
mProjectionMatrix = glm::ortho(0.0f, static_cast<float>(screenWidth), mProjectionMatrix = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(screenHeight), 0.0f, -1.0f, 1.0f); static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
// This is required to avoid a brief white screen flash during startup on some systems. // This is required to avoid a brief white screen flash during startup on some systems.
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()), drawRect(0.0f, 0.0f, static_cast<float>(getScreenWidth()),
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF); static_cast<float>(getScreenHeight()), 0x000000FF, 0x000000FF);
swapBuffers(); swapBuffers();
return true; return true;
} }
void deinit() void Renderer::deinit()
{ {
// Destroy the window. // Destroy the window.
destroyWindow(); destroyWindow();
} }
void pushClipRect(const glm::ivec2& pos, const glm::ivec2& size) void Renderer::pushClipRect(const glm::ivec2& pos, const glm::ivec2& size)
{ {
Rect box(pos.x, pos.y, size.x, size.y); Rect box {pos.x, pos.y, size.x, size.y};
if (box.w == 0) if (box.w == 0)
box.w = screenWidth - box.x; box.w = sScreenWidth - box.x;
if (box.h == 0) if (box.h == 0)
box.h = screenHeight - box.y; box.h = sScreenHeight - box.y;
if (screenRotated) { if (mScreenRotated) {
box = Rect(windowWidth - screenOffsetX - box.x - box.w, box = Rect(mWindowWidth - mScreenOffsetX - box.x - box.w,
windowHeight - screenOffsetY - box.y - box.h, box.w, box.h); mWindowHeight - mScreenOffsetY - box.y - box.h, box.w, box.h);
} }
else { else {
box = Rect(screenOffsetX + box.x, screenOffsetY + box.y, box.w, box.h); box = Rect(mScreenOffsetX + box.x, mScreenOffsetY + box.y, box.w, box.h);
} }
// Make sure the box fits within clipStack.top(), and clip further accordingly. // Make sure the box fits within mClipStack.top(), and clip further accordingly.
if (clipStack.size()) { if (mClipStack.size()) {
const Rect& top = clipStack.top(); const Rect& top {mClipStack.top()};
if (top.x > box.x) if (top.x > box.x)
box.x = top.x; box.x = top.x;
if (top.y > box.y) if (top.y > box.y)
@ -377,27 +334,27 @@ namespace Renderer
if (box.h < 0) if (box.h < 0)
box.h = 0; box.h = 0;
clipStack.push(box); mClipStack.push(box);
setScissor(box); setScissor(box);
} }
void popClipRect() void Renderer::popClipRect()
{ {
if (clipStack.empty()) { if (mClipStack.empty()) {
LOG(LogError) << "Tried to popClipRect while the stack was empty"; LOG(LogError) << "Tried to popClipRect while the stack was empty";
return; return;
} }
clipStack.pop(); mClipStack.pop();
if (clipStack.empty()) if (mClipStack.empty())
setScissor(Rect(0, 0, 0, 0)); setScissor(Rect(0, 0, 0, 0));
else else
setScissor(clipStack.top()); setScissor(mClipStack.top());
} }
void drawRect(const float x, void Renderer::drawRect(const float x,
const float y, const float y,
const float w, const float w,
const float h, const float h,
@ -406,8 +363,8 @@ namespace Renderer
bool horizontalGradient, bool horizontalGradient,
const float opacity, const float opacity,
const float dimming, const float dimming,
const Blend::Factor srcBlendFactor, const BlendFactor srcBlendFactorFactor,
const Blend::Factor dstBlendFactor) const BlendFactor dstBlendFactorFactor)
{ {
Vertex vertices[4]; Vertex vertices[4];
@ -436,44 +393,5 @@ namespace Renderer
vertices->dimming = dimming; vertices->dimming = dimming;
bindTexture(0); bindTexture(0);
drawTriangleStrips(vertices, 4, srcBlendFactor, dstBlendFactor); drawTriangleStrips(vertices, 4, srcBlendFactorFactor, dstBlendFactorFactor);
} }
Shader* getShaderProgram(unsigned int shaderID)
{
unsigned int index = 0;
// Find the index in sShaderProgramVector by counting the number
// of shifts required to reach 0.
while (shaderID > 0) {
shaderID = shaderID >> 1;
++index;
}
if (sShaderProgramVector.size() > index - 1)
return sShaderProgramVector[index - 1];
else
return nullptr;
}
const glm::mat4& getProjectionMatrix()
{
if (screenRotated)
return mProjectionMatrixRotated;
else
return mProjectionMatrix;
}
const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrix; }
SDL_Window* getSDLWindow() { return sdlWindow; }
const float getWindowWidth() { return static_cast<float>(windowWidth); }
const float getWindowHeight() { return static_cast<float>(windowHeight); }
const float getScreenWidth() { return static_cast<float>(screenWidth); }
const float getScreenHeight() { return static_cast<float>(screenHeight); }
const float getScreenOffsetX() { return static_cast<float>(screenOffsetX); }
const float getScreenOffsetY() { return static_cast<float>(screenOffsetY); }
const bool getScreenRotated() { return screenRotated; }
const float getScreenWidthModifier() { return screenWidthModifier; }
const float getScreenHeightModifier() { return screenHeightModifier; }
const float getScreenAspectRatio() { return screenAspectRatio; }
} // namespace Renderer

View file

@ -3,123 +3,25 @@
// EmulationStation Desktop Edition // EmulationStation Desktop Edition
// Renderer.h // Renderer.h
// //
// General rendering functions. // Generic rendering functions.
// //
#ifndef ES_CORE_RENDERER_RENDERER_H #ifndef ES_CORE_RENDERER_RENDERER_H
#define ES_CORE_RENDERER_RENDERER_H #define ES_CORE_RENDERER_RENDERER_H
#include "Log.h" #include "Log.h"
#include "Shader_GL21.h"
#include "utils/MathUtil.h" #include "utils/MathUtil.h"
#include <stack>
#include <string> #include <string>
#include <vector> #include <vector>
struct SDL_Window; struct SDL_Window;
class Shader;
namespace Renderer class Renderer
{ {
// clang-format off public:
const unsigned int SHADER_CORE {0x00000001};
const unsigned int SHADER_BLUR_HORIZONTAL {0x00000002};
const unsigned int SHADER_BLUR_VERTICAL {0x00000004};
const unsigned int SHADER_SCANLINES {0x00000008};
// clang-format on
struct postProcessingParams {
float opacity;
float saturation;
float dimming;
bool convertBGRAToRGBA;
unsigned int blurPasses;
unsigned int shaders;
postProcessingParams()
: opacity {1.0f}
, saturation {1.0f}
, dimming {1.0f}
, convertBGRAToRGBA {false}
, blurPasses {1}
, shaders {0}
{
}
};
static std::vector<Shader*> sShaderProgramVector;
static GLuint shaderFBO1 {0};
static GLuint shaderFBO2 {0};
static GLuint vertexBuffer1 {0};
static GLuint vertexBuffer2 {0};
// This is simply to get rid of some GCC false positive -Wunused-variable compiler warnings.
static GLuint shaderFBODummy1 {shaderFBO1};
static GLuint shaderFBODummy2 {shaderFBO2};
static GLuint vertexBufferDummy1 {vertexBuffer1};
static GLuint vertexBufferDummy2 {vertexBuffer2};
static constexpr glm::mat4 getIdentity() { return glm::mat4 {1.0f}; }
static inline glm::mat4 mTrans {getIdentity()};
#if !defined(NDEBUG)
#define GL_CHECK_ERROR(Function) (Function, _GLCheckError(#Function))
static inline void _GLCheckError(const std::string& _funcName)
{
const GLenum errorCode = glGetError();
if (errorCode != GL_NO_ERROR) {
#if defined(USE_OPENGLES)
LOG(LogError) << "OpenGL ES error: " << _funcName << " failed with error code: 0x"
<< std::hex << errorCode;
#else
LOG(LogError) << "OpenGL error: " << _funcName << " failed with error code: 0x"
<< std::hex << errorCode;
#endif
}
}
#else
#define GL_CHECK_ERROR(Function) (Function)
#endif
namespace Blend
{
enum Factor {
ZERO,
ONE,
SRC_COLOR,
ONE_MINUS_SRC_COLOR,
SRC_ALPHA,
ONE_MINUS_SRC_ALPHA,
DST_COLOR,
ONE_MINUS_DST_COLOR,
DST_ALPHA,
ONE_MINUS_DST_ALPHA
};
}
namespace Texture
{
enum Type {
RGBA, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
BGRA,
RED
};
}
struct Rect {
Rect(const int xValue, const int yValue, const int wValue, const int hValue)
: x(xValue)
, y(yValue)
, w(wValue)
, h(hValue)
{
}
int x;
int y;
int w;
int h;
};
struct Vertex { struct Vertex {
glm::vec2 position; glm::vec2 position;
glm::vec2 texture; glm::vec2 texture;
@ -142,6 +44,7 @@ namespace Renderer
, shaders {0} , shaders {0}
{ {
} }
Vertex(const glm::vec2& position, const glm::vec2& textureCoord, const unsigned int color) Vertex(const glm::vec2& position, const glm::vec2& textureCoord, const unsigned int color)
: position(position) : position(position)
, texture(textureCoord) , texture(textureCoord)
@ -157,10 +60,71 @@ namespace Renderer
} }
}; };
enum class BlendFactor {
ZERO,
ONE,
SRC_COLOR,
ONE_MINUS_SRC_COLOR,
SRC_ALPHA,
ONE_MINUS_SRC_ALPHA,
DST_COLOR,
ONE_MINUS_DST_COLOR,
DST_ALPHA,
ONE_MINUS_DST_ALPHA
};
enum class TextureType {
RGBA, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
BGRA,
RED
};
struct postProcessingParams {
float opacity;
float saturation;
float dimming;
bool convertBGRAToRGBA;
unsigned int blurPasses;
unsigned int shaders;
postProcessingParams()
: opacity {1.0f}
, saturation {1.0f}
, dimming {1.0f}
, convertBGRAToRGBA {false}
, blurPasses {1}
, shaders {0}
{
}
};
struct Rect {
Rect(const int xValue, const int yValue, const int wValue, const int hValue)
: x(xValue)
, y(yValue)
, w(wValue)
, h(hValue)
{
}
int x;
int y;
int w;
int h;
};
static Renderer* getInstance();
void setIcon();
bool createWindow();
void destroyWindow();
bool init(); bool init();
void deinit(); void deinit();
virtual bool loadShaders() = 0;
void pushClipRect(const glm::ivec2& pos, const glm::ivec2& size); void pushClipRect(const glm::ivec2& pos, const glm::ivec2& size);
void popClipRect(); void popClipRect();
void drawRect(const float x, void drawRect(const float x,
const float y, const float y,
const float w, const float w,
@ -170,56 +134,87 @@ namespace Renderer
bool horizontalGradient = false, bool horizontalGradient = false,
const float opacity = 1.0, const float opacity = 1.0,
const float dimming = 1.0, const float dimming = 1.0,
const Blend::Factor srcBlendFactor = Blend::SRC_ALPHA, const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA,
const Blend::Factor dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA); const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA);
SDL_Window* getSDLWindow();
const float getWindowWidth();
const float getWindowHeight();
const float getScreenWidth();
const float getScreenHeight();
const float getScreenOffsetX();
const float getScreenOffsetY();
const bool getScreenRotated();
const float getScreenWidthModifier();
const float getScreenHeightModifier();
const float getScreenAspectRatio();
Shader* getShaderProgram(unsigned int shaderID); const glm::mat4& getProjectionMatrix()
const glm::mat4& getProjectionMatrix(); {
const glm::mat4& getProjectionMatrixNormal(); if (mScreenRotated)
void shaderPostprocessing( return mProjectionMatrixRotated;
else
return mProjectionMatrix;
}
const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrix; }
SDL_Window* getSDLWindow() { return mSDLWindow; }
const bool getScreenRotated() { return mScreenRotated; }
const float getWindowWidth() { return static_cast<float>(mWindowWidth); }
const float getWindowHeight() { return static_cast<float>(mWindowHeight); }
static const float getScreenWidth() { return static_cast<float>(sScreenWidth); }
static const float getScreenHeight() { return static_cast<float>(sScreenHeight); }
static const float getScreenWidthModifier() { return sScreenWidthModifier; }
static const float getScreenHeightModifier() { return sScreenHeightModifier; }
static const float getScreenAspectRatio() { return sScreenAspectRatio; }
static constexpr glm::mat4 getIdentity() { return glm::mat4 {1.0f}; }
glm::mat4 mTrans {getIdentity()};
virtual void shaderPostprocessing(
const unsigned int shaders, const unsigned int shaders,
const Renderer::postProcessingParams& parameters = postProcessingParams(), const Renderer::postProcessingParams& parameters = postProcessingParams(),
unsigned char* textureRGBA = nullptr); unsigned char* textureRGBA = nullptr) = 0;
void setupWindow(); virtual void setup() = 0;
bool createContext(); virtual bool createContext() = 0;
void destroyContext(); virtual void destroyContext() = 0;
unsigned int createTexture(const Texture::Type type, virtual unsigned int createTexture(const TextureType type,
const bool linearMinify, const bool linearMinify,
const bool linearMagnify, const bool linearMagnify,
const bool repeat, const bool repeat,
const unsigned int width, const unsigned int width,
const unsigned int height, const unsigned int height,
void* data); void* data) = 0;
void destroyTexture(const unsigned int texture); virtual void destroyTexture(const unsigned int texture) = 0;
void updateTexture(const unsigned int texture, virtual void updateTexture(const unsigned int texture,
const Texture::Type type, const TextureType type,
const unsigned int x, const unsigned int x,
const unsigned int y, const unsigned int y,
const unsigned int width, const unsigned int width,
const unsigned int height, const unsigned int height,
void* data); void* data) = 0;
void bindTexture(const unsigned int texture); virtual void bindTexture(const unsigned int texture) = 0;
void drawTriangleStrips(const Vertex* vertices, virtual void drawTriangleStrips(
const Vertex* vertices,
const unsigned int numVertices, const unsigned int numVertices,
const Blend::Factor srcBlendFactor = Blend::SRC_ALPHA, const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA,
const Blend::Factor dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA); const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) = 0;
void setMatrix(const glm::mat4& matrix); virtual void setMatrix(const glm::mat4& matrix) = 0;
void setScissor(const Rect& scissor); virtual void setScissor(const Rect& scissor) = 0;
void setSwapInterval(); virtual void setSwapInterval() = 0;
void swapBuffers(); virtual void swapBuffers() = 0;
} // namespace Renderer // clang-format off
static constexpr unsigned int SHADER_CORE {0x00000001};
static constexpr unsigned int SHADER_BLUR_HORIZONTAL {0x00000002};
static constexpr unsigned int SHADER_BLUR_VERTICAL {0x00000004};
static constexpr unsigned int SHADER_SCANLINES {0x00000008};
// clang-format on
std::stack<Rect> mClipStack;
SDL_Window* mSDLWindow {nullptr};
glm::mat4 mProjectionMatrix {};
glm::mat4 mProjectionMatrixRotated {};
int mWindowWidth {0};
int mWindowHeight {0};
static inline int sScreenWidth {0};
static inline int sScreenHeight {0};
int mScreenOffsetX {0};
int mScreenOffsetY {0};
bool mScreenRotated {0};
bool mInitialCursorState {1};
// Screen resolution modifiers relative to the 1920x1080 reference.
static inline float sScreenHeightModifier {0.0f};
static inline float sScreenWidthModifier {0.0f};
static inline float sScreenAspectRatio {0.0f};
};
#endif // ES_CORE_RENDERER_RENDERER_H #endif // ES_CORE_RENDERER_RENDERER_H

View file

@ -3,62 +3,127 @@
// EmulationStation Desktop Edition // EmulationStation Desktop Edition
// Renderer_GL21.cpp // Renderer_GL21.cpp
// //
// OpenGL / OpenGL ES renderer. // OpenGL / OpenGL ES renderering functions.
// //
#include "renderers/Renderer_GL21.h"
#include "Settings.h" #include "Settings.h"
#include "Shader_GL21.h"
#include "renderers/Renderer.h"
#if defined(__APPLE__) #if defined(__APPLE__)
#include <chrono> #include <chrono>
#endif #endif
namespace Renderer RendererOpenGL::RendererOpenGL() noexcept
: mShaderFBO1 {0}
, mShaderFBO2 {0}
, mVertexBuffer1 {0}
, mVertexBuffer2 {0}
, mSDLContext {nullptr}
, mWhiteTexture {0}
, mPostProcTexture1 {0}
, mPostProcTexture2 {0}
, mCoreShader {nullptr}
, mBlurHorizontalShader {nullptr}
, mBlurVerticalShader {nullptr}
, mScanlinelShader {nullptr}
, mLastShader {nullptr}
{ {
static SDL_GLContext sdlContext = nullptr; }
static GLuint whiteTexture {0};
static GLuint postProcTexture1 {0};
static GLuint postProcTexture2 {0};
inline GLenum convertBlendFactor(const Blend::Factor blendFactor) RendererOpenGL::~RendererOpenGL()
{
for (auto it = mShaderProgramVector.cbegin(); it != mShaderProgramVector.cend(); ++it)
delete *it;
}
RendererOpenGL* RendererOpenGL::getInstance()
{
static RendererOpenGL instance;
return &instance;
}
Shader* RendererOpenGL::getShaderProgram(unsigned int shaderID)
{
unsigned int index {0};
// Find the index in mShaderProgramVector by counting the number
// of shifts required to reach 0.
while (shaderID > 0) {
shaderID = shaderID >> 1;
++index;
}
if (mShaderProgramVector.size() > index - 1)
return mShaderProgramVector[index - 1];
else
return nullptr;
}
bool RendererOpenGL::loadShaders()
{
LOG(LogInfo) << "Loading shaders...";
std::vector<std::string> shaderFiles;
shaderFiles.push_back(":/shaders/glsl/core.glsl");
shaderFiles.push_back(":/shaders/glsl/blur_horizontal.glsl");
shaderFiles.push_back(":/shaders/glsl/blur_vertical.glsl");
shaderFiles.push_back(":/shaders/glsl/scanlines.glsl");
for (auto it = shaderFiles.cbegin(); it != shaderFiles.cend(); ++it) {
Shader* loadShader = new Shader();
loadShader->loadShaderFile(*it, GL_VERTEX_SHADER);
loadShader->loadShaderFile(*it, GL_FRAGMENT_SHADER);
if (!loadShader->createProgram()) {
LOG(LogError) << "Could not create shader program.";
return false;
}
mShaderProgramVector.push_back(loadShader);
}
return true;
}
GLenum RendererOpenGL::convertBlendFactor(const BlendFactor BlendFactorFactor)
{ {
// clang-format off // clang-format off
switch (blendFactor) { switch (BlendFactorFactor) {
case Blend::ZERO: { return GL_ZERO; } break; case BlendFactor::ZERO: { return GL_ZERO; } break;
case Blend::ONE: { return GL_ONE; } break; case BlendFactor::ONE: { return GL_ONE; } break;
case Blend::SRC_COLOR: { return GL_SRC_COLOR; } break; case BlendFactor::SRC_COLOR: { return GL_SRC_COLOR; } break;
case Blend::ONE_MINUS_SRC_COLOR: { return GL_ONE_MINUS_SRC_COLOR; } break; case BlendFactor::ONE_MINUS_SRC_COLOR: { return GL_ONE_MINUS_SRC_COLOR; } break;
case Blend::SRC_ALPHA: { return GL_SRC_ALPHA; } break; case BlendFactor::SRC_ALPHA: { return GL_SRC_ALPHA; } break;
case Blend::ONE_MINUS_SRC_ALPHA: { return GL_ONE_MINUS_SRC_ALPHA; } break; case BlendFactor::ONE_MINUS_SRC_ALPHA: { return GL_ONE_MINUS_SRC_ALPHA; } break;
case Blend::DST_COLOR: { return GL_DST_COLOR; } break; case BlendFactor::DST_COLOR: { return GL_DST_COLOR; } break;
case Blend::ONE_MINUS_DST_COLOR: { return GL_ONE_MINUS_DST_COLOR; } break; case BlendFactor::ONE_MINUS_DST_COLOR: { return GL_ONE_MINUS_DST_COLOR; } break;
case Blend::DST_ALPHA: { return GL_DST_ALPHA; } break; case BlendFactor::DST_ALPHA: { return GL_DST_ALPHA; } break;
case Blend::ONE_MINUS_DST_ALPHA: { return GL_ONE_MINUS_DST_ALPHA; } break; case BlendFactor::ONE_MINUS_DST_ALPHA: { return GL_ONE_MINUS_DST_ALPHA; } break;
default: { return GL_ZERO; } default: { return GL_ZERO; }
} }
// clang-format on // clang-format on
} }
inline GLenum convertTextureType(const Texture::Type type) GLenum RendererOpenGL::convertTextureType(const TextureType type)
{ {
// clang-format off // clang-format off
switch (type) { switch (type) {
case Texture::RGBA: { return GL_RGBA; } break; case TextureType::RGBA: { return GL_RGBA; } break;
#if defined(USE_OPENGLES) #if defined(USE_OPENGLES)
case Texture::BGRA: { return GL_BGRA_EXT; } break; case TextureType::BGRA: { return GL_BGRA_EXT; } break;
#else #else
case Texture::BGRA: { return GL_BGRA; } break; case TextureType::BGRA: { return GL_BGRA; } break;
#endif #endif
case Texture::RED: { return GL_RED; } break; case TextureType::RED: { return GL_RED; } break;
default: { return GL_ZERO; } default: { return GL_ZERO; }
} }
// clang-format on // clang-format on
} }
void setupWindow() void RendererOpenGL::setup()
{ {
#if defined(USE_OPENGLES) #if defined(USE_OPENGLES)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
@ -76,11 +141,11 @@ namespace Renderer
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
} }
bool createContext() bool RendererOpenGL::createContext()
{ {
sdlContext = SDL_GL_CreateContext(getSDLWindow()); mSDLContext = SDL_GL_CreateContext(getSDLWindow());
if (!sdlContext) { if (!mSDLContext) {
LOG(LogError) << "Error creating OpenGL context. " << SDL_GetError(); LOG(LogError) << "Error creating OpenGL context. " << SDL_GetError();
return false; return false;
} }
@ -89,17 +154,14 @@ namespace Renderer
glewInit(); glewInit();
#endif #endif
SDL_GL_MakeCurrent(getSDLWindow(), sdlContext); SDL_GL_MakeCurrent(getSDLWindow(), mSDLContext);
std::string vendor = std::string vendor {
glGetString(GL_VENDOR) ? reinterpret_cast<const char*>(glGetString(GL_VENDOR)) : ""; glGetString(GL_VENDOR) ? reinterpret_cast<const char*>(glGetString(GL_VENDOR)) : ""};
std::string renderer = std::string renderer {
glGetString(GL_RENDERER) ? reinterpret_cast<const char*>(glGetString(GL_RENDERER)) : ""; glGetString(GL_RENDERER) ? reinterpret_cast<const char*>(glGetString(GL_RENDERER)) : ""};
std::string version = std::string version {
glGetString(GL_VERSION) ? reinterpret_cast<const char*>(glGetString(GL_VERSION)) : ""; glGetString(GL_VERSION) ? reinterpret_cast<const char*>(glGetString(GL_VERSION)) : ""};
std::string extensions = glGetString(GL_EXTENSIONS) ?
reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)) :
"";
LOG(LogInfo) << "GL vendor: " << vendor; LOG(LogInfo) << "GL vendor: " << vendor;
LOG(LogInfo) << "GL renderer: " << renderer; LOG(LogInfo) << "GL renderer: " << renderer;
@ -126,51 +188,111 @@ namespace Renderer
GL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); GL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
// These are used for the shader post processing. // These are used for the shader post processing.
GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO1)); GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO1));
GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO2)); GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO2));
GL_CHECK_ERROR(glGenBuffers(1, &vertexBuffer1)); GL_CHECK_ERROR(glGenBuffers(1, &mVertexBuffer1));
GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer1)); GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer1));
GL_CHECK_ERROR(glGenVertexArrays(1, &vertexBuffer2)); GL_CHECK_ERROR(glGenVertexArrays(1, &mVertexBuffer2));
GL_CHECK_ERROR(glBindVertexArray(vertexBuffer2)); GL_CHECK_ERROR(glBindVertexArray(mVertexBuffer2));
uint8_t data[4] = {255, 255, 255, 255}; uint8_t data[4] = {255, 255, 255, 255};
whiteTexture = createTexture(Texture::RGBA, false, false, true, 1, 1, data); mWhiteTexture = createTexture(TextureType::RGBA, false, false, true, 1, 1, data);
postProcTexture1 = createTexture(Texture::RGBA, false, false, false, mPostProcTexture1 = createTexture(TextureType::RGBA, false, false, false,
static_cast<unsigned int>(getScreenWidth()), static_cast<unsigned int>(getScreenWidth()),
static_cast<unsigned int>(getScreenHeight()), nullptr); static_cast<unsigned int>(getScreenHeight()), nullptr);
postProcTexture2 = createTexture(Texture::RGBA, false, false, false, mPostProcTexture2 = createTexture(TextureType::RGBA, false, false, false,
static_cast<unsigned int>(getScreenWidth()), static_cast<unsigned int>(getScreenWidth()),
static_cast<unsigned int>(getScreenHeight()), nullptr); static_cast<unsigned int>(getScreenHeight()), nullptr);
// Attach textures to the shader framebuffers. // Attach textures to the shader framebuffers.
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO1)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
postProcTexture1, 0)); mPostProcTexture1, 0));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
postProcTexture2, 0)); mPostProcTexture2, 0));
GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0));
return true; return true;
} }
void destroyContext() void RendererOpenGL::destroyContext()
{ {
GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO1)); GL_CHECK_ERROR(glDeleteFramebuffers(1, &mShaderFBO1));
GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO2)); GL_CHECK_ERROR(glDeleteFramebuffers(1, &mShaderFBO2));
destroyTexture(postProcTexture1); destroyTexture(mPostProcTexture1);
destroyTexture(postProcTexture2); destroyTexture(mPostProcTexture2);
destroyTexture(whiteTexture); destroyTexture(mWhiteTexture);
SDL_GL_DeleteContext(sdlContext); SDL_GL_DeleteContext(mSDLContext);
sdlContext = nullptr; mSDLContext = nullptr;
} }
unsigned int createTexture(const Texture::Type type, void RendererOpenGL::setMatrix(const glm::mat4& matrix)
{
mTrans = matrix;
mTrans[3] = glm::round(mTrans[3]);
mTrans = getProjectionMatrix() * mTrans;
}
void RendererOpenGL::setScissor(const Rect& scissor)
{
if ((scissor.x == 0) && (scissor.y == 0) && (scissor.w == 0) && (scissor.h == 0)) {
GL_CHECK_ERROR(glDisable(GL_SCISSOR_TEST));
}
else {
// glScissor starts at the bottom left of the window.
GL_CHECK_ERROR(glScissor(scissor.x,
static_cast<GLint>(getWindowHeight()) - scissor.y - scissor.h,
scissor.w, scissor.h));
GL_CHECK_ERROR(glEnable(GL_SCISSOR_TEST));
}
}
void RendererOpenGL::setSwapInterval()
{
if (Settings::getInstance()->getBool("VSync")) {
// Adaptive VSync seems to be nonfunctional or having issues on some hardware
// and drivers, so only attempt to apply regular VSync.
if (SDL_GL_SetSwapInterval(1) == 0) {
LOG(LogInfo) << "Enabling VSync...";
}
else {
LOG(LogWarning) << "Could not enable VSync: " << SDL_GetError();
}
}
else {
SDL_GL_SetSwapInterval(0);
LOG(LogInfo) << "Disabling VSync...";
}
}
void RendererOpenGL::swapBuffers()
{
#if defined(__APPLE__)
// On macOS when running in the background, the OpenGL driver apparently does not swap
// the frames which leads to a very fast swap time. This makes ES-DE use a lot of CPU
// resources which slows down the games significantly on slower machines. By introducing
// a delay if the swap time is very low we reduce CPU usage while still keeping the
// application functioning normally.
const auto beforeSwap = std::chrono::system_clock::now();
SDL_GL_SwapWindow(getSDLWindow());
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() -
beforeSwap)
.count() < 3.0)
SDL_Delay(10);
#else
SDL_GL_SwapWindow(getSDLWindow());
#endif
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
}
unsigned int RendererOpenGL::createTexture(const TextureType type,
const bool linearMinify, const bool linearMinify,
const bool linearMagnify, const bool linearMagnify,
const bool repeat, const bool repeat,
@ -178,7 +300,7 @@ namespace Renderer
const unsigned int height, const unsigned int height,
void* data) void* data)
{ {
const GLenum textureType = convertTextureType(type); const GLenum textureType {RendererOpenGL::convertTextureType(type)};
unsigned int texture; unsigned int texture;
GL_CHECK_ERROR(glGenTextures(1, &texture)); GL_CHECK_ERROR(glGenTextures(1, &texture));
@ -202,95 +324,105 @@ namespace Renderer
return texture; return texture;
} }
void destroyTexture(const unsigned int texture) void RendererOpenGL::destroyTexture(const unsigned int texture)
{ {
GL_CHECK_ERROR(glDeleteTextures(1, &texture)); GL_CHECK_ERROR(glDeleteTextures(1, &texture));
} }
void updateTexture(const unsigned int texture, void RendererOpenGL::updateTexture(const unsigned int texture,
const Texture::Type type, const TextureType type,
const unsigned int x, const unsigned int x,
const unsigned int y, const unsigned int y,
const unsigned int width, const unsigned int width,
const unsigned int height, const unsigned int height,
void* data) void* data)
{ {
const GLenum textureType = convertTextureType(type); const GLenum textureType {RendererOpenGL::convertTextureType(type)};
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, textureType, GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, textureType,
GL_UNSIGNED_BYTE, data)); GL_UNSIGNED_BYTE, data));
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, whiteTexture)); GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, mWhiteTexture));
} }
void bindTexture(const unsigned int texture) void RendererOpenGL::bindTexture(const unsigned int texture)
{ {
if (texture == 0) if (texture == 0)
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, whiteTexture)); GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, mWhiteTexture));
else else
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
} }
void drawTriangleStrips(const Vertex* vertices, void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
const unsigned int numVertices, const unsigned int numVertices,
const Blend::Factor srcBlendFactor, const BlendFactor srcBlendFactorFactor,
const Blend::Factor dstBlendFactor) const BlendFactor dstBlendFactorFactor)
{ {
const float width {vertices[3].position[0]}; const float width {vertices[3].position[0]};
const float height {vertices[3].position[1]}; const float height {vertices[3].position[1]};
GL_CHECK_ERROR( GL_CHECK_ERROR(glBlendFunc(RendererOpenGL::convertBlendFactor(srcBlendFactorFactor),
glBlendFunc(convertBlendFactor(srcBlendFactor), convertBlendFactor(dstBlendFactor))); RendererOpenGL::convertBlendFactor(dstBlendFactorFactor)));
if (vertices->shaders == 0 || vertices->shaders & SHADER_CORE) { if (vertices->shaders == 0 || vertices->shaders & SHADER_CORE) {
Shader* shader {getShaderProgram(SHADER_CORE)}; if (mCoreShader == nullptr)
if (shader) { mCoreShader = RendererOpenGL::getShaderProgram(SHADER_CORE);
shader->activateShaders(); if (mCoreShader) {
shader->setModelViewProjectionMatrix(mTrans); if (mLastShader != mCoreShader)
shader->setAttribPointers(); mCoreShader->activateShaders();
mCoreShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mCoreShader)
mCoreShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW)); GL_DYNAMIC_DRAW));
shader->setOpacity(vertices->opacity); mCoreShader->setOpacity(vertices->opacity);
shader->setSaturation(vertices->saturation); mCoreShader->setSaturation(vertices->saturation);
shader->setDimming(vertices->dimming); mCoreShader->setDimming(vertices->dimming);
shader->setBGRAToRGBA(vertices->convertBGRAToRGBA); mCoreShader->setBGRAToRGBA(vertices->convertBGRAToRGBA);
shader->setFont(vertices->font); mCoreShader->setFont(vertices->font);
shader->setPostProcessing(vertices->postProcessing); mCoreShader->setPostProcessing(vertices->postProcessing);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders(); mLastShader = mCoreShader;
} }
} }
else if (vertices->shaders & SHADER_BLUR_HORIZONTAL) { else if (vertices->shaders & SHADER_BLUR_HORIZONTAL) {
Shader* shader {getShaderProgram(SHADER_BLUR_HORIZONTAL)}; if (mBlurHorizontalShader == nullptr)
if (shader) { mBlurHorizontalShader = RendererOpenGL::getShaderProgram(SHADER_BLUR_HORIZONTAL);
shader->activateShaders(); if (mBlurHorizontalShader) {
shader->setModelViewProjectionMatrix(mTrans); if (mLastShader != mBlurHorizontalShader)
shader->setAttribPointers(); mBlurHorizontalShader->activateShaders();
mBlurHorizontalShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mBlurHorizontalShader)
mBlurHorizontalShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW)); GL_DYNAMIC_DRAW));
shader->setTextureSize({width, height}); mBlurHorizontalShader->setTextureSize({width, height});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders(); mLastShader = mBlurHorizontalShader;
} }
return; return;
} }
else if (vertices->shaders & SHADER_BLUR_VERTICAL) { else if (vertices->shaders & SHADER_BLUR_VERTICAL) {
Shader* shader {getShaderProgram(SHADER_BLUR_VERTICAL)}; if (mBlurVerticalShader == nullptr)
if (shader) { mBlurVerticalShader = RendererOpenGL::getShaderProgram(SHADER_BLUR_VERTICAL);
shader->activateShaders(); if (mBlurVerticalShader) {
shader->setModelViewProjectionMatrix(mTrans); if (mLastShader != mBlurVerticalShader)
shader->setAttribPointers(); mBlurVerticalShader->activateShaders();
mBlurVerticalShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mBlurVerticalShader)
mBlurVerticalShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW)); GL_DYNAMIC_DRAW));
shader->setTextureSize({width, height}); mBlurVerticalShader->setTextureSize({width, height});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders(); mLastShader = mBlurVerticalShader;
} }
return; return;
} }
else if (vertices->shaders & SHADER_SCANLINES) { else if (vertices->shaders & SHADER_SCANLINES) {
Shader* shader {getShaderProgram(SHADER_SCANLINES)}; if (mScanlinelShader == nullptr)
mScanlinelShader = RendererOpenGL::getShaderProgram(SHADER_SCANLINES);
float shaderWidth {width * 1.2f}; float shaderWidth {width * 1.2f};
// Scale the scanlines relative to screen resolution. // Scale the scanlines relative to screen resolution.
float screenHeightModifier {getScreenHeightModifier()}; float screenHeightModifier {getScreenHeightModifier()};
@ -310,81 +442,23 @@ namespace Renderer
float modifier {1.41f + relativeAdjustment / 7.0f - (0.14f * screenHeightModifier)}; float modifier {1.41f + relativeAdjustment / 7.0f - (0.14f * screenHeightModifier)};
shaderHeight = height * modifier; shaderHeight = height * modifier;
} }
if (shader) { if (mScanlinelShader) {
shader->activateShaders(); if (mLastShader != mScanlinelShader)
shader->setModelViewProjectionMatrix(mTrans); mScanlinelShader->activateShaders();
shader->setAttribPointers(); mScanlinelShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mScanlinelShader)
mScanlinelShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW)); GL_DYNAMIC_DRAW));
shader->setOpacity(vertices->opacity); mScanlinelShader->setOpacity(vertices->opacity);
shader->setTextureSize({shaderWidth, shaderHeight}); mScanlinelShader->setTextureSize({shaderWidth, shaderHeight});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders(); mLastShader = mScanlinelShader;
} }
} }
} }
void setMatrix(const glm::mat4& matrix) void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
{
mTrans = matrix;
mTrans[3] = glm::round(mTrans[3]);
mTrans = getProjectionMatrix() * mTrans;
}
void setScissor(const Rect& scissor)
{
if ((scissor.x == 0) && (scissor.y == 0) && (scissor.w == 0) && (scissor.h == 0)) {
GL_CHECK_ERROR(glDisable(GL_SCISSOR_TEST));
}
else {
// glScissor starts at the bottom left of the window.
GL_CHECK_ERROR(glScissor(scissor.x,
static_cast<GLint>(getWindowHeight()) - scissor.y - scissor.h,
scissor.w, scissor.h));
GL_CHECK_ERROR(glEnable(GL_SCISSOR_TEST));
}
}
void setSwapInterval()
{
if (Settings::getInstance()->getBool("VSync")) {
// Adaptive VSync seems to be nonfunctional or having issues on some hardware
// and drivers, so only attempt to apply regular VSync.
if (SDL_GL_SetSwapInterval(1) == 0) {
LOG(LogInfo) << "Enabling VSync...";
}
else {
LOG(LogWarning) << "Could not enable VSync: " << SDL_GetError();
}
}
else {
SDL_GL_SetSwapInterval(0);
LOG(LogInfo) << "Disabling VSync...";
}
}
void swapBuffers()
{
#if defined(__APPLE__)
// On macOS when running in the background, the OpenGL driver apparently does not swap
// the frames which leads to a very fast swap time. This makes ES-DE use a lot of CPU
// resources which slows down the games significantly on slower machines. By introducing
// a delay if the swap time is very low we reduce CPU usage while still keeping the
// application functioning normally.
const auto beforeSwap = std::chrono::system_clock::now();
SDL_GL_SwapWindow(getSDLWindow());
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() -
beforeSwap)
.count() < 3.0)
SDL_Delay(10);
#else
SDL_GL_SwapWindow(getSDLWindow());
#endif
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
}
void shaderPostprocessing(unsigned int shaders,
const Renderer::postProcessingParams& parameters, const Renderer::postProcessingParams& parameters,
unsigned char* textureRGBA) unsigned char* textureRGBA)
{ {
@ -409,25 +483,25 @@ namespace Renderer
vertices->dimming = parameters.dimming; vertices->dimming = parameters.dimming;
vertices->postProcessing = true; vertices->postProcessing = true;
if (shaders & Renderer::SHADER_CORE) if (shaders & SHADER_CORE)
shaderList.push_back(Renderer::SHADER_CORE); shaderList.push_back(SHADER_CORE);
if (shaders & Renderer::SHADER_BLUR_HORIZONTAL) if (shaders & SHADER_BLUR_HORIZONTAL)
shaderList.push_back(Renderer::SHADER_BLUR_HORIZONTAL); shaderList.push_back(SHADER_BLUR_HORIZONTAL);
if (shaders & Renderer::SHADER_BLUR_VERTICAL) if (shaders & SHADER_BLUR_VERTICAL)
shaderList.push_back(Renderer::SHADER_BLUR_VERTICAL); shaderList.push_back(SHADER_BLUR_VERTICAL);
if (shaders & Renderer::SHADER_SCANLINES) if (shaders & SHADER_SCANLINES)
shaderList.push_back(Renderer::SHADER_SCANLINES); shaderList.push_back(SHADER_SCANLINES);
setMatrix(getIdentity()); setMatrix(getIdentity());
bindTexture(postProcTexture1); bindTexture(mPostProcTexture1);
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO1)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
// Blit the screen contents to postProcTexture. // Blit the screen contents to mPostProcTexture.
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
GL_COLOR_BUFFER_BIT, GL_NEAREST)); GL_NEAREST));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
bool firstFBO {true}; bool firstFBO {true};
int drawCalls {0}; int drawCalls {0};
@ -455,23 +529,25 @@ namespace Renderer
// If it's the last shader pass, then render directly to the default framebuffer // If it's the last shader pass, then render directly to the default framebuffer
// to avoid having to make an expensive glBlitFramebuffer() call. // to avoid having to make an expensive glBlitFramebuffer() call.
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
drawTriangleStrips(vertices, 4, Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA); drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
BlendFactor::ONE_MINUS_SRC_ALPHA);
break; break;
} }
// Apply/render the shaders. // Apply/render the shaders.
drawTriangleStrips(vertices, 4, Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA); drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
BlendFactor::ONE_MINUS_SRC_ALPHA);
++drawCalls; ++drawCalls;
if (firstFBO) { if (firstFBO) {
bindTexture(postProcTexture2); bindTexture(mPostProcTexture2);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO2)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO1)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT)); GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
firstFBO = false; firstFBO = false;
} }
else { else {
bindTexture(postProcTexture1); bindTexture(mPostProcTexture1);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO1)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO1));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT)); GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
firstFBO = true; firstFBO = true;
} }
@ -484,12 +560,11 @@ namespace Renderer
// screen texture, it doesn't really matter. // screen texture, it doesn't really matter.
if (textureRGBA) { if (textureRGBA) {
if (firstFBO) if (firstFBO)
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO1)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO1));
else else
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO2)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR( GL_CHECK_ERROR(glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA));
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
} }
@ -498,5 +573,3 @@ namespace Renderer
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
} }
} // namespace Renderer

View file

@ -0,0 +1,92 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// Renderer_GL21.h
//
// OpenGL / OpenGL ES renderering functions.
//
#ifndef ES_CORE_RENDERER_RENDERER_GL21_H
#define ES_CORE_RENDERER_RENDERER_GL21_H
#include "Shader_GL21.h"
#include "renderers/Renderer.h"
#if defined(USE_OPENGLES)
#include <GLES3/gl3.h>
#include <SDL2/SDL_opengles.h>
#else
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#endif
class RendererOpenGL : public Renderer
{
public:
RendererOpenGL() noexcept;
~RendererOpenGL();
static RendererOpenGL* getInstance();
Shader* getShaderProgram(unsigned int shaderID);
bool loadShaders() override;
GLenum convertBlendFactor(const BlendFactor BlendFactorFactor);
GLenum convertTextureType(const TextureType type);
void setup() override;
bool createContext() override;
void destroyContext() override;
void setMatrix(const glm::mat4& matrix) override;
void setScissor(const Rect& scissor) override;
void setSwapInterval() override;
void swapBuffers() override;
unsigned int createTexture(const TextureType type,
const bool linearMinify,
const bool linearMagnify,
const bool repeat,
const unsigned int width,
const unsigned int height,
void* data) override;
void destroyTexture(const unsigned int texture) override;
void updateTexture(const unsigned int texture,
const TextureType type,
const unsigned int x,
const unsigned int y,
const unsigned int width,
const unsigned int height,
void* data) override;
void bindTexture(const unsigned int texture) override;
void drawTriangleStrips(
const Vertex* vertices,
const unsigned int numVertices,
const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA,
const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) override;
void shaderPostprocessing(
const unsigned int shaders,
const Renderer::postProcessingParams& parameters = postProcessingParams(),
unsigned char* textureRGBA = nullptr) override;
private:
std::vector<Shader*> mShaderProgramVector;
GLuint mShaderFBO1;
GLuint mShaderFBO2;
GLuint mVertexBuffer1;
GLuint mVertexBuffer2;
SDL_GLContext mSDLContext;
GLuint mWhiteTexture;
GLuint mPostProcTexture1;
GLuint mPostProcTexture2;
Shader* mCoreShader;
Shader* mBlurHorizontalShader;
Shader* mBlurVerticalShader;
Shader* mScanlinelShader;
Shader* mLastShader;
};
#endif // ES_CORE_RENDERER_RENDERER_GL21_H

View file

@ -12,31 +12,29 @@
#include "renderers/Renderer.h" #include "renderers/Renderer.h"
#include "resources/ResourceManager.h" #include "resources/ResourceManager.h"
namespace Renderer Shader::Shader()
{
Renderer::Shader::Shader()
: mProgramID {0} : mProgramID {0}
, shaderMVPMatrix {0} , mShaderMVPMatrix {0}
, shaderPosition {0} , mShaderPosition {0}
, shaderTextureCoord {0} , mShaderTextureCoord {0}
, shaderColor {0} , mShaderColor {0}
, shaderTextureSize {0} , mShaderTextureSize {0}
, shaderOpacity {0} , mShaderOpacity {0}
, shaderSaturation {0} , mShaderSaturation {0}
, shaderDimming {0} , mShaderDimming {0}
, shaderBGRAToRGBA {0} , mShaderBGRAToRGBA {0}
, shaderFont {0} , mShaderFont {0}
, shaderPostProcessing {0} , mShaderPostProcessing {0}
{ {
} }
Renderer::Shader::~Shader() Shader::~Shader()
{ {
// Delete the shader program when destroyed. // Delete the shader program when destroyed.
deleteProgram(mProgramID); deleteProgram(mProgramID);
} }
void Renderer::Shader::loadShaderFile(const std::string& path, GLenum shaderType) void Shader::loadShaderFile(const std::string& path, GLenum shaderType)
{ {
std::string preprocessorDefines; std::string preprocessorDefines;
std::string shaderCode; std::string shaderCode;
@ -58,22 +56,21 @@ namespace Renderer
else if (shaderType == GL_FRAGMENT_SHADER) else if (shaderType == GL_FRAGMENT_SHADER)
preprocessorDefines += "#define FRAGMENT\n"; preprocessorDefines += "#define FRAGMENT\n";
shaderVector.push_back(std::make_tuple(path, preprocessorDefines + shaderCode, shaderType)); mShaderVector.push_back(std::make_tuple(path, preprocessorDefines + shaderCode, shaderType));
} }
bool Renderer::Shader::createProgram() bool Shader::createProgram()
{ {
GLint programSuccess; GLint programSuccess;
mProgramID = glCreateProgram(); mProgramID = glCreateProgram();
// Compile and attach all shaders that have been loaded. // Compile and attach all shaders that have been loaded.
for (auto it = shaderVector.cbegin(); it != shaderVector.cend(); ++it) { for (auto it = mShaderVector.cbegin(); it != mShaderVector.cend(); ++it) {
GLuint currentShader = glCreateShader(std::get<2>(*it)); GLuint currentShader {glCreateShader(std::get<2>(*it))};
GLchar const* shaderCodePtr = std::get<1>(*it).c_str(); GLchar const* shaderCodePtr {std::get<1>(*it).c_str()};
glShaderSource(currentShader, 1, reinterpret_cast<const GLchar**>(&shaderCodePtr), glShaderSource(currentShader, 1, reinterpret_cast<const GLchar**>(&shaderCodePtr), nullptr);
nullptr);
glCompileShader(currentShader); glCompileShader(currentShader);
GLint shaderCompiled; GLint shaderCompiled;
@ -103,118 +100,115 @@ namespace Renderer
getVariableLocations(mProgramID); getVariableLocations(mProgramID);
if (shaderPosition != -1) if (mShaderPosition != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(shaderPosition)); GL_CHECK_ERROR(glEnableVertexAttribArray(mShaderPosition));
if (shaderTextureCoord != -1) if (mShaderTextureCoord != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(shaderTextureCoord)); GL_CHECK_ERROR(glEnableVertexAttribArray(mShaderTextureCoord));
if (shaderColor != -1) if (mShaderColor != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(shaderColor)); GL_CHECK_ERROR(glEnableVertexAttribArray(mShaderColor));
return true; return true;
} }
void Renderer::Shader::deleteProgram(GLuint programID) void Shader::deleteProgram(GLuint programID) { GL_CHECK_ERROR(glDeleteProgram(programID)); }
{
GL_CHECK_ERROR(glDeleteProgram(programID));
}
void Renderer::Shader::getVariableLocations(GLuint programID) void Shader::getVariableLocations(GLuint programID)
{ {
// Some of the variable names are chosen to be compatible with the RetroArch GLSL shaders. // Some of the variable names are chosen to be compatible with the RetroArch GLSL shaders.
shaderMVPMatrix = glGetUniformLocation(mProgramID, "MVPMatrix"); mShaderMVPMatrix = glGetUniformLocation(mProgramID, "MVPMatrix");
shaderPosition = glGetAttribLocation(mProgramID, "positionAttrib"); mShaderPosition = glGetAttribLocation(mProgramID, "positionAttrib");
shaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord"); mShaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord");
shaderColor = glGetAttribLocation(mProgramID, "colorAttrib"); mShaderColor = glGetAttribLocation(mProgramID, "colorAttrib");
shaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize"); mShaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize");
shaderOpacity = glGetUniformLocation(mProgramID, "opacity"); mShaderOpacity = glGetUniformLocation(mProgramID, "opacity");
shaderSaturation = glGetUniformLocation(mProgramID, "saturation"); mShaderSaturation = glGetUniformLocation(mProgramID, "saturation");
shaderDimming = glGetUniformLocation(mProgramID, "dimming"); mShaderDimming = glGetUniformLocation(mProgramID, "dimming");
shaderBGRAToRGBA = glGetUniformLocation(mProgramID, "BGRAToRGBA"); mShaderBGRAToRGBA = glGetUniformLocation(mProgramID, "BGRAToRGBA");
shaderFont = glGetUniformLocation(mProgramID, "font"); mShaderFont = glGetUniformLocation(mProgramID, "font");
shaderPostProcessing = glGetUniformLocation(mProgramID, "postProcessing"); mShaderPostProcessing = glGetUniformLocation(mProgramID, "postProcessing");
} }
void Renderer::Shader::setModelViewProjectionMatrix(glm::mat4 mvpMatrix) void Shader::setModelViewProjectionMatrix(glm::mat4 mvpMatrix)
{ {
if (shaderMVPMatrix != GL_INVALID_VALUE && shaderMVPMatrix != GL_INVALID_OPERATION) if (mShaderMVPMatrix != GL_INVALID_VALUE && mShaderMVPMatrix != GL_INVALID_OPERATION)
GL_CHECK_ERROR(glUniformMatrix4fv(shaderMVPMatrix, 1, GL_FALSE, GL_CHECK_ERROR(glUniformMatrix4fv(mShaderMVPMatrix, 1, GL_FALSE,
reinterpret_cast<GLfloat*>(&mvpMatrix))); reinterpret_cast<GLfloat*>(&mvpMatrix)));
} }
void Renderer::Shader::setAttribPointers() void Shader::setAttribPointers()
{ {
if (shaderPosition != -1) if (mShaderPosition != -1)
GL_CHECK_ERROR( GL_CHECK_ERROR(glVertexAttribPointer(
glVertexAttribPointer(shaderPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), mShaderPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Renderer::Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, position)))); reinterpret_cast<const void*>(offsetof(Renderer::Vertex, position))));
if (shaderTextureCoord != -1) if (mShaderTextureCoord != -1)
GL_CHECK_ERROR( GL_CHECK_ERROR(glVertexAttribPointer(
glVertexAttribPointer(shaderTextureCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), mShaderTextureCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Renderer::Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, texture)))); reinterpret_cast<const void*>(offsetof(Renderer::Vertex, texture))));
if (shaderColor != -1) if (mShaderColor != -1)
GL_CHECK_ERROR( GL_CHECK_ERROR(glVertexAttribPointer(
glVertexAttribPointer(shaderColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), mShaderColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Renderer::Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, color)))); reinterpret_cast<const void*>(offsetof(Renderer::Vertex, color))));
} }
void Renderer::Shader::setTextureSize(std::array<GLfloat, 2> shaderVec2) void Shader::setTextureSize(std::array<GLfloat, 2> shaderVec2)
{ {
if (shaderTextureSize != -1) if (mShaderTextureSize != -1)
GL_CHECK_ERROR(glUniform2f(shaderTextureSize, shaderVec2[0], shaderVec2[1])); GL_CHECK_ERROR(glUniform2f(mShaderTextureSize, shaderVec2[0], shaderVec2[1]));
} }
void Renderer::Shader::setOpacity(GLfloat opacity) void Shader::setOpacity(GLfloat opacity)
{ {
if (shaderOpacity != -1) if (mShaderOpacity != -1)
GL_CHECK_ERROR(glUniform1f(shaderOpacity, opacity)); GL_CHECK_ERROR(glUniform1f(mShaderOpacity, opacity));
} }
void Renderer::Shader::setSaturation(GLfloat saturation) void Shader::setSaturation(GLfloat saturation)
{ {
if (shaderSaturation != -1) if (mShaderSaturation != -1)
GL_CHECK_ERROR(glUniform1f(shaderSaturation, saturation)); GL_CHECK_ERROR(glUniform1f(mShaderSaturation, saturation));
} }
void Renderer::Shader::setDimming(GLfloat dimming) void Shader::setDimming(GLfloat dimming)
{ {
if (shaderDimming != -1) if (mShaderDimming != -1)
GL_CHECK_ERROR(glUniform1f(shaderDimming, dimming)); GL_CHECK_ERROR(glUniform1f(mShaderDimming, dimming));
} }
void Renderer::Shader::setBGRAToRGBA(GLboolean BGRAToRGBA) void Shader::setBGRAToRGBA(GLboolean BGRAToRGBA)
{ {
if (shaderBGRAToRGBA != -1) if (mShaderBGRAToRGBA != -1)
GL_CHECK_ERROR(glUniform1i(shaderBGRAToRGBA, BGRAToRGBA ? 1 : 0)); GL_CHECK_ERROR(glUniform1i(mShaderBGRAToRGBA, BGRAToRGBA ? 1 : 0));
} }
void Renderer::Shader::setFont(GLboolean font) void Shader::setFont(GLboolean font)
{ {
if (shaderFont != -1) if (mShaderFont != -1)
GL_CHECK_ERROR(glUniform1i(shaderFont, font ? 1 : 0)); GL_CHECK_ERROR(glUniform1i(mShaderFont, font ? 1 : 0));
} }
void Renderer::Shader::setPostProcessing(GLboolean postProcessing) void Shader::setPostProcessing(GLboolean postProcessing)
{ {
if (shaderPostProcessing != -1) if (mShaderPostProcessing != -1)
GL_CHECK_ERROR(glUniform1i(shaderPostProcessing, postProcessing ? 1 : 0)); GL_CHECK_ERROR(glUniform1i(mShaderPostProcessing, postProcessing ? 1 : 0));
} }
void Renderer::Shader::activateShaders() void Shader::activateShaders()
{ {
// Install the shader program. // Install the shader program.
GL_CHECK_ERROR(glUseProgram(mProgramID)); GL_CHECK_ERROR(glUseProgram(mProgramID));
} }
void Renderer::Shader::deactivateShaders() void Shader::deactivateShaders()
{ {
// Remove the shader program. // Remove the shader program.
GL_CHECK_ERROR(glUseProgram(0)); GL_CHECK_ERROR(glUseProgram(0));
} }
void Renderer::Shader::printProgramInfoLog(GLuint programID) void Shader::printProgramInfoLog(GLuint programID)
{ {
if (glIsProgram(programID)) { if (glIsProgram(programID)) {
int logLength; int logLength;
@ -235,7 +229,7 @@ namespace Renderer
} }
} }
void Renderer::Shader::printShaderInfoLog(GLuint shaderID, GLenum shaderType, bool error) void Shader::printShaderInfoLog(GLuint shaderID, GLenum shaderType, bool error)
{ {
if (glIsShader(shaderID)) { if (glIsShader(shaderID)) {
int logLength; int logLength;
@ -250,8 +244,8 @@ namespace Renderer
glGetShaderInfoLog(shaderID, maxLength, &logLength, &infoLog.front()); glGetShaderInfoLog(shaderID, maxLength, &logLength, &infoLog.front());
if (logLength > 0) { if (logLength > 0) {
LOG(LogDebug) << "Shader_GL21::printShaderInfoLog(): " LOG(LogDebug) << "Shader_GL21::printShaderInfoLog(): " << (error ? "Error" : "Warning")
<< (error ? "Error" : "Warning") << " in " << " in "
<< (shaderType == GL_VERTEX_SHADER ? "VERTEX section:\n" : << (shaderType == GL_VERTEX_SHADER ? "VERTEX section:\n" :
"FRAGMENT section:\n") "FRAGMENT section:\n")
<< std::string(infoLog.begin(), infoLog.end()); << std::string(infoLog.begin(), infoLog.end());
@ -261,5 +255,3 @@ namespace Renderer
LOG(LogError) << "OpenGL error: " << shaderID << " is not a shader."; LOG(LogError) << "OpenGL error: " << shaderID << " is not a shader.";
} }
} }
} // namespace Renderer

View file

@ -11,6 +11,7 @@
#define GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES
#include "renderers/Renderer.h"
#include "utils/MathUtil.h" #include "utils/MathUtil.h"
#if defined(_WIN64) #if defined(_WIN64)
@ -28,8 +29,26 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace Renderer #if !defined(NDEBUG)
#define GL_CHECK_ERROR(Function) (Function, _GLCheckError(#Function))
static inline void _GLCheckError(const std::string& funcName)
{ {
const GLenum errorCode = glGetError();
if (errorCode != GL_NO_ERROR) {
#if defined(USE_OPENGLES)
LOG(LogError) << "OpenGL ES error: " << funcName << " failed with error code: 0x"
<< std::hex << errorCode;
#else
LOG(LogError) << "OpenGL error: " << funcName << " failed with error code: 0x" << std::hex
<< errorCode;
#endif
}
}
#else
#define GL_CHECK_ERROR(Function) (Function)
#endif
class Shader class Shader
{ {
public: public:
@ -67,22 +86,20 @@ namespace Renderer
private: private:
GLuint mProgramID; GLuint mProgramID;
std::vector<std::tuple<std::string, std::string, GLenum>> shaderVector; std::vector<std::tuple<std::string, std::string, GLenum>> mShaderVector;
// Variables used for communication with the compiled shaders. // Variables used for communication with the compiled shaders.
GLint shaderMVPMatrix; GLint mShaderMVPMatrix;
GLint shaderPosition; GLint mShaderPosition;
GLint shaderTextureCoord; GLint mShaderTextureCoord;
GLint shaderColor; GLint mShaderColor;
GLint shaderTextureSize; GLint mShaderTextureSize;
GLint shaderOpacity; GLint mShaderOpacity;
GLint shaderSaturation; GLint mShaderSaturation;
GLint shaderDimming; GLint mShaderDimming;
GLint shaderBGRAToRGBA; GLint mShaderBGRAToRGBA;
GLint shaderFont; GLint mShaderFont;
GLint shaderPostProcessing; GLint mShaderPostProcessing;
}; };
} // namespace Renderer
#endif // ES_CORE_RENDERER_SHADER_GL21_H #endif // ES_CORE_RENDERER_SHADER_GL21_H

View file

@ -76,7 +76,8 @@ size_t Font::getTotalMemUsage()
} }
Font::Font(int size, const std::string& path) Font::Font(int size, const std::string& path)
: mSize(size) : mRenderer {Renderer::getInstance()}
, mSize(size)
, mPath(path) , mPath(path)
{ {
if (mSize < 9) { if (mSize < 9) {
@ -199,14 +200,14 @@ bool Font::FontTexture::findEmpty(const glm::ivec2& size, glm::ivec2& cursor_out
void Font::FontTexture::initTexture() void Font::FontTexture::initTexture()
{ {
assert(textureId == 0); assert(textureId == 0);
textureId = Renderer::createTexture(Renderer::Texture::RED, false, false, false, textureSize.x, textureId = Renderer::getInstance()->createTexture(
textureSize.y, nullptr); Renderer::TextureType::RED, false, false, false, textureSize.x, textureSize.y, nullptr);
} }
void Font::FontTexture::deinitTexture() void Font::FontTexture::deinitTexture()
{ {
if (textureId != 0) { if (textureId != 0) {
Renderer::destroyTexture(textureId); Renderer::getInstance()->destroyTexture(textureId);
textureId = 0; textureId = 0;
} }
} }
@ -346,8 +347,8 @@ Font::Glyph* Font::getGlyph(unsigned int id)
static_cast<float>(g->metrics.horiBearingY) / 64.0f}; static_cast<float>(g->metrics.horiBearingY) / 64.0f};
// Upload glyph bitmap to texture. // Upload glyph bitmap to texture.
Renderer::updateTexture(tex->textureId, Renderer::Texture::RED, cursor.x, cursor.y, glyphSize.x, mRenderer->updateTexture(tex->textureId, Renderer::TextureType::RED, cursor.x, cursor.y,
glyphSize.y, g->bitmap.buffer); glyphSize.x, glyphSize.y, g->bitmap.buffer);
// Update max glyph height. // Update max glyph height.
if (glyphSize.y > mMaxGlyphHeight) if (glyphSize.y > mMaxGlyphHeight)
@ -380,7 +381,7 @@ void Font::rebuildTextures()
static_cast<int>(it->second.texSize.y * tex->textureSize.y)}; static_cast<int>(it->second.texSize.y * tex->textureSize.y)};
// Upload to texture. // Upload to texture.
Renderer::updateTexture(tex->textureId, Renderer::Texture::RED, cursor.x, cursor.y, mRenderer->updateTexture(tex->textureId, Renderer::TextureType::RED, cursor.x, cursor.y,
glyphSize.x, glyphSize.y, glyphSlot->bitmap.buffer); glyphSize.x, glyphSize.y, glyphSlot->bitmap.buffer);
} }
} }
@ -398,8 +399,8 @@ void Font::renderTextCache(TextCache* cache)
auto vertexList = *it; auto vertexList = *it;
it->verts[0].font = true; it->verts[0].font = true;
Renderer::bindTexture(*it->textureIdPtr); mRenderer->bindTexture(*it->textureIdPtr);
Renderer::drawTriangleStrips(&it->verts[0], mRenderer->drawTriangleStrips(&it->verts[0],
static_cast<const unsigned int>(it->verts.size())); static_cast<const unsigned int>(it->verts.size()));
} }
} }

View file

@ -107,6 +107,7 @@ public:
static size_t getTotalMemUsage(); static size_t getTotalMemUsage();
private: private:
Renderer* mRenderer;
static FT_Library sLibrary; static FT_Library sLibrary;
static std::map<std::pair<std::string, int>, std::weak_ptr<Font>> sFontMap; static std::map<std::pair<std::string, int>, std::weak_ptr<Font>> sFontMap;

View file

@ -24,7 +24,8 @@
#define DPI 96 #define DPI 96
TextureData::TextureData(bool tile) TextureData::TextureData(bool tile)
: mTile {tile} : mRenderer {Renderer::getInstance()}
, mTile {tile}
, mTextureID {0} , mTextureID {0}
, mDataRGBA {} , mDataRGBA {}
, mWidth {0} , mWidth {0}
@ -209,7 +210,7 @@ bool TextureData::uploadAndBind()
// Check if it has already been uploaded. // Check if it has already been uploaded.
std::unique_lock<std::mutex> lock(mMutex); std::unique_lock<std::mutex> lock(mMutex);
if (mTextureID != 0) { if (mTextureID != 0) {
Renderer::bindTexture(mTextureID); mRenderer->bindTexture(mTextureID);
} }
else { else {
// Make sure we're ready to upload. // Make sure we're ready to upload.
@ -218,7 +219,7 @@ bool TextureData::uploadAndBind()
// Upload texture. // Upload texture.
mTextureID = mTextureID =
Renderer::createTexture(Renderer::Texture::RGBA, true, mLinearMagnify, mTile, mRenderer->createTexture(Renderer::TextureType::RGBA, true, mLinearMagnify, mTile,
static_cast<const unsigned int>(mWidth), static_cast<const unsigned int>(mWidth),
static_cast<const unsigned int>(mHeight), mDataRGBA.data()); static_cast<const unsigned int>(mHeight), mDataRGBA.data());
} }
@ -229,7 +230,7 @@ void TextureData::releaseVRAM()
{ {
std::unique_lock<std::mutex> lock(mMutex); std::unique_lock<std::mutex> lock(mMutex);
if (mTextureID != 0) { if (mTextureID != 0) {
Renderer::destroyTexture(mTextureID); mRenderer->destroyTexture(mTextureID);
mTextureID = 0; mTextureID = 0;
} }
} }

View file

@ -72,6 +72,7 @@ public:
bool tiled() { return mTile; } bool tiled() { return mTile; }
private: private:
Renderer* mRenderer;
std::mutex mMutex; std::mutex mMutex;
bool mTile; bool mTile;