mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-06-12 05:07:46 +02:00
feat(skin manager): add elytra preview
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
@ -92,6 +92,10 @@ SkinManageDialog::SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct)
|
|||||||
connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
|
connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
|
||||||
SLOT(selectionChanged(QItemSelection, QItemSelection)));
|
SLOT(selectionChanged(QItemSelection, QItemSelection)));
|
||||||
connect(m_ui->listView, &QListView::customContextMenuRequested, this, &SkinManageDialog::show_context_menu);
|
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();
|
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));
|
return QPixmap::fromImage(capeImage.copy(1, 1, 10, 16).scaled(80, 128, Qt::IgnoreAspectRatio, Qt::FastTransformation));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkinManageDialog::setupCapes()
|
void SkinManageDialog::setupCapes()
|
||||||
{
|
{
|
||||||
// FIXME: add a model for this, download/refresh the capes on demand
|
// FIXME: add a model for this, download/refresh the capes on demand
|
||||||
@ -208,7 +226,7 @@ void SkinManageDialog::setupCapes()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!capeImage.isNull()) {
|
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 {
|
} else {
|
||||||
m_ui->capeCombo->addItem(cape.alias, cape.id);
|
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 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(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 {
|
} else {
|
||||||
m_ui->capeImage->clear();
|
m_ui->capeImage->clear();
|
||||||
}
|
}
|
||||||
@ -319,14 +338,14 @@ bool SkinManageDialog::eventFilter(QObject* obj, QEvent* ev)
|
|||||||
return QDialog::eventFilter(obj, 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()) {
|
if (!m_selectedSkinKey.isEmpty()) {
|
||||||
m_ui->listView->edit(m_ui->listView->currentIndex());
|
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())
|
if (m_selectedSkinKey.isEmpty())
|
||||||
return;
|
return;
|
||||||
@ -523,7 +542,7 @@ void SkinManageDialog::resizeEvent(QResizeEvent* event)
|
|||||||
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, m_ui->elytraCB->isChecked()).scaled(s, Qt::KeepAspectRatio, Qt::FastTransformation));
|
||||||
} else {
|
} else {
|
||||||
m_ui->capeImage->clear();
|
m_ui->capeImage->clear();
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,13 @@
|
|||||||
<string>Cape</string>
|
<string>Cape</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="elytraCB">
|
||||||
|
<property name="text">
|
||||||
|
<string>Elytra</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="capeCombo"/>
|
<widget class="QComboBox" name="capeCombo"/>
|
||||||
</item>
|
</item>
|
||||||
|
@ -180,7 +180,8 @@ QList<QVector2D> getCubeUVs(float u, float v, float width, float height, float d
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
: QOpenGLFunctions(), m_indexBuf(QOpenGLBuffer::IndexBuffer), m_size(size), m_position(position)
|
||||||
{
|
{
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
|
|
||||||
@ -274,4 +275,9 @@ BoxGeometry* BoxGeometry::Plane()
|
|||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BoxGeometry::scale(const QVector3D& vector)
|
||||||
|
{
|
||||||
|
m_matrix.scale(vector);
|
||||||
|
}
|
||||||
} // namespace opengl
|
} // namespace opengl
|
@ -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 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 rotate(float angle, const QVector3D& vector);
|
||||||
|
void scale(const QVector3D& vector);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QOpenGLBuffer m_vertexBuf;
|
QOpenGLBuffer m_vertexBuf;
|
||||||
|
@ -18,9 +18,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ui/dialogs/skins/draw/Scene.h"
|
#include "ui/dialogs/skins/draw/Scene.h"
|
||||||
|
|
||||||
|
#include <QOpenGLFunctions>
|
||||||
|
#include <QOpenGLShaderProgram>
|
||||||
|
#include <QOpenGLTexture>
|
||||||
|
#include <QOpenGLWindow>
|
||||||
|
|
||||||
namespace opengl {
|
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 = {
|
m_staticComponents = {
|
||||||
// head
|
// head
|
||||||
new opengl::BoxGeometry(QVector3D(8, 8, 8), QVector3D(0, 4, 0), QPoint(0, 0), QVector3D(8, 8, 8)),
|
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(10.8, QVector3D(1, 0, 0));
|
||||||
m_cape->rotate(180, QVector3D(0, 1, 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
|
// texture init
|
||||||
m_skinTexture = new QOpenGLTexture(skin.mirrored());
|
m_skinTexture = new QOpenGLTexture(skin.mirrored());
|
||||||
m_skinTexture->setMinificationFilter(QOpenGLTexture::Nearest);
|
m_skinTexture->setMinificationFilter(QOpenGLTexture::Nearest);
|
||||||
@ -68,7 +88,7 @@ Scene::Scene(const QImage& skin, bool slim, const QImage& cape) : m_slim(slim),
|
|||||||
}
|
}
|
||||||
Scene::~Scene()
|
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) {
|
for (auto g : array) {
|
||||||
delete g;
|
delete g;
|
||||||
}
|
}
|
||||||
@ -95,7 +115,15 @@ void Scene::draw(QOpenGLShaderProgram* program)
|
|||||||
if (m_capeVisible) {
|
if (m_capeVisible) {
|
||||||
m_capeTexture->bind();
|
m_capeTexture->bind();
|
||||||
program->setUniformValue("texture", 0);
|
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();
|
m_capeTexture->release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,4 +159,8 @@ void Scene::setCapeVisible(bool visible)
|
|||||||
{
|
{
|
||||||
m_capeVisible = visible;
|
m_capeVisible = visible;
|
||||||
}
|
}
|
||||||
|
void Scene::setElytraVisible(bool elytraVisible)
|
||||||
|
{
|
||||||
|
m_elytraVisible = elytraVisible;
|
||||||
|
}
|
||||||
} // namespace opengl
|
} // namespace opengl
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include <QOpenGLTexture>
|
#include <QOpenGLTexture>
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
class Scene {
|
class Scene : protected QOpenGLFunctions {
|
||||||
public:
|
public:
|
||||||
Scene(const QImage& skin, bool slim, const QImage& cape);
|
Scene(const QImage& skin, bool slim, const QImage& cape);
|
||||||
virtual ~Scene();
|
virtual ~Scene();
|
||||||
@ -32,15 +32,18 @@ class Scene {
|
|||||||
void setCape(const QImage& cape);
|
void setCape(const QImage& cape);
|
||||||
void setMode(bool slim);
|
void setMode(bool slim);
|
||||||
void setCapeVisible(bool visible);
|
void setCapeVisible(bool visible);
|
||||||
|
void setElytraVisible(bool elytraVisible);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<BoxGeometry*> m_staticComponents;
|
QList<BoxGeometry*> m_staticComponents;
|
||||||
QList<BoxGeometry*> m_normalArms;
|
QList<BoxGeometry*> m_normalArms;
|
||||||
QList<BoxGeometry*> m_slimArms;
|
QList<BoxGeometry*> m_slimArms;
|
||||||
BoxGeometry* m_cape = nullptr;
|
BoxGeometry* m_cape = nullptr;
|
||||||
|
QList<BoxGeometry*> m_elytra;
|
||||||
QOpenGLTexture* m_skinTexture = nullptr;
|
QOpenGLTexture* m_skinTexture = nullptr;
|
||||||
QOpenGLTexture* m_capeTexture = nullptr;
|
QOpenGLTexture* m_capeTexture = nullptr;
|
||||||
bool m_slim = false;
|
bool m_slim = false;
|
||||||
bool m_capeVisible = false;
|
bool m_capeVisible = false;
|
||||||
|
bool m_elytraVisible = false;
|
||||||
};
|
};
|
||||||
} // namespace opengl
|
} // namespace opengl
|
@ -263,3 +263,8 @@ void SkinOpenGLWindow::wheelEvent(QWheelEvent* event)
|
|||||||
m_distance = qMax(16.f, m_distance); // Clamp distance
|
m_distance = qMax(16.f, m_distance); // Clamp distance
|
||||||
update(); // Trigger a repaint
|
update(); // Trigger a repaint
|
||||||
}
|
}
|
||||||
|
void SkinOpenGLWindow::setElytraVisible(bool visible)
|
||||||
|
{
|
||||||
|
if (m_scene)
|
||||||
|
m_scene->setElytraVisible(visible);
|
||||||
|
}
|
||||||
|
@ -43,6 +43,7 @@ class SkinOpenGLWindow : public QOpenGLWindow, protected QOpenGLFunctions {
|
|||||||
|
|
||||||
void updateScene(SkinModel* skin);
|
void updateScene(SkinModel* skin);
|
||||||
void updateCape(const QImage& cape);
|
void updateCape(const QImage& cape);
|
||||||
|
void setElytraVisible(bool visible);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mousePressEvent(QMouseEvent* e) override;
|
void mousePressEvent(QMouseEvent* e) override;
|
||||||
|
Reference in New Issue
Block a user