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
// from the game.
if (!runInBackground)
Renderer::swapBuffers();
Renderer::getInstance()->swapBuffers();
Scripting::fireEvent("game-start", romPath, getSourceFileData()->metadata.get("name"),
getSourceFileData()->getSystem()->getName(),

View file

@ -13,7 +13,8 @@
#include "views/ViewController.h"
MediaViewer::MediaViewer()
: mVideo {nullptr}
: mRenderer {Renderer::getInstance()}
, mVideo {nullptr}
, mImage {nullptr}
{
Window::getInstance()->setMediaViewer(this);
@ -77,10 +78,10 @@ void MediaViewer::update(int deltaTime)
void MediaViewer::render(const glm::mat4& /*parentTrans*/)
{
glm::mat4 trans {Renderer::getIdentity()};
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
// 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);
if (mVideo && !mDisplayingImage) {
@ -112,17 +113,17 @@ void MediaViewer::render(const glm::mat4& /*parentTrans*/)
}
if (shaders != 0)
Renderer::shaderPostprocessing(shaders, videoParameters);
mRenderer->shaderPostprocessing(shaders, videoParameters);
}
else if (mImage && mImage->hasImage() && mImage->getSize() != glm::vec2 {}) {
mImage->render(trans);
if (mCurrentImageIndex == mScreenshotIndex &&
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"))
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
mRenderer->shaderPostprocessing(Renderer::SHADER_SCANLINES);
else if (mCurrentImageIndex == mTitleScreenIndex &&
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
// the video ends.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -38,7 +38,8 @@
#define FAILED_VERIFICATION_RETRIES 8
GuiScraperSearch::GuiScraperSearch(SearchType type, unsigned int scrapeCount)
: mGrid {glm::ivec2 {5, 3}}
: mRenderer {Renderer::getInstance()}
, mGrid {glm::ivec2 {5, 3}}
, mSearchType {type}
, mScrapeCount {scrapeCount}
, mRefinedSearch {false}
@ -630,10 +631,10 @@ void GuiScraperSearch::render(const glm::mat4& parentTrans)
glm::mat4 trans {parentTrans * getTransform()};
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) {
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
mBusyAnim.render(trans);
}
}

View file

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

View file

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

View file

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

View file

@ -18,8 +18,9 @@
GamelistView::GamelistView(FileData* root)
: GamelistBase {root}
, mLegacyMode {false}
, mRenderer {Renderer::getInstance()}
, mViewStyle {ViewController::BASIC}
, mLegacyMode {false}
{
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)),
static_cast<int>(std::round(mSize.y * scaleY))};
Renderer::pushClipRect(pos, size);
mRenderer->pushClipRect(pos, size);
renderChildren(trans);
Renderer::popClipRect();
mRenderer->popClipRect();
}
HelpStyle GamelistView::getHelpStyle()

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -74,6 +74,7 @@ set(CORE_HEADERS
# Renderers
${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
# Resources

View file

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

View file

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

View file

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

View file

@ -21,6 +21,7 @@ namespace
CarouselComponent::CarouselComponent()
: IList<CarouselElement, SystemData*> {LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP}
, mRenderer {Renderer::getInstance()}
, mCamOffset {0.0f}
, mPreviousScrollVelocity {0}
, 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});
glm::vec2 clipPos {carouselTrans[3].x, carouselTrans[3].y};
Renderer::setMatrix(carouselTrans);
mRenderer->setMatrix(carouselTrans);
// 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);
// Draw logos.

View file

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

View file

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

View file

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

View file

@ -14,6 +14,7 @@
ComponentList::ComponentList()
: IList<ComponentListRow, void*> {LIST_SCROLL_STYLE_SLOW, LIST_NEVER_LOOP}
, mRenderer {Renderer::getInstance()}
, mFocused {false}
, mSetupCompleted {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 clipRectSizeY {static_cast<int>(std::round(dim.y))};
Renderer::pushClipRect(glm::ivec2 {clipRectPosX, clipRectPosY},
mRenderer->pushClipRect(glm::ivec2 {clipRectPosX, clipRectPosY},
glm::ivec2 {clipRectSizeX, clipRectSizeY});
// Scroll the camera.
@ -374,20 +375,21 @@ void ComponentList::render(const glm::mat4& parentTrans)
}
// Custom rendering.
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
// Draw selector bar.
if (mFocused) {
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
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,
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,
Renderer::Blend::ONE, Renderer::Blend::ONE);
Renderer::BlendFactor::ONE, Renderer::BlendFactor::ONE);
}
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.
if (drawAfterCursor.size())
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
}
// Draw separators.
float y = 0;
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);
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);
Renderer::popClipRect();
mRenderer->popClipRect();
}
float ComponentList::getRowHeight(const ComponentListRow& row) const

View file

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

View file

@ -16,7 +16,8 @@
#include "utils/StringUtil.h"
DateTimeEditComponent::DateTimeEditComponent(bool alignRight, DisplayMode dispMode)
: mEditing {false}
: mRenderer {Renderer::getInstance()}
, mEditing {false}
, mEditIndex {0}
, mDisplayMode {dispMode}
, mKeyRepeatDir {0}
@ -181,15 +182,15 @@ void DateTimeEditComponent::render(const glm::mat4& parentTrans)
off.x += referenceSize - mTextCache->metrics.size.x;
trans = glm::translate(trans, off);
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
if (Settings::getInstance()->getBool("DebugText")) {
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
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);
}
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);
}
@ -198,7 +199,7 @@ void DateTimeEditComponent::render(const glm::mat4& parentTrans)
if (mEditing && mTime != 0) {
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],
0x00000022, 0x00000022);
}

View file

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

View file

@ -20,7 +20,8 @@
#include "ThemeData.h"
FlexboxComponent::FlexboxComponent(std::vector<FlexboxItem>& items)
: mItems {items}
: mRenderer {Renderer::getInstance()}
, mItems {items}
, mDirection {DEFAULT_DIRECTION}
, mAlignment {DEFAULT_ALIGNMENT}
, mLines {DEFAULT_LINES}
@ -42,10 +43,10 @@ void FlexboxComponent::render(const glm::mat4& parentTrans)
computeLayout();
glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
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) {
if (!item.visible)

View file

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

View file

@ -20,7 +20,8 @@
#include "utils/StringUtil.h"
GIFAnimComponent::GIFAnimComponent()
: mFrameSize {0}
: mRenderer {Renderer::getInstance()}
, mFrameSize {0}
, mAnimFile {nullptr}
, mAnimation {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"))
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) {
mTexture->bind();
@ -493,6 +494,6 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans)
vertices->convertBGRAToRGBA = true;
// 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));
}
Renderer* mRenderer;
std::shared_ptr<TextureResource> mTexture;
std::vector<uint8_t> mPictureRGBA;
size_t mFrameSize;

View file

