Implement component preview image decorator
parent
bc82539cf2
commit
24e675911e
|
@ -104,6 +104,8 @@ HEADERS += sources/component_list_model.h
|
||||||
SOURCES += sources/component_list_model.cc
|
SOURCES += sources/component_list_model.cc
|
||||||
HEADERS += sources/component_preview_grid_widget.h
|
HEADERS += sources/component_preview_grid_widget.h
|
||||||
SOURCES += sources/component_preview_grid_widget.cc
|
SOURCES += sources/component_preview_grid_widget.cc
|
||||||
|
HEADERS += sources/component_preview_images_decorator.h
|
||||||
|
SOURCES += sources/component_preview_images_decorator.cc
|
||||||
HEADERS += sources/cut_face_preview.h
|
HEADERS += sources/cut_face_preview.h
|
||||||
SOURCES += sources/cut_face_preview.cc
|
SOURCES += sources/cut_face_preview.cc
|
||||||
HEADERS += sources/dds_file.h
|
HEADERS += sources/dds_file.h
|
||||||
|
|
|
@ -7,7 +7,7 @@ ComponentListModel::ComponentListModel(const Document *document, QObject *parent
|
||||||
QAbstractListModel(parent),
|
QAbstractListModel(parent),
|
||||||
m_document(document)
|
m_document(document)
|
||||||
{
|
{
|
||||||
connect(m_document, &Document::componentPreviewImageChanged, [this](const dust3d::Uuid &componentId) {
|
connect(m_document, &Document::componentPreviewPixmapChanged, [this](const dust3d::Uuid &componentId) {
|
||||||
// FIXME: dont refresh the whole layout
|
// FIXME: dont refresh the whole layout
|
||||||
emit this->layoutChanged();
|
emit this->layoutChanged();
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include <dust3d/base/debug.h>
|
||||||
|
#include <QPainter>
|
||||||
|
#include "theme.h"
|
||||||
|
#include "component_preview_images_decorator.h"
|
||||||
|
|
||||||
|
ComponentPreviewImagesDecorator::ComponentPreviewImagesDecorator(std::unique_ptr<std::vector<PreviewInput>> previewInputs)
|
||||||
|
{
|
||||||
|
m_previewInputs = std::move(previewInputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::unordered_map<dust3d::Uuid, std::unique_ptr<QImage>>> ComponentPreviewImagesDecorator::takeResultImages()
|
||||||
|
{
|
||||||
|
return std::move(m_resultImages);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentPreviewImagesDecorator::decorate()
|
||||||
|
{
|
||||||
|
if (nullptr == m_previewInputs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_resultImages = std::make_unique<std::unordered_map<dust3d::Uuid, std::unique_ptr<QImage>>>();
|
||||||
|
|
||||||
|
for (auto &it: *m_previewInputs) {
|
||||||
|
if (it.isDirectory) {
|
||||||
|
QPainter painter(it.image.get());
|
||||||
|
painter.setRenderHints(QPainter::Antialiasing);
|
||||||
|
QPolygonF polygon;
|
||||||
|
polygon << QPointF(it.image->width() / 4, 0.0) << QPointF(it.image->width() / 2.5, 0.0);
|
||||||
|
polygon << QPointF(0.0, it.image->height() / 2.5) << QPointF(0.0, it.image->height() / 4);
|
||||||
|
QPainterPath painterPath;
|
||||||
|
painterPath.addPolygon(polygon);
|
||||||
|
painter.setBrush(Theme::white);
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.drawPath(painterPath);
|
||||||
|
}
|
||||||
|
m_resultImages->emplace(it.id, std::move(it.image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentPreviewImagesDecorator::process()
|
||||||
|
{
|
||||||
|
decorate();
|
||||||
|
emit finished();
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef DUST3D_APPLICATION_COMPONENT_PREVIEW_IMAGES_DECORATOR_H_
|
||||||
|
#define DUST3D_APPLICATION_COMPONENT_PREVIEW_IMAGES_DECORATOR_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <dust3d/base/uuid.h>
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
|
class ComponentPreviewImagesDecorator: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
struct PreviewInput
|
||||||
|
{
|
||||||
|
dust3d::Uuid id;
|
||||||
|
std::unique_ptr<QImage> image;
|
||||||
|
bool isDirectory = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ComponentPreviewImagesDecorator(std::unique_ptr<std::vector<PreviewInput>> previewInputs);
|
||||||
|
std::unique_ptr<std::unordered_map<dust3d::Uuid, std::unique_ptr<QImage>>> takeResultImages();
|
||||||
|
signals:
|
||||||
|
void finished();
|
||||||
|
public slots:
|
||||||
|
void process();
|
||||||
|
private:
|
||||||
|
std::unique_ptr<std::vector<PreviewInput>> m_previewInputs;
|
||||||
|
std::unique_ptr<std::unordered_map<dust3d::Uuid, std::unique_ptr<QImage>>> m_resultImages;
|
||||||
|
void decorate();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -22,6 +22,7 @@
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QTextBrowser>
|
#include <QTextBrowser>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
#include <QPixmap>
|
||||||
#include <dust3d/base/ds3_file.h>
|
#include <dust3d/base/ds3_file.h>
|
||||||
#include <dust3d/base/snapshot.h>
|
#include <dust3d/base/snapshot.h>
|
||||||
#include <dust3d/base/snapshot_xml.h>
|
#include <dust3d/base/snapshot_xml.h>
|
||||||
|
@ -1197,9 +1198,10 @@ void DocumentWindow::generateComponentPreviewImages()
|
||||||
QThread *thread = new QThread;
|
QThread *thread = new QThread;
|
||||||
|
|
||||||
m_componentPreviewImagesGenerator = new MeshPreviewImagesGenerator(new ModelOffscreenRender(m_modelRenderWidget->format()));
|
m_componentPreviewImagesGenerator = new MeshPreviewImagesGenerator(new ModelOffscreenRender(m_modelRenderWidget->format()));
|
||||||
for (const auto &component: m_document->componentMap) {
|
for (auto &component: m_document->componentMap) {
|
||||||
if (!component.second.isPreviewMeshObsolete)
|
if (!component.second.isPreviewMeshObsolete)
|
||||||
continue;
|
continue;
|
||||||
|
component.second.isPreviewMeshObsolete = false;
|
||||||
m_componentPreviewImagesGenerator->addInput(component.first, std::unique_ptr<ModelMesh>(component.second.takePreviewMesh()));
|
m_componentPreviewImagesGenerator->addInput(component.first, std::unique_ptr<ModelMesh>(component.second.takePreviewMesh()));
|
||||||
}
|
}
|
||||||
m_componentPreviewImagesGenerator->moveToThread(thread);
|
m_componentPreviewImagesGenerator->moveToThread(thread);
|
||||||
|
@ -1216,9 +1218,11 @@ void DocumentWindow::componentPreviewImagesReady()
|
||||||
componentImages.reset(m_componentPreviewImagesGenerator->takeImages());
|
componentImages.reset(m_componentPreviewImagesGenerator->takeImages());
|
||||||
if (nullptr != componentImages) {
|
if (nullptr != componentImages) {
|
||||||
for (const auto &it: *componentImages) {
|
for (const auto &it: *componentImages) {
|
||||||
m_document->setComponentPreviewImage(it.first, it.second);
|
m_document->setComponentPreviewImage(it.first, std::make_unique<QImage>(std::move(it.second)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decorateComponentPreviewImages();
|
||||||
|
|
||||||
delete m_componentPreviewImagesGenerator;
|
delete m_componentPreviewImagesGenerator;
|
||||||
m_componentPreviewImagesGenerator = nullptr;
|
m_componentPreviewImagesGenerator = nullptr;
|
||||||
|
@ -1227,6 +1231,56 @@ void DocumentWindow::componentPreviewImagesReady()
|
||||||
generateComponentPreviewImages();
|
generateComponentPreviewImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentWindow::decorateComponentPreviewImages()
|
||||||
|
{
|
||||||
|
if (nullptr != m_componentPreviewImagesDecorator) {
|
||||||
|
m_isComponentPreviewImageDecorationsObsolete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isComponentPreviewImageDecorationsObsolete = false;
|
||||||
|
|
||||||
|
QThread *thread = new QThread;
|
||||||
|
|
||||||
|
auto previewInputs = std::make_unique<std::vector<ComponentPreviewImagesDecorator::PreviewInput>>();
|
||||||
|
for (auto &component: m_document->componentMap) {
|
||||||
|
if (!component.second.isPreviewImageDecorationObsolete)
|
||||||
|
continue;
|
||||||
|
component.second.isPreviewImageDecorationObsolete = false;
|
||||||
|
if (nullptr == component.second.previewImage)
|
||||||
|
continue;
|
||||||
|
previewInputs->emplace_back(ComponentPreviewImagesDecorator::PreviewInput {
|
||||||
|
component.first,
|
||||||
|
std::make_unique<QImage>(*component.second.previewImage),
|
||||||
|
!component.second.childrenIds.empty()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
m_componentPreviewImagesDecorator = std::make_unique<ComponentPreviewImagesDecorator>(std::move(previewInputs));
|
||||||
|
m_componentPreviewImagesDecorator->moveToThread(thread);
|
||||||
|
connect(thread, &QThread::started, m_componentPreviewImagesDecorator.get(), &ComponentPreviewImagesDecorator::process);
|
||||||
|
connect(m_componentPreviewImagesDecorator.get(), &ComponentPreviewImagesDecorator::finished, this, &DocumentWindow::componentPreviewImageDecorationsReady);
|
||||||
|
connect(m_componentPreviewImagesDecorator.get(), &ComponentPreviewImagesDecorator::finished, thread, &QThread::quit);
|
||||||
|
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentWindow::componentPreviewImageDecorationsReady()
|
||||||
|
{
|
||||||
|
auto resultImages = m_componentPreviewImagesDecorator->takeResultImages();
|
||||||
|
if (nullptr != resultImages) {
|
||||||
|
for (auto &it: *resultImages) {
|
||||||
|
if (nullptr == it.second)
|
||||||
|
continue;
|
||||||
|
m_document->setComponentPreviewPixmap(it.first, QPixmap::fromImage(*it.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_componentPreviewImagesDecorator.reset();
|
||||||
|
|
||||||
|
if (m_isComponentPreviewImageDecorationsObsolete)
|
||||||
|
decorateComponentPreviewImages();
|
||||||
|
}
|
||||||
|
|
||||||
ModelWidget *DocumentWindow::modelWidget()
|
ModelWidget *DocumentWindow::modelWidget()
|
||||||
{
|
{
|
||||||
return m_modelRenderWidget;
|
return m_modelRenderWidget;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef DUST3D_APPLICATION_DOCUMENT_WINDOW_H_
|
#ifndef DUST3D_APPLICATION_DOCUMENT_WINDOW_H_
|
||||||
#define DUST3D_APPLICATION_DOCUMENT_WINDOW_H_
|
#define DUST3D_APPLICATION_DOCUMENT_WINDOW_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
#include "model_widget.h"
|
#include "model_widget.h"
|
||||||
#include "graphics_container_widget.h"
|
#include "graphics_container_widget.h"
|
||||||
#include "mesh_preview_images_generator.h"
|
#include "mesh_preview_images_generator.h"
|
||||||
|
#include "component_preview_images_decorator.h"
|
||||||
|
|
||||||
class Document;
|
class Document;
|
||||||
class SkeletonGraphicsWidget;
|
class SkeletonGraphicsWidget;
|
||||||
|
@ -82,6 +84,8 @@ public slots:
|
||||||
void toggleRotation();
|
void toggleRotation();
|
||||||
void generateComponentPreviewImages();
|
void generateComponentPreviewImages();
|
||||||
void componentPreviewImagesReady();
|
void componentPreviewImagesReady();
|
||||||
|
void decorateComponentPreviewImages();
|
||||||
|
void componentPreviewImageDecorationsReady();
|
||||||
void updateInprogressIndicator();
|
void updateInprogressIndicator();
|
||||||
void openRecentFile();
|
void openRecentFile();
|
||||||
void updateRecentFileActions();
|
void updateRecentFileActions();
|
||||||
|
@ -157,6 +161,9 @@ private:
|
||||||
|
|
||||||
MeshPreviewImagesGenerator *m_componentPreviewImagesGenerator = nullptr;
|
MeshPreviewImagesGenerator *m_componentPreviewImagesGenerator = nullptr;
|
||||||
bool m_isComponentPreviewImagesObsolete = false;
|
bool m_isComponentPreviewImagesObsolete = false;
|
||||||
|
|
||||||
|
std::unique_ptr<ComponentPreviewImagesDecorator> m_componentPreviewImagesDecorator;
|
||||||
|
bool m_isComponentPreviewImageDecorationsObsolete = false;
|
||||||
|
|
||||||
PartManageWidget *m_partManageWidget = nullptr;
|
PartManageWidget *m_partManageWidget = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -1272,14 +1272,22 @@ void SkeletonDocument::setRadiusLockState(bool locked)
|
||||||
emit radiusLockStateChanged();
|
emit radiusLockStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocument::setComponentPreviewImage(const dust3d::Uuid &componentId, const QImage &image)
|
void SkeletonDocument::setComponentPreviewImage(const dust3d::Uuid &componentId, std::unique_ptr<QImage> image)
|
||||||
{
|
{
|
||||||
SkeletonComponent *component = (SkeletonComponent *)findComponent(componentId);
|
SkeletonComponent *component = (SkeletonComponent *)findComponent(componentId);
|
||||||
if (nullptr == component)
|
if (nullptr == component)
|
||||||
return;
|
return;
|
||||||
component->isPreviewMeshObsolete = false;
|
component->isPreviewImageDecorationObsolete = true;
|
||||||
component->previewPixmap = QPixmap::fromImage(image);
|
component->previewImage = std::move(image);
|
||||||
emit componentPreviewImageChanged(componentId);
|
}
|
||||||
|
|
||||||
|
void SkeletonDocument::setComponentPreviewPixmap(const dust3d::Uuid &componentId, const QPixmap &pixmap)
|
||||||
|
{
|
||||||
|
SkeletonComponent *component = (SkeletonComponent *)findComponent(componentId);
|
||||||
|
if (nullptr == component)
|
||||||
|
return;
|
||||||
|
component->previewPixmap = pixmap;
|
||||||
|
emit componentPreviewPixmapChanged(componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocument::setComponentPreviewMesh(const dust3d::Uuid &componentId, std::unique_ptr<ModelMesh> mesh)
|
void SkeletonDocument::setComponentPreviewMesh(const dust3d::Uuid &componentId, std::unique_ptr<ModelMesh> mesh)
|
||||||
|
|
|
@ -427,6 +427,8 @@ public:
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
std::vector<dust3d::Uuid> childrenIds;
|
std::vector<dust3d::Uuid> childrenIds;
|
||||||
bool isPreviewMeshObsolete = false;
|
bool isPreviewMeshObsolete = false;
|
||||||
|
std::unique_ptr<QImage> previewImage;
|
||||||
|
bool isPreviewImageDecorationObsolete = false;
|
||||||
QPixmap previewPixmap;
|
QPixmap previewPixmap;
|
||||||
QString linkData() const
|
QString linkData() const
|
||||||
{
|
{
|
||||||
|
@ -547,7 +549,7 @@ signals:
|
||||||
void componentAdded(dust3d::Uuid componentId);
|
void componentAdded(dust3d::Uuid componentId);
|
||||||
void componentExpandStateChanged(dust3d::Uuid componentId);
|
void componentExpandStateChanged(dust3d::Uuid componentId);
|
||||||
void componentPreviewMeshChanged(const dust3d::Uuid &componentId);
|
void componentPreviewMeshChanged(const dust3d::Uuid &componentId);
|
||||||
void componentPreviewImageChanged(const dust3d::Uuid &componentId);
|
void componentPreviewPixmapChanged(const dust3d::Uuid &componentId);
|
||||||
void nodeRemoved(dust3d::Uuid nodeId);
|
void nodeRemoved(dust3d::Uuid nodeId);
|
||||||
void edgeRemoved(dust3d::Uuid edgeId);
|
void edgeRemoved(dust3d::Uuid edgeId);
|
||||||
void nodeRadiusChanged(dust3d::Uuid nodeId);
|
void nodeRadiusChanged(dust3d::Uuid nodeId);
|
||||||
|
@ -586,6 +588,7 @@ public:
|
||||||
void collectComponentDescendantParts(dust3d::Uuid componentId, std::vector<dust3d::Uuid> &partIds) const;
|
void collectComponentDescendantParts(dust3d::Uuid componentId, std::vector<dust3d::Uuid> &partIds) const;
|
||||||
void collectComponentDescendantComponents(dust3d::Uuid componentId, std::vector<dust3d::Uuid> &componentIds) const;
|
void collectComponentDescendantComponents(dust3d::Uuid componentId, std::vector<dust3d::Uuid> &componentIds) const;
|
||||||
void setComponentPreviewMesh(const dust3d::Uuid &componentId, std::unique_ptr<ModelMesh> mesh);
|
void setComponentPreviewMesh(const dust3d::Uuid &componentId, std::unique_ptr<ModelMesh> mesh);
|
||||||
|
void setComponentPreviewImage(const dust3d::Uuid &componentId, std::unique_ptr<QImage> image);
|
||||||
void resetDirtyFlags();
|
void resetDirtyFlags();
|
||||||
void markAllDirty();
|
void markAllDirty();
|
||||||
|
|
||||||
|
@ -691,7 +694,7 @@ public slots:
|
||||||
void showDescendantComponents(dust3d::Uuid componentId);
|
void showDescendantComponents(dust3d::Uuid componentId);
|
||||||
void lockDescendantComponents(dust3d::Uuid componentId);
|
void lockDescendantComponents(dust3d::Uuid componentId);
|
||||||
void unlockDescendantComponents(dust3d::Uuid componentId);
|
void unlockDescendantComponents(dust3d::Uuid componentId);
|
||||||
void setComponentPreviewImage(const dust3d::Uuid &componentId, const QImage &image);
|
void setComponentPreviewPixmap(const dust3d::Uuid &componentId, const QPixmap &pixmap);
|
||||||
void setPartLockState(dust3d::Uuid partId, bool locked);
|
void setPartLockState(dust3d::Uuid partId, bool locked);
|
||||||
void setPartVisibleState(dust3d::Uuid partId, bool visible);
|
void setPartVisibleState(dust3d::Uuid partId, bool visible);
|
||||||
void setPartDisableState(dust3d::Uuid partId, bool disabled);
|
void setPartDisableState(dust3d::Uuid partId, bool disabled);
|
||||||
|
|
Loading…
Reference in New Issue