diff --git a/application/sources/bone_generator.cc b/application/sources/bone_generator.cc index 2ad920f9..5a1ffd4d 100644 --- a/application/sources/bone_generator.cc +++ b/application/sources/bone_generator.cc @@ -2,6 +2,11 @@ #include #include +std::map>* BoneGenerator::takeBonePreviewMeshes() +{ + return m_bonePreviewMeshes.release(); +} + void BoneGenerator::process() { generate(); diff --git a/application/sources/bone_generator.h b/application/sources/bone_generator.h index 324b4076..39f045ea 100644 --- a/application/sources/bone_generator.h +++ b/application/sources/bone_generator.h @@ -4,10 +4,13 @@ #include "model_mesh.h" #include #include +#include #include class BoneGenerator : public QObject, public dust3d::BoneGenerator { Q_OBJECT +public: + std::map>* takeBonePreviewMeshes(); public slots: void process(); signals: diff --git a/application/sources/document.cc b/application/sources/document.cc index e06257a4..5966f13d 100644 --- a/application/sources/document.cc +++ b/application/sources/document.cc @@ -1,4 +1,5 @@ #include "document.h" +#include "bone_generator.h" #include "image_forever.h" #include "mesh_generator.h" #include "mesh_result_post_processor.h" @@ -2795,6 +2796,11 @@ bool Document::isTextureGenerating() const return nullptr != m_textureGenerator; } +bool Document::isBoneGenerating() const +{ + return nullptr != m_boneGenerator; +} + void Document::copyNodes(std::set nodeIdSet) const { dust3d::Snapshot snapshot; @@ -2865,7 +2871,7 @@ void Document::addBone(const dust3d::Uuid& boneId) return; Bone bone(boneId); - boneMap.emplace(boneId, bone); + boneMap.emplace(boneId, std::move(bone)); boneIdList.push_back(boneId); emit boneAdded(boneId); emit boneIdListChanged(); @@ -3018,3 +3024,66 @@ void Document::pickBoneNode(const dust3d::Uuid& nodeId) stopBoneJointsPicking(); } + +void Document::generateBone() +{ + if (nullptr != m_boneGenerator) { + m_isResultBoneObsolete = true; + return; + } + + m_isResultBoneObsolete = false; + + emit boneGenerating(); + + // TODO: + + QThread* thread = new QThread; + m_boneGenerator = std::make_unique(); + m_boneGenerator->moveToThread(thread); + connect(thread, &QThread::started, m_boneGenerator.get(), &BoneGenerator::process); + connect(m_boneGenerator.get(), &BoneGenerator::finished, this, &Document::boneReady); + connect(m_boneGenerator.get(), &BoneGenerator::finished, thread, &QThread::quit); + connect(thread, &QThread::finished, thread, &QThread::deleteLater); + thread->start(); +} + +void Document::boneReady() +{ + std::unique_ptr>> bonePreviewMeshes; + bonePreviewMeshes.reset(m_boneGenerator->takeBonePreviewMeshes()); + bool bonePreviewsChanged = bonePreviewMeshes && !bonePreviewMeshes->empty(); + if (bonePreviewsChanged) { + for (auto& it : *bonePreviewMeshes) { + setBonePreviewMesh(it.first, std::move(it.second)); + } + emit resultBonePreviewMeshesChanged(); + } + + // TODO: + + m_boneGenerator.reset(); + + emit resultBoneChanged(); + + if (m_isResultBoneObsolete) + generateBone(); +} + +void Document::setBonePreviewMesh(const dust3d::Uuid& boneId, std::unique_ptr mesh) +{ + Document::Bone* bone = (Document::Bone*)findBone(boneId); + if (nullptr == bone) + return; + bone->updatePreviewMesh(std::move(mesh)); + emit bonePreviewMeshChanged(boneId); +} + +void Document::setBonePreviewPixmap(const dust3d::Uuid& boneId, const QPixmap& pixmap) +{ + Document::Bone* bone = (Document::Bone*)findBone(boneId); + if (nullptr == bone) + return; + bone->previewPixmap = pixmap; + emit bonePreviewPixmapChanged(boneId); +} diff --git a/application/sources/document.h b/application/sources/document.h index e5410a19..70303683 100644 --- a/application/sources/document.h +++ b/application/sources/document.h @@ -24,6 +24,7 @@ class UvMapGenerator; class MeshGenerator; class MeshResultPostProcessor; +class BoneGenerator; class Document : public QObject { Q_OBJECT @@ -208,8 +209,14 @@ public: std::vector joints; QString name; QPixmap previewPixmap; + bool isPreviewMeshObsolete = false; + void updatePreviewMesh(std::unique_ptr mesh); + ModelMesh* takePreviewMesh() const; Bone(const dust3d::Uuid& withId = dust3d::Uuid()); + + private: + std::unique_ptr m_previewMesh; }; signals: @@ -218,6 +225,7 @@ signals: void partPreviewChanged(dust3d::Uuid partId); void resultMeshChanged(); void resultComponentPreviewMeshesChanged(); + void resultBonePreviewMeshesChanged(); void turnaroundChanged(); void editModeChanged(); void resultTextureChanged(); @@ -288,9 +296,12 @@ signals: void boneNodesChanged(const dust3d::Uuid& boneId); void boneJointsChanged(const dust3d::Uuid& boneId); void boneNameChanged(const dust3d::Uuid& boneId); + void bonePreviewMeshChanged(const dust3d::Uuid& boneId); void bonePreviewPixmapChanged(const dust3d::Uuid& boneId); void boneIdListChanged(); void rigChanged(); + void boneGenerating(); + void resultBoneChanged(); public: // need initialize QImage* textureImage = nullptr; @@ -359,6 +370,7 @@ public: bool isMeshGenerating() const; bool isPostProcessing() const; bool isTextureGenerating() const; + bool isBoneGenerating() const; void collectCutFaceList(std::vector& cutFaces) const; float getOriginX(bool rotated = false) const { @@ -417,6 +429,8 @@ public: void resetDirtyFlags(); void markAllDirty(); const Bone* findBone(const dust3d::Uuid& boneId) const; + void setBonePreviewMesh(const dust3d::Uuid& boneId, std::unique_ptr mesh); + void setBonePreviewPixmap(const dust3d::Uuid& boneId, const QPixmap& pixmap); public slots: void undo(); @@ -435,6 +449,8 @@ public slots: void textureReady(); void postProcess(); void postProcessedMeshResultReady(); + void generateBone(); + void boneReady(); void setPartSubdivState(dust3d::Uuid partId, bool subdived); void setPartXmirrorState(dust3d::Uuid partId, bool mirrored); void setPartDeformThickness(dust3d::Uuid partId, float thickness); @@ -565,10 +581,14 @@ private: float m_originZ = 0; dust3d::Uuid m_currentCanvasComponentId; bool m_allPositionRelatedLocksEnabled = true; + dust3d::Uuid m_currentBondId; size_t m_currentBoneJoints = 0; std::vector m_currentBoneJointNodes; + std::unique_ptr m_boneGenerator; + bool m_isResultBoneObsolete = false; + private: static unsigned long m_maxSnapshot; std::deque m_undoItems; diff --git a/application/sources/document_bone.cc b/application/sources/document_bone.cc index a4743986..c4e3a76c 100644 --- a/application/sources/document_bone.cc +++ b/application/sources/document_bone.cc @@ -4,3 +4,16 @@ Document::Bone::Bone(const dust3d::Uuid& withId) { id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; } + +void Document::Bone::updatePreviewMesh(std::unique_ptr mesh) +{ + m_previewMesh = std::move(mesh); + isPreviewMeshObsolete = true; +} + +ModelMesh* Document::Bone::takePreviewMesh() const +{ + if (nullptr == m_previewMesh) + return nullptr; + return new ModelMesh(*m_previewMesh); +} diff --git a/application/sources/document_window.cc b/application/sources/document_window.cc index 8ae28266..141c9688 100644 --- a/application/sources/document_window.cc +++ b/application/sources/document_window.cc @@ -208,6 +208,9 @@ DocumentWindow::DocumentWindow() connect(m_document, &Document::textureGenerating, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::resultTextureChanged, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::postProcessedResultChanged, this, &DocumentWindow::updateInprogressIndicator); + connect(m_document, &Document::boneGenerating, this, &DocumentWindow::updateInprogressIndicator); + connect(m_document, &Document::resultBoneChanged, this, &DocumentWindow::updateInprogressIndicator); + connect(m_document, &Document::resultBonePreviewMeshesChanged, this, &DocumentWindow::generateBonePreviewImages); toolButtonLayout->addWidget(addButton); toolButtonLayout->addWidget(selectButton); @@ -616,6 +619,8 @@ DocumentWindow::DocumentWindow() connect(m_document, &Document::textureChanged, m_document, &Document::generateTexture); connect(m_document, &Document::resultMeshChanged, m_document, &Document::postProcess); connect(m_document, &Document::postProcessedResultChanged, m_document, &Document::generateTexture); + connect(m_document, &Document::rigChanged, m_document, &Document::generateBone); + connect(m_document, &Document::postProcessedResultChanged, m_document, &Document::generateBone); connect(m_document, &Document::resultTextureChanged, [=]() { if (m_document->isMeshGenerating()) return; @@ -677,7 +682,7 @@ DocumentWindow::DocumentWindow() void DocumentWindow::updateInprogressIndicator() { - bool inprogress = m_document->isMeshGenerating() || m_document->isPostProcessing() || m_document->isTextureGenerating() || nullptr != m_componentPreviewImagesGenerator || nullptr != m_componentPreviewImagesDecorator; + bool inprogress = m_document->isMeshGenerating() || m_document->isPostProcessing() || m_document->isTextureGenerating() || m_document->isBoneGenerating() || nullptr != m_componentPreviewImagesGenerator || nullptr != m_componentPreviewImagesDecorator; if (inprogress == m_inprogressIndicator->isSpinning()) return; m_inprogressIndicator->showSpinner(inprogress); @@ -1403,3 +1408,52 @@ void DocumentWindow::toggleRenderColor() mesh->removeColor(); m_modelRenderWidget->updateMesh(mesh); } + +void DocumentWindow::generateBonePreviewImages() +{ + if (nullptr != m_bonePreviewImagesGenerator) { + m_isBonePreviewImagesObsolete = true; + return; + } + + m_isBonePreviewImagesObsolete = false; + + QThread* thread = new QThread; + + m_bonePreviewImagesGenerator = new MeshPreviewImagesGenerator(new ModelOffscreenRender(m_modelRenderWidget->format())); + for (auto& bone : m_document->boneMap) { + if (!bone.second.isPreviewMeshObsolete) + continue; + bone.second.isPreviewMeshObsolete = false; + auto previewMesh = std::unique_ptr(bone.second.takePreviewMesh()); + const bool useFrontView = false; + m_bonePreviewImagesGenerator->addInput(bone.first, std::move(previewMesh), useFrontView); + } + m_bonePreviewImagesGenerator->moveToThread(thread); + connect(thread, &QThread::started, m_bonePreviewImagesGenerator, &MeshPreviewImagesGenerator::process); + connect(m_bonePreviewImagesGenerator, &MeshPreviewImagesGenerator::finished, this, &DocumentWindow::bonePreviewImagesReady); + connect(m_bonePreviewImagesGenerator, &MeshPreviewImagesGenerator::finished, thread, &QThread::quit); + connect(thread, &QThread::finished, thread, &QThread::deleteLater); + thread->start(); + + updateInprogressIndicator(); +} + +void DocumentWindow::bonePreviewImagesReady() +{ + std::unique_ptr> boneImages; + boneImages.reset(m_bonePreviewImagesGenerator->takeImages()); + if (nullptr != boneImages) { + for (const auto& it : *boneImages) { + m_document->setBonePreviewPixmap(it.first, QPixmap::fromImage(it.second)); + } + } + + delete m_bonePreviewImagesGenerator; + m_bonePreviewImagesGenerator = nullptr; + + if (m_isBonePreviewImagesObsolete) + generateBonePreviewImages(); + else + updateInprogressIndicator(); +} diff --git a/application/sources/document_window.h b/application/sources/document_window.h index 469de06e..599d9922 100644 --- a/application/sources/document_window.h +++ b/application/sources/document_window.h @@ -90,6 +90,8 @@ public slots: void componentPreviewImagesReady(); void decorateComponentPreviewImages(); void componentPreviewImageDecorationsReady(); + void generateBonePreviewImages(); + void bonePreviewImagesReady(); void updateInprogressIndicator(); void openRecentFile(); void updateRecentFileActions(); @@ -170,6 +172,9 @@ private: std::unique_ptr m_componentPreviewImagesDecorator; bool m_isComponentPreviewImageDecorationsObsolete = false; + MeshPreviewImagesGenerator* m_bonePreviewImagesGenerator = nullptr; + bool m_isBonePreviewImagesObsolete = false; + PartManageWidget* m_partManageWidget = nullptr; BoneManageWidget* m_boneManageWidget = nullptr; diff --git a/dust3d/mesh/mesh_combiner.cc b/dust3d/mesh/mesh_combiner.cc index 030943c3..13a8e217 100644 --- a/dust3d/mesh/mesh_combiner.cc +++ b/dust3d/mesh/mesh_combiner.cc @@ -24,7 +24,6 @@ #include #include #include -#include namespace dust3d { diff --git a/dust3d/mesh/solid_mesh_boolean_operation.cc b/dust3d/mesh/solid_mesh_boolean_operation.cc index 434c7554..f2378d36 100644 --- a/dust3d/mesh/solid_mesh_boolean_operation.cc +++ b/dust3d/mesh/solid_mesh_boolean_operation.cc @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include