@ -30,7 +30,8 @@ glm::vec2 ImageComponent::getSize() const
}
ImageComponent::ImageComponent(bool forceLoad, bool dynamic)
: mTargetSize {0, 0}
: mRenderer {Renderer::getInstance()}
, mTargetSize {0, 0}
, mFlipX {false}
, mFlipY {false}
, mTargetIsMax {false}
@ -396,14 +397,14 @@ void ImageComponent::render(const glm::mat4& parentTrans)
return;
glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
if (mTexture && mOpacity > 0.0f) {
if (Settings::getInstance()->getBool("DebugImage")) {
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);
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.
if (mTexture->getSize() != glm::ivec2 {}) {
@ -422,7 +423,7 @@ void ImageComponent::render(const glm::mat4& parentTrans)
mVertices->opacity = mThemeOpacity;
mVertices->dimming = mDimming;
Renderer::drawTriangleStrips(&mVertices[0], 4);
mRenderer->drawTriangleStrips(&mVertices[0], 4);
}
else {
if (!mTexture) {

View file

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

View file

@ -16,7 +16,8 @@
#include "resources/ResourceManager.h"
LottieAnimComponent::LottieAnimComponent()
: mCacheFrames {true}
: mRenderer {Renderer::getInstance()}
, mCacheFrames {true}
, mMaxCacheSize {0}
, mCacheSize {0}
, mFrameSize {0}
@ -53,8 +54,8 @@ LottieAnimComponent::LottieAnimComponent()
// Set component defaults.
setOrigin(0.5f, 0.5f);
setSize(Renderer::getScreenWidth() * 0.2f, Renderer::getScreenHeight() * 0.2f);
setPosition(Renderer::getScreenWidth() * 0.3f, Renderer::getScreenHeight() * 0.3f);
setSize(mRenderer->getScreenWidth() * 0.2f, mRenderer->getScreenHeight() * 0.2f);
setPosition(mRenderer->getScreenWidth() * 0.3f, mRenderer->getScreenHeight() * 0.3f);
setDefaultZIndex(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"))
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) {
mTexture->bind();
@ -482,6 +483,6 @@ void LottieAnimComponent::render(const glm::mat4& parentTrans)
vertices->convertBGRAToRGBA = true;
// Render it.
Renderer::drawTriangleStrips(&vertices[0], 4);
mRenderer->drawTriangleStrips(&vertices[0], 4);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,7 +15,8 @@
#include "resources/Font.h"
ScrollableContainer::ScrollableContainer()
: mScrollPos {0.0f, 0.0f}
: mRenderer {Renderer::getInstance()}
, mScrollPos {0.0f, 0.0f}
, mScrollDir {0.0f, 0.0f}
, mClipSpacing {0.0f}
, mAutoScrollDelay {0}
@ -233,11 +234,11 @@ void ScrollableContainer::render(const glm::mat4& parentTrans)
clipPos.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});
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
GuiComponent::renderChildren(trans);
Renderer::popClipRect();
mRenderer->popClipRect();
}

View file

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

View file

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

View file

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

View file

@ -14,6 +14,7 @@
TextComponent::TextComponent()
: mFont {Font::get(FONT_SIZE_MEDIUM)}
, mRenderer {Renderer::getInstance()}
, mColor {0x000000FF}
, mBgColor {0x00000000}
, mColorOpacity {1.0f}
@ -39,6 +40,7 @@ TextComponent::TextComponent(const std::string& text,
glm::vec2 size,
unsigned int bgcolor)
: mFont {nullptr}
, mRenderer {Renderer::getInstance()}
, mColor {0x000000FF}
, mBgColor {0x00000000}
, mColorOpacity {1.0f}
@ -161,10 +163,10 @@ void TextComponent::render(const glm::mat4& parentTrans)
return;
glm::mat4 trans {parentTrans * getTransform()};
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
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);
if (mTextCache) {
@ -191,27 +193,27 @@ void TextComponent::render(const glm::mat4& parentTrans)
// Draw the "textbox" area, what we are aligned within.
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);
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
// Draw the text area, where the text actually is located.
if (Settings::getInstance()->getBool("DebugText")) {
switch (mHorizontalAlignment) {
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);
break;
}
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,
0x00000033, 0x00000033);
break;
}
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,
0x00000033, 0x00000033);
break;

View file

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

View file

@ -19,7 +19,8 @@
#define BLINKTIME 1000
TextEditComponent::TextEditComponent()
: mFocused {false}
: mRenderer {Renderer::getInstance()}
, mFocused {false}
, mEditing {false}
, mCursor {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),
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});
Renderer::setMatrix(trans);
mRenderer->setMatrix(trans);
if (mTextCache)
mFont->renderTextCache(mTextCache.get());
// Pop the clip early to allow the cursor to be drawn outside of the "text area".
Renderer::popClipRect();
mRenderer->popClipRect();
// Draw cursor.
glm::vec2 cursorPos;
@ -328,13 +329,13 @@ void TextEditComponent::render(const glm::mat4& parentTrans)
float cursorHeight = mFont->getHeight() * 0.8f;
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,
0xC7C7C7FF);
}
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,
0x777777FF);
}

View file

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

View file

