#ifndef DUST3D_APPLICATION_DOCUMENT_H_ #define DUST3D_APPLICATION_DOCUMENT_H_ #include "debug.h" #include "model_mesh.h" #include "monochrome_mesh.h" #include "theme.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class UvMapGenerator; class MeshGenerator; class MeshResultPostProcessor; class Document : public QObject { Q_OBJECT public: enum class EditMode { Add = 0, Select, Pick }; enum class SnapshotFor { None = 0, Nodes = 0x00000001, Bones = 0x00000002, Document = (SnapshotFor::Nodes | SnapshotFor::Bones) }; class HistoryItem { public: dust3d::Snapshot snapshot; }; enum class Profile { Unknown = 0, Main, Side }; class Node { public: Node(const dust3d::Uuid& withId = dust3d::Uuid()); void setRadius(float toRadius); void setCutRotation(float toRotation); void setCutFace(dust3d::CutFace face); void setCutFaceLinkedId(const dust3d::Uuid& linkedId); void clearCutFaceSettings(); float getX(bool rotated = false) const; float getY(bool rotated = false) const; float getZ(bool rotated = false) const; void setX(float x); void setY(float y); void setZ(float z); void addX(float x); void addY(float y); void addZ(float z); dust3d::Uuid id; dust3d::Uuid partId; QString name; float radius = 0.0; float cutRotation = 0.0; dust3d::CutFace cutFace = dust3d::CutFace::Quad; dust3d::Uuid cutFaceLinkedId; bool hasCutFaceSettings = false; std::vector edgeIds; std::set boneIds; std::set asBontJoints; bool boneJoint = false; private: float m_x = 0.0; float m_y = 0.0; float m_z = 0.0; }; class Edge { public: Edge(const dust3d::Uuid& withId = dust3d::Uuid()); dust3d::Uuid id; dust3d::Uuid partId; QString name; std::vector nodeIds; dust3d::Uuid neighborOf(dust3d::Uuid nodeId) const; }; class Part { public: dust3d::Uuid id; QString name; bool visible; bool locked; bool subdived; bool disabled; bool xMirrored; float deformThickness; float deformWidth; bool deformUnified; bool rounded; bool chamfered; QColor color; bool hasColor; dust3d::Uuid componentId; std::vector nodeIds; bool dirty; float cutRotation; dust3d::CutFace cutFace; dust3d::Uuid cutFaceLinkedId; dust3d::PartTarget target; float colorSolubility; float metalness; float roughness; float hollowThickness; bool countershaded; bool smooth; dust3d::Uuid colorImageId; Part(const dust3d::Uuid& withId = dust3d::Uuid()); bool hasPolyFunction() const; bool hasSmoothFunction() const; bool hasSubdivFunction() const; bool hasRoundEndFunction() const; bool hasMirrorFunction() const; bool hasChamferFunction() const; bool hasRotationFunction() const; bool hasHollowFunction() const; bool hasCutFaceFunction() const; bool hasLayerFunction() const; bool hasTargetFunction() const; bool hasBaseFunction() const; bool hasCombineModeFunction() const; bool hasDeformFunction() const; bool hasColorFunction() const; void setDeformThickness(float toThickness); void setDeformWidth(float toWidth); void setCutRotation(float toRotation); void setCutFace(dust3d::CutFace face); void setCutFaceLinkedId(const dust3d::Uuid& linkedId); bool deformThicknessAdjusted() const; bool deformWidthAdjusted() const; bool deformAdjusted() const; bool colorSolubilityAdjusted() const; bool metalnessAdjusted() const; bool roughnessAdjusted() const; bool cutRotationAdjusted() const; bool hollowThicknessAdjusted() const; bool cutFaceAdjusted() const; bool cutAdjusted() const; bool isEditVisible() const; void copyAttributes(const Part& other); private: Q_DISABLE_COPY(Part); }; class Component { public: Component(); Component(const dust3d::Uuid& withId, const QString& linkData = QString(), const QString& linkDataType = QString()); QString linkData() const; QString linkDataType() const; void addChild(dust3d::Uuid childId); void replaceChildWithOthers(const dust3d::Uuid& childId, const std::vector& others); void removeChild(dust3d::Uuid childId); void replaceChild(dust3d::Uuid childId, dust3d::Uuid newId); void moveChildUp(dust3d::Uuid childId); void moveChildDown(dust3d::Uuid childId); void moveChildToTop(dust3d::Uuid childId); void moveChildToBottom(dust3d::Uuid childId); void updatePreviewMesh(std::unique_ptr mesh); ModelMesh* takePreviewMesh() const; dust3d::Uuid id; QString name; dust3d::Uuid linkToPartId; dust3d::Uuid parentId; bool expanded = true; dust3d::CombineMode combineMode = dust3d::CombineMode::Normal; bool dirty = true; std::vector childrenIds; bool isPreviewMeshObsolete = false; std::unique_ptr previewImage; bool isPreviewImageDecorationObsolete = false; QPixmap previewPixmap; private: std::unique_ptr m_previewMesh; std::set m_childrenIdSet; }; class Bone { public: dust3d::Uuid id; dust3d::Uuid attachBoneId; int attachBoneJointIndex = 0; std::vector joints; QString name; QPixmap previewPixmap; Bone(const dust3d::Uuid& withId = dust3d::Uuid()); }; signals: void nodeCutRotationChanged(dust3d::Uuid nodeId); void nodeCutFaceChanged(dust3d::Uuid nodeId); void partPreviewChanged(dust3d::Uuid partId); void resultMeshChanged(); void resultComponentPreviewMeshesChanged(); void turnaroundChanged(); void editModeChanged(); void resultTextureChanged(); void postProcessedResultChanged(); void partSubdivStateChanged(dust3d::Uuid partId); void partXmirrorStateChanged(dust3d::Uuid partId); void partDeformThicknessChanged(dust3d::Uuid partId); void partDeformWidthChanged(dust3d::Uuid partId); void partDeformUnifyStateChanged(dust3d::Uuid partId); void partRoundStateChanged(dust3d::Uuid partId); void partColorStateChanged(dust3d::Uuid partId); void partCutRotationChanged(dust3d::Uuid partId); void partCutFaceChanged(dust3d::Uuid partId); void partChamferStateChanged(dust3d::Uuid partId); void partTargetChanged(dust3d::Uuid partId); void partColorSolubilityChanged(dust3d::Uuid partId); void partMetalnessChanged(dust3d::Uuid partId); void partRoughnessChanged(dust3d::Uuid partId); void partHollowThicknessChanged(dust3d::Uuid partId); void partCountershadeStateChanged(dust3d::Uuid partId); void partSmoothStateChanged(dust3d::Uuid partId); void componentCombineModeChanged(dust3d::Uuid componentId); void cleanup(); void checkPart(dust3d::Uuid partId); void partChecked(dust3d::Uuid partId); void partUnchecked(dust3d::Uuid partId); void enableBackgroundBlur(); void disableBackgroundBlur(); void exportReady(); void uncheckAll(); void checkNode(dust3d::Uuid nodeId); void checkEdge(dust3d::Uuid edgeId); void meshGenerating(); void postProcessing(); void textureGenerating(); void textureChanged(); void partAdded(dust3d::Uuid partId); void nodeAdded(dust3d::Uuid nodeId); void edgeAdded(dust3d::Uuid edgeId); void partRemoved(dust3d::Uuid partId); void partLockStateChanged(dust3d::Uuid partId); void partVisibleStateChanged(dust3d::Uuid partId); void partDisableStateChanged(dust3d::Uuid partId); void partColorImageChanged(const dust3d::Uuid& partId); void componentNameChanged(dust3d::Uuid componentId); void componentChildrenChanged(dust3d::Uuid componentId); void componentRemoved(dust3d::Uuid componentId); void componentAdded(dust3d::Uuid componentId); void componentExpandStateChanged(dust3d::Uuid componentId); void componentPreviewMeshChanged(const dust3d::Uuid& componentId); void componentPreviewPixmapChanged(const dust3d::Uuid& componentId); void nodeRemoved(dust3d::Uuid nodeId); void edgeRemoved(dust3d::Uuid edgeId); void nodeRadiusChanged(dust3d::Uuid nodeId); void nodeOriginChanged(dust3d::Uuid nodeId); void nodeBoneJointStateChanged(const dust3d::Uuid& nodeId); void edgeReversed(dust3d::Uuid edgeId); void originChanged(); void skeletonChanged(); void optionsChanged(); void xlockStateChanged(); void ylockStateChanged(); void zlockStateChanged(); void radiusLockStateChanged(); void boneAdded(const dust3d::Uuid& boneId); void boneRemoved(const dust3d::Uuid& boneId); void boneAttachmentChanged(const dust3d::Uuid& boneId); void boneNodesChanged(const dust3d::Uuid& boneId); void boneJointsChanged(const dust3d::Uuid& boneId); void boneNameChanged(const dust3d::Uuid& boneId); void bonePreviewPixmapChanged(const dust3d::Uuid& boneId); void boneIdListChanged(); void rigChanged(); public: // need initialize QImage* textureImage = nullptr; QByteArray* textureImageByteArray = nullptr; QImage* textureNormalImage = nullptr; QByteArray* textureNormalImageByteArray = nullptr; QImage* textureMetalnessImage = nullptr; QByteArray* textureMetalnessImageByteArray = nullptr; QImage* textureRoughnessImage = nullptr; QByteArray* textureRoughnessImageByteArray = nullptr; QImage* textureAmbientOcclusionImage = nullptr; QByteArray* textureAmbientOcclusionImageByteArray = nullptr; bool weldEnabled = true; float brushMetalness = ModelMesh::m_defaultMetalness; float brushRoughness = ModelMesh::m_defaultRoughness; EditMode editMode = EditMode::Select; bool xlocked = false; bool ylocked = false; bool zlocked = false; bool radiusLocked = false; QImage turnaround; QByteArray turnaroundPngByteArray; std::map partMap; std::map nodeMap; std::map edgeMap; std::map componentMap; Component rootComponent; std::map boneMap; std::vector boneIdList; public: Document(); ~Document(); bool undoable() const; bool redoable() const; bool hasPastableNodesInClipboard() const; bool originSettled() const; bool isNodeEditable(dust3d::Uuid nodeId) const; bool isEdgeEditable(dust3d::Uuid edgeId) const; void copyNodes(std::set nodeIdSet) const; void toSnapshot(dust3d::Snapshot* snapshot, const std::set& limitNodeIds = std::set(), SnapshotFor forWhat = SnapshotFor::Document) const; void fromSnapshot(const dust3d::Snapshot& snapshot); enum class SnapshotSource { Unknown, Paste, Import }; void addFromSnapshot(const dust3d::Snapshot& snapshot, enum SnapshotSource source = SnapshotSource::Paste); ModelMesh* takeResultMesh(); MonochromeMesh* takeWireframeMesh(); ModelMesh* takePaintedMesh(); bool isMeshGenerationSucceed(); ModelMesh* takeResultTextureMesh(); ModelMesh* takeResultRigWeightMesh(); void updateTurnaround(const QImage& image); void clearTurnaround(); void updateTextureImage(QImage* image); void updateTextureNormalImage(QImage* image); void updateTextureMetalnessImage(QImage* image); void updateTextureRoughnessImage(QImage* image); void updateTextureAmbientOcclusionImage(QImage* image); const dust3d::Object& currentUvMappedObject() const; bool isExportReady() const; bool isPostProcessResultObsolete() const; bool isMeshGenerating() const; bool isPostProcessing() const; bool isTextureGenerating() const; void collectCutFaceList(std::vector& cutFaces) const; float getOriginX(bool rotated = false) const { if (rotated) return m_originY; return m_originX; } float getOriginY(bool rotated = false) const { if (rotated) return m_originX; return m_originY; } float getOriginZ(bool rotated = false) const { (void)rotated; return m_originZ; } void setOriginX(float originX) { m_originX = originX; } void setOriginY(float originY) { m_originY = originY; } void setOriginZ(float originZ) { m_originZ = originZ; } void addOriginX(float originX) { m_originX += originX; } void addOriginY(float originY) { m_originY += originY; } void addOriginZ(float originZ) { m_originZ += originZ; } const Node* findNode(dust3d::Uuid nodeId) const; const Edge* findEdge(dust3d::Uuid edgeId) const; const Part* findPart(dust3d::Uuid partId) const; const Edge* findEdgeByNodes(dust3d::Uuid firstNodeId, dust3d::Uuid secondNodeId) const; void findAllNeighbors(dust3d::Uuid nodeId, std::set& neighbors) const; bool isNodeConnectable(dust3d::Uuid nodeId) const; const Component* findComponent(dust3d::Uuid componentId) const; const Component* findComponentParent(dust3d::Uuid componentId) const; dust3d::Uuid findComponentParentId(dust3d::Uuid componentId) const; void collectComponentDescendantParts(dust3d::Uuid componentId, std::vector& partIds) const; void collectComponentDescendantComponents(dust3d::Uuid componentId, std::vector& componentIds) const; void setComponentPreviewMesh(const dust3d::Uuid& componentId, std::unique_ptr mesh); void setComponentPreviewImage(const dust3d::Uuid& componentId, std::unique_ptr image); void resetDirtyFlags(); void markAllDirty(); const Bone* findBone(const dust3d::Uuid& boneId) const; public slots: void undo(); void redo(); void paste(); void setNodeCutRotation(dust3d::Uuid nodeId, float cutRotation); void setNodeCutFace(dust3d::Uuid nodeId, dust3d::CutFace cutFace); void setNodeCutFaceLinkedId(dust3d::Uuid nodeId, dust3d::Uuid linkedId); void clearNodeCutFaceSettings(dust3d::Uuid nodeId); void setEditMode(EditMode mode); void uiReady(); void generateMesh(); void regenerateMesh(); void meshReady(); void generateTexture(); void textureReady(); void postProcess(); void postProcessedMeshResultReady(); void setPartSubdivState(dust3d::Uuid partId, bool subdived); void setPartXmirrorState(dust3d::Uuid partId, bool mirrored); void setPartDeformThickness(dust3d::Uuid partId, float thickness); void setPartDeformWidth(dust3d::Uuid partId, float width); void setPartDeformUnified(dust3d::Uuid partId, bool unified); void setPartRoundState(dust3d::Uuid partId, bool rounded); void setPartColorState(dust3d::Uuid partId, bool hasColor, QColor color); void setPartCutRotation(dust3d::Uuid partId, float cutRotation); void setPartCutFace(dust3d::Uuid partId, dust3d::CutFace cutFace); void setPartCutFaceLinkedId(dust3d::Uuid partId, dust3d::Uuid linkedId); void setPartChamferState(dust3d::Uuid partId, bool chamfered); void setPartTarget(dust3d::Uuid partId, dust3d::PartTarget target); void setPartColorSolubility(dust3d::Uuid partId, float solubility); void setPartMetalness(dust3d::Uuid partId, float metalness); void setPartRoughness(dust3d::Uuid partId, float roughness); void setPartHollowThickness(dust3d::Uuid partId, float hollowThickness); void setPartCountershaded(dust3d::Uuid partId, bool countershaded); void setPartSmoothState(dust3d::Uuid partId, bool smooth); void setComponentCombineMode(dust3d::Uuid componentId, dust3d::CombineMode combineMode); void saveSnapshot(); void batchChangeBegin(); void batchChangeEnd(); void reset(); void clearHistories(); void silentReset(); void toggleSmoothNormal(); void enableWeld(bool enabled); void removeNode(dust3d::Uuid nodeId); void removeEdge(dust3d::Uuid edgeId); void removePart(dust3d::Uuid partId); void addNodeWithId(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId); void addNode(float x, float y, float z, float radius, dust3d::Uuid fromNodeId); void scaleNodeByAddRadius(dust3d::Uuid nodeId, float amount); void moveNodeBy(dust3d::Uuid nodeId, float x, float y, float z); void setNodeOrigin(dust3d::Uuid nodeId, float x, float y, float z); void setNodeRadius(dust3d::Uuid nodeId, float radius); void setNodeBoneJointState(const dust3d::Uuid& nodeId, bool boneJoint); void switchNodeXZ(dust3d::Uuid nodeId); void moveOriginBy(float x, float y, float z); void addEdge(dust3d::Uuid fromNodeId, dust3d::Uuid toNodeId); void moveComponentUp(dust3d::Uuid componentId); void moveComponentDown(dust3d::Uuid componentId); void moveComponentToTop(dust3d::Uuid componentId); void moveComponentToBottom(dust3d::Uuid componentId); void renameComponent(dust3d::Uuid componentId, QString name); void removeComponent(dust3d::Uuid componentId); void addComponent(dust3d::Uuid parentId); void moveComponent(dust3d::Uuid componentId, dust3d::Uuid toParentId); void setCurrentCanvasComponentId(dust3d::Uuid componentId); void groupComponents(const std::vector& componentIds); void ungroupComponent(const dust3d::Uuid& componentId); void createNewChildComponent(dust3d::Uuid parentComponentId); void setComponentExpandState(dust3d::Uuid componentId, bool expanded); void hideOtherComponents(dust3d::Uuid componentId); void lockOtherComponents(dust3d::Uuid componentId); void hideAllComponents(); void showAllComponents(); void showOrHideAllComponents(); void collapseAllComponents(); void expandAllComponents(); void lockAllComponents(); void unlockAllComponents(); void hideDescendantComponents(dust3d::Uuid componentId); void showDescendantComponents(dust3d::Uuid componentId); void lockDescendantComponents(dust3d::Uuid componentId); void unlockDescendantComponents(dust3d::Uuid componentId); void setComponentPreviewPixmap(const dust3d::Uuid& componentId, const QPixmap& pixmap); void setPartLockState(dust3d::Uuid partId, bool locked); void setPartVisibleState(dust3d::Uuid partId, bool visible); void setPartDisableState(dust3d::Uuid partId, bool disabled); void setPartColorImage(const dust3d::Uuid& partId, const dust3d::Uuid& imageId); void enableAllPositionRelatedLocks(); void disableAllPositionRelatedLocks(); bool isPartReadonly(dust3d::Uuid partId) const; void breakEdge(dust3d::Uuid edgeId); void reduceNode(dust3d::Uuid nodeId); void reverseEdge(dust3d::Uuid edgeId); void setXlockState(bool locked); void setYlockState(bool locked); void setZlockState(bool locked); void setRadiusLockState(bool locked); void addBone(const dust3d::Uuid& boneId); void addNodesToBone(const dust3d::Uuid& boneId, const std::vector& nodeIds); void removeNodesFromBone(const dust3d::Uuid& boneId, const std::vector& nodeIds); void removeBone(const dust3d::Uuid& boneId); void setBoneAttachment(const dust3d::Uuid& boneId, const dust3d::Uuid& toBoneId, int toBoneJointIndex); void renameBone(const dust3d::Uuid& boneId, const QString& name); void applyBoneJoints(const dust3d::Uuid& boneId, const std::vector& nodeIds); void startBoneJointsPicking(const dust3d::Uuid& boneId, size_t boneJoints); void stopBoneJointsPicking(); void pickBoneNode(const dust3d::Uuid& nodeId); private: void resolveSnapshotBoundingBox(const dust3d::Snapshot& snapshot, QRectF* mainProfile, QRectF* sideProfile); void settleOrigin(); void checkExportReadyState(); void splitPartByNode(std::vector>* groups, dust3d::Uuid nodeId); void joinNodeAndNeiborsToGroup(std::vector* group, dust3d::Uuid nodeId, std::set* visitMap, dust3d::Uuid noUseEdgeId = dust3d::Uuid()); void splitPartByEdge(std::vector>* groups, dust3d::Uuid edgeId); void removePartDontCareComponent(dust3d::Uuid partId); void addPartToComponent(dust3d::Uuid partId, dust3d::Uuid componentId); bool isDescendantComponent(dust3d::Uuid componentId, dust3d::Uuid suspiciousId); void removeComponentRecursively(dust3d::Uuid componentId); void updateLinkedPart(dust3d::Uuid oldPartId, dust3d::Uuid newPartId); dust3d::Uuid createNode(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId); void resetCurrentBone(); bool m_isResultMeshObsolete = false; MeshGenerator* m_meshGenerator = nullptr; ModelMesh* m_resultMesh = nullptr; std::unique_ptr m_wireframeMesh; bool m_isMeshGenerationSucceed = true; int m_batchChangeRefCount = 0; dust3d::Object* m_currentObject = nullptr; bool m_isTextureObsolete = false; UvMapGenerator* m_textureGenerator = nullptr; bool m_isPostProcessResultObsolete = false; MeshResultPostProcessor* m_postProcessor = nullptr; std::unique_ptr m_uvMappedObject = std::make_unique(); ModelMesh* m_resultTextureMesh = nullptr; unsigned long long m_textureImageUpdateVersion = 0; bool m_smoothNormal = false; quint64 m_meshGenerationId = 0; quint64 m_nextMeshGenerationId = 0; void* m_generatedCacheContext = nullptr; float m_originX = 0; float m_originY = 0; 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; private: static unsigned long m_maxSnapshot; std::deque m_undoItems; std::deque m_redoItems; }; #endif