Fix parts render crash
Before, app crash on some machines as been reported in #15 and #16, and cannot easily be reproduced on other machines, such as a virtual box guest system, which make it very hard to trace the root cause. Now, the offline render is totally removed from the code base, instead of offline-render to image then show the image, we can directly show the parts model in the parts tree using normal opengl widget, and the result looks better than before.master
parent
2f4102cedc
commit
1ab3d16bd4
|
@ -42,9 +42,6 @@ HEADERS += src/modelshaderprogram.h
|
||||||
SOURCES += src/modelmeshbinder.cpp
|
SOURCES += src/modelmeshbinder.cpp
|
||||||
HEADERS += src/modelmeshbinder.h
|
HEADERS += src/modelmeshbinder.h
|
||||||
|
|
||||||
SOURCES += src/modelofflinerender.cpp
|
|
||||||
HEADERS += src/modelofflinerender.h
|
|
||||||
|
|
||||||
SOURCES += src/modelwidget.cpp
|
SOURCES += src/modelwidget.cpp
|
||||||
HEADERS += src/modelwidget.h
|
HEADERS += src/modelwidget.h
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "dust3dutil.h"
|
#include "dust3dutil.h"
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
#include "meshlite.h"
|
#include "meshlite.h"
|
||||||
#include "modelofflinerender.h"
|
|
||||||
#include "meshutil.h"
|
#include "meshutil.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "positionmap.h"
|
#include "positionmap.h"
|
||||||
|
@ -32,7 +31,7 @@ void GeneratedCacheContext::updateComponentCombinableMesh(QString componentId, v
|
||||||
MeshGenerator::MeshGenerator(SkeletonSnapshot *snapshot, QThread *thread) :
|
MeshGenerator::MeshGenerator(SkeletonSnapshot *snapshot, QThread *thread) :
|
||||||
m_snapshot(snapshot),
|
m_snapshot(snapshot),
|
||||||
m_mesh(nullptr),
|
m_mesh(nullptr),
|
||||||
m_preview(nullptr),
|
//m_preview(nullptr),
|
||||||
m_thread(thread),
|
m_thread(thread),
|
||||||
m_meshResultContext(nullptr),
|
m_meshResultContext(nullptr),
|
||||||
m_sharedContextWidget(nullptr),
|
m_sharedContextWidget(nullptr),
|
||||||
|
@ -45,12 +44,8 @@ MeshGenerator::~MeshGenerator()
|
||||||
{
|
{
|
||||||
delete m_snapshot;
|
delete m_snapshot;
|
||||||
delete m_mesh;
|
delete m_mesh;
|
||||||
delete m_preview;
|
for (const auto &partPreviewMeshIt: m_partPreviewMeshMap) {
|
||||||
for (const auto &partPreviewIt: m_partPreviewMap) {
|
delete partPreviewMeshIt.second;
|
||||||
delete partPreviewIt.second;
|
|
||||||
}
|
|
||||||
for (const auto &render: m_partPreviewRenderMap) {
|
|
||||||
delete render.second;
|
|
||||||
}
|
}
|
||||||
delete m_meshResultContext;
|
delete m_meshResultContext;
|
||||||
}
|
}
|
||||||
|
@ -65,15 +60,10 @@ void MeshGenerator::setGeneratedCacheContext(GeneratedCacheContext *cacheContext
|
||||||
m_cacheContext = cacheContext;
|
m_cacheContext = cacheContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshGenerator::addPartPreviewRequirement(const QString &partId)
|
void MeshGenerator::addPartPreviewRequirement(const QUuid &partId)
|
||||||
{
|
{
|
||||||
//qDebug() << "addPartPreviewRequirement:" << partId;
|
//qDebug() << "addPartPreviewRequirement:" << partId;
|
||||||
m_requirePartPreviewMap.insert(partId);
|
m_requirePreviewPartIds.insert(partId);
|
||||||
if (m_partPreviewRenderMap.find(partId) == m_partPreviewRenderMap.end()) {
|
|
||||||
ModelOfflineRender *render = new ModelOfflineRender(m_sharedContextWidget);
|
|
||||||
render->setRenderThread(m_thread);
|
|
||||||
m_partPreviewRenderMap[partId] = render;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshGenerator::setSharedContextWidget(QOpenGLWidget *widget)
|
void MeshGenerator::setSharedContextWidget(QOpenGLWidget *widget)
|
||||||
|
@ -88,18 +78,21 @@ MeshLoader *MeshGenerator::takeResultMesh()
|
||||||
return resultMesh;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage *MeshGenerator::takePreview()
|
MeshLoader *MeshGenerator::takePartPreviewMesh(const QUuid &partId)
|
||||||
{
|
{
|
||||||
QImage *resultPreview = m_preview;
|
MeshLoader *resultMesh = m_partPreviewMeshMap[partId];
|
||||||
m_preview = nullptr;
|
m_partPreviewMeshMap[partId] = nullptr;
|
||||||
return resultPreview;
|
return resultMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage *MeshGenerator::takePartPreview(const QString &partId)
|
const std::set<QUuid> &MeshGenerator::requirePreviewPartIds()
|
||||||
{
|
{
|
||||||
QImage *resultImage = m_partPreviewMap[partId];
|
return m_requirePreviewPartIds;
|
||||||
m_partPreviewMap[partId] = nullptr;
|
}
|
||||||
return resultImage;
|
|
||||||
|
const std::set<QUuid> &MeshGenerator::generatedPreviewPartIds()
|
||||||
|
{
|
||||||
|
return m_generatedPreviewPartIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshResultContext *MeshGenerator::takeMeshResultContext()
|
MeshResultContext *MeshGenerator::takeMeshResultContext()
|
||||||
|
@ -360,18 +353,10 @@ void *MeshGenerator::combinePartMesh(QString partId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_requirePartPreviewMap.find(partId) != m_requirePartPreviewMap.end()) {
|
if (m_requirePreviewPartIds.find(partIdNotAsString) != m_requirePreviewPartIds.end()) {
|
||||||
ModelOfflineRender *render = m_partPreviewRenderMap[partId];
|
|
||||||
int trimedMeshId = meshlite_trim(m_meshliteContext, meshId, 1);
|
int trimedMeshId = meshlite_trim(m_meshliteContext, meshId, 1);
|
||||||
render->updateMesh(new MeshLoader(m_meshliteContext, trimedMeshId, -1, partColor, nullptr, m_smoothNormal));
|
m_partPreviewMeshMap[partIdNotAsString] = new MeshLoader(m_meshliteContext, trimedMeshId, -1, partColor, nullptr, m_smoothNormal);
|
||||||
QImage *image = new QImage(render->toImage(QSize(Theme::previewImageRenderSize, Theme::previewImageRenderSize)));
|
m_generatedPreviewPartIds.insert(partIdNotAsString);
|
||||||
if (Theme::previewImageSize != Theme::previewImageRenderSize) {
|
|
||||||
int cropOffset = (Theme::previewImageRenderSize - Theme::previewImageSize) / 2;
|
|
||||||
QImage *crop = new QImage(image->copy(cropOffset, cropOffset, Theme::previewImageSize, Theme::previewImageSize));
|
|
||||||
delete image;
|
|
||||||
image = crop;
|
|
||||||
}
|
|
||||||
m_partPreviewMap[partId] = image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDisabled) {
|
if (isDisabled) {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
#include "skeletonsnapshot.h"
|
#include "skeletonsnapshot.h"
|
||||||
#include "meshloader.h"
|
#include "meshloader.h"
|
||||||
#include "modelofflinerender.h"
|
|
||||||
#include "meshresultcontext.h"
|
#include "meshresultcontext.h"
|
||||||
#include "positionmap.h"
|
#include "positionmap.h"
|
||||||
|
|
||||||
|
@ -34,12 +33,13 @@ public:
|
||||||
MeshGenerator(SkeletonSnapshot *snapshot, QThread *thread);
|
MeshGenerator(SkeletonSnapshot *snapshot, QThread *thread);
|
||||||
~MeshGenerator();
|
~MeshGenerator();
|
||||||
void setSharedContextWidget(QOpenGLWidget *widget);
|
void setSharedContextWidget(QOpenGLWidget *widget);
|
||||||
void addPartPreviewRequirement(const QString &partId);
|
void addPartPreviewRequirement(const QUuid &partId);
|
||||||
void setGeneratedCacheContext(GeneratedCacheContext *cacheContext);
|
void setGeneratedCacheContext(GeneratedCacheContext *cacheContext);
|
||||||
void setSmoothNormal(bool smoothNormal);
|
void setSmoothNormal(bool smoothNormal);
|
||||||
MeshLoader *takeResultMesh();
|
MeshLoader *takeResultMesh();
|
||||||
QImage *takePreview();
|
MeshLoader *takePartPreviewMesh(const QUuid &partId);
|
||||||
QImage *takePartPreview(const QString &partId);
|
const std::set<QUuid> &requirePreviewPartIds();
|
||||||
|
const std::set<QUuid> &generatedPreviewPartIds();
|
||||||
MeshResultContext *takeMeshResultContext();
|
MeshResultContext *takeMeshResultContext();
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
@ -48,10 +48,9 @@ public slots:
|
||||||
private:
|
private:
|
||||||
SkeletonSnapshot *m_snapshot;
|
SkeletonSnapshot *m_snapshot;
|
||||||
MeshLoader *m_mesh;
|
MeshLoader *m_mesh;
|
||||||
QImage *m_preview;
|
std::map<QUuid, MeshLoader *> m_partPreviewMeshMap;
|
||||||
std::map<QString, QImage *> m_partPreviewMap;
|
std::set<QUuid> m_requirePreviewPartIds;
|
||||||
std::set<QString> m_requirePartPreviewMap;
|
std::set<QUuid> m_generatedPreviewPartIds;
|
||||||
std::map<QString, ModelOfflineRender *> m_partPreviewRenderMap;
|
|
||||||
QThread *m_thread;
|
QThread *m_thread;
|
||||||
MeshResultContext *m_meshResultContext;
|
MeshResultContext *m_meshResultContext;
|
||||||
QOpenGLWidget *m_sharedContextWidget;
|
QOpenGLWidget *m_sharedContextWidget;
|
||||||
|
|
|
@ -244,6 +244,15 @@ MeshLoader::MeshLoader(MeshResultContext &resultContext) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MeshLoader::MeshLoader() :
|
||||||
|
m_triangleVertices(nullptr),
|
||||||
|
m_triangleVertexCount(0),
|
||||||
|
m_edgeVertices(nullptr),
|
||||||
|
m_edgeVertexCount(0),
|
||||||
|
m_textureImage(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
MeshLoader::~MeshLoader()
|
MeshLoader::~MeshLoader()
|
||||||
{
|
{
|
||||||
delete[] m_triangleVertices;
|
delete[] m_triangleVertices;
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
MeshLoader(MeshResultContext &resultContext);
|
MeshLoader(MeshResultContext &resultContext);
|
||||||
MeshLoader(Vertex *triangleVertices, int vertexNum);
|
MeshLoader(Vertex *triangleVertices, int vertexNum);
|
||||||
MeshLoader(const MeshLoader &mesh);
|
MeshLoader(const MeshLoader &mesh);
|
||||||
|
MeshLoader();
|
||||||
~MeshLoader();
|
~MeshLoader();
|
||||||
Vertex *triangleVertices();
|
Vertex *triangleVertices();
|
||||||
int triangleVertexCount();
|
int triangleVertexCount();
|
||||||
|
@ -54,15 +55,15 @@ public:
|
||||||
void setTextureImage(QImage *textureImage);
|
void setTextureImage(QImage *textureImage);
|
||||||
const QImage *textureImage();
|
const QImage *textureImage();
|
||||||
private:
|
private:
|
||||||
Vertex *m_triangleVertices;
|
Vertex *m_triangleVertices = nullptr;
|
||||||
int m_triangleVertexCount;
|
int m_triangleVertexCount = 0;
|
||||||
Vertex *m_edgeVertices;
|
Vertex *m_edgeVertices = nullptr;
|
||||||
int m_edgeVertexCount;
|
int m_edgeVertexCount = 0;
|
||||||
std::vector<QVector3D> m_vertices;
|
std::vector<QVector3D> m_vertices;
|
||||||
std::vector<std::vector<int>> m_faces;
|
std::vector<std::vector<int>> m_faces;
|
||||||
std::vector<QVector3D> m_triangulatedVertices;
|
std::vector<QVector3D> m_triangulatedVertices;
|
||||||
std::vector<TriangulatedFace> m_triangulatedFaces;
|
std::vector<TriangulatedFace> m_triangulatedFaces;
|
||||||
QImage *m_textureImage;
|
QImage *m_textureImage = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
#include <QOpenGLFramebufferObjectFormat>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QDebug>
|
|
||||||
#include "modelofflinerender.h"
|
|
||||||
|
|
||||||
ModelOfflineRender::ModelOfflineRender(QOpenGLWidget *sharedContextWidget, QScreen *targetScreen) :
|
|
||||||
QOffscreenSurface(targetScreen),
|
|
||||||
m_context(nullptr),
|
|
||||||
m_mesh(nullptr),
|
|
||||||
m_xRot(0),
|
|
||||||
m_yRot(0),
|
|
||||||
m_zRot(0)
|
|
||||||
{
|
|
||||||
create();
|
|
||||||
|
|
||||||
QOpenGLContext *current = nullptr;
|
|
||||||
|
|
||||||
if (nullptr != sharedContextWidget) {
|
|
||||||
current = sharedContextWidget->context();
|
|
||||||
current->doneCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_context = new QOpenGLContext();
|
|
||||||
|
|
||||||
if (nullptr != current) {
|
|
||||||
m_context->setFormat(current->format());
|
|
||||||
m_context->setShareContext(current);
|
|
||||||
} else {
|
|
||||||
QSurfaceFormat fmt = format();
|
|
||||||
fmt.setAlphaBufferSize(8);
|
|
||||||
fmt.setSamples(4);
|
|
||||||
|
|
||||||
setFormat(fmt);
|
|
||||||
|
|
||||||
m_context->setFormat(fmt);
|
|
||||||
}
|
|
||||||
m_context->create();
|
|
||||||
|
|
||||||
if (nullptr != sharedContextWidget) {
|
|
||||||
sharedContextWidget->makeCurrent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelOfflineRender::~ModelOfflineRender()
|
|
||||||
{
|
|
||||||
delete m_context;
|
|
||||||
m_context = nullptr;
|
|
||||||
destroy();
|
|
||||||
delete m_mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelOfflineRender::updateMesh(MeshLoader *mesh)
|
|
||||||
{
|
|
||||||
delete m_mesh;
|
|
||||||
m_mesh = mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelOfflineRender::setRenderThread(QThread *thread)
|
|
||||||
{
|
|
||||||
m_context->moveToThread(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage ModelOfflineRender::toImage(const QSize &size)
|
|
||||||
{
|
|
||||||
QImage image;
|
|
||||||
|
|
||||||
m_context->makeCurrent(this);
|
|
||||||
|
|
||||||
QOpenGLFramebufferObjectFormat format;
|
|
||||||
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
|
|
||||||
format.setSamples(16);
|
|
||||||
QOpenGLFramebufferObject *renderFbo = new QOpenGLFramebufferObject(size, format);
|
|
||||||
renderFbo->bind();
|
|
||||||
m_context->functions()->glViewport(0, 0, size.width(), size.height());
|
|
||||||
|
|
||||||
if (nullptr != m_mesh) {
|
|
||||||
int xRot = m_xRot;
|
|
||||||
int yRot = m_yRot;
|
|
||||||
int zRot = m_zRot;
|
|
||||||
QMatrix4x4 proj;
|
|
||||||
QMatrix4x4 camera;
|
|
||||||
QMatrix4x4 world;
|
|
||||||
|
|
||||||
ModelShaderProgram *program = new ModelShaderProgram;
|
|
||||||
ModelMeshBinder meshBinder;
|
|
||||||
meshBinder.initialize();
|
|
||||||
meshBinder.hideWireframes();
|
|
||||||
|
|
||||||
program->setUniformValue(program->lightPosLoc(), QVector3D(0, 0, 70));
|
|
||||||
|
|
||||||
m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
m_context->functions()->glEnable(GL_DEPTH_TEST);
|
|
||||||
m_context->functions()->glEnable(GL_CULL_FACE);
|
|
||||||
m_context->functions()->glEnable(GL_LINE_SMOOTH);
|
|
||||||
|
|
||||||
camera.setToIdentity();
|
|
||||||
camera.translate(0, 0, -4.5);
|
|
||||||
|
|
||||||
world.setToIdentity();
|
|
||||||
world.rotate(xRot / 16.0f, 1, 0, 0);
|
|
||||||
world.rotate(yRot / 16.0f, 0, 1, 0);
|
|
||||||
world.rotate(zRot / 16.0f, 0, 0, 1);
|
|
||||||
|
|
||||||
proj.setToIdentity();
|
|
||||||
proj.perspective(45.0f, GLfloat(size.width()) / size.height(), 0.01f, 100.0f);
|
|
||||||
|
|
||||||
program->bind();
|
|
||||||
program->setUniformValue(program->projMatrixLoc(), proj);
|
|
||||||
program->setUniformValue(program->mvMatrixLoc(), camera * world);
|
|
||||||
QMatrix3x3 normalMatrix = world.normalMatrix();
|
|
||||||
program->setUniformValue(program->normalMatrixLoc(), normalMatrix);
|
|
||||||
program->setUniformValue(program->textureEnabledLoc(), 0);
|
|
||||||
|
|
||||||
meshBinder.updateMesh(m_mesh);
|
|
||||||
meshBinder.paint(program);
|
|
||||||
|
|
||||||
meshBinder.cleanup();
|
|
||||||
|
|
||||||
program->release();
|
|
||||||
delete program;
|
|
||||||
|
|
||||||
m_mesh = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_context->functions()->glFlush();
|
|
||||||
|
|
||||||
image = renderFbo->toImage();
|
|
||||||
|
|
||||||
renderFbo->bindDefault();
|
|
||||||
delete renderFbo;
|
|
||||||
|
|
||||||
m_context->doneCurrent();
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelOfflineRender::setXRotation(int angle)
|
|
||||||
{
|
|
||||||
m_xRot = angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelOfflineRender::setYRotation(int angle)
|
|
||||||
{
|
|
||||||
m_yRot = angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelOfflineRender::setZRotation(int angle)
|
|
||||||
{
|
|
||||||
m_zRot = angle;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef MODEL_OFFLINE_RENDER_H
|
|
||||||
#define MODEL_OFFLINE_RENDER_H
|
|
||||||
#include <QOffscreenSurface>
|
|
||||||
#include <QScreen>
|
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
#include <QOpenGLContext>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QOpenGLWidget>
|
|
||||||
#include "modelshaderprogram.h"
|
|
||||||
#include "modelmeshbinder.h"
|
|
||||||
#include "meshloader.h"
|
|
||||||
|
|
||||||
class ModelOfflineRender : QOffscreenSurface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ModelOfflineRender(QOpenGLWidget *sharedContextWidget = nullptr, QScreen *targetScreen = Q_NULLPTR);
|
|
||||||
~ModelOfflineRender();
|
|
||||||
void setRenderThread(QThread *thread);
|
|
||||||
void updateMesh(MeshLoader *mesh);
|
|
||||||
QImage toImage(const QSize &size);
|
|
||||||
void setXRotation(int angle);
|
|
||||||
void setYRotation(int angle);
|
|
||||||
void setZRotation(int angle);
|
|
||||||
private:
|
|
||||||
QOpenGLContext *m_context;
|
|
||||||
MeshLoader *m_mesh;
|
|
||||||
int m_xRot;
|
|
||||||
int m_yRot;
|
|
||||||
int m_zRot;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -19,7 +19,9 @@ ModelWidget::ModelWidget(QWidget *parent) :
|
||||||
m_zRot(0),
|
m_zRot(0),
|
||||||
m_program(nullptr),
|
m_program(nullptr),
|
||||||
m_moveStarted(false),
|
m_moveStarted(false),
|
||||||
m_graphicsFunctions(NULL)
|
m_graphicsFunctions(NULL),
|
||||||
|
m_moveEnabled(true),
|
||||||
|
m_zoomEnabled(true)
|
||||||
{
|
{
|
||||||
// --transparent causes the clear color to be transparent. Therefore, on systems that
|
// --transparent causes the clear color to be transparent. Therefore, on systems that
|
||||||
// support it, the widget will become transparent apart from the logo.
|
// support it, the widget will become transparent apart from the logo.
|
||||||
|
@ -192,7 +194,7 @@ void ModelWidget::mousePressEvent(QMouseEvent *event)
|
||||||
shouldStartMove = true;
|
shouldStartMove = true;
|
||||||
}
|
}
|
||||||
} else if (event->button() == Qt::MidButton) {
|
} else if (event->button() == Qt::MidButton) {
|
||||||
shouldStartMove = true;
|
shouldStartMove = m_moveEnabled;
|
||||||
}
|
}
|
||||||
if (shouldStartMove) {
|
if (shouldStartMove) {
|
||||||
m_lastPos = event->pos();
|
m_lastPos = event->pos();
|
||||||
|
@ -270,6 +272,8 @@ void ModelWidget::wheelEvent(QWheelEvent *event)
|
||||||
return;
|
return;
|
||||||
if (m_moveStarted)
|
if (m_moveStarted)
|
||||||
return;
|
return;
|
||||||
|
if (!m_zoomEnabled)
|
||||||
|
return;
|
||||||
qreal delta = event->delta() / 10;
|
qreal delta = event->delta() / 10;
|
||||||
if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) {
|
if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) {
|
||||||
if (delta > 0)
|
if (delta > 0)
|
||||||
|
@ -299,3 +303,12 @@ void ModelWidget::exportMeshAsObjPlusMaterials(const QString &filename)
|
||||||
m_meshBinder.exportMeshAsObjPlusMaterials(filename);
|
m_meshBinder.exportMeshAsObjPlusMaterials(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelWidget::enableMove(bool enabled)
|
||||||
|
{
|
||||||
|
m_moveEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelWidget::enableZoom(bool enabled)
|
||||||
|
{
|
||||||
|
m_zoomEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
|
@ -16,19 +16,24 @@ class SkeletonGraphicsFunctions;
|
||||||
class ModelWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
class ModelWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModelWidget(QWidget *parent = 0);
|
ModelWidget(QWidget *parent = 0);
|
||||||
~ModelWidget();
|
~ModelWidget();
|
||||||
|
static bool isTransparent()
|
||||||
static bool isTransparent() { return m_transparent; }
|
{
|
||||||
static void setTransparent(bool t) { m_transparent = t; }
|
return m_transparent;
|
||||||
|
}
|
||||||
|
static void setTransparent(bool t)
|
||||||
|
{
|
||||||
|
m_transparent = t;
|
||||||
|
}
|
||||||
void updateMesh(MeshLoader *mesh);
|
void updateMesh(MeshLoader *mesh);
|
||||||
void exportMeshAsObj(const QString &filename);
|
void exportMeshAsObj(const QString &filename);
|
||||||
void exportMeshAsObjPlusMaterials(const QString &filename);
|
void exportMeshAsObjPlusMaterials(const QString &filename);
|
||||||
void setGraphicsFunctions(SkeletonGraphicsFunctions *graphicsFunctions);
|
void setGraphicsFunctions(SkeletonGraphicsFunctions *graphicsFunctions);
|
||||||
void toggleWireframe();
|
void toggleWireframe();
|
||||||
|
void enableMove(bool enabled);
|
||||||
|
void enableZoom(bool enabled);
|
||||||
public slots:
|
public slots:
|
||||||
void setXRotation(int angle);
|
void setXRotation(int angle);
|
||||||
void setYRotation(int angle);
|
void setYRotation(int angle);
|
||||||
|
@ -39,7 +44,6 @@ signals:
|
||||||
void xRotationChanged(int angle);
|
void xRotationChanged(int angle);
|
||||||
void yRotationChanged(int angle);
|
void yRotationChanged(int angle);
|
||||||
void zRotationChanged(int angle);
|
void zRotationChanged(int angle);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initializeGL() override;
|
void initializeGL() override;
|
||||||
void paintGL() override;
|
void paintGL() override;
|
||||||
|
@ -61,6 +65,8 @@ private:
|
||||||
ModelShaderProgram *m_program;
|
ModelShaderProgram *m_program;
|
||||||
bool m_moveStarted;
|
bool m_moveStarted;
|
||||||
SkeletonGraphicsFunctions *m_graphicsFunctions;
|
SkeletonGraphicsFunctions *m_graphicsFunctions;
|
||||||
|
bool m_moveEnabled;
|
||||||
|
bool m_zoomEnabled;
|
||||||
private:
|
private:
|
||||||
QPoint m_lastPos;
|
QPoint m_lastPos;
|
||||||
ModelMeshBinder m_meshBinder;
|
ModelMeshBinder m_meshBinder;
|
||||||
|
|
|
@ -137,7 +137,9 @@ void SkeletonDocument::removeEdge(QUuid edgeId)
|
||||||
std::vector<std::vector<QUuid>> groups;
|
std::vector<std::vector<QUuid>> groups;
|
||||||
splitPartByEdge(&groups, edgeId);
|
splitPartByEdge(&groups, edgeId);
|
||||||
for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) {
|
for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) {
|
||||||
SkeletonPart part;
|
const auto newUuid = QUuid::createUuid();
|
||||||
|
SkeletonPart &part = partMap[newUuid];
|
||||||
|
part.id = newUuid;
|
||||||
part.copyAttributes(*oldPart);
|
part.copyAttributes(*oldPart);
|
||||||
part.name = nextPartName;
|
part.name = nextPartName;
|
||||||
for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) {
|
for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) {
|
||||||
|
@ -157,7 +159,6 @@ void SkeletonDocument::removeEdge(QUuid edgeId)
|
||||||
edgeIt->second.partId = part.id;
|
edgeIt->second.partId = part.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
partMap[part.id] = part;
|
|
||||||
addPartToComponent(part.id, findComponentParentId(part.componentId));
|
addPartToComponent(part.id, findComponentParentId(part.componentId));
|
||||||
emit partAdded(part.id);
|
emit partAdded(part.id);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +197,9 @@ void SkeletonDocument::removeNode(QUuid nodeId)
|
||||||
std::vector<std::vector<QUuid>> groups;
|
std::vector<std::vector<QUuid>> groups;
|
||||||
splitPartByNode(&groups, nodeId);
|
splitPartByNode(&groups, nodeId);
|
||||||
for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) {
|
for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) {
|
||||||
SkeletonPart part;
|
const auto newUuid = QUuid::createUuid();
|
||||||
|
SkeletonPart &part = partMap[newUuid];
|
||||||
|
part.id = newUuid;
|
||||||
part.copyAttributes(*oldPart);
|
part.copyAttributes(*oldPart);
|
||||||
part.name = nextPartName;
|
part.name = nextPartName;
|
||||||
for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) {
|
for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) {
|
||||||
|
@ -216,7 +219,6 @@ void SkeletonDocument::removeNode(QUuid nodeId)
|
||||||
edgeIt->second.partId = part.id;
|
edgeIt->second.partId = part.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
partMap[part.id] = part;
|
|
||||||
addPartToComponent(part.id, findComponentParentId(part.componentId));
|
addPartToComponent(part.id, findComponentParentId(part.componentId));
|
||||||
emit partAdded(part.id);
|
emit partAdded(part.id);
|
||||||
}
|
}
|
||||||
|
@ -254,8 +256,9 @@ QUuid SkeletonDocument::createNode(float x, float y, float z, float radius, QUui
|
||||||
const SkeletonNode *fromNode = nullptr;
|
const SkeletonNode *fromNode = nullptr;
|
||||||
bool newPartAdded = false;
|
bool newPartAdded = false;
|
||||||
if (fromNodeId.isNull()) {
|
if (fromNodeId.isNull()) {
|
||||||
SkeletonPart part;
|
const auto newUuid = QUuid::createUuid();
|
||||||
partMap[part.id] = part;
|
SkeletonPart &part = partMap[newUuid];
|
||||||
|
part.id = newUuid;
|
||||||
partId = part.id;
|
partId = part.id;
|
||||||
emit partAdded(partId);
|
emit partAdded(partId);
|
||||||
newPartAdded = true;
|
newPartAdded = true;
|
||||||
|
@ -828,7 +831,9 @@ void SkeletonDocument::addFromSnapshot(const SkeletonSnapshot &snapshot, bool fr
|
||||||
|
|
||||||
std::map<QUuid, QUuid> oldNewIdMap;
|
std::map<QUuid, QUuid> oldNewIdMap;
|
||||||
for (const auto &partKv: snapshot.parts) {
|
for (const auto &partKv: snapshot.parts) {
|
||||||
SkeletonPart part;
|
const auto newUuid = QUuid::createUuid();
|
||||||
|
SkeletonPart &part = partMap[newUuid];
|
||||||
|
part.id = newUuid;
|
||||||
oldNewIdMap[QUuid(partKv.first)] = part.id;
|
oldNewIdMap[QUuid(partKv.first)] = part.id;
|
||||||
part.name = valueOfKeyInMapOrEmpty(partKv.second, "name");
|
part.name = valueOfKeyInMapOrEmpty(partKv.second, "name");
|
||||||
part.visible = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "visible"));
|
part.visible = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "visible"));
|
||||||
|
@ -852,7 +857,6 @@ void SkeletonDocument::addFromSnapshot(const SkeletonSnapshot &snapshot, bool fr
|
||||||
const auto &deformWidthIt = partKv.second.find("deformWidth");
|
const auto &deformWidthIt = partKv.second.find("deformWidth");
|
||||||
if (deformWidthIt != partKv.second.end())
|
if (deformWidthIt != partKv.second.end())
|
||||||
part.setDeformWidth(deformWidthIt->second.toFloat());
|
part.setDeformWidth(deformWidthIt->second.toFloat());
|
||||||
partMap[part.id] = part;
|
|
||||||
newAddedPartIds.insert(part.id);
|
newAddedPartIds.insert(part.id);
|
||||||
}
|
}
|
||||||
for (const auto &nodeKv: snapshot.nodes) {
|
for (const auto &nodeKv: snapshot.nodes) {
|
||||||
|
@ -1037,18 +1041,12 @@ void SkeletonDocument::meshReady()
|
||||||
MeshLoader *resultMesh = m_meshGenerator->takeResultMesh();
|
MeshLoader *resultMesh = m_meshGenerator->takeResultMesh();
|
||||||
MeshResultContext *meshResultContext = m_meshGenerator->takeMeshResultContext();
|
MeshResultContext *meshResultContext = m_meshGenerator->takeMeshResultContext();
|
||||||
|
|
||||||
QImage *resultPreview = m_meshGenerator->takePreview();
|
for (auto &partId: m_meshGenerator->generatedPreviewPartIds()) {
|
||||||
if (resultPreview) {
|
auto part = partMap.find(partId);
|
||||||
preview = *resultPreview;
|
if (part != partMap.end()) {
|
||||||
delete resultPreview;
|
MeshLoader *resultPartPreviewMesh = m_meshGenerator->takePartPreviewMesh(partId);
|
||||||
}
|
part->second.updatePreviewMesh(resultPartPreviewMesh);
|
||||||
|
emit partPreviewChanged(partId);
|
||||||
for (auto &part: partMap) {
|
|
||||||
QImage *resultPartPreview = m_meshGenerator->takePartPreview(part.first.toString());
|
|
||||||
if (resultPartPreview) {
|
|
||||||
part.second.preview = *resultPartPreview;
|
|
||||||
emit partPreviewChanged(part.first);
|
|
||||||
delete resultPartPreview;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,7 +1132,7 @@ void SkeletonDocument::generateMesh()
|
||||||
m_meshGenerator->setSharedContextWidget(m_sharedContextWidget);
|
m_meshGenerator->setSharedContextWidget(m_sharedContextWidget);
|
||||||
m_meshGenerator->moveToThread(thread);
|
m_meshGenerator->moveToThread(thread);
|
||||||
for (auto &part: partMap) {
|
for (auto &part: partMap) {
|
||||||
m_meshGenerator->addPartPreviewRequirement(part.first.toString());
|
m_meshGenerator->addPartPreviewRequirement(part.first);
|
||||||
}
|
}
|
||||||
connect(thread, &QThread::started, m_meshGenerator, &MeshGenerator::process);
|
connect(thread, &QThread::started, m_meshGenerator, &MeshGenerator::process);
|
||||||
connect(m_meshGenerator, &MeshGenerator::finished, this, &SkeletonDocument::meshReady);
|
connect(m_meshGenerator, &MeshGenerator::finished, this, &SkeletonDocument::meshReady);
|
||||||
|
|
|
@ -74,6 +74,10 @@ public:
|
||||||
class SkeletonPart
|
class SkeletonPart
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
~SkeletonPart()
|
||||||
|
{
|
||||||
|
delete m_previewMesh;
|
||||||
|
}
|
||||||
QUuid id;
|
QUuid id;
|
||||||
QString name;
|
QString name;
|
||||||
bool visible;
|
bool visible;
|
||||||
|
@ -87,7 +91,6 @@ public:
|
||||||
bool rounded;
|
bool rounded;
|
||||||
QColor color;
|
QColor color;
|
||||||
bool hasColor;
|
bool hasColor;
|
||||||
QImage preview;
|
|
||||||
QUuid componentId;
|
QUuid componentId;
|
||||||
std::vector<QUuid> nodeIds;
|
std::vector<QUuid> nodeIds;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
|
@ -157,6 +160,20 @@ public:
|
||||||
wrapped = other.wrapped;
|
wrapped = other.wrapped;
|
||||||
componentId = other.componentId;
|
componentId = other.componentId;
|
||||||
}
|
}
|
||||||
|
void updatePreviewMesh(MeshLoader *previewMesh)
|
||||||
|
{
|
||||||
|
delete m_previewMesh;
|
||||||
|
m_previewMesh = previewMesh;
|
||||||
|
}
|
||||||
|
MeshLoader *takePreviewMesh() const
|
||||||
|
{
|
||||||
|
if (nullptr == m_previewMesh)
|
||||||
|
return nullptr;
|
||||||
|
return new MeshLoader(*m_previewMesh);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(SkeletonPart);
|
||||||
|
MeshLoader *m_previewMesh = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SkeletonProfile
|
enum class SkeletonProfile
|
||||||
|
@ -564,8 +581,8 @@ private: // need initialize
|
||||||
MeshLoader *m_resultRigWeightMesh;
|
MeshLoader *m_resultRigWeightMesh;
|
||||||
std::vector<AutoRiggerBone> *m_resultRigBones;
|
std::vector<AutoRiggerBone> *m_resultRigBones;
|
||||||
std::map<int, AutoRiggerVertexWeights> *m_resultRigWeights;
|
std::map<int, AutoRiggerVertexWeights> *m_resultRigWeights;
|
||||||
MeshResultContext *m_riggedResultContext;
|
|
||||||
bool m_isRigObsolete;
|
bool m_isRigObsolete;
|
||||||
|
MeshResultContext *m_riggedResultContext;
|
||||||
private:
|
private:
|
||||||
static unsigned long m_maxSnapshot;
|
static unsigned long m_maxSnapshot;
|
||||||
std::deque<SkeletonHistoryItem> m_undoItems;
|
std::deque<SkeletonHistoryItem> m_undoItems;
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include "graphicscontainerwidget.h"
|
#include "graphicscontainerwidget.h"
|
||||||
#include "skeletonparttreewidget.h"
|
#include "skeletonparttreewidget.h"
|
||||||
#include "rigwidget.h"
|
#include "rigwidget.h"
|
||||||
#include "modelofflinerender.h"
|
|
||||||
#include "markiconcreator.h"
|
#include "markiconcreator.h"
|
||||||
#include "tetrapodposeeditwidget.h"
|
#include "tetrapodposeeditwidget.h"
|
||||||
|
|
||||||
|
@ -1055,18 +1054,6 @@ void SkeletonDocumentWindow::exportObjPlusMaterialsResult()
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocumentWindow::exportRenderedResult()
|
|
||||||
{
|
|
||||||
QString filename = QFileDialog::getSaveFileName(this, QString(), QString(),
|
|
||||||
tr("Image (*.png)"));
|
|
||||||
if (filename.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
||||||
exportRenderedAsImage(filename);
|
|
||||||
QApplication::restoreOverrideCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkeletonDocumentWindow::showExportPreview()
|
void SkeletonDocumentWindow::showExportPreview()
|
||||||
{
|
{
|
||||||
if (nullptr == m_exportPreviewWidget) {
|
if (nullptr == m_exportPreviewWidget) {
|
||||||
|
@ -1146,14 +1133,3 @@ void SkeletonDocumentWindow::updateRadiusLockButtonState()
|
||||||
else
|
else
|
||||||
m_radiusLockButton->setStyleSheet("QPushButton {color: " + Theme::white.name() + "}");
|
m_radiusLockButton->setStyleSheet("QPushButton {color: " + Theme::white.name() + "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocumentWindow::exportRenderedAsImage(const QString &filename)
|
|
||||||
{
|
|
||||||
ModelOfflineRender offlineRender(m_modelRenderWidget);
|
|
||||||
offlineRender.setXRotation(m_modelRenderWidget->xRot());
|
|
||||||
offlineRender.setYRotation(m_modelRenderWidget->yRot());
|
|
||||||
offlineRender.setZRotation(m_modelRenderWidget->zRot());
|
|
||||||
offlineRender.updateMesh(m_document->takeResultMesh());
|
|
||||||
QImage renderedImage = offlineRender.toImage(QSize(1024, 1024));
|
|
||||||
renderedImage.save(filename);
|
|
||||||
}
|
|
||||||
|
|
|
@ -39,7 +39,6 @@ public slots:
|
||||||
void exportObjResult();
|
void exportObjResult();
|
||||||
void exportObjPlusMaterialsResult();
|
void exportObjPlusMaterialsResult();
|
||||||
void exportGltfResult();
|
void exportGltfResult();
|
||||||
void exportRenderedResult();
|
|
||||||
void showExportPreview();
|
void showExportPreview();
|
||||||
void newWindow();
|
void newWindow();
|
||||||
void newDocument();
|
void newDocument();
|
||||||
|
@ -60,7 +59,6 @@ private:
|
||||||
void initLockButton(QPushButton *button);
|
void initLockButton(QPushButton *button);
|
||||||
void setCurrentFilename(const QString &filename);
|
void setCurrentFilename(const QString &filename);
|
||||||
void updateTitle();
|
void updateTitle();
|
||||||
void exportRenderedAsImage(const QString &filename);
|
|
||||||
private:
|
private:
|
||||||
SkeletonDocument *m_document;
|
SkeletonDocument *m_document;
|
||||||
bool m_firstShow;
|
bool m_firstShow;
|
||||||
|
|
|
@ -62,6 +62,42 @@ SkeletonPartTreeWidget::SkeletonPartTreeWidget(const SkeletonDocument *document,
|
||||||
connect(this, &QTreeWidget::itemCollapsed, this, &SkeletonPartTreeWidget::groupCollapsed);
|
connect(this, &QTreeWidget::itemCollapsed, this, &SkeletonPartTreeWidget::groupCollapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkeletonPartTreeWidget::mouseMove(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkeletonPartTreeWidget::wheel(QWheelEvent *event)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkeletonPartTreeWidget::mouseRelease(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkeletonPartTreeWidget::mousePress(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::RightButton) {
|
||||||
|
showContextMenu(mapFromGlobal(event->globalPos()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkeletonPartTreeWidget::mouseDoubleClick(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkeletonPartTreeWidget::keyPress(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if (m_graphicsFunctions)
|
||||||
|
return m_graphicsFunctions->keyPress(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonPartTreeWidget::selectComponent(QUuid componentId, bool multiple)
|
void SkeletonPartTreeWidget::selectComponent(QUuid componentId, bool multiple)
|
||||||
{
|
{
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
|
@ -194,6 +230,7 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
const SkeletonComponent *component = nullptr;
|
const SkeletonComponent *component = nullptr;
|
||||||
const SkeletonPart *part = nullptr;
|
const SkeletonPart *part = nullptr;
|
||||||
|
SkeletonPartWidget *partWidget = nullptr;
|
||||||
|
|
||||||
std::set<QUuid> unorderedComponentIds = m_selectedComponentIds;
|
std::set<QUuid> unorderedComponentIds = m_selectedComponentIds;
|
||||||
if (!m_currentSelectedComponentId.isNull())
|
if (!m_currentSelectedComponentId.isNull())
|
||||||
|
@ -229,22 +266,38 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidgetAction forDisplayPartImage(this);
|
|
||||||
QLabel *previewLabel = new QLabel;
|
|
||||||
previewLabel->setFixedHeight(Theme::previewImageSize);
|
|
||||||
previewLabel->setStyleSheet("QLabel {color: " + Theme::red.name() + "}");
|
|
||||||
if (nullptr != part) {
|
|
||||||
previewLabel->setPixmap(QPixmap::fromImage(part->preview));
|
|
||||||
} else if (nullptr != component) {
|
|
||||||
previewLabel->setText(component->name);
|
|
||||||
} else if (!componentIds.empty()) {
|
|
||||||
previewLabel->setText(tr("(%1 items)").arg(QString::number(componentIds.size())));
|
|
||||||
}
|
|
||||||
QHBoxLayout *layout = new QHBoxLayout;
|
QHBoxLayout *layout = new QHBoxLayout;
|
||||||
|
QWidgetAction forDisplayPartImage(this);
|
||||||
layout->setAlignment(Qt::AlignCenter);
|
layout->setAlignment(Qt::AlignCenter);
|
||||||
layout->addWidget(previewLabel);
|
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
|
if (nullptr != part) {
|
||||||
|
auto findItem = m_partItemMap.find(part->id);
|
||||||
|
if (findItem != m_partItemMap.end()) {
|
||||||
|
partWidget = (SkeletonPartWidget *)itemWidget(findItem->second, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nullptr != part && nullptr != partWidget) {
|
||||||
|
ModelWidget *previewWidget = new ModelWidget;
|
||||||
|
previewWidget->enableMove(false);
|
||||||
|
previewWidget->enableZoom(false);
|
||||||
|
previewWidget->setFixedSize(Theme::previewImageSize, Theme::previewImageSize);
|
||||||
|
previewWidget->setXRotation(partWidget->previewWidget()->xRot());
|
||||||
|
previewWidget->setYRotation(partWidget->previewWidget()->yRot());
|
||||||
|
previewWidget->setZRotation(partWidget->previewWidget()->zRot());
|
||||||
|
previewWidget->updateMesh(part->takePreviewMesh());
|
||||||
|
layout->addWidget(previewWidget);
|
||||||
|
} else {
|
||||||
|
QLabel *previewLabel = new QLabel;
|
||||||
|
previewLabel->setFixedHeight(Theme::previewImageSize);
|
||||||
|
previewLabel->setStyleSheet("QLabel {color: " + Theme::red.name() + "}");
|
||||||
|
if (nullptr != component) {
|
||||||
|
previewLabel->setText(component->name);
|
||||||
|
} else if (!componentIds.empty()) {
|
||||||
|
previewLabel->setText(tr("(%1 items)").arg(QString::number(componentIds.size())));
|
||||||
|
}
|
||||||
|
layout->addWidget(previewLabel);
|
||||||
|
}
|
||||||
QWidget *widget = new QWidget;
|
QWidget *widget = new QWidget;
|
||||||
widget->setLayout(layout);
|
widget->setLayout(layout);
|
||||||
forDisplayPartImage.setDefaultWidget(widget);
|
forDisplayPartImage.setDefaultWidget(widget);
|
||||||
|
@ -650,6 +703,7 @@ void SkeletonPartTreeWidget::addComponentChildrenToItem(QUuid componentId, QTree
|
||||||
item->setFlags(item->flags() & ~(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable));
|
item->setFlags(item->flags() & ~(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable));
|
||||||
QUuid partId = component->linkToPartId;
|
QUuid partId = component->linkToPartId;
|
||||||
SkeletonPartWidget *widget = new SkeletonPartWidget(m_document, partId);
|
SkeletonPartWidget *widget = new SkeletonPartWidget(m_document, partId);
|
||||||
|
widget->previewWidget()->setGraphicsFunctions(this);
|
||||||
item->setSizeHint(0, SkeletonPartWidget::preferredSize());
|
item->setSizeHint(0, SkeletonPartWidget::preferredSize());
|
||||||
setItemWidget(item, 0, widget);
|
setItemWidget(item, 0, widget);
|
||||||
widget->reload();
|
widget->reload();
|
||||||
|
|
|
@ -4,10 +4,9 @@
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
|
#include "skeletongraphicswidget.h"
|
||||||
|
|
||||||
class SkeletonGraphicsFunctions;
|
class SkeletonPartTreeWidget : public QTreeWidget, public SkeletonGraphicsFunctions
|
||||||
|
|
||||||
class SkeletonPartTreeWidget : public QTreeWidget
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
signals:
|
signals:
|
||||||
|
@ -74,6 +73,12 @@ protected:
|
||||||
virtual QSize sizeHint() const;
|
virtual QSize sizeHint() const;
|
||||||
virtual void mousePressEvent(QMouseEvent *event);
|
virtual void mousePressEvent(QMouseEvent *event);
|
||||||
virtual void keyPressEvent(QKeyEvent *event);
|
virtual void keyPressEvent(QKeyEvent *event);
|
||||||
|
bool mouseMove(QMouseEvent *event);
|
||||||
|
bool wheel(QWheelEvent *event);
|
||||||
|
bool mouseRelease(QMouseEvent *event);
|
||||||
|
bool mousePress(QMouseEvent *event);
|
||||||
|
bool mouseDoubleClick(QMouseEvent *event);
|
||||||
|
bool keyPress(QKeyEvent *event);
|
||||||
private:
|
private:
|
||||||
void addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem);
|
void addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem);
|
||||||
void deleteItemChildren(QTreeWidgetItem *item);
|
void deleteItemChildren(QTreeWidgetItem *item);
|
||||||
|
|
|
@ -52,8 +52,10 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p
|
||||||
m_wrapButton->setSizePolicy(retainSizePolicy);
|
m_wrapButton->setSizePolicy(retainSizePolicy);
|
||||||
initButton(m_wrapButton);
|
initButton(m_wrapButton);
|
||||||
|
|
||||||
m_previewLabel = new QLabel;
|
m_previewWidget = new ModelWidget;
|
||||||
m_previewLabel->setFixedSize(Theme::previewImageSize, Theme::previewImageSize);
|
m_previewWidget->enableMove(false);
|
||||||
|
m_previewWidget->enableZoom(false);
|
||||||
|
m_previewWidget->setFixedSize(Theme::previewImageSize, Theme::previewImageSize);
|
||||||
|
|
||||||
QWidget *hrLightWidget = new QWidget;
|
QWidget *hrLightWidget = new QWidget;
|
||||||
hrLightWidget->setFixedHeight(1);
|
hrLightWidget->setFixedHeight(1);
|
||||||
|
@ -89,7 +91,7 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p
|
||||||
previewAndToolsLayout->setSpacing(0);
|
previewAndToolsLayout->setSpacing(0);
|
||||||
previewAndToolsLayout->setContentsMargins(0, 0, 0, 0);
|
previewAndToolsLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
previewAndToolsLayout->addWidget(m_visibleButton);
|
previewAndToolsLayout->addWidget(m_visibleButton);
|
||||||
previewAndToolsLayout->addWidget(m_previewLabel);
|
previewAndToolsLayout->addWidget(m_previewWidget);
|
||||||
previewAndToolsLayout->addLayout(toolsLayout);
|
previewAndToolsLayout->addLayout(toolsLayout);
|
||||||
previewAndToolsLayout->setStretch(0, 0);
|
previewAndToolsLayout->setStretch(0, 0);
|
||||||
previewAndToolsLayout->setStretch(1, 0);
|
previewAndToolsLayout->setStretch(1, 0);
|
||||||
|
@ -229,6 +231,11 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p
|
||||||
updateAllButtons();
|
updateAllButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelWidget *SkeletonPartWidget::previewWidget()
|
||||||
|
{
|
||||||
|
return m_previewWidget;
|
||||||
|
}
|
||||||
|
|
||||||
QSize SkeletonPartWidget::preferredSize()
|
QSize SkeletonPartWidget::preferredSize()
|
||||||
{
|
{
|
||||||
return QSize(Theme::miniIconSize + Theme::previewImageSize + Theme::miniIconSize * 4 + 5 + 2, Theme::previewImageSize + 6);
|
return QSize(Theme::miniIconSize + Theme::previewImageSize + Theme::miniIconSize * 4 + 5 + 2, Theme::previewImageSize + 6);
|
||||||
|
@ -408,7 +415,9 @@ void SkeletonPartWidget::updatePreview()
|
||||||
qDebug() << "Part not found:" << m_partId;
|
qDebug() << "Part not found:" << m_partId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_previewLabel->setPixmap(QPixmap::fromImage(part->preview));
|
//m_previewLabel->setPixmap(QPixmap::fromImage(part->preview));
|
||||||
|
MeshLoader *previewMesh = part->takePreviewMesh();
|
||||||
|
m_previewWidget->updateMesh(previewMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonPartWidget::updateLockButton()
|
void SkeletonPartWidget::updateLockButton()
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
|
#include "modelwidget.h"
|
||||||
|
|
||||||
class SkeletonPartWidget : public QWidget
|
class SkeletonPartWidget : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -44,6 +45,7 @@ public:
|
||||||
void updateWrapButton();
|
void updateWrapButton();
|
||||||
void updateCheckedState(bool checked);
|
void updateCheckedState(bool checked);
|
||||||
static QSize preferredSize();
|
static QSize preferredSize();
|
||||||
|
ModelWidget *previewWidget();
|
||||||
protected:
|
protected:
|
||||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -53,7 +55,7 @@ private: // need initialize
|
||||||
const SkeletonDocument *m_document;
|
const SkeletonDocument *m_document;
|
||||||
QUuid m_partId;
|
QUuid m_partId;
|
||||||
private:
|
private:
|
||||||
QLabel *m_previewLabel;
|
ModelWidget *m_previewWidget;
|
||||||
QPushButton *m_visibleButton;
|
QPushButton *m_visibleButton;
|
||||||
QPushButton *m_lockButton;
|
QPushButton *m_lockButton;
|
||||||
QPushButton *m_subdivButton;
|
QPushButton *m_subdivButton;
|
||||||
|
@ -64,7 +66,6 @@ private:
|
||||||
QPushButton *m_roundButton;
|
QPushButton *m_roundButton;
|
||||||
QPushButton *m_colorButton;
|
QPushButton *m_colorButton;
|
||||||
QPushButton *m_wrapButton;
|
QPushButton *m_wrapButton;
|
||||||
QLabel *m_nameLabel;
|
|
||||||
QWidget *m_backgroundWidget;
|
QWidget *m_backgroundWidget;
|
||||||
private:
|
private:
|
||||||
void initToolButton(QPushButton *button);
|
void initToolButton(QPushButton *button);
|
||||||
|
|
Loading…
Reference in New Issue