@ -135,6 +135,7 @@ protected:
void onCursorChanged(const CursorState& state) override;
private:
Renderer* mRenderer;
int mLoopOffset;
int mLoopOffset2;
int mLoopTime;
@ -164,6 +165,7 @@ private:
template <typename T> TextListComponent<T>::TextListComponent()
{
mRenderer = Renderer::getInstance();
mLoopOffset = 0;
mLoopOffset2 = 0;
mLoopTime = 0;
@ -232,17 +234,17 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
mSelectorImage.render(trans);
}
else {
Renderer::setMatrix(trans);
Renderer::drawRect(0.0f, (mCursor - startEntry) * entrySize + mSelectorOffsetY, mSize.x,
mSelectorHeight, mSelectorColor, mSelectorColorEnd,
mRenderer->setMatrix(trans);
mRenderer->drawRect(0.0f, (mCursor - startEntry) * entrySize + mSelectorOffsetY,
mSize.x, mSelectorHeight, mSelectorColor, mSelectorColorEnd,
mSelectorColorGradientHorizontal);
}
}
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);
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.
@ -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.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)),
static_cast<int>(std::round(trans[3].y))},
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)
mLoopScroll = false;
Renderer::setMatrix(drawTrans);
mRenderer->setMatrix(drawTrans);
font->renderTextCache(entry.data.textCache.get());
// 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 = glm::translate(
drawTrans, offset - glm::vec3 {static_cast<float>(mLoopOffset2), 0.0f, 0.0f});
Renderer::setMatrix(drawTrans);
mRenderer->setMatrix(drawTrans);
font->renderTextCache(entry.data.textCache.get());
}
y += entrySize;
}
Renderer::popClipRect();
mRenderer->popClipRect();
List::listRenderTitleOverlay(trans);
GuiComponent::renderChildren(trans);
}

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@
// EmulationStation Desktop Edition
// Renderer.cpp
//
// General rendering functions.
// Generic rendering functions.
//
#include "renderers/Renderer.h"
@ -12,36 +12,21 @@
#include "Log.h"
#include "Settings.h"
#include "Shader_GL21.h"
#include "renderers/Renderer_GL21.h"
#include "resources/ResourceManager.h"
#include <SDL2/SDL.h>
#include <stack>
#if defined(_WIN64)
#include <windows.h>
#endif
namespace Renderer
Renderer* Renderer::getInstance()
{
static std::stack<Rect> clipStack;
static SDL_Window* sdlWindow {nullptr};
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 RendererOpenGL instance;
return &instance;
}
static void setIcon()
{
void Renderer::setIcon()
{
size_t width {0};
size_t height {0};
ResourceData resData {
@ -66,19 +51,18 @@ namespace Renderer
// Try creating SDL surface from logo data.
SDL_Surface* logoSurface {SDL_CreateRGBSurfaceFrom(
static_cast<void*>(rawData.data()), static_cast<int>(width),
static_cast<int>(height), 32, static_cast<int>((width * 4)), rmask, gmask, bmask,
amask)};
static_cast<void*>(rawData.data()), static_cast<int>(width), static_cast<int>(height),
32, static_cast<int>((width * 4)), rmask, gmask, bmask, amask)};
if (logoSurface != nullptr) {
SDL_SetWindowIcon(sdlWindow, logoSurface);
SDL_SetWindowIcon(mSDLWindow, logoSurface);
SDL_FreeSurface(logoSurface);
}
}
}
}
static bool createWindow()
{
bool Renderer::createWindow()
{
LOG(LogInfo) << "Creating window...";
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
@ -86,7 +70,7 @@ namespace Renderer
return false;
}
initialCursorState = (SDL_ShowCursor(0) != 0);
mInitialCursorState = (SDL_ShowCursor(0) != 0);
int displayIndex {Settings::getInstance()->getInt("DisplayIndex")};
// 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;
#endif
windowWidth = Settings::getInstance()->getInt("WindowWidth") ?
mWindowWidth = Settings::getInstance()->getInt("WindowWidth") ?
Settings::getInstance()->getInt("WindowWidth") :
displayMode.w;
windowHeight = Settings::getInstance()->getInt("WindowHeight") ?
mWindowHeight = Settings::getInstance()->getInt("WindowHeight") ?
Settings::getInstance()->getInt("WindowHeight") :
displayMode.h;
screenWidth = Settings::getInstance()->getInt("ScreenWidth") ?
sScreenWidth = Settings::getInstance()->getInt("ScreenWidth") ?
Settings::getInstance()->getInt("ScreenWidth") :
windowWidth;
screenHeight = Settings::getInstance()->getInt("ScreenHeight") ?
mWindowWidth;
sScreenHeight = Settings::getInstance()->getInt("ScreenHeight") ?
Settings::getInstance()->getInt("ScreenHeight") :
windowHeight;
screenOffsetX = Settings::getInstance()->getInt("ScreenOffsetX") ?
mWindowHeight;
mScreenOffsetX = Settings::getInstance()->getInt("ScreenOffsetX") ?
Settings::getInstance()->getInt("ScreenOffsetX") :
0;
screenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ?
mScreenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ?
Settings::getInstance()->getInt("ScreenOffsetY") :
0;
screenRotated = Settings::getInstance()->getBool("ScreenRotate");
mScreenRotated = Settings::getInstance()->getBool("ScreenRotate");
// Prevent the application window from minimizing when switching windows (when launching
// games or when manually switching windows using the task switcher).
@ -160,11 +144,11 @@ namespace Renderer
bool userResolution = false;
// 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;
unsigned int windowFlags;
setupWindow();
setup();
#if defined(_WIN64)
// 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;
#endif
if ((sdlWindow =
if ((mSDLWindow =
SDL_CreateWindow("EmulationStation", SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex),
SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), windowWidth,
windowHeight, windowFlags)) == nullptr) {
SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), mWindowWidth,
mWindowHeight, windowFlags)) == nullptr) {
LOG(LogError) << "Couldn't create SDL window. " << SDL_GetError();
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
// display so that the full application window is used for rendering.
int width = 0;
SDL_GL_GetDrawableSize(sdlWindow, &width, nullptr);
int scaleFactor = static_cast<int>(width / windowWidth);
SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr);
int scaleFactor = static_cast<int>(width / mWindowWidth);
LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x"
<< std::to_string(displayMode.h) << " (physical resolution "
<< std::to_string(displayMode.w * scaleFactor) << "x"
<< std::to_string(displayMode.h * scaleFactor) << ")";
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate)
<< " Hz";
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(windowWidth) << "x"
<< std::to_string(windowHeight) << " (physical resolution "
<< std::to_string(windowWidth * scaleFactor) << "x"
<< std::to_string(windowHeight * scaleFactor) << ")";
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz";
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x"
<< std::to_string(mWindowHeight) << " (physical resolution "
<< std::to_string(mWindowWidth * scaleFactor) << "x"
<< std::to_string(mWindowHeight * scaleFactor) << ")";
windowWidth *= scaleFactor;
windowHeight *= scaleFactor;
screenWidth *= scaleFactor;
screenHeight *= scaleFactor;
mWindowWidth *= scaleFactor;
mWindowHeight *= scaleFactor;
sScreenWidth *= scaleFactor;
sScreenHeight *= scaleFactor;
#else
LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x"
<< std::to_string(displayMode.h);
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate)
<< " Hz";
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(windowWidth) << "x"
<< std::to_string(windowHeight);
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz";
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x"
<< std::to_string(mWindowHeight);
#endif
screenHeightModifier = static_cast<float>(screenHeight) / 1080.0f;
screenWidthModifier = static_cast<float>(screenWidth) / 1920.0f;
screenAspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
sScreenHeightModifier = static_cast<float>(sScreenHeight) / 1080.0f;
sScreenWidthModifier = static_cast<float>(sScreenWidth) / 1920.0f;
sScreenAspectRatio = static_cast<float>(sScreenWidth) / static_cast<float>(sScreenHeight);
LOG(LogInfo) << "Setting up OpenGL...";
@ -264,104 +246,79 @@ namespace Renderer
swapBuffers();
#endif
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;
}
sShaderProgramVector.push_back(loadShader);
}
return true;
}
static void destroyWindow()
{
for (auto it = sShaderProgramVector.cbegin(); it != sShaderProgramVector.cend(); ++it)
delete *it;
return loadShaders();
}
void Renderer::destroyWindow()
{
destroyContext();
SDL_DestroyWindow(sdlWindow);
SDL_DestroyWindow(mSDLWindow);
sdlWindow = nullptr;
mSDLWindow = nullptr;
SDL_ShowCursor(initialCursorState);
SDL_ShowCursor(mInitialCursorState);
SDL_Quit();
}
}
bool init()
{
bool Renderer::init()
{
if (!createWindow())
return false;
glm::mat4 projection {getIdentity()};
Rect viewport {0, 0, 0, 0};
viewport.x = windowWidth - screenOffsetX - screenWidth;
viewport.y = windowHeight - screenOffsetY - screenHeight;
viewport.w = screenWidth;
viewport.h = screenHeight;
projection = glm::ortho(0.0f, static_cast<float>(screenWidth),
static_cast<float>(screenHeight), 0.0f, -1.0f, 1.0f);
viewport.x = mWindowWidth - mScreenOffsetX - sScreenWidth;
viewport.y = mWindowHeight - mScreenOffsetY - sScreenHeight;
viewport.w = sScreenWidth;
viewport.h = sScreenHeight;
projection = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f});
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.y = screenOffsetY;
viewport.w = screenWidth;
viewport.h = screenHeight;
mProjectionMatrix = glm::ortho(0.0f, static_cast<float>(screenWidth),
static_cast<float>(screenHeight), 0.0f, -1.0f, 1.0f);
viewport.x = mScreenOffsetX;
viewport.y = mScreenOffsetY;
viewport.w = sScreenWidth;
viewport.h = sScreenHeight;
mProjectionMatrix = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
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.
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
drawRect(0.0f, 0.0f, static_cast<float>(getScreenWidth()),
static_cast<float>(getScreenHeight()), 0x000000FF, 0x000000FF);
swapBuffers();
return true;
}
}
void deinit()
{
void Renderer::deinit()
{
// Destroy the window.
destroyWindow();
}
}
void pushClipRect(const glm::ivec2& pos, const glm::ivec2& size)
{
Rect box(pos.x, pos.y, size.x, size.y);
void Renderer::pushClipRect(const glm::ivec2& pos, const glm::ivec2& size)
{
Rect box {pos.x, pos.y, size.x, size.y};
if (box.w == 0)
box.w = screenWidth - box.x;
box.w = sScreenWidth - box.x;
if (box.h == 0)
box.h = screenHeight - box.y;
box.h = sScreenHeight - box.y;
if (screenRotated) {
box = Rect(windowWidth - screenOffsetX - box.x - box.w,
windowHeight - screenOffsetY - box.y - box.h, box.w, box.h);
if (mScreenRotated) {
box = Rect(mWindowWidth - mScreenOffsetX - box.x - box.w,
mWindowHeight - mScreenOffsetY - box.y - box.h, box.w, box.h);
}
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.
if (clipStack.size()) {
const Rect& top = clipStack.top();
// Make sure the box fits within mClipStack.top(), and clip further accordingly.
if (mClipStack.size()) {
const Rect& top {mClipStack.top()};
if (top.x > box.x)
box.x = top.x;
if (top.y > box.y)
@ -377,27 +334,27 @@ namespace Renderer
if (box.h < 0)
box.h = 0;
clipStack.push(box);
mClipStack.push(box);
setScissor(box);
}
}
void popClipRect()
{
if (clipStack.empty()) {
void Renderer::popClipRect()
{
if (mClipStack.empty()) {
LOG(LogError) << "Tried to popClipRect while the stack was empty";
return;
}
clipStack.pop();
mClipStack.pop();
if (clipStack.empty())
if (mClipStack.empty())
setScissor(Rect(0, 0, 0, 0));
else
setScissor(clipStack.top());
}
setScissor(mClipStack.top());
}
void drawRect(const float x,
void Renderer::drawRect(const float x,
const float y,
const float w,
const float h,
@ -406,9 +363,9 @@ namespace Renderer
bool horizontalGradient,
const float opacity,
const float dimming,
const Blend::Factor srcBlendFactor,
const Blend::Factor dstBlendFactor)
{
const BlendFactor srcBlendFactorFactor,
const BlendFactor dstBlendFactorFactor)
{
Vertex vertices[4];
float wL {w};
@ -436,44 +393,5 @@ namespace Renderer
vertices->dimming = dimming;
bindTexture(0);
drawTriangleStrips(vertices, 4, srcBlendFactor, dstBlendFactor);
}
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
drawTriangleStrips(vertices, 4, srcBlendFactorFactor, dstBlendFactorFactor);
}

View file

@ -3,123 +3,25 @@
// EmulationStation Desktop Edition
// Renderer.h
//
// General rendering functions.
// Generic rendering functions.
//
#ifndef ES_CORE_RENDERER_RENDERER_H
#define ES_CORE_RENDERER_RENDERER_H
#include "Log.h"
#include "Shader_GL21.h"
#include "utils/MathUtil.h"
#include <stack>
#include <string>
#include <vector>
struct SDL_Window;
class Shader;
namespace Renderer
class Renderer
{
// clang-format off
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;
};
public:
struct Vertex {
glm::vec2 position;
glm::vec2 texture;
@ -142,6 +44,7 @@ namespace Renderer
, shaders {0}
{
}
Vertex(const glm::vec2& position, const glm::vec2& textureCoord, const unsigned int color)
: position(position)
, 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();
void deinit();
virtual bool loadShaders() = 0;
void pushClipRect(const glm::ivec2& pos, const glm::ivec2& size);
void popClipRect();
void drawRect(const float x,
const float y,
const float w,
@ -170,56 +134,87 @@ namespace Renderer
bool horizontalGradient = false,
const float opacity = 1.0,
const float dimming = 1.0,
const Blend::Factor srcBlendFactor = Blend::SRC_ALPHA,
const Blend::Factor dstBlendFactor = Blend::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();
const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA,
const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA);
Shader* getShaderProgram(unsigned int shaderID);
const glm::mat4& getProjectionMatrix();
const glm::mat4& getProjectionMatrixNormal();
void shaderPostprocessing(
const glm::mat4& getProjectionMatrix()
{
if (mScreenRotated)
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 Renderer::postProcessingParams& parameters = postProcessingParams(),
unsigned char* textureRGBA = nullptr);
unsigned char* textureRGBA = nullptr) = 0;
void setupWindow();
bool createContext();
void destroyContext();
unsigned int createTexture(const Texture::Type type,
virtual void setup() = 0;
virtual bool createContext() = 0;
virtual void destroyContext() = 0;
virtual 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);
void destroyTexture(const unsigned int texture);
void updateTexture(const unsigned int texture,
const Texture::Type type,
void* data) = 0;
virtual void destroyTexture(const unsigned int texture) = 0;
virtual 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);
void bindTexture(const unsigned int texture);
void drawTriangleStrips(const Vertex* vertices,
void* data) = 0;
virtual void bindTexture(const unsigned int texture) = 0;
virtual void drawTriangleStrips(
const Vertex* vertices,
const unsigned int numVertices,
const Blend::Factor srcBlendFactor = Blend::SRC_ALPHA,
const Blend::Factor dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA);
void setMatrix(const glm::mat4& matrix);
void setScissor(const Rect& scissor);
void setSwapInterval();
void swapBuffers();
const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA,
const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) = 0;
virtual void setMatrix(const glm::mat4& matrix) = 0;
virtual void setScissor(const Rect& scissor) = 0;
virtual void setSwapInterval() = 0;
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

View file

@ -3,62 +3,127 @@
// EmulationStation Desktop Edition
// Renderer_GL21.cpp
//
// OpenGL / OpenGL ES renderer.
// OpenGL / OpenGL ES renderering functions.
//
#include "renderers/Renderer_GL21.h"
#include "Settings.h"
#include "Shader_GL21.h"
#include "renderers/Renderer.h"
#if defined(__APPLE__)
#include <chrono>
#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
switch (blendFactor) {
case Blend::ZERO: { return GL_ZERO; } break;
case Blend::ONE: { return GL_ONE; } break;
case Blend::SRC_COLOR: { return GL_SRC_COLOR; } break;
case Blend::ONE_MINUS_SRC_COLOR: { return GL_ONE_MINUS_SRC_COLOR; } break;
case Blend::SRC_ALPHA: { return GL_SRC_ALPHA; } break;
case Blend::ONE_MINUS_SRC_ALPHA: { return GL_ONE_MINUS_SRC_ALPHA; } break;
case Blend::DST_COLOR: { return GL_DST_COLOR; } break;
case Blend::ONE_MINUS_DST_COLOR: { return GL_ONE_MINUS_DST_COLOR; } break;
case Blend::DST_ALPHA: { return GL_DST_ALPHA; } break;
case Blend::ONE_MINUS_DST_ALPHA: { return GL_ONE_MINUS_DST_ALPHA; } break;
switch (BlendFactorFactor) {
case BlendFactor::ZERO: { return GL_ZERO; } break;
case BlendFactor::ONE: { return GL_ONE; } break;
case BlendFactor::SRC_COLOR: { return GL_SRC_COLOR; } break;
case BlendFactor::ONE_MINUS_SRC_COLOR: { return GL_ONE_MINUS_SRC_COLOR; } break;
case BlendFactor::SRC_ALPHA: { return GL_SRC_ALPHA; } break;
case BlendFactor::ONE_MINUS_SRC_ALPHA: { return GL_ONE_MINUS_SRC_ALPHA; } break;
case BlendFactor::DST_COLOR: { return GL_DST_COLOR; } break;
case BlendFactor::ONE_MINUS_DST_COLOR: { return GL_ONE_MINUS_DST_COLOR; } break;
case BlendFactor::DST_ALPHA: { return GL_DST_ALPHA; } break;
case BlendFactor::ONE_MINUS_DST_ALPHA: { return GL_ONE_MINUS_DST_ALPHA; } break;
default: { return GL_ZERO; }
}
// clang-format on
}
}
inline GLenum convertTextureType(const Texture::Type type)
{
GLenum RendererOpenGL::convertTextureType(const TextureType type)
{
// clang-format off
switch (type) {
case Texture::RGBA: { return GL_RGBA; } break;
case TextureType::RGBA: { return GL_RGBA; } break;
#if defined(USE_OPENGLES)
case Texture::BGRA: { return GL_BGRA_EXT; } break;
case TextureType::BGRA: { return GL_BGRA_EXT; } break;
#else
case Texture::BGRA: { return GL_BGRA; } break;
case TextureType::BGRA: { return GL_BGRA; } break;
#endif
case Texture::RED: { return GL_RED; } break;
case TextureType::RED: { return GL_RED; } break;
default: { return GL_ZERO; }
}
// clang-format on
}
void setupWindow()
{
}
void RendererOpenGL::setup()
{
#if defined(USE_OPENGLES)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
@ -74,13 +139,13 @@ namespace Renderer
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
}
}
bool createContext()
{
sdlContext = SDL_GL_CreateContext(getSDLWindow());
bool RendererOpenGL::createContext()
{
mSDLContext = SDL_GL_CreateContext(getSDLWindow());
if (!sdlContext) {
if (!mSDLContext) {
LOG(LogError) << "Error creating OpenGL context. " << SDL_GetError();
return false;
}
@ -89,17 +154,14 @@ namespace Renderer
glewInit();
#endif
SDL_GL_MakeCurrent(getSDLWindow(), sdlContext);
SDL_GL_MakeCurrent(getSDLWindow(), mSDLContext);
std::string vendor =
glGetString(GL_VENDOR) ? reinterpret_cast<const char*>(glGetString(GL_VENDOR)) : "";
std::string renderer =
glGetString(GL_RENDERER) ? reinterpret_cast<const char*>(glGetString(GL_RENDERER)) : "";
std::string version =
glGetString(GL_VERSION) ? reinterpret_cast<const char*>(glGetString(GL_VERSION)) : "";
std::string extensions = glGetString(GL_EXTENSIONS) ?
reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)) :
"";
std::string vendor {
glGetString(GL_VENDOR) ? reinterpret_cast<const char*>(glGetString(GL_VENDOR)) : ""};
std::string renderer {
glGetString(GL_RENDERER) ? reinterpret_cast<const char*>(glGetString(GL_RENDERER)) : ""};
std::string version {
glGetString(GL_VERSION) ? reinterpret_cast<const char*>(glGetString(GL_VERSION)) : ""};
LOG(LogInfo) << "GL vendor: " << vendor;
LOG(LogInfo) << "GL renderer: " << renderer;
@ -126,59 +188,119 @@ namespace Renderer
GL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
// These are used for the shader post processing.
GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO1));
GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO2));
GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO1));
GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO2));
GL_CHECK_ERROR(glGenBuffers(1, &vertexBuffer1));
GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer1));
GL_CHECK_ERROR(glGenVertexArrays(1, &vertexBuffer2));
GL_CHECK_ERROR(glBindVertexArray(vertexBuffer2));
GL_CHECK_ERROR(glGenBuffers(1, &mVertexBuffer1));
GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer1));
GL_CHECK_ERROR(glGenVertexArrays(1, &mVertexBuffer2));
GL_CHECK_ERROR(glBindVertexArray(mVertexBuffer2));
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>(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>(getScreenHeight()), nullptr);
// 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,
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,
postProcTexture2, 0));
mPostProcTexture2, 0));
GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0));
return true;
}
}
void destroyContext()
{
GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO1));
GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO2));
destroyTexture(postProcTexture1);
destroyTexture(postProcTexture2);
destroyTexture(whiteTexture);
SDL_GL_DeleteContext(sdlContext);
sdlContext = nullptr;
}
void RendererOpenGL::destroyContext()
{
GL_CHECK_ERROR(glDeleteFramebuffers(1, &mShaderFBO1));
GL_CHECK_ERROR(glDeleteFramebuffers(1, &mShaderFBO2));
destroyTexture(mPostProcTexture1);
destroyTexture(mPostProcTexture2);
destroyTexture(mWhiteTexture);
SDL_GL_DeleteContext(mSDLContext);
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 linearMagnify,
const bool repeat,
const unsigned int width,
const unsigned int height,
void* data)
{
const GLenum textureType = convertTextureType(type);
{
const GLenum textureType {RendererOpenGL::convertTextureType(type)};
unsigned int texture;
GL_CHECK_ERROR(glGenTextures(1, &texture));
@ -200,97 +322,107 @@ namespace Renderer
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType,
GL_UNSIGNED_BYTE, data));
return texture;
}
}
void destroyTexture(const unsigned int texture)
{
void RendererOpenGL::destroyTexture(const unsigned int texture)
{
GL_CHECK_ERROR(glDeleteTextures(1, &texture));
}
}
void updateTexture(const unsigned int texture,
const Texture::Type type,
void RendererOpenGL::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)
{
const GLenum textureType = convertTextureType(type);
{
const GLenum textureType {RendererOpenGL::convertTextureType(type)};
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, textureType,
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)
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, whiteTexture));
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, mWhiteTexture));
else
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
}
}
void drawTriangleStrips(const Vertex* vertices,
void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
const unsigned int numVertices,
const Blend::Factor srcBlendFactor,
const Blend::Factor dstBlendFactor)
{
const BlendFactor srcBlendFactorFactor,
const BlendFactor dstBlendFactorFactor)
{
const float width {vertices[3].position[0]};
const float height {vertices[3].position[1]};
GL_CHECK_ERROR(
glBlendFunc(convertBlendFactor(srcBlendFactor), convertBlendFactor(dstBlendFactor)));
GL_CHECK_ERROR(glBlendFunc(RendererOpenGL::convertBlendFactor(srcBlendFactorFactor),
RendererOpenGL::convertBlendFactor(dstBlendFactorFactor)));
if (vertices->shaders == 0 || vertices->shaders & SHADER_CORE) {
Shader* shader {getShaderProgram(SHADER_CORE)};
if (shader) {
shader->activateShaders();
shader->setModelViewProjectionMatrix(mTrans);
shader->setAttribPointers();
if (mCoreShader == nullptr)
mCoreShader = RendererOpenGL::getShaderProgram(SHADER_CORE);
if (mCoreShader) {
if (mLastShader != mCoreShader)
mCoreShader->activateShaders();
mCoreShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mCoreShader)
mCoreShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW));
shader->setOpacity(vertices->opacity);
shader->setSaturation(vertices->saturation);
shader->setDimming(vertices->dimming);
shader->setBGRAToRGBA(vertices->convertBGRAToRGBA);
shader->setFont(vertices->font);
shader->setPostProcessing(vertices->postProcessing);
mCoreShader->setOpacity(vertices->opacity);
mCoreShader->setSaturation(vertices->saturation);
mCoreShader->setDimming(vertices->dimming);
mCoreShader->setBGRAToRGBA(vertices->convertBGRAToRGBA);
mCoreShader->setFont(vertices->font);
mCoreShader->setPostProcessing(vertices->postProcessing);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders();
mLastShader = mCoreShader;
}
}
else if (vertices->shaders & SHADER_BLUR_HORIZONTAL) {
Shader* shader {getShaderProgram(SHADER_BLUR_HORIZONTAL)};
if (shader) {
shader->activateShaders();
shader->setModelViewProjectionMatrix(mTrans);
shader->setAttribPointers();
if (mBlurHorizontalShader == nullptr)
mBlurHorizontalShader = RendererOpenGL::getShaderProgram(SHADER_BLUR_HORIZONTAL);
if (mBlurHorizontalShader) {
if (mLastShader != mBlurHorizontalShader)
mBlurHorizontalShader->activateShaders();
mBlurHorizontalShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mBlurHorizontalShader)
mBlurHorizontalShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW));
shader->setTextureSize({width, height});
mBlurHorizontalShader->setTextureSize({width, height});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders();
mLastShader = mBlurHorizontalShader;
}
return;
}
else if (vertices->shaders & SHADER_BLUR_VERTICAL) {
Shader* shader {getShaderProgram(SHADER_BLUR_VERTICAL)};
if (shader) {
shader->activateShaders();
shader->setModelViewProjectionMatrix(mTrans);
shader->setAttribPointers();
if (mBlurVerticalShader == nullptr)
mBlurVerticalShader = RendererOpenGL::getShaderProgram(SHADER_BLUR_VERTICAL);
if (mBlurVerticalShader) {
if (mLastShader != mBlurVerticalShader)
mBlurVerticalShader->activateShaders();
mBlurVerticalShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mBlurVerticalShader)
mBlurVerticalShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW));
shader->setTextureSize({width, height});
mBlurVerticalShader->setTextureSize({width, height});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders();
mLastShader = mBlurVerticalShader;
}
return;
}
else if (vertices->shaders & SHADER_SCANLINES) {
Shader* shader {getShaderProgram(SHADER_SCANLINES)};
if (mScanlinelShader == nullptr)
mScanlinelShader = RendererOpenGL::getShaderProgram(SHADER_SCANLINES);
float shaderWidth {width * 1.2f};
// Scale the scanlines relative to screen resolution.
float screenHeightModifier {getScreenHeightModifier()};
@ -310,84 +442,26 @@ namespace Renderer
float modifier {1.41f + relativeAdjustment / 7.0f - (0.14f * screenHeightModifier)};
shaderHeight = height * modifier;
}
if (shader) {
shader->activateShaders();
shader->setModelViewProjectionMatrix(mTrans);
shader->setAttribPointers();
if (mScanlinelShader) {
if (mLastShader != mScanlinelShader)
mScanlinelShader->activateShaders();
mScanlinelShader->setModelViewProjectionMatrix(mTrans);
if (mLastShader != mScanlinelShader)
mScanlinelShader->setAttribPointers();
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW));
shader->setOpacity(vertices->opacity);
shader->setTextureSize({shaderWidth, shaderHeight});
mScanlinelShader->setOpacity(vertices->opacity);
mScanlinelShader->setTextureSize({shaderWidth, shaderHeight});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
shader->deactivateShaders();
}
mLastShader = mScanlinelShader;
}
}
}
void setMatrix(const glm::mat4& matrix)
{
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,
void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
const Renderer::postProcessingParams& parameters,
unsigned char* textureRGBA)
{
{
Vertex vertices[4];
std::vector<unsigned int> shaderList;
float widthf {getScreenWidth()};
@ -409,25 +483,25 @@ namespace Renderer
vertices->dimming = parameters.dimming;
vertices->postProcessing = true;
if (shaders & Renderer::SHADER_CORE)
shaderList.push_back(Renderer::SHADER_CORE);
if (shaders & Renderer::SHADER_BLUR_HORIZONTAL)
shaderList.push_back(Renderer::SHADER_BLUR_HORIZONTAL);
if (shaders & Renderer::SHADER_BLUR_VERTICAL)
shaderList.push_back(Renderer::SHADER_BLUR_VERTICAL);
if (shaders & Renderer::SHADER_SCANLINES)
shaderList.push_back(Renderer::SHADER_SCANLINES);
if (shaders & SHADER_CORE)
shaderList.push_back(SHADER_CORE);
if (shaders & SHADER_BLUR_HORIZONTAL)
shaderList.push_back(SHADER_BLUR_HORIZONTAL);
if (shaders & SHADER_BLUR_VERTICAL)
shaderList.push_back(SHADER_BLUR_VERTICAL);
if (shaders & SHADER_SCANLINES)
shaderList.push_back(SHADER_SCANLINES);
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.
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
GL_COLOR_BUFFER_BIT, GL_NEAREST));
// Blit the screen contents to mPostProcTexture.
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
GL_NEAREST));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
bool firstFBO {true};
int drawCalls {0};
@ -455,23 +529,25 @@ namespace Renderer
// If it's the last shader pass, then render directly to the default framebuffer
// to avoid having to make an expensive glBlitFramebuffer() call.
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;
}
// 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;
if (firstFBO) {
bindTexture(postProcTexture2);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO2));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO1));
bindTexture(mPostProcTexture2);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
firstFBO = false;
}
else {
bindTexture(postProcTexture1);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO1));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2));
bindTexture(mPostProcTexture1);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO1));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
firstFBO = true;
}
@ -484,12 +560,11 @@ namespace Renderer
// screen texture, it doesn't really matter.
if (textureRGBA) {
if (firstFBO)
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO1));
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO1));
else
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO2));
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR(
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA));
GL_CHECK_ERROR(glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA));
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
}
@ -497,6 +572,4 @@ namespace Renderer
setMatrix(getIdentity());
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,32 +12,30 @@
#include "renderers/Renderer.h"
#include "resources/ResourceManager.h"
namespace Renderer
{
Renderer::Shader::Shader()
Shader::Shader()
: mProgramID {0}
, shaderMVPMatrix {0}
, shaderPosition {0}
, shaderTextureCoord {0}
, shaderColor {0}
, shaderTextureSize {0}
, shaderOpacity {0}
, shaderSaturation {0}
, shaderDimming {0}
, shaderBGRAToRGBA {0}
, shaderFont {0}
, shaderPostProcessing {0}
{
}
, mShaderMVPMatrix {0}
, mShaderPosition {0}
, mShaderTextureCoord {0}
, mShaderColor {0}
, mShaderTextureSize {0}
, mShaderOpacity {0}
, mShaderSaturation {0}
, mShaderDimming {0}
, mShaderBGRAToRGBA {0}
, mShaderFont {0}
, mShaderPostProcessing {0}
{
}
Renderer::Shader::~Shader()
{
Shader::~Shader()
{
// Delete the shader program when destroyed.
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 shaderCode;
@ -58,22 +56,21 @@ namespace Renderer
else if (shaderType == GL_FRAGMENT_SHADER)
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;
mProgramID = glCreateProgram();
// Compile and attach all shaders that have been loaded.
for (auto it = shaderVector.cbegin(); it != shaderVector.cend(); ++it) {
GLuint currentShader = glCreateShader(std::get<2>(*it));
GLchar const* shaderCodePtr = std::get<1>(*it).c_str();
for (auto it = mShaderVector.cbegin(); it != mShaderVector.cend(); ++it) {
GLuint currentShader {glCreateShader(std::get<2>(*it))};
GLchar const* shaderCodePtr {std::get<1>(*it).c_str()};
glShaderSource(currentShader, 1, reinterpret_cast<const GLchar**>(&shaderCodePtr),
nullptr);
glShaderSource(currentShader, 1, reinterpret_cast<const GLchar**>(&shaderCodePtr), nullptr);
glCompileShader(currentShader);
GLint shaderCompiled;
@ -103,119 +100,116 @@ namespace Renderer
getVariableLocations(mProgramID);
if (shaderPosition != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(shaderPosition));
if (mShaderPosition != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(mShaderPosition));
if (shaderTextureCoord != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(shaderTextureCoord));
if (mShaderTextureCoord != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(mShaderTextureCoord));
if (shaderColor != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(shaderColor));
if (mShaderColor != -1)
GL_CHECK_ERROR(glEnableVertexAttribArray(mShaderColor));
return true;
}
}
void Renderer::Shader::deleteProgram(GLuint programID)
{
GL_CHECK_ERROR(glDeleteProgram(programID));
}
void Shader::deleteProgram(GLuint 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.
shaderMVPMatrix = glGetUniformLocation(mProgramID, "MVPMatrix");
shaderPosition = glGetAttribLocation(mProgramID, "positionAttrib");
shaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord");
shaderColor = glGetAttribLocation(mProgramID, "colorAttrib");
shaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize");
shaderOpacity = glGetUniformLocation(mProgramID, "opacity");
shaderSaturation = glGetUniformLocation(mProgramID, "saturation");
shaderDimming = glGetUniformLocation(mProgramID, "dimming");
shaderBGRAToRGBA = glGetUniformLocation(mProgramID, "BGRAToRGBA");
shaderFont = glGetUniformLocation(mProgramID, "font");
shaderPostProcessing = glGetUniformLocation(mProgramID, "postProcessing");
}
mShaderMVPMatrix = glGetUniformLocation(mProgramID, "MVPMatrix");
mShaderPosition = glGetAttribLocation(mProgramID, "positionAttrib");
mShaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord");
mShaderColor = glGetAttribLocation(mProgramID, "colorAttrib");
mShaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize");
mShaderOpacity = glGetUniformLocation(mProgramID, "opacity");
mShaderSaturation = glGetUniformLocation(mProgramID, "saturation");
mShaderDimming = glGetUniformLocation(mProgramID, "dimming");
mShaderBGRAToRGBA = glGetUniformLocation(mProgramID, "BGRAToRGBA");
mShaderFont = glGetUniformLocation(mProgramID, "font");
mShaderPostProcessing = glGetUniformLocation(mProgramID, "postProcessing");
}
void Renderer::Shader::setModelViewProjectionMatrix(glm::mat4 mvpMatrix)
{
if (shaderMVPMatrix != GL_INVALID_VALUE && shaderMVPMatrix != GL_INVALID_OPERATION)
GL_CHECK_ERROR(glUniformMatrix4fv(shaderMVPMatrix, 1, GL_FALSE,
void Shader::setModelViewProjectionMatrix(glm::mat4 mvpMatrix)
{
if (mShaderMVPMatrix != GL_INVALID_VALUE && mShaderMVPMatrix != GL_INVALID_OPERATION)
GL_CHECK_ERROR(glUniformMatrix4fv(mShaderMVPMatrix, 1, GL_FALSE,
reinterpret_cast<GLfloat*>(&mvpMatrix)));
}
}
void Renderer::Shader::setAttribPointers()
{
if (shaderPosition != -1)
GL_CHECK_ERROR(
glVertexAttribPointer(shaderPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, position))));
if (shaderTextureCoord != -1)
GL_CHECK_ERROR(
glVertexAttribPointer(shaderTextureCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, texture))));
void Shader::setAttribPointers()
{
if (mShaderPosition != -1)
GL_CHECK_ERROR(glVertexAttribPointer(
mShaderPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Renderer::Vertex),
reinterpret_cast<const void*>(offsetof(Renderer::Vertex, position))));
if (mShaderTextureCoord != -1)
GL_CHECK_ERROR(glVertexAttribPointer(
mShaderTextureCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Renderer::Vertex),
reinterpret_cast<const void*>(offsetof(Renderer::Vertex, texture))));
if (shaderColor != -1)
GL_CHECK_ERROR(
glVertexAttribPointer(shaderColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex),
reinterpret_cast<const void*>(offsetof(Vertex, color))));
}
if (mShaderColor != -1)
GL_CHECK_ERROR(glVertexAttribPointer(
mShaderColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Renderer::Vertex),
reinterpret_cast<const void*>(offsetof(Renderer::Vertex, color))));
}
void Renderer::Shader::setTextureSize(std::array<GLfloat, 2> shaderVec2)
{
if (shaderTextureSize != -1)
GL_CHECK_ERROR(glUniform2f(shaderTextureSize, shaderVec2[0], shaderVec2[1]));
}
void Shader::setTextureSize(std::array<GLfloat, 2> shaderVec2)
{
if (mShaderTextureSize != -1)
GL_CHECK_ERROR(glUniform2f(mShaderTextureSize, shaderVec2[0], shaderVec2[1]));
}
void Renderer::Shader::setOpacity(GLfloat opacity)
{
if (shaderOpacity != -1)
GL_CHECK_ERROR(glUniform1f(shaderOpacity, opacity));
}
void Shader::setOpacity(GLfloat opacity)
{
if (mShaderOpacity != -1)
GL_CHECK_ERROR(glUniform1f(mShaderOpacity, opacity));
}
void Renderer::Shader::setSaturation(GLfloat saturation)
{
if (shaderSaturation != -1)
GL_CHECK_ERROR(glUniform1f(shaderSaturation, saturation));
}
void Shader::setSaturation(GLfloat saturation)
{
if (mShaderSaturation != -1)
GL_CHECK_ERROR(glUniform1f(mShaderSaturation, saturation));
}
void Renderer::Shader::setDimming(GLfloat dimming)
{
if (shaderDimming != -1)
GL_CHECK_ERROR(glUniform1f(shaderDimming, dimming));
}
void Shader::setDimming(GLfloat dimming)
{
if (mShaderDimming != -1)
GL_CHECK_ERROR(glUniform1f(mShaderDimming, dimming));
}
void Renderer::Shader::setBGRAToRGBA(GLboolean BGRAToRGBA)
{
if (shaderBGRAToRGBA != -1)
GL_CHECK_ERROR(glUniform1i(shaderBGRAToRGBA, BGRAToRGBA ? 1 : 0));
}
void Shader::setBGRAToRGBA(GLboolean BGRAToRGBA)
{
if (mShaderBGRAToRGBA != -1)
GL_CHECK_ERROR(glUniform1i(mShaderBGRAToRGBA, BGRAToRGBA ? 1 : 0));
}
void Renderer::Shader::setFont(GLboolean font)
{
if (shaderFont != -1)
GL_CHECK_ERROR(glUniform1i(shaderFont, font ? 1 : 0));
}
void Shader::setFont(GLboolean font)
{
if (mShaderFont != -1)
GL_CHECK_ERROR(glUniform1i(mShaderFont, font ? 1 : 0));
}
void Renderer::Shader::setPostProcessing(GLboolean postProcessing)
{
if (shaderPostProcessing != -1)
GL_CHECK_ERROR(glUniform1i(shaderPostProcessing, postProcessing ? 1 : 0));
}
void Shader::setPostProcessing(GLboolean postProcessing)
{
if (mShaderPostProcessing != -1)
GL_CHECK_ERROR(glUniform1i(mShaderPostProcessing, postProcessing ? 1 : 0));
}
void Renderer::Shader::activateShaders()
{
void Shader::activateShaders()
{
// Install the shader program.
GL_CHECK_ERROR(glUseProgram(mProgramID));
}
}
void Renderer::Shader::deactivateShaders()
{
void Shader::deactivateShaders()
{
// Remove the shader program.
GL_CHECK_ERROR(glUseProgram(0));
}
}
void Renderer::Shader::printProgramInfoLog(GLuint programID)
{
void Shader::printProgramInfoLog(GLuint programID)
{
if (glIsProgram(programID)) {
int logLength;
int maxLength;
@ -233,10 +227,10 @@ namespace Renderer
else {
LOG(LogError) << "OpenGL error: " << programID << " is not a program.";
}
}
}
void Renderer::Shader::printShaderInfoLog(GLuint shaderID, GLenum shaderType, bool error)
{
void Shader::printShaderInfoLog(GLuint shaderID, GLenum shaderType, bool error)
{
if (glIsShader(shaderID)) {
int logLength;
int maxLength;
@ -250,8 +244,8 @@ namespace Renderer
glGetShaderInfoLog(shaderID, maxLength, &logLength, &infoLog.front());
if (logLength > 0) {
LOG(LogDebug) << "Shader_GL21::printShaderInfoLog(): "
<< (error ? "Error" : "Warning") << " in "
LOG(LogDebug) << "Shader_GL21::printShaderInfoLog(): " << (error ? "Error" : "Warning")
<< " in "
<< (shaderType == GL_VERTEX_SHADER ? "VERTEX section:\n" :
"FRAGMENT section:\n")
<< std::string(infoLog.begin(), infoLog.end());
@ -260,6 +254,4 @@ namespace Renderer
else {
LOG(LogError) << "OpenGL error: " << shaderID << " is not a shader.";
}
}
} // namespace Renderer
}

View file

@ -11,6 +11,7 @@
#define GL_GLEXT_PROTOTYPES
#include "renderers/Renderer.h"
#include "utils/MathUtil.h"
#if defined(_WIN64)
@ -28,11 +29,29 @@
#include <string>
#include <vector>
namespace Renderer
#if !defined(NDEBUG)
#define GL_CHECK_ERROR(Function) (Function, _GLCheckError(#Function))
static inline void _GLCheckError(const std::string& funcName)
{
class Shader
{
public:
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
{
public:
Shader();
~Shader();
@ -65,24 +84,22 @@ namespace Renderer
void printProgramInfoLog(GLuint programID);
void printShaderInfoLog(GLuint shaderID, GLenum shaderType, bool error);
private:
private:
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.
GLint shaderMVPMatrix;
GLint shaderPosition;
GLint shaderTextureCoord;
GLint shaderColor;
GLint shaderTextureSize;
GLint shaderOpacity;
GLint shaderSaturation;
GLint shaderDimming;
GLint shaderBGRAToRGBA;
GLint shaderFont;
GLint shaderPostProcessing;
};
} // namespace Renderer
GLint mShaderMVPMatrix;
GLint mShaderPosition;
GLint mShaderTextureCoord;
GLint mShaderColor;
GLint mShaderTextureSize;
GLint mShaderOpacity;
GLint mShaderSaturation;
GLint mShaderDimming;
GLint mShaderBGRAToRGBA;
GLint mShaderFont;
GLint mShaderPostProcessing;
};
#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)
: mSize(size)
: mRenderer {Renderer::getInstance()}
, mSize(size)
, mPath(path)
{
if (mSize < 9) {
@ -199,14 +200,14 @@ bool Font::FontTexture::findEmpty(const glm::ivec2& size, glm::ivec2& cursor_out
void Font::FontTexture::initTexture()
{
assert(textureId == 0);
textureId = Renderer::createTexture(Renderer::Texture::RED, false, false, false, textureSize.x,
textureSize.y, nullptr);
textureId = Renderer::getInstance()->createTexture(
Renderer::TextureType::RED, false, false, false, textureSize.x, textureSize.y, nullptr);
}
void Font::FontTexture::deinitTexture()
{
if (textureId != 0) {
Renderer::destroyTexture(textureId);
Renderer::getInstance()->destroyTexture(textureId);
textureId = 0;
}
}
@ -346,8 +347,8 @@ Font::Glyph* Font::getGlyph(unsigned int id)
static_cast<float>(g->metrics.horiBearingY) / 64.0f};
// Upload glyph bitmap to texture.
Renderer::updateTexture(tex->textureId, Renderer::Texture::RED, cursor.x, cursor.y, glyphSize.x,
glyphSize.y, g->bitmap.buffer);
mRenderer->updateTexture(tex->textureId, Renderer::TextureType::RED, cursor.x, cursor.y,
glyphSize.x, glyphSize.y, g->bitmap.buffer);
// Update max glyph height.
if (glyphSize.y > mMaxGlyphHeight)
@ -380,7 +381,7 @@ void Font::rebuildTextures()
static_cast<int>(it->second.texSize.y * tex->textureSize.y)};
// 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);
}
}
@ -398,8 +399,8 @@ void Font::renderTextCache(TextCache* cache)
auto vertexList = *it;
it->verts[0].font = true;
Renderer::bindTexture(*it->textureIdPtr);
Renderer::drawTriangleStrips(&it->verts[0],
mRenderer->bindTexture(*it->textureIdPtr);
mRenderer->drawTriangleStrips(&it->verts[0],
static_cast<const unsigned int>(it->verts.size()));
}
}

View file

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

View file

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

View file

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