diff --git a/launcher/ui/dialogs/skins/SkinManageDialog.cpp b/launcher/ui/dialogs/skins/SkinManageDialog.cpp
index 3bc0bc2d9..8e661d37c 100644
--- a/launcher/ui/dialogs/skins/SkinManageDialog.cpp
+++ b/launcher/ui/dialogs/skins/SkinManageDialog.cpp
@@ -92,6 +92,10 @@ SkinManageDialog::SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct)
connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
SLOT(selectionChanged(QItemSelection, QItemSelection)));
connect(m_ui->listView, &QListView::customContextMenuRequested, this, &SkinManageDialog::show_context_menu);
+ connect(m_ui->elytraCB, &QCheckBox::stateChanged, this, [this]() {
+ m_skinPreview->setElytraVisible(m_ui->elytraCB->isChecked());
+ on_capeCombo_currentIndexChanged(0);
+ });
setupCapes();
@@ -159,10 +163,24 @@ void SkinManageDialog::on_fileBtn_clicked()
}
}
-QPixmap previewCape(QImage capeImage)
+QPixmap previewCape(QImage capeImage, bool elytra = false)
{
+ if (elytra) {
+ auto wing = capeImage.copy(34, 0, 12, 22);
+ QImage mirrored = wing.mirrored(true, false);
+
+ QImage combined(wing.width() * 2 - 2, wing.height(), capeImage.format());
+ combined.fill(Qt::transparent);
+
+ QPainter painter(&combined);
+ painter.drawImage(0, 0, wing);
+ painter.drawImage(wing.width() - 2, 0, mirrored);
+ painter.end();
+ return QPixmap::fromImage(combined.scaled(96, 176, Qt::IgnoreAspectRatio, Qt::FastTransformation));
+ }
return QPixmap::fromImage(capeImage.copy(1, 1, 10, 16).scaled(80, 128, Qt::IgnoreAspectRatio, Qt::FastTransformation));
}
+
void SkinManageDialog::setupCapes()
{
// FIXME: add a model for this, download/refresh the capes on demand
@@ -208,7 +226,7 @@ void SkinManageDialog::setupCapes()
}
}
if (!capeImage.isNull()) {
- m_ui->capeCombo->addItem(previewCape(capeImage), cape.alias, cape.id);
+ m_ui->capeCombo->addItem(previewCape(capeImage, m_ui->elytraCB->isChecked()), cape.alias, cape.id);
} else {
m_ui->capeCombo->addItem(cape.alias, cape.id);
}
@@ -222,7 +240,8 @@ void SkinManageDialog::on_capeCombo_currentIndexChanged(int index)
auto id = m_ui->capeCombo->currentData();
auto cape = m_capes.value(id.toString(), {});
if (!cape.isNull()) {
- m_ui->capeImage->setPixmap(previewCape(cape).scaled(size() * (1. / 3), Qt::KeepAspectRatio, Qt::FastTransformation));
+ m_ui->capeImage->setPixmap(
+ previewCape(cape, m_ui->elytraCB->isChecked()).scaled(size() * (1. / 3), Qt::KeepAspectRatio, Qt::FastTransformation));
} else {
m_ui->capeImage->clear();
}
@@ -319,14 +338,14 @@ bool SkinManageDialog::eventFilter(QObject* obj, QEvent* ev)
return QDialog::eventFilter(obj, ev);
}
-void SkinManageDialog::on_action_Rename_Skin_triggered(bool checked)
+void SkinManageDialog::on_action_Rename_Skin_triggered(bool)
{
if (!m_selectedSkinKey.isEmpty()) {
m_ui->listView->edit(m_ui->listView->currentIndex());
}
}
-void SkinManageDialog::on_action_Delete_Skin_triggered(bool checked)
+void SkinManageDialog::on_action_Delete_Skin_triggered(bool)
{
if (m_selectedSkinKey.isEmpty())
return;
@@ -523,7 +542,7 @@ void SkinManageDialog::resizeEvent(QResizeEvent* event)
auto id = m_ui->capeCombo->currentData();
auto cape = m_capes.value(id.toString(), {});
if (!cape.isNull()) {
- m_ui->capeImage->setPixmap(previewCape(cape).scaled(s, Qt::KeepAspectRatio, Qt::FastTransformation));
+ m_ui->capeImage->setPixmap(previewCape(cape, m_ui->elytraCB->isChecked()).scaled(s, Qt::KeepAspectRatio, Qt::FastTransformation));
} else {
m_ui->capeImage->clear();
}
diff --git a/launcher/ui/dialogs/skins/SkinManageDialog.ui b/launcher/ui/dialogs/skins/SkinManageDialog.ui
index 7e8b4bc46..065c5cafc 100644
--- a/launcher/ui/dialogs/skins/SkinManageDialog.ui
+++ b/launcher/ui/dialogs/skins/SkinManageDialog.ui
@@ -59,6 +59,13 @@
Cape
+ -
+
+
+ Elytra
+
+
+
-
diff --git a/launcher/ui/dialogs/skins/draw/BoxGeometry.cpp b/launcher/ui/dialogs/skins/draw/BoxGeometry.cpp
index b4ab8d4cc..f91fe2f1f 100644
--- a/launcher/ui/dialogs/skins/draw/BoxGeometry.cpp
+++ b/launcher/ui/dialogs/skins/draw/BoxGeometry.cpp
@@ -180,7 +180,8 @@ QList getCubeUVs(float u, float v, float width, float height, float d
}
namespace opengl {
-BoxGeometry::BoxGeometry(QVector3D size, QVector3D position) : m_indexBuf(QOpenGLBuffer::IndexBuffer), m_size(size), m_position(position)
+BoxGeometry::BoxGeometry(QVector3D size, QVector3D position)
+ : QOpenGLFunctions(), m_indexBuf(QOpenGLBuffer::IndexBuffer), m_size(size), m_position(position)
{
initializeOpenGLFunctions();
@@ -274,4 +275,9 @@ BoxGeometry* BoxGeometry::Plane()
return b;
}
+
+void BoxGeometry::scale(const QVector3D& vector)
+{
+ m_matrix.scale(vector);
+}
} // namespace opengl
\ No newline at end of file
diff --git a/launcher/ui/dialogs/skins/draw/BoxGeometry.h b/launcher/ui/dialogs/skins/draw/BoxGeometry.h
index 1a245bc14..fa1a4c622 100644
--- a/launcher/ui/dialogs/skins/draw/BoxGeometry.h
+++ b/launcher/ui/dialogs/skins/draw/BoxGeometry.h
@@ -36,6 +36,7 @@ class BoxGeometry : protected QOpenGLFunctions {
void initGeometry(float u, float v, float width, float height, float depth, float textureWidth = 64, float textureHeight = 64);
void rotate(float angle, const QVector3D& vector);
+ void scale(const QVector3D& vector);
private:
QOpenGLBuffer m_vertexBuf;
diff --git a/launcher/ui/dialogs/skins/draw/Scene.cpp b/launcher/ui/dialogs/skins/draw/Scene.cpp
index 45d0ba191..89a783622 100644
--- a/launcher/ui/dialogs/skins/draw/Scene.cpp
+++ b/launcher/ui/dialogs/skins/draw/Scene.cpp
@@ -18,9 +18,16 @@
*/
#include "ui/dialogs/skins/draw/Scene.h"
+
+#include
+#include
+#include
+#include
+
namespace opengl {
-Scene::Scene(const QImage& skin, bool slim, const QImage& cape) : m_slim(slim), m_capeVisible(!cape.isNull())
+Scene::Scene(const QImage& skin, bool slim, const QImage& cape) : QOpenGLFunctions(), m_slim(slim), m_capeVisible(!cape.isNull())
{
+ initializeOpenGLFunctions();
m_staticComponents = {
// head
new opengl::BoxGeometry(QVector3D(8, 8, 8), QVector3D(0, 4, 0), QPoint(0, 0), QVector3D(8, 8, 8)),
@@ -57,6 +64,19 @@ Scene::Scene(const QImage& skin, bool slim, const QImage& cape) : m_slim(slim),
m_cape->rotate(10.8, QVector3D(1, 0, 0));
m_cape->rotate(180, QVector3D(0, 1, 0));
+ auto leftWing =
+ new opengl::BoxGeometry(QVector3D(12, 22, 4), QVector3D(0, -13, -2), QPoint(22, 0), QVector3D(10, 20, 2), QSize(64, 32));
+ leftWing->rotate(15, QVector3D(1, 0, 0));
+ leftWing->rotate(15, QVector3D(0, 0, 1));
+ leftWing->rotate(1, QVector3D(1, 0, 0));
+ auto rightWing =
+ new opengl::BoxGeometry(QVector3D(12, 22, 4), QVector3D(0, -13, -2), QPoint(22, 0), QVector3D(10, 20, 2), QSize(64, 32));
+ rightWing->scale(QVector3D(-1, 1, 1));
+ rightWing->rotate(15, QVector3D(1, 0, 0));
+ rightWing->rotate(15, QVector3D(0, 0, 1));
+ rightWing->rotate(1, QVector3D(1, 0, 0));
+ m_elytra << leftWing << rightWing;
+
// texture init
m_skinTexture = new QOpenGLTexture(skin.mirrored());
m_skinTexture->setMinificationFilter(QOpenGLTexture::Nearest);
@@ -68,7 +88,7 @@ Scene::Scene(const QImage& skin, bool slim, const QImage& cape) : m_slim(slim),
}
Scene::~Scene()
{
- for (auto array : { m_staticComponents, m_normalArms, m_slimArms }) {
+ for (auto array : { m_staticComponents, m_normalArms, m_slimArms, m_elytra }) {
for (auto g : array) {
delete g;
}
@@ -95,7 +115,15 @@ void Scene::draw(QOpenGLShaderProgram* program)
if (m_capeVisible) {
m_capeTexture->bind();
program->setUniformValue("texture", 0);
- m_cape->draw(program);
+ if (!m_elytraVisible) {
+ m_cape->draw(program);
+ } else {
+ glDisable(GL_CULL_FACE);
+ for (auto e : m_elytra) {
+ e->draw(program);
+ }
+ glEnable(GL_CULL_FACE);
+ }
m_capeTexture->release();
}
}
@@ -131,4 +159,8 @@ void Scene::setCapeVisible(bool visible)
{
m_capeVisible = visible;
}
+void Scene::setElytraVisible(bool elytraVisible)
+{
+ m_elytraVisible = elytraVisible;
+}
} // namespace opengl
\ No newline at end of file
diff --git a/launcher/ui/dialogs/skins/draw/Scene.h b/launcher/ui/dialogs/skins/draw/Scene.h
index 3560d1d74..c9bba1f20 100644
--- a/launcher/ui/dialogs/skins/draw/Scene.h
+++ b/launcher/ui/dialogs/skins/draw/Scene.h
@@ -22,7 +22,7 @@
#include
namespace opengl {
-class Scene {
+class Scene : protected QOpenGLFunctions {
public:
Scene(const QImage& skin, bool slim, const QImage& cape);
virtual ~Scene();
@@ -32,15 +32,18 @@ class Scene {
void setCape(const QImage& cape);
void setMode(bool slim);
void setCapeVisible(bool visible);
+ void setElytraVisible(bool elytraVisible);
private:
QList m_staticComponents;
QList m_normalArms;
QList m_slimArms;
BoxGeometry* m_cape = nullptr;
+ QList m_elytra;
QOpenGLTexture* m_skinTexture = nullptr;
QOpenGLTexture* m_capeTexture = nullptr;
bool m_slim = false;
bool m_capeVisible = false;
+ bool m_elytraVisible = false;
};
} // namespace opengl
\ No newline at end of file
diff --git a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp
index e1e539050..f035e6b91 100644
--- a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp
+++ b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp
@@ -263,3 +263,8 @@ void SkinOpenGLWindow::wheelEvent(QWheelEvent* event)
m_distance = qMax(16.f, m_distance); // Clamp distance
update(); // Trigger a repaint
}
+void SkinOpenGLWindow::setElytraVisible(bool visible)
+{
+ if (m_scene)
+ m_scene->setElytraVisible(visible);
+}
diff --git a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h
index e2c32da0f..2a06c23e5 100644
--- a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h
+++ b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.h
@@ -43,6 +43,7 @@ class SkinOpenGLWindow : public QOpenGLWindow, protected QOpenGLFunctions {
void updateScene(SkinModel* skin);
void updateCape(const QImage& cape);
+ void setElytraVisible(bool visible);
protected:
void mousePressEvent(QMouseEvent* e) override;