fix the freeze with openglwidget

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97
2025-01-21 23:36:40 +02:00
parent d2516cbecc
commit 7010b8acb6
8 changed files with 81 additions and 66 deletions

View File

@ -1077,8 +1077,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/skins/SkinManageDialog.cpp ui/dialogs/skins/SkinManageDialog.cpp
ui/dialogs/skins/SkinManageDialog.h ui/dialogs/skins/SkinManageDialog.h
ui/dialogs/skins/draw/SkinOpenGLWidget.h ui/dialogs/skins/draw/SkinOpenGLWindow.h
ui/dialogs/skins/draw/SkinOpenGLWidget.cpp ui/dialogs/skins/draw/SkinOpenGLWindow.cpp
ui/dialogs/skins/draw/Scene.h ui/dialogs/skins/draw/Scene.h
ui/dialogs/skins/draw/Scene.cpp ui/dialogs/skins/draw/Scene.cpp
ui/dialogs/skins/draw/BoxGeometry.h ui/dialogs/skins/draw/BoxGeometry.h

View File

@ -17,7 +17,7 @@
*/ */
#include "SkinManageDialog.h" #include "SkinManageDialog.h"
#include "ui/dialogs/skins/draw/SkinOpenGLWidget.h" #include "ui/dialogs/skins/draw/SkinOpenGLWindow.h"
#include "ui_SkinManageDialog.h" #include "ui_SkinManageDialog.h"
#include <FileSystem.h> #include <FileSystem.h>
@ -53,13 +53,12 @@
#include "ui/instanceview/InstanceDelegate.h" #include "ui/instanceview/InstanceDelegate.h"
SkinManageDialog::SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct) SkinManageDialog::SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct)
: QDialog(nullptr) : QDialog(parent), m_acct(acct), m_ui(new Ui::SkinManageDialog), m_list(this, APPLICATION->settings()->get("SkinsDir").toString(), acct)
, m_acct(acct)
, m_ui(new Ui::SkinManageDialog)
, m_list(this, APPLICATION->settings()->get("SkinsDir").toString(), acct)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
m_skinPreview = new SkinOpenGLWindow(this, palette().color(QPalette::Normal, QPalette::Base));
setWindowModality(Qt::WindowModal); setWindowModality(Qt::WindowModal);
auto contentsWidget = m_ui->listView; auto contentsWidget = m_ui->listView;
@ -100,11 +99,14 @@ SkinManageDialog::SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct)
m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel")); m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK")); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
m_ui->skinLayout->insertWidget(0, QWidget::createWindowContainer(m_skinPreview, this));
} }
SkinManageDialog::~SkinManageDialog() SkinManageDialog::~SkinManageDialog()
{ {
delete m_ui; delete m_ui;
delete m_skinPreview;
} }
void SkinManageDialog::activated(QModelIndex index) void SkinManageDialog::activated(QModelIndex index)
@ -126,7 +128,7 @@ void SkinManageDialog::selectionChanged(QItemSelection selected, [[maybe_unused]
if (!skin) if (!skin)
return; return;
m_ui->selectedModel->updateScene(skin); m_skinPreview->updateScene(skin);
m_ui->capeCombo->setCurrentIndex(m_capesIdx.value(skin->getCapeId())); m_ui->capeCombo->setCurrentIndex(m_capesIdx.value(skin->getCapeId()));
m_ui->steveBtn->setChecked(skin->getModel() == SkinModel::CLASSIC); m_ui->steveBtn->setChecked(skin->getModel() == SkinModel::CLASSIC);
m_ui->alexBtn->setChecked(skin->getModel() == SkinModel::SLIM); m_ui->alexBtn->setChecked(skin->getModel() == SkinModel::SLIM);
@ -222,10 +224,10 @@ void SkinManageDialog::on_capeCombo_currentIndexChanged(int index)
if (!cape.isNull()) { if (!cape.isNull()) {
m_ui->capeImage->setPixmap(previewCape(cape).scaled(size() * (1. / 3), Qt::KeepAspectRatio, Qt::FastTransformation)); m_ui->capeImage->setPixmap(previewCape(cape).scaled(size() * (1. / 3), Qt::KeepAspectRatio, Qt::FastTransformation));
} }
m_ui->selectedModel->updateCape(cape); m_skinPreview->updateCape(cape);
if (auto skin = getSelectedSkin(); skin) { if (auto skin = getSelectedSkin(); skin) {
skin->setCapeId(id.toString()); skin->setCapeId(id.toString());
m_ui->selectedModel->updateScene(skin); m_skinPreview->updateScene(skin);
} }
} }
@ -233,7 +235,7 @@ void SkinManageDialog::on_steveBtn_toggled(bool checked)
{ {
if (auto skin = getSelectedSkin(); skin) { if (auto skin = getSelectedSkin(); skin) {
skin->setModel(checked ? SkinModel::CLASSIC : SkinModel::SLIM); skin->setModel(checked ? SkinModel::CLASSIC : SkinModel::SLIM);
m_ui->selectedModel->updateScene(skin); m_skinPreview->updateScene(skin);
} }
} }
@ -516,13 +518,11 @@ void SkinManageDialog::resizeEvent(QResizeEvent* event)
QWidget::resizeEvent(event); QWidget::resizeEvent(event);
QSize s = size() * (1. / 3); QSize s = size() * (1. / 3);
m_ui->selectedModel->updateScene(getSelectedSkin());
auto id = m_ui->capeCombo->currentData(); auto id = m_ui->capeCombo->currentData();
auto cape = m_capes.value(id.toString(), {}); auto cape = m_capes.value(id.toString(), {});
if (!cape.isNull()) { if (!cape.isNull()) {
m_ui->capeImage->setPixmap(previewCape(cape).scaled(s, Qt::KeepAspectRatio, Qt::FastTransformation)); m_ui->capeImage->setPixmap(previewCape(cape).scaled(s, Qt::KeepAspectRatio, Qt::FastTransformation));
} }
m_ui->selectedModel->updateCape(cape);
} }
SkinModel* SkinManageDialog::getSelectedSkin() SkinModel* SkinManageDialog::getSelectedSkin()

