VisualizationContainer::VisualizationContainer(QWidget *parent) : QMainWindow(parent), projectm_visualization_(new ProjectMVisualization(this)), overlay_(new VisualizationOverlay), selector_(new VisualizationSelector(this)), overlay_proxy_(nullptr), engine_(nullptr), menu_(new QMenu(this)), fps_(kDefaultFps), size_(kDefaultTextureSize) { setWindowTitle(tr("Visualizations")); setWindowIcon(IconLoader::Load(QStringLiteral("strawberry"))); setMinimumSize(64, 64); { Settings s; s.beginGroup(QLatin1String(kSettingsGroup)); if (!restoreGeometry(s.value("geometry").toByteArray())) { resize(kDefaultWidth, kDefaultHeight); } fps_ = s.value("fps", kDefaultFps).toInt(); size_ = s.value("size", kDefaultTextureSize).toInt(); s.endGroup(); } QShortcut *close = new QShortcut(QKeySequence::Close, this); QObject::connect(close, &QShortcut::activated, this, &VisualizationContainer::close); QObject::connect(overlay_, &VisualizationOverlay::OpacityChanged, this, &VisualizationContainer::ChangeOverlayOpacity); QObject::connect(overlay_, &VisualizationOverlay::ShowPopupMenu, this, &VisualizationContainer::ShowPopupMenu); ChangeOverlayOpacity(1.0); projectm_visualization_->SetTextureSize(size_); SizeChanged(); selector_->SetVisualization(projectm_visualization_); menu_->addAction(IconLoader::Load(QStringLiteral("view-fullscreen")), tr("Toggle fullscreen"), this, &VisualizationContainer::ToggleFullscreen); QMenu *fps_menu = menu_->addMenu(tr("Framerate")); QActionGroup *fps_group = new QActionGroup(this); AddFramerateMenuItem(tr("Low (%1 fps)").arg(kLowFramerate), kLowFramerate, fps_, fps_group); AddFramerateMenuItem(tr("Medium (%1 fps)").arg(kMediumFramerate), kMediumFramerate, fps_, fps_group); AddFramerateMenuItem(tr("High (%1 fps)").arg(kHighFramerate), kHighFramerate, fps_, fps_group); AddFramerateMenuItem(tr("Super high (%1 fps)").arg(kSuperHighFramerate), kSuperHighFramerate, fps_, fps_group); fps_menu->addActions(fps_group->actions()); QMenu *quality_menu = menu_->addMenu(tr("Quality", "Visualization quality")); QActionGroup *quality_group = new QActionGroup(this); AddQualityMenuItem(tr("Low (256x256)"), 256, size_, quality_group); AddQualityMenuItem(tr("Medium (512x512)"), 512, size_, quality_group); AddQualityMenuItem(tr("High (1024x1024)"), 1024, size_, quality_group); AddQualityMenuItem(tr("Super high (2048x2048)"), 2048, size_, quality_group); quality_menu->addActions(quality_group->actions()); menu_->addAction(tr("Select visualizations..."), selector_, &VisualizationContainer::show); menu_->addSeparator(); menu_->addAction(IconLoader::Load(QStringLiteral("application-exit")), tr("Close visualization"), this, &VisualizationContainer::hide); // OpenGL // Create and configure the QSurfaceFormat QSurfaceFormat format; format.setVersion(3, 3); // Set OpenGL version to 3.3 format.setProfile(QSurfaceFormat::CoreProfile); // Use the core profile format.setDepthBufferSize(24); format.setStencilBufferSize(8); // Initialize the primary OpenGL context QOpenGLContext *openGLContext = new QOpenGLContext(this); openGLContext->setFormat(format); if (!openGLContext->create()) { qWarning() << "Failed to create OpenGL context"; } else { qDebug() << "OpenGL context created successfully"; } // Create a new shared context QOpenGLContext *sharedContext = new QOpenGLContext(this); sharedContext->setFormat(format); if (!sharedContext->create()) { qWarning() << "Failed to create shared OpenGL context"; } else { qDebug() << "Shared OpenGL context created successfully"; } // Set the shared context openGLContext->setShareContext(sharedContext); // Create the OpenGL window using the primary OpenGL context openGLWindow_ = new VisualizationOpenGLWidget(projectm_visualization_, openGLContext); openGLWindow_->setFormat(format); // Make the OpenGL context current if (!openGLContext->makeCurrent(openGLWindow_)) { qWarning() << "Failed to make OpenGL context current"; } // Wrap the QOpenGLWindow in a QWidget container glContainer = QWidget::createWindowContainer(openGLWindow_); glContainer->setFocusPolicy(Qt::TabFocus); glContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); glContainer->setParent(this); glContainer->setVisible(true); setCentralWidget(glContainer); projectm_visualization_->Resize(width(), height()); // Add the overlay as a child of the container and set its visibility overlay_->setParent(glContainer); overlay_->resize(glContainer->size()); // Resize the overlay to match the container size overlay_->setVisible(true); overlay_->raise(); } #ifndef VISUALIZATIONOPENGLWIDGET_H #define VISUALIZATIONOPENGLWIDGET_H #include "config.h" #include <QOpenGLWindow> #include <QOpenGLFunctions> class ProjectMVisualization; class VisualizationOpenGLWidget : public QOpenGLWindow, protected QOpenGLFunctions { Q_OBJECT public: explicit VisualizationOpenGLWidget(ProjectMVisualization* projectm_visualization, QOpenGLContext* sharedContext, QWindow* parent = nullptr); void initializeGL() override; protected: void paintGL() override; void resizeGL(int width, int height) override; private: void Setup(int width, int height); ProjectMVisualization* projectm_visualization_; QOpenGLContext* sharedContext_; }; #endif // VISUALIZATIONOPENGLWIDGET_H #include "config.h" #include <QPainter> #include "core/logging.h" #include "visualizationopenglwidget.h" #include "projectmvisualization.h" VisualizationOpenGLWidget::VisualizationOpenGLWidget(ProjectMVisualization* projectm_visualization, QOpenGLContext* sharedContext, QWindow* parent) : QOpenGLWindow(NoPartialUpdate, parent), projectm_visualization_(projectm_visualization), sharedContext_(sharedContext) { setFormat(sharedContext_->format()); } void VisualizationOpenGLWidget::initializeGL() { QOpenGLWindow::initializeGL(); sharedContext_->makeCurrent(this); initializeOpenGLFunctions(); projectm_visualization_->Init(); } void VisualizationOpenGLWidget::paintGL() { sharedContext_->makeCurrent(this); QPainter p(this); p.beginNativePainting(); if (projectm_visualization_) { Setup(width(), height()); projectm_visualization_->RenderFrame(width(), height()); } update(); p.endNativePainting(); GLenum error = glGetError(); if (error != GL_NO_ERROR) { qWarning() << "OpenGL error in paintGL:" << error; } qLog(Debug) << __PRETTY_FUNCTION__ << "Completed"; } void VisualizationOpenGLWidget::resizeGL(int width, int height) { sharedContext_->makeCurrent(this); Setup(width, height); projectm_visualization_->Resize(width, height); GLenum error = glGetError(); if (error != GL_NO_ERROR) { qWarning() << "OpenGL error in resizeGL:" << error; } } void VisualizationOpenGLWidget::Setup(int width, int height) { // Ensure the correct OpenGL context is current if (!sharedContext_->makeCurrent(this)) { qWarning() << "Failed to make OpenGL context current in Setup"; return; } // Initialize OpenGL functions initializeOpenGLFunctions(); // Set up OpenGL state glShadeModel(GL_SMOOTH); glClearColor(0, 0, 0, 0); glViewport(0, 0, width, height); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, height, 0, -1, 1); // Set an orthographic projection matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDrawBuffer(GL_BACK); glReadBuffer(GL_BACK); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); glEnable(GL_POINT_SMOOTH); glClearColor(0.0F, 0.0F, 0.0F, 0.0F); glLineStipple(2, 0xAAAA); GLenum error = glGetError(); if (error != GL_NO_ERROR) { qWarning() << "OpenGL error in Setup:" << error; } }