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;
}
}