View File

@ -25,20 +25,20 @@
#include "minecraft/auth/MinecraftAccount.h" #include "minecraft/auth/MinecraftAccount.h"
#include "minecraft/skins/SkinList.h" #include "minecraft/skins/SkinList.h"
#include "minecraft/skins/SkinModel.h" #include "minecraft/skins/SkinModel.h"
#include "ui/dialogs/skins/draw/SkinOpenGLWindow.h"
namespace Ui { namespace Ui {
class SkinManageDialog; class SkinManageDialog;
} }
class SkinManageDialog : public QDialog, public SkinProvider {
class SkinManageDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct); explicit SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct);
virtual ~SkinManageDialog(); virtual ~SkinManageDialog();
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;
SkinModel* getSelectedSkin(); virtual SkinModel* getSelectedSkin() override;
QHash<QString, QImage> capes(); virtual QHash<QString, QImage> capes() override;
public slots: public slots:
void selectionChanged(QItemSelection, QItemSelection); void selectionChanged(QItemSelection, QItemSelection);
@ -60,10 +60,12 @@ class SkinManageDialog : public QDialog {
private: private:
void setupCapes(); void setupCapes();
private:
MinecraftAccountPtr m_acct; MinecraftAccountPtr m_acct;
Ui::SkinManageDialog* m_ui; Ui::SkinManageDialog* m_ui;
SkinList m_list; SkinList m_list;
QString m_selectedSkinKey; QString m_selectedSkinKey;
QHash<QString, QImage> m_capes; QHash<QString, QImage> m_capes;
QHash<QString, int> m_capesIdx; QHash<QString, int> m_capesIdx;
SkinOpenGLWindow* m_skinPreview = nullptr;
}; };

View File

