// This file is part of Desktop App Toolkit, // a set of libraries for developing nice desktop applications. // // For license and copyright information please follow this link: // https://github.com/desktop-app/legal/blob/master/LEGAL // #include "ui/gl/gl_surface.h" #include "ui/rp_widget.h" #include "ui/painter.h" #include #include #include #include #include namespace Ui::GL { namespace { struct SurfaceTraits : RpWidgetDefaultTraits { static constexpr bool kSetZeroGeometry = false; }; class SurfaceOpenGL final : public RpWidgetBase { public: SurfaceOpenGL(QWidget *parent, std::unique_ptr renderer); ~SurfaceOpenGL(); private: void initializeGL() override; void resizeGL(int w, int h) override; void paintEvent(QPaintEvent *e) override; void callDeInit(); const std::unique_ptr _renderer; QMetaObject::Connection _connection; }; class SurfaceRaster final : public RpWidgetBase { public: SurfaceRaster(QWidget *parent, std::unique_ptr renderer); private: void paintEvent(QPaintEvent *e) override; const std::unique_ptr _renderer; }; SurfaceOpenGL::SurfaceOpenGL( QWidget *parent, std::unique_ptr renderer) : RpWidgetBase(parent) , _renderer(std::move(renderer)) { } SurfaceOpenGL::~SurfaceOpenGL() { callDeInit(); } void SurfaceOpenGL::initializeGL() { Expects(window()->windowHandle() != nullptr); if (_connection) { QObject::disconnect(base::take(_connection)); } const auto context = this->context(); _connection = QObject::connect( context, &QOpenGLContext::aboutToBeDestroyed, [=] { callDeInit(); }); _renderer->init(this, *context->functions()); } void SurfaceOpenGL::resizeGL(int w, int h) { _renderer->resize(this, *context()->functions(), w, h); } void SurfaceOpenGL::paintEvent(QPaintEvent *e) { if (!updatesEnabled() || size().isEmpty() || !isValid()) { return; } auto redirectOffset = QPoint(); const auto rpd = redirected(&redirectOffset); const auto device = rpd ? rpd : static_cast(this); const auto engine = device->paintEngine(); if (!engine) { return; } engine->begin(device); const auto f = context()->functions(); if (const auto bg = _renderer->clearColor()) { f->glClearColor(bg->redF(), bg->greenF(), bg->blueF(), bg->alphaF()); f->glClear(GL_COLOR_BUFFER_BIT); } f->glDisable(GL_BLEND); f->glViewport(0, 0, device->width(), device->height()); _renderer->paint(this, *f); engine->end(); } void SurfaceOpenGL::callDeInit() { if (!_connection) { return; } QObject::disconnect(base::take(_connection)); const auto surface = window()->windowHandle(); Assert(surface != nullptr); const auto context = this->context(); context->makeCurrent(surface); _renderer->deinit(this, *context->functions()); } SurfaceRaster::SurfaceRaster( QWidget *parent, std::unique_ptr renderer) : RpWidgetBase(parent) , _renderer(std::move(renderer)) { } void SurfaceRaster::paintEvent(QPaintEvent *e) { _renderer->paintFallback(Painter(this), e->region(), Backend::Raster); } } // namespace void Renderer::paint( not_null widget, QOpenGLFunctions &f) { paintFallback(Painter(widget.get()), widget->rect(), Backend::OpenGL); } std::unique_ptr CreateSurface( Fn chooseRenderer) { auto chosen = chooseRenderer(CheckCapabilities(nullptr)); switch (chosen.backend) { case Backend::OpenGL: return std::make_unique( nullptr, std::move(chosen.renderer)); case Backend::Raster: return std::make_unique( nullptr, std::move(chosen.renderer)); } Unexpected("Backend value in Ui::GL::CreateSurface."); } std::unique_ptr CreateSurface( QWidget *parent, ChosenRenderer chosen) { switch (chosen.backend) { case Backend::OpenGL: return std::make_unique( parent, std::move(chosen.renderer)); case Backend::Raster: return std::make_unique( parent, std::move(chosen.renderer)); } Unexpected("Backend value in Ui::GL::CreateSurface."); } } // namespace Ui::GL