@ -19,14 +19,7 @@
<item> <item>
<layout class="QVBoxLayout" name="selectedVLayout" stretch="2,1,3"> <layout class="QVBoxLayout" name="selectedVLayout" stretch="2,1,3">
<item> <item>
<widget class="SkinOpenGLWidget" name="selectedModel"> <layout class="QVBoxLayout" name="skinLayout"/>
<property name="text" stdset="0">
<string/>
</property>
<property name="scaledContents" stdset="0">
<bool>false</bool>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="modelBox"> <widget class="QGroupBox" name="modelBox">
@ -185,13 +178,6 @@
</property> </property>
</action> </action>
</widget> </widget>
<customwidgets>
<customwidget>
<class>SkinOpenGLWidget</class>
<extends>QOpenGLWidget</extends>
<header>ui/dialogs/skins/draw/SkinOpenGLWidget.h</header>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections> <connections>
<connection> <connection>

View File

@ -182,8 +182,6 @@ QVector<QVector2D> getCubeUVs(float u, float v, float width, float height, float
namespace opengl { namespace opengl {
BoxGeometry::BoxGeometry(QVector3D size, QVector3D position) : m_indexBuf(QOpenGLBuffer::IndexBuffer), m_size(size), m_position(position) BoxGeometry::BoxGeometry(QVector3D size, QVector3D position) : m_indexBuf(QOpenGLBuffer::IndexBuffer), m_size(size), m_position(position)
{ {
initializeOpenGLFunctions();
// Generate 2 VBOs // Generate 2 VBOs
m_vertexBuf.create(); m_vertexBuf.create();
m_indexBuf.create(); m_indexBuf.create();

View File

@ -25,7 +25,7 @@
#include <QVector3D> #include <QVector3D>
namespace opengl { namespace opengl {
class BoxGeometry : protected QOpenGLFunctions { class BoxGeometry {
public: public:
BoxGeometry(QVector3D size, QVector3D position); BoxGeometry(QVector3D size, QVector3D position);
BoxGeometry(QVector3D size, QVector3D position, QPoint uv, QVector3D textureDim, QSize textureSize = { 64, 64 }); BoxGeometry(QVector3D size, QVector3D position, QPoint uv, QVector3D textureDim, QSize textureSize = { 64, 64 });

View File

@ -26,34 +26,54 @@
#include <cmath> #include <cmath>
#include "minecraft/skins/SkinModel.h" #include "minecraft/skins/SkinModel.h"
#include "ui/dialogs/skins/SkinManageDialog.h"
#include "ui/dialogs/skins/draw/BoxGeometry.h" #include "ui/dialogs/skins/draw/BoxGeometry.h"
#include "ui/dialogs/skins/draw/Scene.h" #include "ui/dialogs/skins/draw/Scene.h"
SkinOpenGLWidget::~SkinOpenGLWidget() SkinOpenGLWindow::SkinOpenGLWindow(SkinProvider* parent, QColor color)
: QOpenGLWindow(), QOpenGLFunctions(), m_baseColor(color), m_parent(parent)
{
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
format.setDepthBufferSize(24);
setFormat(format);
}
SkinOpenGLWindow::~SkinOpenGLWindow()
{ {
// Make sure the context is current when deleting the texture // Make sure the context is current when deleting the texture
// and the buffers. // and the buffers.
makeCurrent(); makeCurrent();
delete m_scene; // double check if resources were initialized because they are not
delete m_background; // initialized together with the object
m_backgroundTexture->destroy(); if (m_scene) {
delete m_backgroundTexture; delete m_scene;
if (m_program->isLinked()) { }
m_program->release(); if (m_background) {
delete m_background;
}
if (m_backgroundTexture) {
if (m_backgroundTexture->isCreated()) {
m_backgroundTexture->destroy();
}
delete m_backgroundTexture;
}
if (m_program) {
if (m_program->isLinked()) {
m_program->release();
}
m_program->removeAllShaders();
delete m_program;
} }
m_program->removeAllShaders();
delete m_program;
doneCurrent(); doneCurrent();
} }
void SkinOpenGLWidget::mousePressEvent(QMouseEvent* e) void SkinOpenGLWindow::mousePressEvent(QMouseEvent* e)
{ {
// Save mouse press position // Save mouse press position
m_mousePosition = QVector2D(e->pos()); m_mousePosition = QVector2D(e->pos());
m_isMousePressed = true; m_isMousePressed = true;
} }
void SkinOpenGLWidget::mouseMoveEvent(QMouseEvent* event)
void SkinOpenGLWindow::mouseMoveEvent(QMouseEvent* event)
{ {
if (m_isMousePressed) { if (m_isMousePressed) {
int dx = event->x() - m_mousePosition.x(); int dx = event->x() - m_mousePosition.x();
@ -72,12 +92,13 @@ void SkinOpenGLWidget::mouseMoveEvent(QMouseEvent* event)
update(); // Trigger a repaint update(); // Trigger a repaint
} }
} }
void SkinOpenGLWidget::mouseReleaseEvent([[maybe_unused]] QMouseEvent* e)
void SkinOpenGLWindow::mouseReleaseEvent([[maybe_unused]] QMouseEvent* e)
{ {
m_isMousePressed = false; m_isMousePressed = false;
} }
void SkinOpenGLWidget::initializeGL() void SkinOpenGLWindow::initializeGL()
{ {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
@ -89,11 +110,11 @@ void SkinOpenGLWidget::initializeGL()
QImage skin, cape; QImage skin, cape;
bool slim = false; bool slim = false;
if (auto p = dynamic_cast<SkinManageDialog*>(parent()); p) { if (m_parent) {
if (auto s = p->getSelectedSkin()) { if (auto s = m_parent->getSelectedSkin()) {
skin = s->getTexture(); skin = s->getTexture();
slim = s->getModel() == SkinModel::SLIM; slim = s->getModel() == SkinModel::SLIM;
cape = p->capes().value(s->getCapeId(), {}); cape = m_parent->capes().value(s->getCapeId(), {});
} }
} }
@ -102,7 +123,7 @@ void SkinOpenGLWidget::initializeGL()
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
} }
void SkinOpenGLWidget::initShaders() void SkinOpenGLWindow::initShaders()
{ {
m_program = new QOpenGLShaderProgram(this); m_program = new QOpenGLShaderProgram(this);
// Compile vertex shader // Compile vertex shader
@ -122,7 +143,7 @@ void SkinOpenGLWidget::initShaders()
close(); close();
} }
void SkinOpenGLWidget::resizeGL(int w, int h) void SkinOpenGLWindow::resizeGL(int w, int h)
{ {
// Calculate aspect ratio // Calculate aspect ratio
qreal aspect = qreal(w) / qreal(h ? h : 1); qreal aspect = qreal(w) / qreal(h ? h : 1);
@ -136,7 +157,7 @@ void SkinOpenGLWidget::resizeGL(int w, int h)
m_projection.perspective(fov, aspect, zNear, zFar); m_projection.perspective(fov, aspect, zNear, zFar);
} }
void SkinOpenGLWidget::paintGL() void SkinOpenGLWindow::paintGL()
{ {
// Clear color and depth buffer // Clear color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -171,7 +192,7 @@ void SkinOpenGLWidget::paintGL()
m_program->release(); m_program->release();
} }
void SkinOpenGLWidget::updateScene(SkinModel* skin) void SkinOpenGLWindow::updateScene(SkinModel* skin)
{ {
if (skin && m_scene) { if (skin && m_scene) {
m_scene->setMode(skin->getModel() == SkinModel::SLIM); m_scene->setMode(skin->getModel() == SkinModel::SLIM);
@ -179,7 +200,7 @@ void SkinOpenGLWidget::updateScene(SkinModel* skin)
update(); update();
} }
} }
void SkinOpenGLWidget::updateCape(const QImage& cape) void SkinOpenGLWindow::updateCape(const QImage& cape)
{ {
if (m_scene) { if (m_scene) {
m_scene->setCapeVisible(!cape.isNull()); m_scene->setCapeVisible(!cape.isNull());
@ -236,16 +257,16 @@ QImage generateChessboardImage(int width, int height, int tileSize, QColor baseC
return image; return image;
} }
void SkinOpenGLWidget::generateBackgroundTexture(int width, int height, int tileSize) void SkinOpenGLWindow::generateBackgroundTexture(int width, int height, int tileSize)
{ {
m_backgroundTexture = m_backgroundTexture = new QOpenGLTexture(generateChessboardImage(width, height, tileSize, m_baseColor));
new QOpenGLTexture(generateChessboardImage(width, height, tileSize, palette().color(QPalette::Normal, QPalette::Base)));
m_backgroundTexture->setMinificationFilter(QOpenGLTexture::Nearest); m_backgroundTexture->setMinificationFilter(QOpenGLTexture::Nearest);
m_backgroundTexture->setMagnificationFilter(QOpenGLTexture::Nearest); m_backgroundTexture->setMagnificationFilter(QOpenGLTexture::Nearest);
} }
void SkinOpenGLWidget::renderBackground() void SkinOpenGLWindow::renderBackground()
{ {
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE); // Disable depth buffer writing glDepthMask(GL_FALSE); // Disable depth buffer writing
m_backgroundTexture->bind(); m_backgroundTexture->bind();
QMatrix4x4 matrix; QMatrix4x4 matrix;
@ -254,9 +275,10 @@ void SkinOpenGLWidget::renderBackground()
m_background->draw(m_program); m_background->draw(m_program);
m_backgroundTexture->release(); m_backgroundTexture->release();
glDepthMask(GL_TRUE); // Re-enable depth buffer writing glDepthMask(GL_TRUE); // Re-enable depth buffer writing
glEnable(GL_DEPTH_TEST);
} }
void SkinOpenGLWidget::wheelEvent(QWheelEvent* event) void SkinOpenGLWindow::wheelEvent(QWheelEvent* event)
{ {
// Adjust distance based on scroll // Adjust distance based on scroll
int delta = event->angleDelta().y(); // Positive for scroll up, negative for scroll down int delta = event->angleDelta().y(); // Positive for scroll up, negative for scroll down

View File

@ -22,18 +22,23 @@
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <QOpenGLWidget> #include <QOpenGLWindow>
#include <QVector2D> #include <QVector2D>
#include "minecraft/skins/SkinModel.h" #include "minecraft/skins/SkinModel.h"
#include "ui/dialogs/skins/draw/BoxGeometry.h" #include "ui/dialogs/skins/draw/BoxGeometry.h"
#include "ui/dialogs/skins/draw/Scene.h" #include "ui/dialogs/skins/draw/Scene.h"
class SkinOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { class SkinProvider {
public:
virtual SkinModel* getSelectedSkin() = 0;
virtual QHash<QString, QImage> capes() = 0;
};
class SkinOpenGLWindow : public QOpenGLWindow, protected QOpenGLFunctions {
Q_OBJECT Q_OBJECT
public: public:
SkinOpenGLWidget(QWidget* parent = nullptr) : QOpenGLWidget(parent), QOpenGLFunctions() {} SkinOpenGLWindow(SkinProvider* parent, QColor color);
virtual ~SkinOpenGLWidget(); virtual ~SkinOpenGLWindow();
void updateScene(SkinModel* skin); void updateScene(SkinModel* skin);
void updateCape(const QImage& cape); void updateCape(const QImage& cape);
@ -68,4 +73,6 @@ class SkinOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
opengl::BoxGeometry* m_background = nullptr; opengl::BoxGeometry* m_background = nullptr;
QOpenGLTexture* m_backgroundTexture = nullptr; QOpenGLTexture* m_backgroundTexture = nullptr;
QColor m_baseColor;
SkinProvider* m_parent = nullptr;
}; };