From 72f0f78e644a783aa8096a479a25804c8d37e936 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Tue, 14 Mar 2023 14:53:36 +0800 Subject: [PATCH 01/40] bug fix --- .../src/Editor/GraphicElement.cpp | 15 ++++++ .../src/Editor/GraphicElement.h | 3 ++ .../src/Editor/LayerWrapper.cpp | 53 ++++++++++--------- .../src/Editor/LayerWrapper.h | 10 ++-- .../src/Editor/RightBar/LayerTreeWidget.cpp | 4 ++ 5 files changed, 57 insertions(+), 28 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 403ae3f..d3dc67b 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -83,4 +83,19 @@ QJsonObject GraphicElement::toJson() const QJsonObject result; result.insert("name", name); return result; +} + +void SimpleElement::paint(QPainter* painter, QTransform transform, vector> styles) +{ + Renderer::ElementStyleStrokeDemo demo(2); + auto [img, mov] = renderer->drawElement(painterPath, demo, 1.0); + painter->save(); + painter->setTransform(transform); + painter->drawImage(mov, img); + painter->restore(); +} + +void GroupElement::paint(QPainter* painter, QTransform transform, vector> styles) +{ + sourceLayer->paint(painter, transform); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index c0b3c09..577f7db 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -28,6 +28,7 @@ public: virtual QJsonObject toJson() const; virtual PixelPath getPaintObject() const = 0; virtual PixelPath getPaintObject(std::vector>*) const = 0; + virtual void paint(QPainter* painter, QTransform transform, std::vector> styles) = 0; }; class SimpleElement : public GraphicElement @@ -44,6 +45,7 @@ public: ~SimpleElement() = default; PixelPath getPaintObject() const override; PixelPath getPaintObject(std::vector>*) const override; + void paint(QPainter* painter, QTransform transform, std::vector> styles) override; }; class GroupElement : public GraphicElement @@ -58,6 +60,7 @@ public: PixelPath getPaintObject() const override; PixelPath getPaintObject(std::vector>*) const override; void setSourceLayer(FolderLayerWrapper* sourceLayer); + void paint(QPainter* painter, QTransform transform, std::vector> styles) override; }; //******************************** BitmapPath ********************************// diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 9e1febe..c914236 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -46,6 +46,7 @@ LayerWrapper::LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementM property.scale = {transformJson.value("scale").toObject().value("x").toDouble(), transformJson.value("scale").toObject().value("y").toDouble()}; property.rotation = {transformJson.value("rotation").toDouble()}; + selected = false; } FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent) @@ -80,19 +81,19 @@ LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager *elementMana wrappedElement = elementManager->getElementById(elementIndex); } -void LayerWrapper::SimpleProperty::apply(PixelPath&cache) const +void LayerWrapper::SimpleProperty::apply(PixelPath&cache) { - QTransform trans; + transform.reset(); double centerX = cache.getBoundingRect().center().x(); double centerY = cache.getBoundingRect().center().y(); //qDebug() << name << " " << cache.boundingRect().center(); //qDebug() << name << " " << cache.boundingRect(); - trans.translate(centerX, centerY); - trans.translate(offset.x(), offset.y()); - trans.rotate(rotation); - trans.scale(scale.x(), scale.y()); - trans.translate(-centerX, -centerY); - cache = cache.trans(trans); + transform.translate(-centerX, -centerY); + transform.translate(offset.x(), offset.y()); + transform.rotate(rotation); + transform.scale(scale.x(), scale.y()); + transform.translate(centerX, centerY); + cache = cache.trans(transform); } QTransform LayerWrapper::getTransform() @@ -250,31 +251,35 @@ int FolderLayerWrapper::getReferencedBy()const return -1; } -void LayerWrapper::paint(QPainter* painter) +void LayerWrapper::paint(QPainter* painter, QTransform transform) { - + if (this->selected) + { + painter->save(); + painter->setTransform(transform); + painter->setPen(QPen(Qt::gray, 2)); + painter->setPen(Qt::DashLine); + painter->drawRect(cache.getBoundingRect()); + painter->restore(); + } } -void FolderLayerWrapper::paint(QPainter* painter) +void FolderLayerWrapper::paint(QPainter* painter, QTransform transform) { + LayerWrapper::paint(painter, transform); + transform = property.transform * transform; + qDebug() << transform; for (auto& child : children) - child->paint(painter); + child->paint(painter, transform); } -void LeafLayerWrapper::paint(QPainter* painter) +void LeafLayerWrapper::paint(QPainter* painter, QTransform transform) { + LayerWrapper::paint(painter, transform); + transform = property.transform * transform; + qDebug() << transform; if (wrappedElement != nullptr) { - //painter->save(); - QTransform trans; - LayerWrapper* layer = this; - while (layer != nullptr) { - trans *= layer->getTransform(); - layer = layer->getParent(); - } - auto p = wrappedElement->getPaintObject(&this->styles); - p.trans(trans); - painter->drawPixmap(0, 0, p.getPixmap()); - //painter->restore(); + wrappedElement->paint(painter, transform, styles); } } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 2186cd6..7df5d13 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -35,6 +35,7 @@ class LayerWrapper public: QTreeWidgetItem* qTreeWidgetItem; + bool selected; struct SimpleProperty { QString name = ""; @@ -43,8 +44,9 @@ class LayerWrapper double rotation = 0; bool flipHorizontally = 0; bool flipVertically = 0; + QTransform transform; // TODO: 将QPainterPath改为BitmapPath - void apply(PixelPath&cache) const; + void apply(PixelPath&cache); } property; virtual void setParent(FolderLayerWrapper*newParent); virtual void refresh(LayerWrapper* layer = nullptr); @@ -55,7 +57,7 @@ class LayerWrapper FolderLayerWrapper*getParent() const; // invoke by manager, then invoke parent's applyStyles LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementManager* elementManager=nullptr); LayerWrapper() = default; - virtual void paint(QPainter* painter); + virtual void paint(QPainter* painter, QTransform transform=QTransform()); // TODO : export Function // virtual LayerWrapper *addChild() = 0; // Leaf Child Only // virtual LayerWrapper *addParent() = 0; // Folder Parent Only @@ -88,7 +90,7 @@ class FolderLayerWrapper : public LayerWrapper QTreeWidgetItem* getQTreeItem() override; QJsonObject toJson() const override; int getReferencedBy()const; - void paint(QPainter* painter) override; + void paint(QPainter* painter, QTransform transform = QTransform()) override; }; class LeafLayerWrapper : public LayerWrapper @@ -104,7 +106,7 @@ class LeafLayerWrapper : public LayerWrapper LeafLayerWrapper() = default; LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); QJsonObject toJson() const override; - void paint(QPainter* painter) override; + void paint(QPainter* painter, QTransform transform = QTransform()) override; }; Q_DECLARE_METATYPE(LayerWrapper *) diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index f6962db..1e84c88 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -12,9 +12,13 @@ LayerTreeWidget::LayerTreeWidget(QWidget *parent) this->setHeaderLabel("Layer Content"); connect(this, &QTreeWidget::customContextMenuRequested, this, &LayerTreeWidget::popMenu); connect(this, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *currentItem) { + if (this->selectedItem != nullptr) { + this->selectedItem->data(0, Qt::UserRole).value()->selected = false; + } this->selectedItem = currentItem; if (this->selectedItem != nullptr) { auto layer = this->selectedItem->data(0, Qt::UserRole).value(); + layer->selected = true; emit displayLayerChange(layer); } else { From 684c28dafd2dd99c0831dabfcb2d8af65d336a64 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Tue, 14 Mar 2023 14:53:36 +0800 Subject: [PATCH 02/40] bug fix --- .../src/Editor/GraphicElement.cpp | 15 ++++++ .../src/Editor/GraphicElement.h | 3 ++ .../src/Editor/LayerWrapper.cpp | 53 ++++++++++--------- .../src/Editor/LayerWrapper.h | 10 ++-- .../src/Editor/PreviewWindow.cpp | 4 +- .../src/Editor/RightBar/LayerTreeWidget.cpp | 4 ++ 6 files changed, 58 insertions(+), 31 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 403ae3f..d3dc67b 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -83,4 +83,19 @@ QJsonObject GraphicElement::toJson() const QJsonObject result; result.insert("name", name); return result; +} + +void SimpleElement::paint(QPainter* painter, QTransform transform, vector> styles) +{ + Renderer::ElementStyleStrokeDemo demo(2); + auto [img, mov] = renderer->drawElement(painterPath, demo, 1.0); + painter->save(); + painter->setTransform(transform); + painter->drawImage(mov, img); + painter->restore(); +} + +void GroupElement::paint(QPainter* painter, QTransform transform, vector> styles) +{ + sourceLayer->paint(painter, transform); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index c0b3c09..577f7db 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -28,6 +28,7 @@ public: virtual QJsonObject toJson() const; virtual PixelPath getPaintObject() const = 0; virtual PixelPath getPaintObject(std::vector>*) const = 0; + virtual void paint(QPainter* painter, QTransform transform, std::vector> styles) = 0; }; class SimpleElement : public GraphicElement @@ -44,6 +45,7 @@ public: ~SimpleElement() = default; PixelPath getPaintObject() const override; PixelPath getPaintObject(std::vector>*) const override; + void paint(QPainter* painter, QTransform transform, std::vector> styles) override; }; class GroupElement : public GraphicElement @@ -58,6 +60,7 @@ public: PixelPath getPaintObject() const override; PixelPath getPaintObject(std::vector>*) const override; void setSourceLayer(FolderLayerWrapper* sourceLayer); + void paint(QPainter* painter, QTransform transform, std::vector> styles) override; }; //******************************** BitmapPath ********************************// diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 9e1febe..c914236 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -46,6 +46,7 @@ LayerWrapper::LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementM property.scale = {transformJson.value("scale").toObject().value("x").toDouble(), transformJson.value("scale").toObject().value("y").toDouble()}; property.rotation = {transformJson.value("rotation").toDouble()}; + selected = false; } FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent) @@ -80,19 +81,19 @@ LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager *elementMana wrappedElement = elementManager->getElementById(elementIndex); } -void LayerWrapper::SimpleProperty::apply(PixelPath&cache) const +void LayerWrapper::SimpleProperty::apply(PixelPath&cache) { - QTransform trans; + transform.reset(); double centerX = cache.getBoundingRect().center().x(); double centerY = cache.getBoundingRect().center().y(); //qDebug() << name << " " << cache.boundingRect().center(); //qDebug() << name << " " << cache.boundingRect(); - trans.translate(centerX, centerY); - trans.translate(offset.x(), offset.y()); - trans.rotate(rotation); - trans.scale(scale.x(), scale.y()); - trans.translate(-centerX, -centerY); - cache = cache.trans(trans); + transform.translate(-centerX, -centerY); + transform.translate(offset.x(), offset.y()); + transform.rotate(rotation); + transform.scale(scale.x(), scale.y()); + transform.translate(centerX, centerY); + cache = cache.trans(transform); } QTransform LayerWrapper::getTransform() @@ -250,31 +251,35 @@ int FolderLayerWrapper::getReferencedBy()const return -1; } -void LayerWrapper::paint(QPainter* painter) +void LayerWrapper::paint(QPainter* painter, QTransform transform) { - + if (this->selected) + { + painter->save(); + painter->setTransform(transform); + painter->setPen(QPen(Qt::gray, 2)); + painter->setPen(Qt::DashLine); + painter->drawRect(cache.getBoundingRect()); + painter->restore(); + } } -void FolderLayerWrapper::paint(QPainter* painter) +void FolderLayerWrapper::paint(QPainter* painter, QTransform transform) { + LayerWrapper::paint(painter, transform); + transform = property.transform * transform; + qDebug() << transform; for (auto& child : children) - child->paint(painter); + child->paint(painter, transform); } -void LeafLayerWrapper::paint(QPainter* painter) +void LeafLayerWrapper::paint(QPainter* painter, QTransform transform) { + LayerWrapper::paint(painter, transform); + transform = property.transform * transform; + qDebug() << transform; if (wrappedElement != nullptr) { - //painter->save(); - QTransform trans; - LayerWrapper* layer = this; - while (layer != nullptr) { - trans *= layer->getTransform(); - layer = layer->getParent(); - } - auto p = wrappedElement->getPaintObject(&this->styles); - p.trans(trans); - painter->drawPixmap(0, 0, p.getPixmap()); - //painter->restore(); + wrappedElement->paint(painter, transform, styles); } } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 2186cd6..7df5d13 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -35,6 +35,7 @@ class LayerWrapper public: QTreeWidgetItem* qTreeWidgetItem; + bool selected; struct SimpleProperty { QString name = ""; @@ -43,8 +44,9 @@ class LayerWrapper double rotation = 0; bool flipHorizontally = 0; bool flipVertically = 0; + QTransform transform; // TODO: 将QPainterPath改为BitmapPath - void apply(PixelPath&cache) const; + void apply(PixelPath&cache); } property; virtual void setParent(FolderLayerWrapper*newParent); virtual void refresh(LayerWrapper* layer = nullptr); @@ -55,7 +57,7 @@ class LayerWrapper FolderLayerWrapper*getParent() const; // invoke by manager, then invoke parent's applyStyles LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementManager* elementManager=nullptr); LayerWrapper() = default; - virtual void paint(QPainter* painter); + virtual void paint(QPainter* painter, QTransform transform=QTransform()); // TODO : export Function // virtual LayerWrapper *addChild() = 0; // Leaf Child Only // virtual LayerWrapper *addParent() = 0; // Folder Parent Only @@ -88,7 +90,7 @@ class FolderLayerWrapper : public LayerWrapper QTreeWidgetItem* getQTreeItem() override; QJsonObject toJson() const override; int getReferencedBy()const; - void paint(QPainter* painter) override; + void paint(QPainter* painter, QTransform transform = QTransform()) override; }; class LeafLayerWrapper : public LayerWrapper @@ -104,7 +106,7 @@ class LeafLayerWrapper : public LayerWrapper LeafLayerWrapper() = default; LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); QJsonObject toJson() const override; - void paint(QPainter* painter) override; + void paint(QPainter* painter, QTransform transform = QTransform()) override; }; Q_DECLARE_METATYPE(LayerWrapper *) diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp index 723f0b1..d8199c7 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp @@ -87,13 +87,11 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event) currentLayer->property.offset.setX(currentLayer->property.offset.x() + dx); currentLayer->property.offset.setY(currentLayer->property.offset.y() + dy); qDebug() << dx << "----" << dy; - emit layerInfoChanged(); } else if (event->buttons() & Qt::RightButton) { // 如果按下的是右键,那么旋转图形 qreal angle = -sqrt(dx * dx + dy * dy) / 1.0; currentLayer->property.rotation += angle; - emit layerInfoChanged(); } } // 更新上一次的位置 @@ -103,5 +101,5 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event) void PreviewWindow::mouseReleaseEvent(QMouseEvent* event) { - // 当鼠标释放时,不做任何操作 + emit layerInfoChanged(); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index f6962db..1e84c88 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -12,9 +12,13 @@ LayerTreeWidget::LayerTreeWidget(QWidget *parent) this->setHeaderLabel("Layer Content"); connect(this, &QTreeWidget::customContextMenuRequested, this, &LayerTreeWidget::popMenu); connect(this, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *currentItem) { + if (this->selectedItem != nullptr) { + this->selectedItem->data(0, Qt::UserRole).value()->selected = false; + } this->selectedItem = currentItem; if (this->selectedItem != nullptr) { auto layer = this->selectedItem->data(0, Qt::UserRole).value(); + layer->selected = true; emit displayLayerChange(layer); } else { From 97097fcc3abccdbd4230ec8553e5b952853eff47 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Tue, 14 Mar 2023 15:36:19 +0800 Subject: [PATCH 03/40] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=8B=E8=BD=AC?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=EF=BC=8C=E6=B7=BB=E5=8A=A0style=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/GraphicElement.cpp | 15 ++++++++++++--- .../src/Editor/PreviewWindow.cpp | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index d3dc67b..9602f2d 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -87,11 +87,20 @@ QJsonObject GraphicElement::toJson() const void SimpleElement::paint(QPainter* painter, QTransform transform, vector> styles) { - Renderer::ElementStyleStrokeDemo demo(2); - auto [img, mov] = renderer->drawElement(painterPath, demo, 1.0); painter->save(); painter->setTransform(transform); - painter->drawImage(mov, img); + if (styles.empty()) + { + painter->drawPath(painterPath); + } + else + { + // TODO:应用style + Renderer::ElementStyleStrokeDemo demo(2); + auto [img, mov] = renderer->drawElement(painterPath, demo, 1.0); + painter->drawImage(mov, img); + } + painter->restore(); } diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp index d8199c7..485977d 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp @@ -88,9 +88,9 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event) currentLayer->property.offset.setY(currentLayer->property.offset.y() + dy); qDebug() << dx << "----" << dy; } - else if (event->buttons() & Qt::RightButton) { + else if (event->buttons() & Qt::RightButton) { // 如果按下的是右键,那么旋转图形 - qreal angle = -sqrt(dx * dx + dy * dy) / 1.0; + qreal angle = dx; currentLayer->property.rotation += angle; } } From 62b9c2b02656f4dbf8209c36cd89c319712a5c0a Mon Sep 17 00:00:00 2001 From: wuyize Date: Tue, 14 Mar 2023 22:44:23 +0800 Subject: [PATCH 04/40] =?UTF-8?q?FIX:=20style=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/Shaders/element.comp | 98 +- .../res/Shaders/painting.comp | 2026 +++++++++-------- .../src/Editor/util/PainterPathUtil.cpp | 8 +- .../src/Editor/util/PainterPathUtil.h | 4 +- .../src/Renderer/Model.cpp | 54 +- .../Renderer/Painting/MaterialStyleStroke.cpp | 6 +- .../Renderer/Painting/MaterialStyleStroke.h | 2 +- .../src/Renderer/RendererWidget.cpp | 6 +- UnitTest/ElementRendererTest.cpp | 21 + 9 files changed, 1232 insertions(+), 993 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/element.comp b/ArchitectureColoredPainting/res/Shaders/element.comp index 36f4220..93c0166 100644 --- a/ArchitectureColoredPainting/res/Shaders/element.comp +++ b/ArchitectureColoredPainting/res/Shaders/element.comp @@ -969,7 +969,7 @@ void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2 } } -bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, vec2 tangentBegin, vec2 tangentEndLast) +bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast) { vec2 normal; if (onVeryBegin) @@ -985,17 +985,26 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, ve vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); normal = normalLast + normalNow; } - return angleLargeThanPi(normal, localUV - p3); + return angleLargeThanPi(normal, localUV - p0); } -bool shouldFillEndCap(vec2 localUV, int endType, vec2 p0, vec2 tangentEnd) +bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext) { vec2 normal; - if (endType == 0) - return true; - else if (endType == 1) - normal = normalize(mat2(0, 1, -1, 0) * tangentEnd); - return angleLargeThanPi(localUV - p0, normal); + if (onVeryEnd) + { + if (endType == 0) + return true; + else if (endType == 1) + normal = normalize(mat2(0, 1, -1, 0) * tangentEnd); + } + else + { + vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd); + vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext)); + normal = normalLast + normalNow; + } + return angleLargeThanPi(localUV - p3, normal); } void main() @@ -1055,21 +1064,25 @@ void main() float lineType = floor(styleHead.b * 10); // float lineType = 2; int endType = int(round(styleHead.b * 100)) % 10; - //endType = 1; + // endType = 1; int debugBegin = 0; bool onVeryBegin = false; + bool onVeryEnd = false; vec2 tangentEndLast; + uint lastHitIndex = 0; + bool lastHitElement = false; + hitElement = false; for (uint pathIndex = 0; pathIndex < pathSize; pathIndex++) - // for (uint pathIndex = 0; pathIndex < 4; pathIndex++) + //for (uint pathIndex = 0; pathIndex < 46; pathIndex++) { vec2 pTemp = path[pathIndex]; if (isinf(pTemp.x)) { // TODO: 检测是否封闭并处理 - if (hitElement && distance(localUV, p3Last) <= strokeWidth) - { - hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast); - } + if (hitElement && distance(localUV, p3Last) <= strokeWidth) + { + // hitElement = shouldFillEndCap(localUV, true, endType, p3Last, tangentEndLast); + } pBegin = path[++pathIndex]; p3Last = pBegin; @@ -1079,10 +1092,30 @@ void main() } mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]); + vec2 tangentBeginNext; + if (pathIndex + 1 < pathSize) + { + vec2 pTemp = path[pathIndex + 1]; + if (isinf(pTemp.x)) + { + onVeryEnd = true; + } + else + { + onVeryEnd = false; + vec2 pNext[3] = {p[3], pTemp, path[pathIndex + 2]}; + if (pNext[0] != pNext[1]) + tangentBeginNext = normalize(pNext[0] - pNext[1]); + else + tangentBeginNext = normalize(pNext[0] - pNext[2]); + } + } + float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); if (d <= strokeWidth) { - bool onBegin = distance(localUV, p[0]) <= strokeWidth && p3Last == p[0]; + bool onBegin = distance(localUV, p[0]) <= strokeWidth; + bool onEnd = distance(localUV, p[3]) <= strokeWidth; vec2 tangentBegin; vec2 tangentEnd; if (p[0] != p[1]) @@ -1094,11 +1127,19 @@ void main() else tangentEnd = normalize(p[3] - p[1]); - if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, p3Last - p2Last) - : d < minDistance) + // if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, + // tangentEndLast) + // : (onEnd ? /*shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, + // tangentBeginNext)*/ false + // : d < minDistance)) + bool hit = d < minDistance; + if (onBegin) + hit = hit && + shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast); + if (onEnd) + hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext); + if (hit) { - minDistance = min(minDistance, d); - bool reverse = p[3].y - p[0].y < 0.; if (tangentBegin.y == 0.) @@ -1111,13 +1152,26 @@ void main() if (lineType == 2 || (intTest % 2 == int(lineType))) { + minDistance = min(minDistance, d); + lastHitElement = hitElement; + lastHitIndex = pathIndex; hitElement = true; // elementColor = vec4(1, 1, 0, 1); vec2 metallicRoughness; drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); } - else if (p3Last == p[0]) - hitElement = false; + // else if (lastHitIndex == pathIndex - 3) + // { + // hitElement = lastHitElement; + // lastHitElement = false; + // // if(lastHitElement ==false) + // //{ + // // hitElement = true; + // // elementColor = vec4(1, 1, 0, 1); + // //} + + // minDistance = 1e38; + // } } tangentEndLast = tangentEnd; } @@ -1127,7 +1181,7 @@ void main() } if (hitElement && distance(localUV, p3Last) <= strokeWidth) { - hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast); + // hitElement = shouldFillEndCap(localUV, true, endType, p3Last, tangentEndLast); } } if (hitElement) diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp index e7280a0..9ba19a9 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.comp +++ b/ArchitectureColoredPainting/res/Shaders/painting.comp @@ -1,6 +1,6 @@ #version 450 core -layout (local_size_x = 8, local_size_y = 8) in; +layout(local_size_x = 8, local_size_y = 8) in; layout(location = 0) uniform ivec2 pixelOffset; @@ -9,97 +9,95 @@ layout(rg8, binding = 1) uniform image2D gMetallicRoughness; layout(std430, binding = 0) buffer bvhBuffer { - uvec2 bvhChildren[]; + uvec2 bvhChildren[]; }; layout(std430, binding = 1) buffer bvhBoundBuffer { - vec4 bvhBound[]; + vec4 bvhBound[]; }; layout(std430, binding = 2) buffer elementOffsetBuffer { - /** - * @[0] elementBvhRoot - * @[1] styleOffset - * @[2] pointsOffset - * @[3] linesOffset + /** + * @[0] elementBvhRoot + * @[1] styleOffset + * @[2] pointsOffset + * @[3] linesOffset - */ - uint elementOffset[][5]; + */ + uint elementOffset[][5]; }; layout(std430, binding = 3) buffer elementIndexBuffer { - uint elementIndexs[]; //线和面 + uint elementIndexs[]; // 线和面 }; layout(std430, binding = 4) buffer elementDataBuffer { - float elementData[]; //点和Style + float elementData[]; // 点和Style }; const float PI = 3.14159265358979; - const uint STACK_SIZE = 10; struct Stack { - uint top; - uint data[STACK_SIZE]; + uint top; + uint data[STACK_SIZE]; - bool empty() - { - return top == 0; - } - bool full() - { - return top == STACK_SIZE; - } - bool getTop(out uint x) - { - if (empty()) - return false; - x = data[top - 1]; - return true; - } - bool pop() - { - if (empty()) - return false; - top--; - return true; - } - bool push(in uint x) - { - if (full()) - return false; - data[top] = x; - top++; - return true; - } + bool empty() + { + return top == 0; + } + bool full() + { + return top == STACK_SIZE; + } + bool getTop(out uint x) + { + if (empty()) + return false; + x = data[top - 1]; + return true; + } + bool pop() + { + if (empty()) + return false; + top--; + return true; + } + bool push(in uint x) + { + if (full()) + return false; + data[top] = x; + top++; + return true; + } } stack, elementStack; - // Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c // Credits to Doublefresh for hinting there int solve_quadric(vec2 coeffs, inout vec2 roots) { - // normal form: x^2 + px + q = 0 - float p = coeffs[1] / 2.; - float q = coeffs[0]; + // normal form: x^2 + px + q = 0 + float p = coeffs[1] / 2.; + float q = coeffs[0]; - float D = p * p - q; + float D = p * p - q; - if (D < 0.) - { - return 0; - } - else - { - roots[0] = -sqrt(D) - p; - roots[1] = sqrt(D) - p; + if (D < 0.) + { + return 0; + } + else + { + roots[0] = -sqrt(D) - p; + roots[1] = sqrt(D) - p; - return 2; - } + return 2; + } } // From Trisomie21 @@ -107,490 +105,520 @@ int solve_quadric(vec2 coeffs, inout vec2 roots) int solve_cubic(vec3 coeffs, inout vec3 r) { - float a = coeffs[2]; - float b = coeffs[1]; - float c = coeffs[0]; + float a = coeffs[2]; + float b = coeffs[1]; + float c = coeffs[0]; - float p = b - a * a / 3.0; - float q = a * (2.0 * a * a - 9.0 * b) / 27.0 + c; - float p3 = p * p * p; - float d = q * q + 4.0 * p3 / 27.0; - float offset = -a / 3.0; - if (d >= 0.0) - { // Single solution - float z = sqrt(d); - float u = (-q + z) / 2.0; - float v = (-q - z) / 2.0; - u = sign(u) * pow(abs(u), 1.0 / 3.0); - v = sign(v) * pow(abs(v), 1.0 / 3.0); - r[0] = offset + u + v; + float p = b - a * a / 3.0; + float q = a * (2.0 * a * a - 9.0 * b) / 27.0 + c; + float p3 = p * p * p; + float d = q * q + 4.0 * p3 / 27.0; + float offset = -a / 3.0; + if (d >= 0.0) + { // Single solution + float z = sqrt(d); + float u = (-q + z) / 2.0; + float v = (-q - z) / 2.0; + u = sign(u) * pow(abs(u), 1.0 / 3.0); + v = sign(v) * pow(abs(v), 1.0 / 3.0); + r[0] = offset + u + v; - // Single newton iteration to account for cancellation - float f = ((r[0] + a) * r[0] + b) * r[0] + c; - float f1 = (3. * r[0] + 2. * a) * r[0] + b; + // Single newton iteration to account for cancellation + float f = ((r[0] + a) * r[0] + b) * r[0] + c; + float f1 = (3. * r[0] + 2. * a) * r[0] + b; - r[0] -= f / f1; + r[0] -= f / f1; - return 1; - } - float u = sqrt(-p / 3.0); - float v = acos(-sqrt(-27.0 / p3) * q / 2.0) / 3.0; - float m = cos(v), n = sin(v) * 1.732050808; + return 1; + } + float u = sqrt(-p / 3.0); + float v = acos(-sqrt(-27.0 / p3) * q / 2.0) / 3.0; + float m = cos(v), n = sin(v) * 1.732050808; - // Single newton iteration to account for cancellation - //(once for every root) - r[0] = offset + u * (m + m); - r[1] = offset - u * (n + m); - r[2] = offset + u * (n - m); + // Single newton iteration to account for cancellation + //(once for every root) + r[0] = offset + u * (m + m); + r[1] = offset - u * (n + m); + r[2] = offset + u * (n - m); - vec3 f = ((r + a) * r + b) * r + c; - vec3 f1 = (3. * r + 2. * a) * r + b; + vec3 f = ((r + a) * r + b) * r + c; + vec3 f1 = (3. * r + 2. * a) * r + b; - r -= f / f1; + r -= f / f1; - return 3; + return 3; } - int segment_int_test(vec2 uv, vec2 p0, vec2 p1) { - p0 -= uv; - p1 -= uv; + p0 -= uv; + p1 -= uv; - int ret; + int ret; - if (p0.y * p1.y < 0.) - { - vec2 nor = p0 - p1; - nor = vec2(nor.y, -nor.x); + if (p0.y * p1.y < 0.) + { + vec2 nor = p0 - p1; + nor = vec2(nor.y, -nor.x); - float sgn; + float sgn; - if (p0.y > p1.y) - { - sgn = 1.; - } - else - { - sgn = -1.; - } + if (p0.y > p1.y) + { + sgn = 1.; + } + else + { + sgn = -1.; + } - if (dot(nor, p0) * sgn < 0.) - { - ret = 0; - } - else - { - ret = 1; - } - } - else - { - ret = 0; - } + if (dot(nor, p0) * sgn < 0.) + { + ret = 0; + } + else + { + ret = 1; + } + } + else + { + ret = 0; + } - return ret; + return ret; } int cubic_bezier_int_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { - float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y); - float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y); - float li = (-3. * p0.y + 3. * p1.y); - float co = p0.y - uv.y; + float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y); + float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y); + float li = (-3. * p0.y + 3. * p1.y); + float co = p0.y - uv.y; - vec3 roots = vec3(1e38); - int n_roots; + vec3 roots = vec3(1e38); + int n_roots; - int n_ints = 0; + int n_ints = 0; - if (uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x))) - { - if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y)) - { - n_ints = 1; - } - } - else - { + if (uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x))) + { + if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y)) + { + n_ints = 1; + } + } + else + { - if (abs(cu) < .0001) - { - n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy); - } - else - { - n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots); - } + if (abs(cu) < .0001) + { + n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy); + } + else + { + n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots); + } - for (int i = 0; i < n_roots; i++) - { - if (roots[i] >= 0. && roots[i] <= 1.) - { - float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x; - x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x; - x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; - x_pos = x_pos * roots[i] + p0.x; + for (int i = 0; i < n_roots; i++) + { + if (roots[i] >= 0. && roots[i] <= 1.) + { + float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x; + x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x; + x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; + x_pos = x_pos * roots[i] + p0.x; - if (x_pos > uv.x) - { - n_ints++; - } - } - } - } + if (x_pos > uv.x) + { + n_ints++; + } + } + } + } - return n_ints; + return n_ints; } bvec3 segment_sign_test(vec2 uv, vec2 p0, vec2 p1) { - p0 -= uv; - p1 -= uv; - bvec3 ret; - vec2 nor = p0 - p1; - nor = vec2(nor.y, -nor.x); + p0 -= uv; + p1 -= uv; + bvec3 ret; + vec2 nor = p0 - p1; + nor = vec2(nor.y, -nor.x); - float sgn; + float sgn; - if (p0.y > p1.y) - { - sgn = 1.; - } - else - { - sgn = -1.; - } + if (p0.y > p1.y) + { + sgn = 1.; + } + else + { + sgn = -1.; + } - if (dot(nor, p0) * sgn < 0.) - { - if (p0.y * p1.y < 0.) - ret.y = false; - else - ret.y = false; - ret.xz = bvec2(false); - } - else - { - if (p0.y * p1.y < 0.) - ret.y = true; - else - ret.y = false; - ret.xz = bvec2(true); - } - return ret; + if (dot(nor, p0) * sgn < 0.) + { + if (p0.y * p1.y < 0.) + ret.y = false; + else + ret.y = false; + ret.xz = bvec2(false); + } + else + { + if (p0.y * p1.y < 0.) + ret.y = true; + else + ret.y = false; + ret.xz = bvec2(true); + } + return ret; } bvec3 cubic_bezier_sign_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { -// if(abs(p3.y-p0.y)< 1e-4) -// { -// return segment_sign_test(uv, p0,p3); -// } + // if(abs(p3.y-p0.y)< 1e-4) + // { + // return segment_sign_test(uv, p0,p3); + // } - float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y); - float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y); - float li = (-3. * p0.y + 3. * p1.y); - float co = p0.y - uv.y; + float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y); + float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y); + float li = (-3. * p0.y + 3. * p1.y); + float co = p0.y - uv.y; - vec3 roots = vec3(1e38); - int n_roots = solve_cubic(vec3(co/cu,li/cu,qu/cu),roots); + vec3 roots = vec3(1e38); + int n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots); - //int n_ints = 0; - bvec3 result = bvec3(false); - for(int i=0;i<3;i++){ - if(i < n_roots){ - if(roots[i] >= 0. && roots[i] <= 1.){ - float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x; - x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x; - x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; - x_pos = x_pos * roots[i] + p0.x; + // int n_ints = 0; + bvec3 result = bvec3(false); + for (int i = 0; i < 3; i++) + { + if (i < n_roots) + { + if (roots[i] >= 0. && roots[i] <= 1.) + { + float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x; + x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x; + x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; + x_pos = x_pos * roots[i] + p0.x; - if(x_pos > uv.x){ - result[1] = !result[1]; - } - } - } - } + if (x_pos > uv.x) + { + result[1] = !result[1]; + } + } + } + } - vec2 tang1 = p0.xy - p1.xy; - vec2 tang2 = p2.xy - p3.xy; + vec2 tang1 = p0.xy - p1.xy; + vec2 tang2 = p2.xy - p3.xy; - vec2 nor1 = vec2(tang1.y,-tang1.x); - vec2 nor2 = vec2(tang2.y,-tang2.x); + vec2 nor1 = vec2(tang1.y, -tang1.x); + vec2 nor2 = vec2(tang2.y, -tang2.x); - if(p0.y < p1.y){ - if((uv.y<=p0.y) && (dot(uv-p0.xy,nor1)>0.)){ - result[0]=!result[0]; - } - } - else{ - if(!(uv.y<=p0.y) && !(dot(uv-p0.xy,nor1)>0.)){ - result[0]=!result[0]; - } - } + if (p0.y < p1.y) + { + if ((uv.y <= p0.y) && (dot(uv - p0.xy, nor1) > 0.)) + { + result[0] = !result[0]; + } + } + else + { + if (!(uv.y <= p0.y) && !(dot(uv - p0.xy, nor1) > 0.)) + { + result[0] = !result[0]; + } + } - if(p2.y0.){ - result[2]=!result[2]; - } - } - else{ - if((uv.y<=p3.y) && !(dot(uv-p3.xy,nor2)>0.)){ - result[2]=!result[2]; - } - } - - return result; - // if(n_ints==0 || n_ints==2 || n_ints==4){ - // return 1; - // } - // else{ - // return 0; - // } + if (p2.y < p3.y) + { + if (!(uv.y <= p3.y) && dot(uv - p3.xy, nor2) > 0.) + { + result[2] = !result[2]; + } + } + else + { + if ((uv.y <= p3.y) && !(dot(uv - p3.xy, nor2) > 0.)) + { + result[2] = !result[2]; + } + } + + return result; + // if(n_ints==0 || n_ints==2 || n_ints==4){ + // return 1; + // } + // else{ + // return 0; + // } } const float eps = .000005; const int halley_iterations = 8; -//lagrange positive real root upper bound -//see for example: https://doi.org/10.1016/j.jsc.2014.09.038 -float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){ +// lagrange positive real root upper bound +// see for example: https://doi.org/10.1016/j.jsc.2014.09.038 +float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4) +{ - vec4 coeffs1 = vec4(a0,a1,a2,a3); + vec4 coeffs1 = vec4(a0, a1, a2, a3); - vec4 neg1 = max(-coeffs1,vec4(0)); - float neg2 = max(-a4,0.); + vec4 neg1 = max(-coeffs1, vec4(0)); + float neg2 = max(-a4, 0.); - const vec4 indizes1 = vec4(0,1,2,3); - const float indizes2 = 4.; + const vec4 indizes1 = vec4(0, 1, 2, 3); + const float indizes2 = 4.; - vec4 bounds1 = pow(neg1,1./(5.-indizes1)); - float bounds2 = pow(neg2,1./(5.-indizes2)); + vec4 bounds1 = pow(neg1, 1. / (5. - indizes1)); + float bounds2 = pow(neg2, 1. / (5. - indizes2)); - vec2 min1_2 = min(bounds1.xz,bounds1.yw); - vec2 max1_2 = max(bounds1.xz,bounds1.yw); + vec2 min1_2 = min(bounds1.xz, bounds1.yw); + vec2 max1_2 = max(bounds1.xz, bounds1.yw); - float maxmin = max(min1_2.x,min1_2.y); - float minmax = min(max1_2.x,max1_2.y); + float maxmin = max(min1_2.x, min1_2.y); + float minmax = min(max1_2.x, max1_2.y); - float max3 = max(max1_2.x,max1_2.y); + float max3 = max(max1_2.x, max1_2.y); - float max_max = max(max3,bounds2); - float max_max2 = max(min(max3,bounds2),max(minmax,maxmin)); + float max_max = max(max3, bounds2); + float max_max2 = max(min(max3, bounds2), max(minmax, maxmin)); - return max_max + max_max2; + return max_max + max_max2; } -//lagrange upper bound applied to f(-x) to get lower bound -float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){ +// lagrange upper bound applied to f(-x) to get lower bound +float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4) +{ - vec4 coeffs1 = vec4(-a0,a1,-a2,a3); + vec4 coeffs1 = vec4(-a0, a1, -a2, a3); - vec4 neg1 = max(-coeffs1,vec4(0)); - float neg2 = max(-a4,0.); + vec4 neg1 = max(-coeffs1, vec4(0)); + float neg2 = max(-a4, 0.); - const vec4 indizes1 = vec4(0,1,2,3); - const float indizes2 = 4.; + const vec4 indizes1 = vec4(0, 1, 2, 3); + const float indizes2 = 4.; - vec4 bounds1 = pow(neg1,1./(5.-indizes1)); - float bounds2 = pow(neg2,1./(5.-indizes2)); + vec4 bounds1 = pow(neg1, 1. / (5. - indizes1)); + float bounds2 = pow(neg2, 1. / (5. - indizes2)); - vec2 min1_2 = min(bounds1.xz,bounds1.yw); - vec2 max1_2 = max(bounds1.xz,bounds1.yw); + vec2 min1_2 = min(bounds1.xz, bounds1.yw); + vec2 max1_2 = max(bounds1.xz, bounds1.yw); - float maxmin = max(min1_2.x,min1_2.y); - float minmax = min(max1_2.x,max1_2.y); + float maxmin = max(min1_2.x, min1_2.y); + float minmax = min(max1_2.x, max1_2.y); - float max3 = max(max1_2.x,max1_2.y); + float max3 = max(max1_2.x, max1_2.y); - float max_max = max(max3,bounds2); - float max_max2 = max(min(max3,bounds2),max(minmax,maxmin)); + float max_max = max(max3, bounds2); + float max_max2 = max(min(max3, bounds2), max(minmax, maxmin)); - return -max_max - max_max2; + return -max_max - max_max2; } -vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3){ - vec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3); - vec2 a1 = (3. * p0 -6. * p1 + 3. * p2); - vec2 a2 = (-3. * p0 + 3. * p1); - vec2 a3 = p0; +vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3) +{ + vec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3); + vec2 a1 = (3. * p0 - 6. * p1 + 3. * p2); + vec2 a2 = (-3. * p0 + 3. * p1); + vec2 a3 = p0; - return (((a0 * t) + a1) * t + a2) * t + a3; + return (((a0 * t) + a1) * t + a2) * t + a3; } -void sort_roots3(inout vec3 roots){ - vec3 tmp; +void sort_roots3(inout vec3 roots) +{ + vec3 tmp; - tmp[0] = min(roots[0],min(roots[1],roots[2])); - tmp[1] = max(roots[0],min(roots[1],roots[2])); - tmp[2] = max(roots[0],max(roots[1],roots[2])); + tmp[0] = min(roots[0], min(roots[1], roots[2])); + tmp[1] = max(roots[0], min(roots[1], roots[2])); + tmp[2] = max(roots[0], max(roots[1], roots[2])); - roots=tmp; + roots = tmp; } -void sort_roots4(inout vec4 roots){ - vec4 tmp; +void sort_roots4(inout vec4 roots) +{ + vec4 tmp; - vec2 min1_2 = min(roots.xz,roots.yw); - vec2 max1_2 = max(roots.xz,roots.yw); + vec2 min1_2 = min(roots.xz, roots.yw); + vec2 max1_2 = max(roots.xz, roots.yw); - float maxmin = max(min1_2.x,min1_2.y); - float minmax = min(max1_2.x,max1_2.y); + float maxmin = max(min1_2.x, min1_2.y); + float minmax = min(max1_2.x, max1_2.y); - tmp[0] = min(min1_2.x,min1_2.y); - tmp[1] = min(maxmin,minmax); - tmp[2] = max(minmax,maxmin); - tmp[3] = max(max1_2.x,max1_2.y); + tmp[0] = min(min1_2.x, min1_2.y); + tmp[1] = min(maxmin, minmax); + tmp[2] = max(minmax, maxmin); + tmp[3] = max(max1_2.x, max1_2.y); - roots = tmp; + roots = tmp; } -float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x){ +float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x) +{ - float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0; + float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0; - return f; + return f; } -//halley's method -//basically a variant of newton raphson which converges quicker and has bigger basins of convergence -//see http://mathworld.wolfram.com/HalleysMethod.html -//or https://en.wikipedia.org/wiki/Halley%27s_method -float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x){ +// halley's method +// basically a variant of newton raphson which converges quicker and has bigger basins of convergence +// see http://mathworld.wolfram.com/HalleysMethod.html +// or https://en.wikipedia.org/wiki/Halley%27s_method +float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x) +{ - float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0; - float f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1; - float f2 = ((20. * x + 12. * a4) * x + 6. * a3) * x + 2. * a2; + float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0; + float f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1; + float f2 = ((20. * x + 12. * a4) * x + 6. * a3) * x + 2. * a2; - return x - (2. * f * f1) / (2. * f1 * f1 - f * f2); + return x - (2. * f * f1) / (2. * f1 * f1 - f * f2); } -float halley_iteration4(vec4 coeffs, float x){ +float halley_iteration4(vec4 coeffs, float x) +{ - float f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0]; - float f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1]; - float f2 = (12. * x + 6. * coeffs[3]) * x + 2. * coeffs[2]; + float f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0]; + float f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1]; + float f2 = (12. * x + 6. * coeffs[3]) * x + 2. * coeffs[2]; - return x - (2. * f * f1) / (2. * f1 * f1 - f * f2); + return x - (2. * f * f1) / (2. * f1 * f1 - f * f2); } // Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c // Credits to Doublefresh for hinting there -int solve_quartic(vec4 coeffs, inout vec4 s){ +int solve_quartic(vec4 coeffs, inout vec4 s) +{ - float a = coeffs[3]; - float b = coeffs[2]; - float c = coeffs[1]; - float d = coeffs[0]; + float a = coeffs[3]; + float b = coeffs[2]; + float c = coeffs[1]; + float d = coeffs[0]; - /* substitute x = y - A/4 to eliminate cubic term: - x^4 + px^2 + qx + r = 0 */ + /* substitute x = y - A/4 to eliminate cubic term: + x^4 + px^2 + qx + r = 0 */ - float sq_a = a * a; - float p = - 3./8. * sq_a + b; - float q = 1./8. * sq_a * a - 1./2. * a * b + c; - float r = - 3./256.*sq_a*sq_a + 1./16.*sq_a*b - 1./4.*a*c + d; + float sq_a = a * a; + float p = -3. / 8. * sq_a + b; + float q = 1. / 8. * sq_a * a - 1. / 2. * a * b + c; + float r = -3. / 256. * sq_a * sq_a + 1. / 16. * sq_a * b - 1. / 4. * a * c + d; - int num; + int num; - /* doesn't seem to happen for me */ - //if(abs(r) -eps){ - u = sqrt(abs(u)); - } - else{ - return 0; - } + if (u > -eps) + { + u = sqrt(abs(u)); + } + else + { + return 0; + } - if(v > -eps){ - v = sqrt(abs(v)); - } - else{ - return 0; - } + if (v > -eps) + { + v = sqrt(abs(v)); + } + else + { + return 0; + } - vec2 quad_coeffs; + vec2 quad_coeffs; - quad_coeffs[0] = z - u; - quad_coeffs[1] = q < 0. ? -v : v; + quad_coeffs[0] = z - u; + quad_coeffs[1] = q < 0. ? -v : v; - num = solve_quadric(quad_coeffs, s.xy); + num = solve_quadric(quad_coeffs, s.xy); - quad_coeffs[0]= z + u; - quad_coeffs[1] = q < 0. ? v : -v; + quad_coeffs[0] = z + u; + quad_coeffs[1] = q < 0. ? v : -v; - vec2 tmp=vec2(1e38); - int old_num=num; + vec2 tmp = vec2(1e38); + int old_num = num; - num += solve_quadric(quad_coeffs, tmp); - if(old_num!=num){ - if(old_num == 0){ - s[0] = tmp[0]; - s[1] = tmp[1]; - } - else{//old_num == 2 - s[2] = tmp[0]; - s[3] = tmp[1]; - } - } - } + num += solve_quadric(quad_coeffs, tmp); + if (old_num != num) + { + if (old_num == 0) + { + s[0] = tmp[0]; + s[1] = tmp[1]; + } + else + { // old_num == 2 + s[2] = tmp[0]; + s[3] = tmp[1]; + } + } + } - /* resubstitute */ + /* resubstitute */ - float sub = 1./4. * a; + float sub = 1. / 4. * a; - /* single halley iteration to fix cancellation */ - for(int i=0;i<4;i+=2){ - if(i < num){ - s[i] -= sub; - s[i] = halley_iteration4(coeffs,s[i]); + /* single halley iteration to fix cancellation */ + for (int i = 0; i < 4; i += 2) + { + if (i < num) + { + s[i] -= sub; + s[i] = halley_iteration4(coeffs, s[i]); - s[i+1] -= sub; - s[i+1] = halley_iteration4(coeffs,s[i+1]); - } - } + s[i + 1] -= sub; + s[i + 1] = halley_iteration4(coeffs, s[i + 1]); + } + } - return num; + return num; } -float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd){ +float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd) +{ - //switch points when near to end point to minimize numerical error - //only needed when control point(s) very far away - #if 0 +// switch points when near to end point to minimize numerical error +// only needed when control point(s) very far away +#if 0 vec2 mid_curve = parametric_cub_bezier(.5,p0,p1,p2,p3); vec2 mid_points = (p0 + p3)/2.; @@ -606,322 +634,355 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn p2 = p1; p1 = tmp; } - #endif +#endif - vec2 a3 = (-p0 + 3. * p1 - 3. * p2 + p3); - vec2 a2 = (3. * p0 - 6. * p1 + 3. * p2); - vec2 a1 = (-3. * p0 + 3. * p1); - vec2 a0 = p0 - uv; - - //compute polynomial describing distance to current pixel dependent on a parameter t - float bc6 = dot(a3,a3); - float bc5 = 2.*dot(a3,a2); - float bc4 = dot(a2,a2) + 2.*dot(a1,a3); - float bc3 = 2.*(dot(a1,a2) + dot(a0,a3)); - float bc2 = dot(a1,a1) + 2.*dot(a0,a2); - float bc1 = 2.*dot(a0,a1); - float bc0 = dot(a0,a0); + vec2 a3 = (-p0 + 3. * p1 - 3. * p2 + p3); + vec2 a2 = (3. * p0 - 6. * p1 + 3. * p2); + vec2 a1 = (-3. * p0 + 3. * p1); + vec2 a0 = p0 - uv; - bc5 /= bc6; - bc4 /= bc6; - bc3 /= bc6; - bc2 /= bc6; - bc1 /= bc6; - bc0 /= bc6; - - //compute derivatives of this polynomial + // compute polynomial describing distance to current pixel dependent on a parameter t + float bc6 = dot(a3, a3); + float bc5 = 2. * dot(a3, a2); + float bc4 = dot(a2, a2) + 2. * dot(a1, a3); + float bc3 = 2. * (dot(a1, a2) + dot(a0, a3)); + float bc2 = dot(a1, a1) + 2. * dot(a0, a2); + float bc1 = 2. * dot(a0, a1); + float bc0 = dot(a0, a0); - float b0 = bc1 / 6.; - float b1 = 2. * bc2 / 6.; - float b2 = 3. * bc3 / 6.; - float b3 = 4. * bc4 / 6.; - float b4 = 5. * bc5 / 6.; + bc5 /= bc6; + bc4 /= bc6; + bc3 /= bc6; + bc2 /= bc6; + bc1 /= bc6; + bc0 /= bc6; - vec4 c1 = vec4(b1,2.*b2,3.*b3,4.*b4)/5.; - vec3 c2 = vec3(c1[1],2.*c1[2],3.*c1[3])/4.; - vec2 c3 = vec2(c2[1],2.*c2[2])/3.; - float c4 = c3[1]/2.; + // compute derivatives of this polynomial - vec4 roots_drv = vec4(1e38); + float b0 = bc1 / 6.; + float b1 = 2. * bc2 / 6.; + float b2 = 3. * bc3 / 6.; + float b3 = 4. * bc4 / 6.; + float b4 = 5. * bc5 / 6.; - int num_roots_drv = solve_quartic(c1,roots_drv); - sort_roots4(roots_drv); + vec4 c1 = vec4(b1, 2. * b2, 3. * b3, 4. * b4) / 5.; + vec3 c2 = vec3(c1[1], 2. * c1[2], 3. * c1[3]) / 4.; + vec2 c3 = vec2(c2[1], 2. * c2[2]) / 3.; + float c4 = c3[1] / 2.; - float ub = upper_bound_lagrange5(b0,b1,b2,b3,b4); - float lb = lower_bound_lagrange5(b0,b1,b2,b3,b4); + vec4 roots_drv = vec4(1e38); - vec3 a = vec3(1e38); - vec3 b = vec3(1e38); + int num_roots_drv = solve_quartic(c1, roots_drv); + sort_roots4(roots_drv); - vec3 roots = vec3(1e38); + float ub = upper_bound_lagrange5(b0, b1, b2, b3, b4); + float lb = lower_bound_lagrange5(b0, b1, b2, b3, b4); - int num_roots = 0; - - //compute root isolating intervals by roots of derivative and outer root bounds - //only roots going form - to + considered, because only those result in a minimum - if(num_roots_drv==4){ - if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) > 0.){ - a[0]=lb; - b[0]=roots_drv[0]; - num_roots=1; - } + vec3 a = vec3(1e38); + vec3 b = vec3(1e38); - if(sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1])) != sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[2]))){ - if(num_roots == 0){ - a[0]=roots_drv[1]; - b[0]=roots_drv[2]; - num_roots=1; - } - else{ - a[1]=roots_drv[1]; - b[1]=roots_drv[2]; - num_roots=2; - } - } + vec3 roots = vec3(1e38); - if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[3]) < 0.){ - if(num_roots == 0){ - a[0]=roots_drv[3]; - b[0]=ub; - num_roots=1; - } - else if(num_roots == 1){ - a[1]=roots_drv[3]; - b[1]=ub; - num_roots=2; - } - else{ - a[2]=roots_drv[3]; - b[2]=ub; - num_roots=3; - } - } - } - else{ - if(num_roots_drv==2){ - if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) < 0.){ - num_roots=1; - a[0]=roots_drv[1]; - b[0]=ub; - } - else if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1]) > 0.){ - num_roots=1; - a[0]=lb; - b[0]=roots_drv[0]; - } - else{ - num_roots=2; + int num_roots = 0; - a[0]=lb; - b[0]=roots_drv[0]; + // compute root isolating intervals by roots of derivative and outer root bounds + // only roots going form - to + considered, because only those result in a minimum + if (num_roots_drv == 4) + { + if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) > 0.) + { + a[0] = lb; + b[0] = roots_drv[0]; + num_roots = 1; + } - a[1]=roots_drv[1]; - b[1]=ub; - } + if (sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[1])) != sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[2]))) + { + if (num_roots == 0) + { + a[0] = roots_drv[1]; + b[0] = roots_drv[2]; + num_roots = 1; + } + else + { + a[1] = roots_drv[1]; + b[1] = roots_drv[2]; + num_roots = 2; + } + } - } - else{//num_roots_drv==0 - vec3 roots_snd_drv=vec3(1e38); - int num_roots_snd_drv=solve_cubic(c2,roots_snd_drv); + if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[3]) < 0.) + { + if (num_roots == 0) + { + a[0] = roots_drv[3]; + b[0] = ub; + num_roots = 1; + } + else if (num_roots == 1) + { + a[1] = roots_drv[3]; + b[1] = ub; + num_roots = 2; + } + else + { + a[2] = roots_drv[3]; + b[2] = ub; + num_roots = 3; + } + } + } + else + { + if (num_roots_drv == 2) + { + if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) < 0.) + { + num_roots = 1; + a[0] = roots_drv[1]; + b[0] = ub; + } + else if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[1]) > 0.) + { + num_roots = 1; + a[0] = lb; + b[0] = roots_drv[0]; + } + else + { + num_roots = 2; - vec2 roots_trd_drv=vec2(1e38); - int num_roots_trd_drv=solve_quadric(c3,roots_trd_drv); - num_roots=1; + a[0] = lb; + b[0] = roots_drv[0]; - a[0]=lb; - b[0]=ub; - } - - //further subdivide intervals to guarantee convergence of halley's method - //by using roots of further derivatives - vec3 roots_snd_drv=vec3(1e38); - int num_roots_snd_drv=solve_cubic(c2,roots_snd_drv); - sort_roots3(roots_snd_drv); + a[1] = roots_drv[1]; + b[1] = ub; + } + } + else + { // num_roots_drv==0 + vec3 roots_snd_drv = vec3(1e38); + int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv); - int num_roots_trd_drv=0; - vec2 roots_trd_drv=vec2(1e38); + vec2 roots_trd_drv = vec2(1e38); + int num_roots_trd_drv = solve_quadric(c3, roots_trd_drv); + num_roots = 1; - if(num_roots_snd_drv!=3){ - num_roots_trd_drv=solve_quadric(c3,roots_trd_drv); - } + a[0] = lb; + b[0] = ub; + } - for(int i=0;i<3;i++){ - if(i < num_roots){ - for(int j=0;j<3;j+=2){ - if(j < num_roots_snd_drv){ - if(a[i] < roots_snd_drv[j] && b[i] > roots_snd_drv[j]){ - if(eval_poly5(b0,b1,b2,b3,b4,roots_snd_drv[j]) > 0.){ - b[i]=roots_snd_drv[j]; - } - else{ - a[i]=roots_snd_drv[j]; - } - } - } - } - for(int j=0;j<2;j++){ - if(j < num_roots_trd_drv){ - if(a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j]){ - if(eval_poly5(b0,b1,b2,b3,b4,roots_trd_drv[j]) > 0.){ - b[i]=roots_trd_drv[j]; - } - else{ - a[i]=roots_trd_drv[j]; - } - } - } - } - } - } - } + // further subdivide intervals to guarantee convergence of halley's method + // by using roots of further derivatives + vec3 roots_snd_drv = vec3(1e38); + int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv); + sort_roots3(roots_snd_drv); - float d0 = 1e38; + int num_roots_trd_drv = 0; + vec2 roots_trd_drv = vec2(1e38); - //compute roots with halley's method - - for(int i=0;i<3;i++){ - if(i < num_roots){ - roots[i] = .5 * (a[i] + b[i]); + if (num_roots_snd_drv != 3) + { + num_roots_trd_drv = solve_quadric(c3, roots_trd_drv); + } - for(int j=0;j roots_snd_drv[j]) + { + if (eval_poly5(b0, b1, b2, b3, b4, roots_snd_drv[j]) > 0.) + { + b[i] = roots_snd_drv[j]; + } + else + { + a[i] = roots_snd_drv[j]; + } + } + } + } + for (int j = 0; j < 2; j++) + { + if (j < num_roots_trd_drv) + { + if (a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j]) + { + if (eval_poly5(b0, b1, b2, b3, b4, roots_trd_drv[j]) > 0.) + { + b[i] = roots_trd_drv[j]; + } + else + { + a[i] = roots_trd_drv[j]; + } + } + } + } + } + } + } - //compute squared distance to nearest point on curve - if(roundEnd) - { - roots[i] = clamp(roots[i],0.,1.); - vec2 to_curve = uv - parametric_cub_bezier(roots[i],p0,p1,p2,p3); - d0 = min(d0,dot(to_curve,to_curve)); - } - else - { - if(roots[i]<0.||roots[i]>1.) d0=min(d0,1e38); - else - { - vec2 to_curve = uv - parametric_cub_bezier(roots[i],p0,p1,p2,p3); - d0 = min(d0,dot(to_curve,to_curve)); - } - } - - } - } + float d0 = 1e38; - return sqrt(d0); + // compute roots with halley's method + + for (int i = 0; i < 3; i++) + { + if (i < num_roots) + { + roots[i] = .5 * (a[i] + b[i]); + + for (int j = 0; j < halley_iterations; j++) + { + roots[i] = halley_iteration5(b0, b1, b2, b3, b4, roots[i]); + } + + // compute squared distance to nearest point on curve + if (roundEnd) + { + roots[i] = clamp(roots[i], 0., 1.); + vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3); + d0 = min(d0, dot(to_curve, to_curve)); + } + else + { + if (roots[i] < 0. || roots[i] > 1.) + d0 = min(d0, 1e38); + else + { + vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3); + d0 = min(d0, dot(to_curve, to_curve)); + } + } + } + } + + return sqrt(d0); } - int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool reverse) { - float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y); - float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y); - float li = (-3. * p0.y + 3. * p1.y); - float co = p0.y - uv.y; + float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y); + float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y); + float li = (-3. * p0.y + 3. * p1.y); + float co = p0.y - uv.y; - vec3 roots = vec3(1e38); - int n_roots; + vec3 roots = vec3(1e38); + int n_roots; - int n_ints = 0; + int n_ints = 0; - if (reverse? uv.x > max(max(p0.x, p1.x), max(p2.x, p3.x)): uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x))) - { - if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y)) - n_ints = 1; - } - else - { - if (abs(cu) < .0001) n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy); - else n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots); - - for (int i = 0; i < n_roots; i++) - { - if (roots[i] >= 0. && roots[i] <= 1.) - { - float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x; - x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x; - x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; - x_pos = x_pos * roots[i] + p0.x; + if (reverse ? uv.x > max(max(p0.x, p1.x), max(p2.x, p3.x)) : uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x))) + { + if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y)) + n_ints = 1; + } + else + { + if (abs(cu) < .0001) + n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy); + else + n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots); - if (reverse? x_pos < uv.x: x_pos > uv.x) n_ints++; - } - } - } - return n_ints; + for (int i = 0; i < n_roots; i++) + { + if (roots[i] >= 0. && roots[i] <= 1.) + { + float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x; + x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x; + x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; + x_pos = x_pos * roots[i] + p0.x; + + if (reverse ? x_pos < uv.x : x_pos > uv.x) + n_ints++; + } + } + } + return n_ints; } int ray_int_test(vec2 uv, vec2 p0, vec2 direction, bool reverse) { - p0 -= uv; - if (-p0.y * direction.y > 0.) - { - vec2 nor = -direction; - nor = vec2(nor.y, -nor.x); - float sgn = p0.y > direction.y? 1.: -1.; - if(reverse) sgn = -sgn; - return dot(nor, p0) * sgn < 0.? 0: 1; - } - else return 0; + p0 -= uv; + if (-p0.y * direction.y > 0.) + { + vec2 nor = -direction; + nor = vec2(nor.y, -nor.x); + float sgn = p0.y > direction.y ? 1. : -1.; + if (reverse) + sgn = -sgn; + return dot(nor, p0) * sgn < 0. ? 0 : 1; + } + else + return 0; } vec2 bezierTangent(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { - float u = 1 - t; - float uu = u * u; - float tu = t * u; - float tt = t * t; + float u = 1 - t; + float uu = u * u; + float tu = t * u; + float tt = t * t; - vec2 P = p0 * 3 * uu * (-1.0); - P += p1 * 3 * (uu - 2 * tu); - P += p2 * 3 * (2 * tu - tt); - P += p3 * 3 * tt; + vec2 P = p0 * 3 * uu * (-1.0); + P += p1 * 3 * (uu - 2 * tu); + P += p2 * 3 * (2 * tu - tt); + P += p3 * 3 * tt; - //返回单位向量 - return normalize(P); + // 返回单位向量 + return normalize(P); } -//判断两向量夹角(向量A逆时针到向量B)是否大于180°,大于180°返回真,否则返回假 +// 判断两向量夹角(向量A逆时针到向量B)是否大于180°,大于180°返回真,否则返回假 bool angleLargeThanPi(vec2 a, vec2 b) { - return a.x * b.y - b.x * a.y < 0; + return a.x * b.y - b.x * a.y < 0; } void drawLine(in float d, in uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness) { - elementColor = vec4(1); - metallicRoughness = vec2(0.8); - uint headUint = floatBitsToUint(elementData[styleIndex+1]); + elementColor = vec4(1); + metallicRoughness = vec2(0.8); + uint headUint = floatBitsToUint(elementData[styleIndex + 1]); vec4 head = unpackUnorm4x8(headUint); - switch (int(head.a*100)%10) - //switch (2) + switch (int(head.a * 100) % 10) + // switch (2) { /// Plain case 0: { metallicRoughness = head.rg; - elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+2])).rgb, 1); + elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 2])).rgb, 1); break; } /// RadialGradient case 1: { - uint size = headUint%(1<<15); - bool gradual = (headUint&(1<<15))!=0; + uint size = headUint % (1 << 15); + bool gradual = (headUint & (1 << 15)) != 0; - uint lastData = floatBitsToUint(elementData[styleIndex+2+0*2]); + uint lastData = floatBitsToUint(elementData[styleIndex + 2 + 0 * 2]); float lastLevel = 0; vec2 lastMetallicRoughness = unpackUnorm4x8(lastData).rg; - vec4 lastColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+3+0*2])).rgb, 1); + vec4 lastColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 3 + 0 * 2])).rgb, 1); - for(uint i = 0; i < size; i++) + for (uint i = 0; i < size; i++) { - uint data = floatBitsToUint(elementData[styleIndex+2+i*2]); + uint data = floatBitsToUint(elementData[styleIndex + 2 + i * 2]); float level = unpackUnorm2x16(data).y; - vec4 currentColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+3+i*2])).rgb, 1); + vec4 currentColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 3 + i * 2])).rgb, 1); vec2 currentMetallicRoughness = unpackUnorm4x8(data).rg; if (d <= level) { - if(gradual) + if (gradual) { - float a = (d-lastLevel)/(level-lastLevel); + float a = (d - lastLevel) / (level - lastLevel); elementColor = mix(lastColor, currentColor, a); metallicRoughness = mix(lastMetallicRoughness, currentMetallicRoughness, a); } @@ -962,315 +1023,364 @@ void drawLine(in float d, in uint styleIndex, out vec4 elementColor, out vec2 me } } -bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, out vec2 metallicRoughness, inout vec3 debugBVH = vec3(0)) +bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, vec2 tangentBegin, vec2 tangentEndLast) { - bool hitElement = false; - vec4 elementColor = vec4(-1); - metallicRoughness = vec2(0, 0.8); - - uint currentOffset[] = elementOffset[elementIndex]; - uint elementBvhRoot = currentOffset[0]; - uint styleIndex = currentOffset[1]; - uint elementBvhLength = 0x80000000; - uint pointsOffset = currentOffset[2]; - uint linesOffset = currentOffset[3]; - - elementStack.top = 0; - uint elementBvhIndex = 0; - while (elementBvhIndex < elementBvhLength || !elementStack.empty()) - { - - while (elementBvhIndex < elementBvhLength) - { - vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex]; - uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x; - - if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw))) - { - if (leftChild >= elementBvhLength) - { - if (any(greaterThan(bound.xy+vec2(0.003), localUV)) || any(greaterThan(localUV, bound.zw-vec2(0.003)))) - { - debugBVH.g = 0; - debugBVH.r += 1; - } - //uint styleIndex = bvhChildren[elementBvhRoot + elementBvhIndex].y; - //uint elementType = bvhChildren[elementBvhRoot + elementBvhIndex].y; - //float elementType = elementData[styleIndex]; - bool isFillStyle = elementData[styleIndex]<=0; - // for(int i = 0; i<200;i++) - if (isFillStyle) //面 - { - uint contourIndex = linesOffset + leftChild - 0x80000000; - - uint num_its = 0; - - uint lineCount = elementIndexs[contourIndex]; - - for ( uint contourIterator = contourIndex + 1;contourIterator < contourIndex + 1 + lineCount; contourIterator++) - { - uint lineIndex = elementIndexs[contourIterator]; - uint pLocation = linesOffset + 2 * lineIndex; - uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF); - uvec4 pyIndex = uvec4(1)+pxIndex; - mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], - elementData[pxIndex[1]], elementData[pyIndex[1]], - elementData[pxIndex[2]],elementData[pyIndex[2]], - elementData[pxIndex[3]], elementData[pyIndex[3]]); -// vec2 p[4] = {vec2(elementData[pxIndex[0]], elementData[pyIndex[0]]), -// vec2(elementData[pxIndex[1]], elementData[pyIndex[1]]), -// vec2(elementData[pxIndex[2]],elementData[pyIndex[2]]), -// vec2(elementData[pxIndex[3]], elementData[pyIndex[3]])}; -// if( bound.z==p[0].x && distance(localUV, p[3])<0.01) -// { -// debugBVH = vec3(0,0,1); -// } -// else if(distance(localUV, p[0])<0.01) -// debugBVH = vec3(1,1,1); -// if (p0 == p1 && p2 == p3) -// { -// num_its += segment_int_test(localUV, p0, p3); -// } -// -// else - num_its += cubic_bezier_int_test(localUV, p[0], p[1], p[2], p[3]); - } - - if (num_its % 2 == 1 && elementColor.a<1) - { - hitElement = true; - elementColor = vec4(1,1,0,0); - - vec4 head = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex])); - if(head.z==0) - { - elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+1])).rgb,0); - metallicRoughness = head.xy; - } - - - } - } - else //线 - { - float strokeWidth = elementData[styleIndex]; - float widthHeightRatio = uintBitsToFloat(currentOffset[4]); - - vec2 size = normalize(vec2(widthHeightRatio, 1)) + vec2(2 * strokeWidth); - vec2 ratio = widthHeightRatio < 1 ? vec2(widthHeightRatio, 1) : vec2(1, 1 / widthHeightRatio); - localUV *= ratio; - - - uint contourIndex = linesOffset + leftChild - 0x80000000; - float minDistance = 1e38; - uint lineCount = elementIndexs[contourIndex]; - vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+1])); - float lineType = floor(styleHead.b*10); - //float lineType = 2; - vec2 p3Last = vec2(1e38); - vec2 p2Last = vec2(1e38); - int debugBegin = 0; - for ( uint contourIterator_ = contourIndex + 1;contourIterator_ <= contourIndex + 1 + lineCount; contourIterator_++) - { - uint contourIterator = contourIterator_; - if(contourIterator_==contourIndex + 1 + lineCount) - contourIterator = contourIndex + 1; - uint lineIndex = elementIndexs[contourIterator]; - uint pLocation = linesOffset + 3 * lineIndex; - uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF); - uvec4 pyIndex = uvec4(1)+pxIndex; - - mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], - elementData[pxIndex[1]], elementData[pyIndex[1]], - elementData[pxIndex[2]], elementData[pyIndex[2]], - elementData[pxIndex[3]], elementData[pyIndex[3]]); - - p[0] *= ratio; - p[1] *= ratio; - p[2] *= ratio; - p[3] *= ratio; - - if(p[0]==p[1]&&p[2]==p[3]) - { - p[1] = (p[0]+p[3])/2; - p[2] = p[1]; - } - - if(distance(localUV,p[0])<=0.001) - { - if(p3Last==p[0]) debugBegin = 2; - else debugBegin = 1; - } - - float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); - if(d<=strokeWidth) - { - bool onBegin = distance(localUV,p[0])<=strokeWidth&&p3Last==p[0]; - bool fill = true; - if(onBegin) - { - vec2 normalLast = normalize(mat2(0,1,-1,0)*(p3Last-p2Last)); - vec2 normalNow = normalize(mat2(0,1,-1,0)*(p[1]-p[0])); - vec2 normal = normalLast+normalNow; - fill = angleLargeThanPi(normal, localUV-p[0]); - } - if(onBegin?fill:d> 16, elementIndexs[pLocation] & 0xFFFF, + elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF); + uvec4 pyIndex = uvec4(1) + pxIndex; + mat4x2 p = + mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]], + elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]); + + // if (bound.z == p[0].x && distance(localUV, p[3]) < 0.01) + // { + // debugBVH = vec3(0, 0, 1); + // } + // else if (distance(localUV, p[0]) < 0.01) + // debugBVH = vec3(1, 1, 1); + // if (p0 == p1 && p2 == p3) + // { + // num_its += segment_int_test(localUV, p0, p3); + // } + // else + num_its += cubic_bezier_int_test(localUV, p[0], p[1], p[2], p[3]); + } + + if (num_its % 2 == 1 && elementColor.a < 1) + { + hitElement = true; + elementColor = vec4(1, 1, 0, 0); + + vec4 head = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex])); + if (head.z == 0) + { + elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])).rgb, 0); + metallicRoughness = head.xy; + } + } + return hitElement; +} + +bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex, float widthHeightRatio, + inout vec4 elementColor, inout vec2 metallicRoughness) +{ + bool hitElement = false; + float strokeWidth = elementData[styleIndex]; + + vec2 size = normalize(vec2(widthHeightRatio, 1)) + vec2(2 * strokeWidth); + vec2 ratio = widthHeightRatio < 1 ? vec2(widthHeightRatio, 1) : vec2(1, 1 / widthHeightRatio); + localUV *= ratio; + + float minDistance = 1e38; + uint lineCount = elementIndexs[contourIndex]; + vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])); + float lineType = floor(styleHead.b * 10); + int endType = int(round(styleHead.b * 100)) % 10; + vec2 p3Last = vec2(1e38); + vec2 p2Last = vec2(1e38); + vec2 tangentEndLast; + int debugBegin = 0; + for (uint contourIterator_ = contourIndex + 1; contourIterator_ < contourIndex + 1 + lineCount; contourIterator_++) + { + uint contourIterator = contourIterator_; + if (contourIterator_ == contourIndex + 1 + lineCount) + contourIterator = contourIndex + 1; + uint lineIndex = elementIndexs[contourIterator]; + uint pLocation = linesOffset + 3 * lineIndex; + vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]); + uvec4 pxIndex = + uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF, + elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF); + uvec4 pyIndex = uvec4(1) + pxIndex; + + mat4x2 p = + mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]], + elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]); + + p[0] *= ratio; + p[1] *= ratio; + p[2] *= ratio; + p[3] *= ratio; + + if (p[0] == p[1] && p[2] == p[3]) + { + p[1] = (p[0] + p[3]) / 2; + p[2] = p[1]; + } + + if (distance(localUV, p[0]) <= 0.001) + { + if (p3Last == p[0]) + debugBegin = 2; + else + debugBegin = 1; + } + + float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); + if (d <= strokeWidth) + { + bool onBegin = distance(localUV, p[0]) <= strokeWidth && ( p3Last == p[0] || contourIterator==contourIndex + 1); + vec2 tangentBegin; + vec2 tangentEnd; + if (p[0] != p[1]) + tangentBegin = normalize(p[0] - p[1]); + else + tangentBegin = normalize(p[0] - p[2]); + if (p[3] != p[2]) + tangentEnd = normalize(p[3] - p[2]); + else + tangentEnd = normalize(p[3] - p[1]); + + if (onBegin ? shouldFillBeginCap(localUV, percent[0]<1e-5, endType, p[0], tangentBegin, p3Last - p2Last) + : d < minDistance) + { + minDistance = min(minDistance, d); + + bool reverse = p[3].y - p[0].y < 0.; + + if (tangentBegin.y == 0.) + tangentBegin.y = reverse ? eps : -eps; + if (tangentEnd.y == 0.) + tangentEnd.y = reverse ? -eps : eps; + int intTest = cubic_bezier_int_test2(localUV, p[0], p[1], p[2], p[3], reverse) + + ray_int_test(localUV, p[0], tangentBegin, reverse) + + ray_int_test(localUV, p[3], tangentEnd, reverse); + + if (lineType == 2 || (intTest % 2 == int(lineType))) + { + hitElement = true; + // elementColor = vec4(1, 1, 0, 1); + vec2 metallicRoughness; + drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); + } + else if (p3Last == p[0]) + hitElement = false; + } + tangentEndLast = tangentEnd; + } + p3Last = p[3]; + p2Last = p[2]; + } + if (hitElement && distance(localUV, p3Last) <= strokeWidth) + { + hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast); + } + + // if (minDistance <= 0.001) + // { + // hitElement = true; + // elementColor = vec4(0, 0, 0, 1); + // if (debugBegin == 1) + // elementColor = vec4(1, 1, 0, 1); + // else if (debugBegin == 2) + // elementColor = vec4(0, 1, 0, 1); + // } + return hitElement; +} + +bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, out vec2 metallicRoughness, + inout vec3 debugBVH = vec3(0)) +{ + bool hitElement = false; + vec4 elementColor = vec4(-1); + metallicRoughness = vec2(0, 0.8); + + uint currentOffset[] = elementOffset[elementIndex]; + uint elementBvhRoot = currentOffset[0]; + uint styleIndex = currentOffset[1]; + uint pointsOffset = currentOffset[2]; + uint linesOffset = currentOffset[3]; + float widthHeightRatio = uintBitsToFloat(currentOffset[4]); + + elementStack.top = 0; + uint elementBvhIndex = 0; + uint elementBvhLength = 0x80000000; + while (elementBvhIndex < elementBvhLength || !elementStack.empty()) + { + while (elementBvhIndex < elementBvhLength) + { + vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex]; + uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x; + + if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw))) + { + if (leftChild >= elementBvhLength) + { + if (any(greaterThan(bound.xy + vec2(0.003), localUV)) || + any(greaterThan(localUV, bound.zw - vec2(0.003)))) + { + debugBVH.g = 0; + debugBVH.r += 1; + } + + uint contourIndex = linesOffset + leftChild - 0x80000000; + bool isFillStyle = elementData[styleIndex] <= 0; + if (isFillStyle) // 面 + { + hitElement = fillElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex, + elementColor, metallicRoughness); + } + else // 线 + { + hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex, widthHeightRatio, + elementColor, metallicRoughness); + } + + elementBvhIndex = elementBvhLength; + color = elementColor.xyz; + return hitElement; + } + else + { + // debugBVH.b += 0.2; + elementStack.push(elementBvhIndex); + elementBvhIndex = leftChild; + } + } + else + elementBvhIndex = elementBvhLength; + } + if (!elementStack.empty()) + { + elementStack.getTop(elementBvhIndex); + elementStack.pop(); + elementBvhIndex = bvhChildren[elementBvhRoot + elementBvhIndex].y; + } + } + color = elementColor.xyz; + return hitElement; +} void main() { - ivec2 pixelLocation = ivec2(pixelOffset + gl_GlobalInvocationID.xy); - vec2 uv = (pixelLocation + vec2(0.5)) / imageSize(gBaseColor); - //imageStore(gBaseColor, pixelLocation, vec4(uv,1,1)); - //imageStore(gMetallicRoughness, pixelLocation, vec4(uv,1,1)); - //return; - uv = uv*2-vec2(1); - //vec2 uv = imageLoad(gPaintingTexCoord, pixelLocation).rg; + ivec2 pixelLocation = ivec2(pixelOffset + gl_GlobalInvocationID.xy); + vec2 uv = (pixelLocation + vec2(0.5)) / imageSize(gBaseColor); + // imageStore(gBaseColor, pixelLocation, vec4(uv,1,1)); + // imageStore(gMetallicRoughness, pixelLocation, vec4(uv,1,1)); + // return; + uv = uv * 2 - vec2(1); + // vec2 uv = imageLoad(gPaintingTexCoord, pixelLocation).rg; - vec3 debugBVH = vec3(0); - //bool debugHit = false; - vec4 color = vec4(1,1,1,-1); - vec2 metallicRoughness = vec2(0, 0.8); - stack.top = 0; - uint index = 0, visitTime = 0; - //uint bvhLength = paintingOffsets[paintingIndex-1].y; - uint bvhLength = 0x80000000; - while (index < bvhLength || !stack.empty()) - { - while (index < bvhLength) - { - visitTime++; - vec4 bound = bvhBound[index]; - uint leftChild = bvhChildren[index].x; - if (leftChild >= bvhLength) - { - uint zIndex = bvhChildren[index].y >> 18; - bvec2 flip = bvec2(bvhChildren[index].y & (1<<16), bvhChildren[index].y & (1<<17)); - float angle = (float(bvhChildren[index].y&((1<<16)-1)) / 65535.0) * 2 * PI; - mat2 rotation = {{cos(angle), -sin(angle)}, {sin(angle), cos(angle)}}; - vec2 localUV = uv - (bound.xy + bound.zw) / 2; - localUV = rotation * localUV; - vec2 scale = (bound.zw - bound.xy) / 2; - localUV /= scale; - if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex>color.w) - { - //if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005)))) - if (any(greaterThan(vec2(-1)+vec2(0.005), localUV)) || any(greaterThan(localUV, vec2(1)-vec2(0.005)))) - debugBVH.g += 0.3; - //uint elementIndex = leftChild - bvhLength; - //debugBVH.bg += 0.5 * (localUV + vec2(1)); + vec3 debugBVH = vec3(0); + // bool debugHit = false; + vec4 color = vec4(0.76, 0.33, 0.15, -1); + //vec4 color = vec4(1,1,1, -1); + vec2 metallicRoughness = vec2(0, 0.8); + stack.top = 0; + uint index = 0, visitTime = 0; + // uint bvhLength = paintingOffsets[paintingIndex-1].y; + uint bvhLength = 0x80000000; + while (index < bvhLength || !stack.empty()) + { + while (index < bvhLength) + { + visitTime++; + vec4 bound = bvhBound[index]; + uint leftChild = bvhChildren[index].x; + if (leftChild >= bvhLength) + { + uint zIndex = bvhChildren[index].y >> 18; + bvec2 flip = bvec2(bvhChildren[index].y & (1 << 16), bvhChildren[index].y & (1 << 17)); + float angle = (float(bvhChildren[index].y & ((1 << 16) - 1)) / 65535.0) * 2 * PI; + mat2 rotation = {{cos(angle), -sin(angle)}, {sin(angle), cos(angle)}}; + vec2 localUV = uv - (bound.xy + bound.zw) / 2; + localUV = rotation * localUV; + vec2 scale = (bound.zw - bound.xy) / 2; + localUV /= scale; + if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex > color.w) + { + // if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005)))) + if (any(greaterThan(vec2(-1) + vec2(0.005), localUV)) || + any(greaterThan(localUV, vec2(1) - vec2(0.005)))) + debugBVH.g += 0.3; + // uint elementIndex = leftChild - bvhLength; + // debugBVH.bg += 0.5 * (localUV + vec2(1)); - //debugBVH = vec3(0); - if(flip.x) localUV.x = -localUV.x; - if(flip.y) localUV.y = -localUV.y; - vec3 elementColor; - vec2 elementMetallicRoughness; - if(drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness, debugBVH)) - { - color = vec4(elementColor, zIndex); - metallicRoughness = elementMetallicRoughness; - } - - } + // debugBVH = vec3(0); + if (flip.x) + localUV.x = -localUV.x; + if (flip.y) + localUV.y = -localUV.y; + vec3 elementColor; + vec2 elementMetallicRoughness; + if (drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness, + debugBVH)) + { + color = vec4(elementColor, zIndex); + metallicRoughness = elementMetallicRoughness; + } + } - index = bvhLength; - } - else if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw))) - { - if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005)))) - debugBVH.g += 0.3; - //debugBVH.r += 0.02; - stack.push(index); - index = leftChild; - } - else - index = bvhLength; - } - if (!stack.empty()) - { - stack.getTop(index); - stack.pop(); - index = bvhChildren[index].y; - } - } - - imageStore(gBaseColor, pixelLocation, vec4(color.rgb,1)); - imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1)); - return; - if (/*color.a!=-1&&*/debugBVH==vec3(0)) - { - //imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1)); - } - else - { - imageStore(gBaseColor, pixelLocation, vec4(debugBVH,1)); - imageStore(gMetallicRoughness, pixelLocation, vec4(0,0.8, 0, 1)); - } + index = bvhLength; + } + else if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw))) + { + if (any(greaterThan(bound.xy + vec2(0.005), uv)) || any(greaterThan(uv, bound.zw - vec2(0.005)))) + debugBVH.g += 0.3; + // debugBVH.r += 0.02; + stack.push(index); + index = leftChild; + } + else + index = bvhLength; + } + if (!stack.empty()) + { + stack.getTop(index); + stack.pop(); + index = bvhChildren[index].y; + } + } + imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1)); + imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1)); + return; + if (/*color.a!=-1&&*/ debugBVH == vec3(0)) + { + // imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1)); + } + else + { + imageStore(gBaseColor, pixelLocation, vec4(debugBVH, 1)); + imageStore(gMetallicRoughness, pixelLocation, vec4(0, 0.8, 0, 1)); + } } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp index f679dc2..e7d3b49 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp @@ -62,15 +62,15 @@ QPainterPath PainterPathUtil::monotonization(QPainterPath& painterPath) { return resPath; } -std::pair PainterPathUtil::normalized(const QPainterPath& path) +std::pair PainterPathUtil::normalized(const QPainterPath& path, float width) { auto rect = path.boundingRect(); - return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999))).map(path), + return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999)) * QTransform::fromScale(1 / (1 + width),1 / (1 + width))).map(path), rect.width() / rect.height() }; } -std::pair>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path) +std::pair>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path, float width) { - auto [p, ratio] = normalized(path); + auto [p, ratio] = normalized(path, width); return { transformToLines(p), ratio }; } diff --git a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h index 0e0d579..f6fabcb 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h +++ b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h @@ -8,7 +8,7 @@ class PainterPathUtil public: static std::vector> transformToLines(const QPainterPath& painterPath); static QPainterPath monotonization(QPainterPath& painterPath); - static std::pair normalized(const QPainterPath& path); - static std::pair>, float> toNormalizedLines(const QPainterPath& path); + static std::pair normalized(const QPainterPath& path, float width = 0); + static std::pair>, float> toNormalizedLines(const QPainterPath& path, float width = 0); }; diff --git a/ArchitectureColoredPainting/src/Renderer/Model.cpp b/ArchitectureColoredPainting/src/Renderer/Model.cpp index 644863d..fc9c585 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Model.cpp @@ -14,6 +14,7 @@ #include "../Editor/util/PainterPathUtil.h" #include "../Editor/util/SvgFileLoader.h" #include +#include "Painting/MaterialStyleStroke.h" using namespace Renderer; using std::vector; @@ -156,14 +157,13 @@ std::unique_ptr Model::processMesh(aiMesh* mesh, const aiScene* scene, for (auto& v : vertices) { - //qDebug() << v.TexCoords.x << v.TexCoords.y; v.TexCoords = (v.TexCoords - leftBottom) / (rightTop - leftBottom); - qDebug() << v.TexCoords.x << v.TexCoords.y; + //qDebug() << v.TexCoords.x << v.TexCoords.y; } - + mesh->vertices = vertices; mesh->indices = indices; - + mesh->paintingId = loadPainting(paintingPath); auto& handle = vtManager->getPaintingHandle(mesh->paintingId); mesh->textureBasecolor = handle.baseColor; @@ -271,6 +271,52 @@ GLuint Renderer::Model::loadPainting(std::string path) painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45, 0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); painting.addElement(*element[2], ElementTransform{ glm::vec2(0.50,-0.45), glm::vec2(0.6,0.7) / 2.f, 0, glm::bvec2(false), 0 }); } + else if (path == "1.json") + { + float widths[] = { 0.43, 0.43 * 0.25 / 0.15, 0.13 * 0.25 / 0.15 }; + QPainterPath painterPaths[6]; + for (int i = 0; i < 6; i++) + if (!SvgFileLoader().loadSvgFile(QString(std::format("../svg/{}.svg", i + 1).c_str()), painterPaths[i])) + qCritical() << "load error"; + + vector, float>> contours; + for (int i = 0; i < 3; i++) + { + auto [contour, ratio] = PainterPathUtil::toNormalizedLines(painterPaths[i], widths[i]); + contours.emplace_back(std::make_shared(contour), ratio); + } + class StyleStrokeRadialGradient : public Renderer::ElementStyle + { + public: + float width; + StrokeType type; + StyleStrokeRadialGradient(float width, StrokeType type) :width(width), type(type) {}; + virtual std::vector toBaseStyles() const override + { + std::map materialMap = { + {0.09, Material{QColor(255,255,255),0,0.8}}, + {0.63, Material{QColor(165,176,207),0,0.8}}, + {1.00, Material{QColor(58,64,151),0,0.8}} + }; + return { BaseStyle(std::make_shared(), + std::make_shared(width, type, StrokeEndType::kFlat, + std::make_shared(materialMap, false))) }; + } + }; + vector> style = { + std::make_shared(widths[0], StrokeType::kLeftSide), + std::make_shared(widths[1], StrokeType::kRightSide), + std::make_shared(widths[2], StrokeType::kLeftSide), + }; + vector> element = { + std::make_shared(Element{ contours[0].first, style[0], contours[0].second}), + std::make_shared(Element{ contours[1].first, style[1], contours[1].second}), + std::make_shared(Element{ contours[2].first, style[2], contours[2].second}), + }; + painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,0.45), glm::vec2(0.25), 0, glm::bvec2(false), 0 }); + painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.535,0.33), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); + painting.addElement(*element[2], ElementTransform{ glm::vec2(-0.535,0.23), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); + } else { for (int i = 0; i < 1000; i++) diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp index 340b767..8af376d 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp @@ -104,7 +104,11 @@ std::unique_ptr Renderer::MaterialStyleStroke::clone() const bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const { - return type() == m.type() && *materialStroke == *static_cast(m).materialStroke; + return type() == m.type() + && halfWidth == static_cast(m).halfWidth + && strokeType == static_cast(m).strokeType + && endType == static_cast(m).endType + && *materialStroke == *static_cast(m).materialStroke; } float Renderer::MaterialStyleStroke::getHalfWidth() const diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h index db5ddbf..95f5957 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h @@ -54,7 +54,7 @@ namespace Renderer virtual std::unique_ptr clone() const override; virtual bool operator==(const MaterialStyle&) const override; float getHalfWidth() const; - //protected: + float halfWidth; StrokeType strokeType; StrokeEndType endType; diff --git a/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp b/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp index 5e777a4..d0df771 100644 --- a/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp +++ b/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp @@ -12,9 +12,11 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent) auto openAction = new QAction(QStringLiteral("打开"), menu); auto saveAction = new QAction(QStringLiteral("保存"), menu); auto testAction = new QAction(QStringLiteral("测试"), menu); + auto test2Action = new QAction(QStringLiteral("测试2"), menu); menu->addAction(openAction); menu->addAction(saveAction); menu->addAction(testAction); + menu->addAction(test2Action); ui.openButton->setHaloVisible(false); ui.openButton->setOverlayStyle(::Material::TintedOverlay); @@ -47,7 +49,9 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent) QObject::connect(testAction, &QAction::triggered, [&] { ui.openGLWidget->setModel("Models/Sponza/Sponza.gltf"); }); - + QObject::connect(test2Action, &QAction::triggered, [&] { + ui.openGLWidget->setModel("E:\\3D Objects\\Gate\\Gate.gltf"); + }); ui.horizontalSlider->setValue(105); ui.horizontalSlider_2->setValue(80); ui.exposureSlider->setValue(60); diff --git a/UnitTest/ElementRendererTest.cpp b/UnitTest/ElementRendererTest.cpp index 2ff2e88..1d34130 100644 --- a/UnitTest/ElementRendererTest.cpp +++ b/UnitTest/ElementRendererTest.cpp @@ -108,6 +108,27 @@ namespace UnitTest w.show(); a.exec(); } + TEST_METHOD(TestRightSideFlat) + { + QApplication a(argc, argv); + class StyleStrokeRadialGradient : public Renderer::ElementStyle + { + virtual std::vector toBaseStyles() const override + { + std::map materialMap = { + {0.20, Material{QColor(255,255,255)}}, + {0.60, Material{QColor(165,176,207)}}, + {1.00, Material{QColor(58,64,151)}} + }; + return { BaseStyle(std::make_shared(), + std::make_shared(200, StrokeType::kRightSide, StrokeEndType::kFlat, + std::make_shared(materialMap, false))) }; + } + } style; + TestGLWidget w(style); + w.show(); + a.exec(); + } }; TEST_CLASS(ElementRendererStokeMaterialTest) From 4ec58dbb8be5a74f085e5d589dae10efd9d6f631 Mon Sep 17 00:00:00 2001 From: wuyize Date: Tue, 14 Mar 2023 23:39:56 +0800 Subject: [PATCH 05/40] =?UTF-8?q?FIX:=20=E5=A4=9A=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E4=B8=8D=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/Shaders/element.comp | 37 ++++++++++++++++--- .../src/Renderer/Preview/ElementRenderer.cpp | 1 + UnitTest/ElementRendererTest.cpp | 3 ++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/element.comp b/ArchitectureColoredPainting/res/Shaders/element.comp index 93c0166..eb169f8 100644 --- a/ArchitectureColoredPainting/res/Shaders/element.comp +++ b/ArchitectureColoredPainting/res/Shaders/element.comp @@ -893,7 +893,7 @@ bool angleLargeThanPi(vec2 a, vec2 b) /************************************************************************************/ -void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness) +void drawLine(in float d, uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness) { elementColor = vec4(1); metallicRoughness = vec2(0.8); @@ -969,6 +969,30 @@ void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2 } } +void nextStyleIndex(inout uint styleIndex) +{ + uint headUint = floatBitsToUint(style[styleIndex + 1]); + vec4 head = unpackUnorm4x8(headUint); + switch (int(head.a * 100) % 10) + { + /// Plain + case 0: { + styleIndex += 3; + break; + } + /// RadialGradient + case 1: { + uint size = headUint % (1 << 15); + styleIndex += 2 + size * 2; + break; + } + case 2: { + + break; + } + } +} + bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast) { vec2 normal; @@ -1015,9 +1039,8 @@ void main() vec4 color = vec4(0); // if(isinf(path[0].x)) imageStore(gBaseColor, ivec2(pixelLocation), // vec4(vec2(pixelLocation)/vec2(imageSize(gBaseColor)), 1,1)); return; - for (uint styleIndex = 0; styleIndex < styleSize; styleIndex++) + for (uint styleIndex = 0; styleIndex < styleSize;) { - styleIndex += 6; vec2 localUV = vec2(pixelLocation) / pixelRatio + leftTop; @@ -1056,6 +1079,7 @@ void main() elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1); } } + } else // Stroke { @@ -1129,8 +1153,8 @@ void main() // if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, // tangentEndLast) - // : (onEnd ? /*shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, - // tangentBeginNext)*/ false + // : (onEnd ? shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, + // tangentBeginNext) // : d < minDistance)) bool hit = d < minDistance; if (onBegin) @@ -1183,10 +1207,11 @@ void main() { // hitElement = shouldFillEndCap(localUV, true, endType, p3Last, tangentEndLast); } + nextStyleIndex(styleIndex); + } if (hitElement) color = elementColor; - styleIndex += 100; } if (color.a != 0) imageStore(gBaseColor, ivec2(pixelLocation), color); diff --git a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp index 756222b..471d931 100644 --- a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp @@ -77,6 +77,7 @@ std::vector generateStyleBuffer(const std::vector& styles) styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip))); auto encoded = style.material->encoded(); styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end()); + qDebug() << "style size" << styleBuffer.size(); } return styleBuffer; } diff --git a/UnitTest/ElementRendererTest.cpp b/UnitTest/ElementRendererTest.cpp index 1d34130..2efebee 100644 --- a/UnitTest/ElementRendererTest.cpp +++ b/UnitTest/ElementRendererTest.cpp @@ -10,6 +10,8 @@ using namespace Renderer; namespace UnitTest { + void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); + TEST_CLASS(ElementRendererStokeTypeTest) { private: @@ -20,6 +22,7 @@ namespace UnitTest TEST_METHOD_INITIALIZE(initialize) { + qInstallMessageHandler(messageHandler); QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); From c6a4d798880e992100118ec83544b13f4941e055 Mon Sep 17 00:00:00 2001 From: wuyize Date: Wed, 15 Mar 2023 00:09:30 +0800 Subject: [PATCH 06/40] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=BA=86StrokeEndType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/Shaders/element.comp | 31 +++++-------------- .../Renderer/Painting/MaterialStyleStroke.h | 2 +- UnitTest/ElementRendererTest.cpp | 4 +-- 3 files changed, 10 insertions(+), 27 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/element.comp b/ArchitectureColoredPainting/res/Shaders/element.comp index eb169f8..66910e7 100644 --- a/ArchitectureColoredPainting/res/Shaders/element.comp +++ b/ArchitectureColoredPainting/res/Shaders/element.comp @@ -998,9 +998,9 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, ve vec2 normal; if (onVeryBegin) { - if (endType == 0) + if (endType%2 == 0) return true; - else if (endType == 1) + else if (endType%2 == 1) normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); } else @@ -1017,9 +1017,9 @@ bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 t vec2 normal; if (onVeryEnd) { - if (endType == 0) + if ((endType/2)%2 == 0) return true; - else if (endType == 1) + else if ((endType/2)%2 == 1) normal = normalize(mat2(0, 1, -1, 0) * tangentEnd); } else @@ -1103,10 +1103,7 @@ void main() if (isinf(pTemp.x)) { // TODO: 检测是否封闭并处理 - if (hitElement && distance(localUV, p3Last) <= strokeWidth) - { - // hitElement = shouldFillEndCap(localUV, true, endType, p3Last, tangentEndLast); - } + pBegin = path[++pathIndex]; p3Last = pBegin; @@ -1134,6 +1131,8 @@ void main() tangentBeginNext = normalize(pNext[0] - pNext[2]); } } + else + onVeryEnd = true; float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); if (d <= strokeWidth) @@ -1184,18 +1183,6 @@ void main() vec2 metallicRoughness; drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); } - // else if (lastHitIndex == pathIndex - 3) - // { - // hitElement = lastHitElement; - // lastHitElement = false; - // // if(lastHitElement ==false) - // //{ - // // hitElement = true; - // // elementColor = vec4(1, 1, 0, 1); - // //} - - // minDistance = 1e38; - // } } tangentEndLast = tangentEnd; } @@ -1203,10 +1190,6 @@ void main() p2Last = p[2]; onVeryBegin = false; } - if (hitElement && distance(localUV, p3Last) <= strokeWidth) - { - // hitElement = shouldFillEndCap(localUV, true, endType, p3Last, tangentEndLast); - } nextStyleIndex(styleIndex); } diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h index 95f5957..29fd55b 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.h @@ -43,7 +43,7 @@ namespace Renderer }; enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 }; - enum class StrokeEndType { kRound = 0, kFlat = 1 }; + enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01 }; class MaterialStyleStroke : public MaterialStyle { diff --git a/UnitTest/ElementRendererTest.cpp b/UnitTest/ElementRendererTest.cpp index 2efebee..7a0c035 100644 --- a/UnitTest/ElementRendererTest.cpp +++ b/UnitTest/ElementRendererTest.cpp @@ -111,7 +111,7 @@ namespace UnitTest w.show(); a.exec(); } - TEST_METHOD(TestRightSideFlat) + TEST_METHOD(TestRightSideFlatRound) { QApplication a(argc, argv); class StyleStrokeRadialGradient : public Renderer::ElementStyle @@ -124,7 +124,7 @@ namespace UnitTest {1.00, Material{QColor(58,64,151)}} }; return { BaseStyle(std::make_shared(), - std::make_shared(200, StrokeType::kRightSide, StrokeEndType::kFlat, + std::make_shared(160, StrokeType::kRightSide, StrokeEndType::kFlatRound, std::make_shared(materialMap, false))) }; } } style; From 57d6de47f8eee41ac6b0965850e4f4dee0802952 Mon Sep 17 00:00:00 2001 From: wuyize Date: Wed, 15 Mar 2023 11:23:21 +0800 Subject: [PATCH 07/40] Fix: painting.comp bug --- .../res/Shaders/element.comp | 5 - .../res/Shaders/painting.comp | 106 +++++++++++++----- 2 files changed, 78 insertions(+), 33 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/element.comp b/ArchitectureColoredPainting/res/Shaders/element.comp index 66910e7..b44b514 100644 --- a/ArchitectureColoredPainting/res/Shaders/element.comp +++ b/ArchitectureColoredPainting/res/Shaders/element.comp @@ -1150,11 +1150,6 @@ void main() else tangentEnd = normalize(p[3] - p[1]); - // if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, - // tangentEndLast) - // : (onEnd ? shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, - // tangentBeginNext) - // : d < minDistance)) bool hit = d < minDistance; if (onBegin) hit = hit && diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp index 9ba19a9..50a32b8 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.comp +++ b/ArchitectureColoredPainting/res/Shaders/painting.comp @@ -1023,14 +1023,14 @@ void drawLine(in float d, in uint styleIndex, out vec4 elementColor, out vec2 me } } -bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, vec2 tangentBegin, vec2 tangentEndLast) +bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast) { vec2 normal; if (onVeryBegin) { - if (endType == 0) + if (endType % 2 == 0) return true; - else if (endType == 1) + else if (endType % 2 == 1) normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); } else @@ -1039,17 +1039,26 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, ve vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); normal = normalLast + normalNow; } - return angleLargeThanPi(normal, localUV - p3); + return angleLargeThanPi(normal, localUV - p0); } -bool shouldFillEndCap(vec2 localUV, int endType, vec2 p0, vec2 tangentEnd) +bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext) { vec2 normal; - if (endType == 0) - return true; - else if (endType == 1) - normal = normalize(mat2(0, 1, -1, 0) * tangentEnd); - return angleLargeThanPi(localUV - p0, normal); + if (onVeryEnd) + { + if ((endType / 2) % 2 == 0) + return true; + else if ((endType / 2) % 2 == 1) + normal = normalize(mat2(0, 1, -1, 0) * tangentEnd); + } + else + { + vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd); + vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext)); + normal = normalLast + normalNow; + } + return angleLargeThanPi(localUV - p3, normal); } bool fillElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex, @@ -1100,8 +1109,8 @@ bool fillElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsO return hitElement; } -bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex, float widthHeightRatio, - inout vec4 elementColor, inout vec2 metallicRoughness) +bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex, + float widthHeightRatio, inout vec4 elementColor, inout vec2 metallicRoughness) { bool hitElement = false; float strokeWidth = elementData[styleIndex]; @@ -1135,12 +1144,44 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]); - p[0] *= ratio; p[1] *= ratio; p[2] *= ratio; p[3] *= ratio; + vec2 tangentBeginNext; + if (contourIterator + 1 < contourIndex + 1 + lineCount) + { + uint lineIndex = elementIndexs[contourIterator + 1]; + uint pLocation = linesOffset + 3 * lineIndex; + //vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]); + uvec4 pxIndex = uvec4(pointsOffset) + + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF, + elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF); + uvec4 pyIndex = uvec4(1) + pxIndex; + + mat4x2 pNext = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], + elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]], + elementData[pxIndex[3]], elementData[pyIndex[3]]); + pNext[0] *= ratio; + pNext[1] *= ratio; + pNext[2] *= ratio; + pNext[3] *= ratio; + + if (pNext[0] == pNext[1] && pNext[2] == pNext[3]) + { + pNext[1] = (pNext[0] + pNext[3]) / 2; + pNext[2] = pNext[1]; + } + + //if(pNext[0]!=p[3]) + // break; + if (pNext[0] != pNext[1]) + tangentBeginNext = normalize(pNext[0] - pNext[1]); + else + tangentBeginNext = normalize(pNext[0] - pNext[2]); + } + if (p[0] == p[1] && p[2] == p[3]) { p[1] = (p[0] + p[3]) / 2; @@ -1158,7 +1199,10 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); if (d <= strokeWidth) { - bool onBegin = distance(localUV, p[0]) <= strokeWidth && ( p3Last == p[0] || contourIterator==contourIndex + 1); + bool onBegin = + distance(localUV, p[0]) <= strokeWidth; //&& (p3Last == p[0] || contourIterator == contourIndex + 1); + bool onEnd = distance(localUV, p[3]) <= strokeWidth; + vec2 tangentBegin; vec2 tangentEnd; if (p[0] != p[1]) @@ -1170,30 +1214,36 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point else tangentEnd = normalize(p[3] - p[1]); - if (onBegin ? shouldFillBeginCap(localUV, percent[0]<1e-5, endType, p[0], tangentBegin, p3Last - p2Last) - : d < minDistance) + bool hit = d < minDistance; + if (onBegin) + hit = + hit && shouldFillBeginCap(localUV, percent[0] < 1e-5, endType, p[0], tangentBegin, p3Last - p2Last); + if (onEnd) + hit = hit && + shouldFillEndCap(localUV, percent[1] > 1 - 1e-5, endType, p[3], tangentEnd, tangentBeginNext); + if (hit) { - minDistance = min(minDistance, d); bool reverse = p[3].y - p[0].y < 0.; - if (tangentBegin.y == 0.) - tangentBegin.y = reverse ? eps : -eps; - if (tangentEnd.y == 0.) - tangentEnd.y = reverse ? -eps : eps; + // if (tangentBegin.y == 0.) + // tangentBegin.y = reverse ? eps : -eps; + // if (tangentEnd.y == 0.) + // tangentEnd.y = reverse ? -eps : eps; int intTest = cubic_bezier_int_test2(localUV, p[0], p[1], p[2], p[3], reverse) + ray_int_test(localUV, p[0], tangentBegin, reverse) + ray_int_test(localUV, p[3], tangentEnd, reverse); if (lineType == 2 || (intTest % 2 == int(lineType))) { + minDistance = min(minDistance, d); hitElement = true; // elementColor = vec4(1, 1, 0, 1); vec2 metallicRoughness; drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); } - else if (p3Last == p[0]) - hitElement = false; + // else if (p3Last == p[0]) + // hitElement = false; } tangentEndLast = tangentEnd; } @@ -1202,7 +1252,7 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point } if (hitElement && distance(localUV, p3Last) <= strokeWidth) { - hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast); + // hitElement = shouldFillEndCap(localUV, percent[1] > 1 - 1e-5, endType, p3Last, tangentEndLast, vec2(0)); } // if (minDistance <= 0.001) @@ -1261,8 +1311,8 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou } else // 线 { - hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex, widthHeightRatio, - elementColor, metallicRoughness); + hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex, + widthHeightRatio, elementColor, metallicRoughness); } elementBvhIndex = elementBvhLength; @@ -1303,7 +1353,7 @@ void main() vec3 debugBVH = vec3(0); // bool debugHit = false; vec4 color = vec4(0.76, 0.33, 0.15, -1); - //vec4 color = vec4(1,1,1, -1); + // vec4 color = vec4(1,1,1, -1); vec2 metallicRoughness = vec2(0, 0.8); stack.top = 0; uint index = 0, visitTime = 0; @@ -1373,7 +1423,7 @@ void main() imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1)); imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1)); - return; + //return; if (/*color.a!=-1&&*/ debugBVH == vec3(0)) { // imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1)); From d47d94d04476106c0b2bf0e955f2c3182e62e348 Mon Sep 17 00:00:00 2001 From: "yang.yongquan" <3395816735@qq.com> Date: Wed, 15 Mar 2023 11:23:26 +0800 Subject: [PATCH 08/40] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=AF=B9?= =?UTF-8?q?=E4=BA=8EPainting=E7=9A=84=E8=BD=AC=E6=8D=A2=EF=BC=8C=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E8=80=83=E8=99=91=E7=BA=BF=E5=AE=BD=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/util/PaintingUtil.cpp | 66 ++++++++++--------- .../src/Editor/util/PaintingUtil.h | 3 +- .../src/Renderer/Model.cpp | 54 +-------------- .../src/Renderer/Painting/LineTree.cpp | 5 +- UnitTest/UnitTest.cpp | 19 ++++++ 5 files changed, 61 insertions(+), 86 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp index 45747dc..07e0224 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp @@ -8,6 +8,9 @@ using Renderer::Element; using Renderer::ElementTransform; using glm::bvec2; using std::max; +using std::min; + +const double PaintingUtil::pi = acos(-1); QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) { QFile jsonFile(jsonFilePath); @@ -27,74 +30,69 @@ Painting PaintingUtil::transfromToPainting(QString jsonFilePath) { ElementManager *elementManager = new ElementManager(jsonObj, Renderer::ElementRenderer::instance()); LayerManager* layerManager = new LayerManager(jsonObj, elementManager); traverseLayTree(layerManager->getRoot(), transform, flip, painting); - // FIXME: 为了编译通过添加的返回 return painting; } void PaintingUtil::traverseLayTree(LayerWrapper* nowLayer, QTransform transform, bvec2 flip, Painting& painting) { LeafLayerWrapper* leafLayer = dynamic_cast(nowLayer); PixelPath pixelPath = nowLayer->getCache(); - double centerX = pixelPath.getBoundingRect().center().x(); - double centerY = pixelPath.getBoundingRect().center().y(); + QPainterPath painterPath = pixelPath.getPainterPath(); + QRectF bound = painterPath.boundingRect(); flip ^= bvec2(nowLayer->property.flipHorizontally, nowLayer->property.flipVertically); - QRectF transBound = transform.map(pixelPath.getPainterPath()).boundingRect(); + transform = nowLayer->property.transform * transform; - transform.translate(nowLayer->property.offset.x(), nowLayer->property.offset.y()) - .translate(-centerX, -centerY) - .rotate(nowLayer->property.rotation) - .scale(nowLayer->property.scale.x(), nowLayer->property.scale.y()) - .translate(centerX, centerY); if (leafLayer != nullptr) { Element element; ElementTransform elementTrans; - QRectF bound = pixelPath.getBoundingRect(); element.ratio = bound.width() / bound.height(); // transform to initial painterPath - QTransform trans; - trans.translate(-centerX, -centerY) - .scale(1 / nowLayer->property.scale.x(), 1 / nowLayer->property.scale.y()) - .rotate(-nowLayer->property.rotation) - .translate(centerX, centerY) - .translate(-nowLayer->property.offset.x(), -nowLayer->property.offset.y()); - QPainterPath painterPath = trans.map(pixelPath.getPainterPath()); // transfrom to -1, 1 - bound = painterPath.boundingRect(); - trans.reset(); - trans.translate(1, 1); - trans.scale(2 / bound.width(), 2 / bound.height()); - trans.translate(bound.x(), bound.y()); - painterPath = trans.map(painterPath); + QTransform trans; + trans.scale(1 / bound.width(), 1 / bound.height()); + trans.translate(-bound.center().x(), -bound.center().y()); - element.contour.reset(new vector >(PainterPathUtil::transformToLines(painterPath))); + element.contour.reset(new vector >(PainterPathUtil::transformToLines(trans.map(painterPath)))); QSize screenSize = pixelPath.getPixmap().size(); + //element.style.reset(new Renderer::ElementStyleStrokeDemo(0.06)); + + painterPath = transform.map(painterPath); + bound = painterPath.boundingRect(); elementTrans.center = glm::vec2( - (2 * (transBound.x() + transBound.width()) - screenSize.width()) / screenSize.width(), - (2 * (transBound.y() + transBound.height()) - screenSize.height()) / screenSize.height() + (bound.center().x() - screenSize.width()) / screenSize.width(), + (bound.center().y() - screenSize.height()) / screenSize.height() ); decomposeTransform(transform, elementTrans.rotation, elementTrans.scale); elementTrans.flip = glm::bvec2( nowLayer->property.flipHorizontally, nowLayer->property.flipVertically ); + painting.addElement(element, elementTrans); return; } FolderLayerWrapper* folderLayer = dynamic_cast(nowLayer); - for (auto sonLayer : folderLayer->children) { - traverseLayTree(sonLayer.get(), transform, flip, painting); + if (folderLayer != nullptr) { + for (auto sonLayer : folderLayer->children) { + traverseLayTree(sonLayer.get(), transform, flip, painting); + } } return; } void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2& scale) { - trans.translate(-trans.dx(), -trans.dy()); + qDebug() << trans; + trans.setMatrix( + trans.m11(), trans.m12(), trans.m13(), + trans.m21(), trans.m22(), trans.m23(), + 0, 0, 1); + //qDebug() << trans.dx() << trans.dy(); int count = 0; double norm = 0, n = 0; QTransform R = trans, Rit, Rnext; do { ++count; - Rit = R.inverted(); + Rit = R.transposed().inverted(); Rnext.setMatrix( (R.m11() + Rit.m11()) / 2, (R.m12() + Rit.m12()) / 2, @@ -121,7 +119,13 @@ void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2& + fabs(R.m33() - Rnext.m33())); R = Rnext; } while (count < 100 && norm > 0.0001); - angle = acos(R.m11()); + double cosValue = max(-1.0, min(R.m11(), 1.0)); + double sinValue = max(-1.0, min(R.m12(), 1.0)); + angle = acos(cosValue) * 180 / pi; + if (sinValue < 0) { + angle = 360 - angle; + } + qDebug() << angle; R = R.inverted() * trans; scale = glm::vec2(R.m11(), R.m22()); return; diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h index bb27a73..35ebe03 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h @@ -5,11 +5,12 @@ class PaintingUtil { private: + static const double pi; static QJsonObject readJsonFile(QString jsonFilePath); static void traverseLayTree(LayerWrapper* nowLayer, QTransform transform, glm::bvec2 flip, Renderer::Painting& painting); - static void decomposeTransform(QTransform trans, float& angle, glm::vec2& scale); public: static Renderer::Painting transfromToPainting(QString jsonFilePath); + static void decomposeTransform(QTransform trans, float& angle, glm::vec2& scale); }; diff --git a/ArchitectureColoredPainting/src/Renderer/Model.cpp b/ArchitectureColoredPainting/src/Renderer/Model.cpp index 644863d..89684c5 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Model.cpp @@ -14,6 +14,7 @@ #include "../Editor/util/PainterPathUtil.h" #include "../Editor/util/SvgFileLoader.h" #include +#include using namespace Renderer; using std::vector; @@ -228,58 +229,7 @@ GLuint Renderer::Model::loadPainting(std::string path) if (iter != paintingLoaded.end()) return iter->second; - //vector> contour = { - // std::make_shared(SvgParser("M100,100C-.5,100,0,100.5,0,0L40,.07C40,59.5,39.5,60,100,60Z", 100, 100).parse()), - // std::make_shared(SvgParser("M308.49,212.25l23,28.38-82,78.31c-14.28,13.64-26.34-20.6-53.44,9.32l-30.24-13.4,63.56-51.59L190.71,215.6l-32.92,26.72L149.5,232.1l32.92-26.72L173.2,194l-32.91,26.72-7.38-9.08L165.83,185l-38.69-47.66L94.22,164,85,152.65l32.91-26.72-9.21-11.35L75.79,141.3l-5.53-6.81,32.92-26.72L94,96.42,61.05,123.14l-12-14.76L37.72,117.6l12,14.75L30.41,148,0,110.55,136.2,0l30.4,37.46L147.31,53.12l-12-14.76L124,47.58l12,14.75L103.05,89.05l9.21,11.35,32.92-26.72,5.52,6.81-32.91,26.72L127,118.56l32.92-26.72,9.21,11.35-32.91,26.72,38.69,47.67,32.91-26.72,7.37,9.08-32.91,26.72L191.49,198l32.92-26.72,8.29,10.22-32.92,26.71,38.7,47.68L302,204.3l6.45,7.95Z", 331.52, 328.26).parse()), - // std::make_shared(SvgParser("M377,459.61a11.26,11.26,0,0,1,11.27-11.27H696.12a11.27,11.27,0,0,0,11-8.62A359.84,359.84,0,0,0,708,280.56a11.26,11.26,0,0,0-11-8.73H388.27A11.26,11.26,0,0,1,377,260.57h0a11.26,11.26,0,0,1,11.27-11.26H683.71A11.32,11.32,0,0,0,694.28,234C649.8,113.69,542.57,23.85,412.3,4.12a11.22,11.22,0,0,0-12.76,11.17v158.9a11.26,11.26,0,0,0,11.26,11.27H583.12a11.32,11.32,0,0,0,9.26-17.75c-31.67-46.59-78.51-75.2-109.11-90.07a11.25,11.25,0,0,0-16.13,10.17V115.2a11.24,11.24,0,0,0,6.22,10.07l7.51,3.76a11.28,11.28,0,0,1,5,15.12h0a11.27,11.27,0,0,1-15.11,5l-20-10a11.27,11.27,0,0,1-6.22-10.07V54a11.27,11.27,0,0,1,14.62-10.75c5.11,1.59,125.66,40.35,172.24,149A11.27,11.27,0,0,1,621.11,208H388.27A11.26,11.26,0,0,1,377,196.73V11.36A11.32,11.32,0,0,0,365.89.08C363.34,0,360.79,0,358.22,0s-5.11,0-7.66.08a11.32,11.32,0,0,0-11.11,11.28V196.74A11.26,11.26,0,0,1,328.18,208H95.35A11.27,11.27,0,0,1,85,192.3c46.57-108.67,167.12-147.42,172.23-149A11.26,11.26,0,0,1,271.86,54v75.11a11.25,11.25,0,0,1-6.23,10.07l-20,10a11.27,11.27,0,0,1-15.11-5h0a11.26,11.26,0,0,1,5-15.11l7.52-3.76a11.27,11.27,0,0,0,6.22-10.07V87.82a11.25,11.25,0,0,0-16.14-10.16c-30.6,14.87-77.45,43.48-109.1,90.07a11.3,11.3,0,0,0,9.25,17.74H305.66a11.26,11.26,0,0,0,11.27-11.26V15.31A11.22,11.22,0,0,0,304.17,4.14C173.88,23.86,66.66,113.71,22.17,234a11.32,11.32,0,0,0,10.56,15.29H328.18a11.26,11.26,0,0,1,11.27,11.26v0a11.26,11.26,0,0,1-11.27,11.26H19.52a11.26,11.26,0,0,0-11,8.72,359.84,359.84,0,0,0,.83,159.16,11.26,11.26,0,0,0,11,8.61H328.18a11.26,11.26,0,0,1,11.27,11.27h0a11.26,11.26,0,0,1-11.27,11.26h-294a11.32,11.32,0,0,0-10.53,15.4C69,604.65,175.3,692.78,304.16,712.3a11.21,11.21,0,0,0,12.76-11.16V542.22A11.26,11.26,0,0,0,305.66,531h-166c-9.53,0-14.89,11.22-8.69,18.47,34.09,39.77,74.45,65.66,101.77,80.18a11.25,11.25,0,0,0,16.53-10V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,271.85,591v63.85A11.27,11.27,0,0,1,256.8,665.5c-4.45-1.59-109.58-40-171-139.9a11.27,11.27,0,0,1,9.59-17.17H328.18a11.26,11.26,0,0,1,11.27,11.26V705.08a11.32,11.32,0,0,0,11.11,11.28q3.82.07,7.66.08c2.57,0,5.12,0,7.67-.08A11.32,11.32,0,0,0,377,705.08V519.69a11.25,11.25,0,0,1,11.27-11.26H621.1a11.26,11.26,0,0,1,9.59,17.16c-61.46,99.87-166.59,138.3-171,139.9a11.27,11.27,0,0,1-15-10.61V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,467.14,591v28.6a11.25,11.25,0,0,0,16.53,10c27.33-14.53,67.68-40.42,101.77-80.19,6.2-7.23.85-18.46-8.69-18.46h-166a11.26,11.26,0,0,0-11.26,11.26V701.12a11.21,11.21,0,0,0,12.76,11.17c128.86-19.51,235.14-107.66,280.48-226a11.33,11.33,0,0,0-10.53-15.41h-294A11.25,11.25,0,0,1,377,459.61ZM35.27,399.53V316.9a11.26,11.26,0,0,1,11.27-11.26H669.92a11.25,11.25,0,0,1,11.26,11.26v82.63a11.25,11.25,0,0,1-11.26,11.26H46.54a11.27,11.27,0,0,1-11.27-11.26Z", 716.45, 716.44).parse()) - //}; - - vector, float>> contours; - - QPainterPath painterPaths[3]; - QQuickSvgParser::parsePathDataFast("M100,100C-.5,100,0,100.5,0,0L40,.07C40,59.5,39.5,60,100,60Z", - painterPaths[0]); - if (!SvgFileLoader().loadSvgFile("../svg/2.svg", painterPaths[1])) - qCritical() << "load error"; - /*QQuickSvgParser::parsePathDataFast("M292.82,107.78s0,0,0,0,0,3.59,0,7.62c0,3.85,0,5.78.06,6.43a19.94,19.94,0,0,0,2.87,7.58,15.85,15.85,0,0,0,6.61,6.23A14.75,14.75,0,0,0,310,137a11.69,11.69,0,0,0,7.59-2.92,11,11,0,0,0,3.2-6.84c.15-1.27.58-4.84-1.79-7.64a8.54,8.54,0,0,0-3.56-2.44c-1.32-.52-3.32-1.31-5.06-.33a5.41,5.41,0,0,0-2.14,3,3.48,3.48,0,0,0-.16,2.71c.78,1.86,3.36,2.14,3.47,2.15", - painterPaths[1]);*/ - QQuickSvgParser::parsePathDataFast("M377,459.61a11.26,11.26,0,0,1,11.27-11.27H696.12a11.27,11.27,0,0,0,11-8.62A359.84,359.84,0,0,0,708,280.56a11.26,11.26,0,0,0-11-8.73H388.27A11.26,11.26,0,0,1,377,260.57h0a11.26,11.26,0,0,1,11.27-11.26H683.71A11.32,11.32,0,0,0,694.28,234C649.8,113.69,542.57,23.85,412.3,4.12a11.22,11.22,0,0,0-12.76,11.17v158.9a11.26,11.26,0,0,0,11.26,11.27H583.12a11.32,11.32,0,0,0,9.26-17.75c-31.67-46.59-78.51-75.2-109.11-90.07a11.25,11.25,0,0,0-16.13,10.17V115.2a11.24,11.24,0,0,0,6.22,10.07l7.51,3.76a11.28,11.28,0,0,1,5,15.12h0a11.27,11.27,0,0,1-15.11,5l-20-10a11.27,11.27,0,0,1-6.22-10.07V54a11.27,11.27,0,0,1,14.62-10.75c5.11,1.59,125.66,40.35,172.24,149A11.27,11.27,0,0,1,621.11,208H388.27A11.26,11.26,0,0,1,377,196.73V11.36A11.32,11.32,0,0,0,365.89.08C363.34,0,360.79,0,358.22,0s-5.11,0-7.66.08a11.32,11.32,0,0,0-11.11,11.28V196.74A11.26,11.26,0,0,1,328.18,208H95.35A11.27,11.27,0,0,1,85,192.3c46.57-108.67,167.12-147.42,172.23-149A11.26,11.26,0,0,1,271.86,54v75.11a11.25,11.25,0,0,1-6.23,10.07l-20,10a11.27,11.27,0,0,1-15.11-5h0a11.26,11.26,0,0,1,5-15.11l7.52-3.76a11.27,11.27,0,0,0,6.22-10.07V87.82a11.25,11.25,0,0,0-16.14-10.16c-30.6,14.87-77.45,43.48-109.1,90.07a11.3,11.3,0,0,0,9.25,17.74H305.66a11.26,11.26,0,0,0,11.27-11.26V15.31A11.22,11.22,0,0,0,304.17,4.14C173.88,23.86,66.66,113.71,22.17,234a11.32,11.32,0,0,0,10.56,15.29H328.18a11.26,11.26,0,0,1,11.27,11.26v0a11.26,11.26,0,0,1-11.27,11.26H19.52a11.26,11.26,0,0,0-11,8.72,359.84,359.84,0,0,0,.83,159.16,11.26,11.26,0,0,0,11,8.61H328.18a11.26,11.26,0,0,1,11.27,11.27h0a11.26,11.26,0,0,1-11.27,11.26h-294a11.32,11.32,0,0,0-10.53,15.4C69,604.65,175.3,692.78,304.16,712.3a11.21,11.21,0,0,0,12.76-11.16V542.22A11.26,11.26,0,0,0,305.66,531h-166c-9.53,0-14.89,11.22-8.69,18.47,34.09,39.77,74.45,65.66,101.77,80.18a11.25,11.25,0,0,0,16.53-10V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,271.85,591v63.85A11.27,11.27,0,0,1,256.8,665.5c-4.45-1.59-109.58-40-171-139.9a11.27,11.27,0,0,1,9.59-17.17H328.18a11.26,11.26,0,0,1,11.27,11.26V705.08a11.32,11.32,0,0,0,11.11,11.28q3.82.07,7.66.08c2.57,0,5.12,0,7.67-.08A11.32,11.32,0,0,0,377,705.08V519.69a11.25,11.25,0,0,1,11.27-11.26H621.1a11.26,11.26,0,0,1,9.59,17.16c-61.46,99.87-166.59,138.3-171,139.9a11.27,11.27,0,0,1-15-10.61V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,467.14,591v28.6a11.25,11.25,0,0,0,16.53,10c27.33-14.53,67.68-40.42,101.77-80.19,6.2-7.23.85-18.46-8.69-18.46h-166a11.26,11.26,0,0,0-11.26,11.26V701.12a11.21,11.21,0,0,0,12.76,11.17c128.86-19.51,235.14-107.66,280.48-226a11.33,11.33,0,0,0-10.53-15.41h-294A11.25,11.25,0,0,1,377,459.61ZM35.27,399.53V316.9a11.26,11.26,0,0,1,11.27-11.26H669.92a11.25,11.25,0,0,1,11.26,11.26v82.63a11.25,11.25,0,0,1-11.26,11.26H46.54a11.27,11.27,0,0,1-11.27-11.26Z", - painterPaths[2]); - - for (auto& i : painterPaths) - { - auto [contour, ratio] = PainterPathUtil::toNormalizedLines(i); - contours.emplace_back(std::make_shared(contour), ratio); - } - - vector> style = { - std::make_shared(), - std::make_shared(0.02), - std::make_shared(0.2) - }; - - vector> element = { - std::make_shared(Element{ contours[0].first, style[0], contours[0].second}), - std::make_shared(Element{ contours[1].first, style[2], contours[1].second}), - std::make_shared(Element{ contours[2].first, style[0], contours[2].second}), - }; - Painting painting; - - if (path == "0.json") - { - painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,-0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); - painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45, 0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); - painting.addElement(*element[2], ElementTransform{ glm::vec2(0.50,-0.45), glm::vec2(0.6,0.7) / 2.f, 0, glm::bvec2(false), 0 }); - } - else - { - for (int i = 0; i < 1000; i++) - { - float x = (float)rand() / RAND_MAX * 2 - 1; - float y = (float)rand() / RAND_MAX * 2 - 1; - painting.addElement(*element[i % 3], ElementTransform{ glm::vec2(x,y), glm::vec2(0.025), (float)rand() / RAND_MAX * 360, glm::bvec2(false), 0 }); - } - } + Painting painting = PaintingUtil::transfromToPainting("D:\\BigC\\Project\\ArchitectureColoredPainting\\data.json"); painting.generateBuffers(glFunc); diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/LineTree.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/LineTree.cpp index 2b4cd56..db84c3c 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/LineTree.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/LineTree.cpp @@ -141,12 +141,13 @@ bool LineTree::handleShortCutNode(LineTreeNode& fa, LineTreeNode& nowTreeNode, d nowTreeNode.lineSet.push_back(lineIndex); } } - if (nowTreeNode.lineSet.size() <= requiredLineMin) { + if (nowTreeNode.lineSet.size() <= requiredLineMin + || (nowTreeNode.bound.z()-nowTreeNode.bound.x())*sqrt(2) <= lineWidth) { if (nowTreeNode.lineSet.empty()) return false; restOfTreeNodes.push_back(nowTreeNode); nowTreeNode.divided = false; - v.push_back(nowTreeNode); + //v.push_back(nowTreeNode); return false; } else { diff --git a/UnitTest/UnitTest.cpp b/UnitTest/UnitTest.cpp index 2d7d95a..25bcf67 100644 --- a/UnitTest/UnitTest.cpp +++ b/UnitTest/UnitTest.cpp @@ -7,6 +7,7 @@ #include "Renderer/Painting/CubicBezier.h" #include #include +#include using namespace Microsoft::VisualStudio::CppUnitTestFramework; @@ -119,4 +120,22 @@ namespace UnitTest a.exec(); } }; + TEST_CLASS(PaintingUtilTest) + { + TEST_METHOD(TransfromTest) + { + qInstallMessageHandler(messageHandler); + QPainterPath path; + path.addRect(0, 0, 20, 20); + QTransform trans; + qDebug() << path.boundingRect(); + //qDebug() << trans; + //qDebug() << acos(-0.707107); + glm::vec2 scale; + float rotate; + PaintingUtil::decomposeTransform(trans, rotate, scale); + qDebug() << rotate; + qDebug() << scale.x << scale.y; + } + }; } From 073f68e36060a127a42876d40822a2193830ab57 Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Wed, 15 Mar 2023 11:43:16 +0800 Subject: [PATCH 09/40] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86=E7=BC=96=E8=BE=91=E5=99=A8=E4=B8=AD=E7=9A=84StrokeSty?= =?UTF-8?q?le=20[style/stroke]=20=E5=AE=9E=E7=8E=B0=E4=BA=86=E8=A1=8C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=20[style/stroke]=20=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E7=A8=B3=E5=AE=9A=E4=BA=86strokeStyle=E7=9A=84=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20[paint]=20=E4=BB=A4drawElement=E6=97=B6=E4=BC=9A?= =?UTF-8?q?=E5=BA=94=E7=94=A8style=20[style]=20=E4=BF=AE=E6=94=B9=E4=BA=86?= =?UTF-8?q?LayerStyle=20[editor]=20=E6=96=B0=E5=A2=9E=E4=BA=86ColorPicker?= =?UTF-8?q?=E7=B1=BB=E5=92=8CStrokeStyleListView=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 4 + ...rchitectureColoredPainting.vcxproj.filters | 86 ++++++++------ .../EditorWidgetComponent/ColorPicker.cpp | 38 ++++++ .../EditorWidgetComponent/ColorPicker.h | 16 +++ .../LayerStyleDialog.cpp | 2 +- .../StrokeStyleListView.cpp | 108 ++++++++++++++++++ .../StrokeStyleListView.h | 21 ++++ .../src/Editor/GraphicElement.cpp | 41 +++++-- .../src/Editor/GraphicElement.h | 6 +- .../src/Editor/LayerStyle.cpp | 98 +++++++++++++--- .../src/Editor/LayerStyle.h | 27 +++-- .../Renderer/Painting/MaterialStyleStroke.cpp | 1 + .../src/Renderer/Preview/ElementRenderer.cpp | 1 + 13 files changed, 380 insertions(+), 69 deletions(-) create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.cpp create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.cpp create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.h diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index bc422d1..a0e5563 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -104,6 +104,7 @@ + @@ -152,6 +153,7 @@ + @@ -187,12 +189,14 @@ + + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index f7e8d97..e019bc3 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -65,6 +65,12 @@ {7ead1a66-586a-4584-ae80-9e7a4e667364} + + {be3f4585-c8ba-410f-8619-2adcd4349f02} + + + {b9732a33-aa2e-4f8d-886f-1b1730c66519} + @@ -111,9 +117,6 @@ Source Files\Renderer - - Source Files - Source Files\Renderer\Painting @@ -156,12 +159,6 @@ Source Files\Renderer\Painting - - Source Files - - - Source Files - Source Files\Renderer\Painting @@ -189,9 +186,6 @@ Source Files\Renderer\Preview - - Source Files - Source Files\Renderer @@ -216,11 +210,29 @@ Source Files\Editor\util - - Source Files + + Source Files\Editor\Style - Source Files + Source Files\Editor\Style + + + Source Files\Editor\Style + + + Source Files\Editor + + + Source Files\Editor + + + Source Files\Editor + + + Source Files\Editor + + + Source Files\Editor @@ -233,35 +245,41 @@ Header Files\Renderer - - Header Files - - - Header Files - Header Files\Editor - - Header Files - - - Header Files - - - Header Files - Header Files\Editor Header Files - - Header Files + + Header Files\Editor\Style - Header Files + Header Files\Editor\Style + + + Header Files\Editor + + + Header Files\Editor + + + Header Files\Editor + + + Header Files\Editor + + + Header Files\Editor + + + Header Files\Editor + + + Header Files\Editor @@ -457,7 +475,7 @@ Header Files\Editor\util - Header Files\Editor + Header Files\Editor\Style diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.cpp new file mode 100644 index 0000000..7010ae4 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.cpp @@ -0,0 +1,38 @@ +#include "ColorPicker.h" +#include + +QString getStyleSheet(const QColor& color) +{ + return + "QPushButton#colorPicker {" + " border-style: solid;" + " border-width: 1px;" + " border-color: black;" + " background-color: " + color.name() + ";" + "}"; +} + +ColorPicker::ColorPicker(const QColor& color, QWidget* parent) : QPushButton(parent), color(color) +{ + this->setObjectName("colorPicker"); + this->setStyleSheet(getStyleSheet(color)); + connect(this, &QPushButton::clicked, this, &ColorPicker::onClicked); +} + +QColor ColorPicker::getColor() const +{ + return color; +} + +void ColorPicker::onClicked() +{ + QColorDialog dialog(this->color, this); + dialog.exec(); + QColor newColor = dialog.selectedColor(); + if (newColor.isValid() && this->color != newColor) + { + this->color = newColor; + this->setStyleSheet(getStyleSheet(newColor)); + emit colorChanged(newColor); + } +} \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h new file mode 100644 index 0000000..aca00ea --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h @@ -0,0 +1,16 @@ +#pragma once +#include +class ColorPicker : public QPushButton +{ + Q_OBJECT +private: + QColor color; +public: + ColorPicker(const QColor& color, QWidget* parent = nullptr); + QColor getColor() const; +public slots: + void onClicked(); +signals: + void colorChanged(QColor newColor); +}; + diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp index 7a7db8d..478301a 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp @@ -18,7 +18,7 @@ LayerStyleDialog::LayerStyleDialog( if (existedStyle) { - this->modifyingStyle = existedStyle->clonePtr(); + this->modifyingStyle = existedStyle->clone(); this->styleContainer = nullptr; this->styleWidget = modifyingStyle->getInputWidget(); diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.cpp new file mode 100644 index 0000000..5b011a7 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.cpp @@ -0,0 +1,108 @@ +#include "StrokeStyleListView.h" +#include "ColorPicker.h" +#include + +constexpr int COLUMN_WIDTH = 0; +constexpr int COLUMN_COLOR = 1; +constexpr int COLUMN_METALLIC = 2; +constexpr int COLUMN_ROUGHNESS = 3; +constexpr int COLUMN_OPERATIONS = 4; + +// TODO: 将这个类改为继承QWidget,把table转为其中的一个元素,加上新增行按钮和宽度设置 +StrokeStyleListView::StrokeStyleListView( + std::shared_ptr stroke, + QWidget* parent +) : QTableWidget(parent), stroke(stroke) +{ + this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow); + this->setColumnCount(5); + this->setRowCount(stroke->materialMap.size()); + QStringList headers; + headers.append(QStringLiteral("离心距离占比")); + headers.append(QStringLiteral("颜色")); + headers.append(QStringLiteral("金属度")); + headers.append(QStringLiteral("粗糙度")); + headers.append(QStringLiteral("其他操作")); + this->setHorizontalHeaderLabels(headers); + for (int row = 0; auto& strokePair : stroke->materialMap) + { + QTableWidgetItem* widthItem = new QTableWidgetItem; + widthItem->setData(Qt::EditRole, strokePair.first); + this->setItem(row, COLUMN_WIDTH, widthItem); + + QColor* colorPtr = &(strokePair.second.color); + QTableWidgetItem* colorItem = new QTableWidgetItem; + colorItem->setData(Qt::DisplayRole, *colorPtr); + this->setItem(row, COLUMN_COLOR, colorItem); + ColorPicker* colorPicker = new ColorPicker(*colorPtr, this); + this->setCellWidget(row, COLUMN_COLOR, colorPicker); + connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) { + *colorPtr = color; + this->update(); + }); + + QTableWidgetItem* metallicItem = new QTableWidgetItem; + metallicItem->setData(Qt::EditRole, strokePair.second.metallic); + this->setItem(row, COLUMN_METALLIC, metallicItem); + + QTableWidgetItem* roughnessItem = new QTableWidgetItem; + roughnessItem->setData(Qt::EditRole, strokePair.second.roughness); + this->setItem(row, COLUMN_ROUGHNESS, roughnessItem); + + QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", this); + removeButton->setFixedSize(20, 20); + this->setCellWidget(row, COLUMN_OPERATIONS, removeButton); + connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() { + this->stroke->materialMap.erase(this->item(row, COLUMN_WIDTH)->text().toFloat()); + this->removeRow(row); + }); + + row++; + } + connect(this, &StrokeStyleListView::currentItemChanged, this, &StrokeStyleListView::onCurrentItemChanged); + connect(this, &StrokeStyleListView::cellChanged, this, &StrokeStyleListView::onCellChanged); + this->adjustSize(); +} + +void StrokeStyleListView::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) +{ + if (!current) return; + int column = current->column(); + if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS) + { + this->currentItemValue = current->text(); + } +} + +void StrokeStyleListView::onCellChanged(int row, int column) +{ + auto changedItem = this->item(row, column); + auto changedItemValue = changedItem->text().toFloat(); + if (changedItemValue < 0 || 1 < changedItemValue) + { + changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat()); + return; + } + auto changedWidth = this->item(row, COLUMN_WIDTH)->text().toFloat(); + switch (row) + { + case COLUMN_WIDTH: + { + float oldWidth = this->currentItemValue.toFloat(); + auto node = stroke->materialMap.extract(oldWidth); + node.key() = changedWidth; + stroke->materialMap.insert(std::move(node)); + break; + } + case COLUMN_METALLIC: + { + stroke->materialMap[changedWidth].metallic = changedItemValue; + break; + } + case COLUMN_ROUGHNESS: + { + stroke->materialMap[changedWidth].roughness = changedItemValue; + break; + } + } +} \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.h new file mode 100644 index 0000000..f12e400 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.h @@ -0,0 +1,21 @@ +#pragma once +#include "LayerStyle.h" +#include "../Renderer/Painting/MaterialStyleStroke.h" +#include +#include +#include +class StrokeStyleListView : public QTableWidget +{ + Q_OBJECT +private: + QString currentItemValue; + +public: + StrokeStyleListView(std::shared_ptr stroke, QWidget* parent = nullptr); + std::shared_ptr stroke; + +protected slots: + void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous); + void onCellChanged(int row, int column); +}; + diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 9602f2d..2775fe5 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -45,9 +45,22 @@ PixelPath GroupElement::getPaintObject() const //TODO: apply styles and send back PixelPath SimpleElement::getPaintObject(std::vector>* styles) const { PixelPath result; - Renderer::ElementStyleStrokeDemo demo(2); - auto [img, mov] = renderer->drawElement(painterPath, demo, 1.0); - //qDebug() << mov; + std::shared_ptr style; + if ((*styles).empty()) + { + style = std::make_shared(2); + } + else + { + style = (*styles)[0]; + /*qDebug() << std::dynamic_pointer_cast( + std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke + )->material.color.name();*/ + /*qDebug() << std::dynamic_pointer_cast( + std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke + )->materialMap[1.0].color;*/ + } + auto [img, mov] = renderer->drawElement(painterPath, *style, 1.0); //qDebug() << img << " ------"; result.addImage(img, mov); //result.addPath(painterPath); @@ -85,7 +98,7 @@ QJsonObject GraphicElement::toJson() const return result; } -void SimpleElement::paint(QPainter* painter, QTransform transform, vector> styles) +void SimpleElement::paint(QPainter* painter, QTransform transform, const vector> &styles) { painter->save(); painter->setTransform(transform); @@ -95,16 +108,30 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, vectordrawElement(painterPath, demo, 1.0); + std::shared_ptr style; + if (styles.empty()) + { + style = std::make_shared(2); + } + else + { + style = styles[0]; + /*qDebug() << std::dynamic_pointer_cast( + std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke + )->material.color.name();*/ + /*qDebug() << std::dynamic_pointer_cast( + std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke + )->materialMap[1.0].color;*/ + } + auto [img, mov] = renderer->drawElement(painterPath, *style, 1.0); painter->drawImage(mov, img); } painter->restore(); } -void GroupElement::paint(QPainter* painter, QTransform transform, vector> styles) +void GroupElement::paint(QPainter* painter, QTransform transform, const vector> &styles) { sourceLayer->paint(painter, transform); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index 577f7db..ce54ad7 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -28,7 +28,7 @@ public: virtual QJsonObject toJson() const; virtual PixelPath getPaintObject() const = 0; virtual PixelPath getPaintObject(std::vector>*) const = 0; - virtual void paint(QPainter* painter, QTransform transform, std::vector> styles) = 0; + virtual void paint(QPainter* painter, QTransform transform, const std::vector> &styles) = 0; }; class SimpleElement : public GraphicElement @@ -45,7 +45,7 @@ public: ~SimpleElement() = default; PixelPath getPaintObject() const override; PixelPath getPaintObject(std::vector>*) const override; - void paint(QPainter* painter, QTransform transform, std::vector> styles) override; + void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; }; class GroupElement : public GraphicElement @@ -60,7 +60,7 @@ public: PixelPath getPaintObject() const override; PixelPath getPaintObject(std::vector>*) const override; void setSourceLayer(FolderLayerWrapper* sourceLayer); - void paint(QPainter* painter, QTransform transform, std::vector> styles) override; + void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; }; //******************************** BitmapPath ********************************// diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index c76432f..e44e855 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -1,9 +1,13 @@ #include "LayerStyle.h" +#include "./EditorWidgetComponent/StrokeStyleListView.h" +#include #include #include #include #include #include +#include +#include const std::vector()>>> LayerStyle::types = { { @@ -18,7 +22,22 @@ const std::vector() std::vector StrokeElementLayerStyle::toBaseStyles() const { - return std::vector(); + std::vector baseStyles; + if (enableEachSideIndependent) + { + baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), + strokePair.first)); + baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), + strokePair.second)); + } + else + { + auto material = std::shared_ptr(std::move(strokePair.first->clone())); + std::dynamic_pointer_cast(material)->strokeType = Renderer::StrokeType::kBothSides; + + baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), material)); + } + return baseStyles; } QString StrokeElementLayerStyle::getStyleName() const @@ -26,12 +45,61 @@ QString StrokeElementLayerStyle::getStyleName() const return QStringLiteral("描边"); } -QWidget* StrokeElementLayerStyle::getInputWidget() const +QWidget* StrokeElementLayerStyle::getInputWidget() { - // TODO - QLabel* le = new QLabel; - le->setText(QStringLiteral("描边")); - return le; + if (this->strokePair.first == nullptr) + { + auto materialMap = std::map(); + materialMap[0.3] = Renderer::Material{ QColor(0,255,255), 0.f, .8f }; + materialMap[1.0] = Renderer::Material{ QColor(80,25,255), 0.f, .8f }; + this->strokePair.first = std::shared_ptr(new Renderer::MaterialStyleStroke( + 15, + Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, + std::shared_ptr(new Renderer::StrokeRadialGradient( + materialMap, false + )) + )); + } + if (this->strokePair.second == nullptr) + { + auto materialMap = std::map(); + materialMap[0.3] = Renderer::Material{ QColor(0,255,255), 0.f, .8f }; + materialMap[1.0] = Renderer::Material{ QColor(80,25,255), 0.f, .8f }; + this->strokePair.second = std::shared_ptr(new Renderer::MaterialStyleStroke( + 15, + Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, + std::shared_ptr(new Renderer::StrokeRadialGradient( + materialMap, false + )) + )); + } + QWidget* w = new QWidget; + QListView* materialList = new QListView; + + QVBoxLayout* layout = new QVBoxLayout(w); + layout->setMargin(0); + + StrokeStyleListView* leftStrokeView = new StrokeStyleListView( + std::dynamic_pointer_cast(this->strokePair.first->materialStroke), w + ); + layout->addWidget(leftStrokeView); + + QtMaterialCheckBox* checkEachSideIndependent = new QtMaterialCheckBox(w); + checkEachSideIndependent->setText(QStringLiteral("启用两侧独立描边")); + checkEachSideIndependent->setChecked(enableEachSideIndependent); + layout->addWidget(checkEachSideIndependent); + + StrokeStyleListView* rightStrokeView = new StrokeStyleListView( + std::dynamic_pointer_cast(this->strokePair.second->materialStroke), w + ); + layout->addWidget(rightStrokeView); + rightStrokeView->setDisabled(!this->enableEachSideIndependent); + + QObject::connect(checkEachSideIndependent, &QtMaterialCheckBox::toggled, [this, rightStrokeView](bool toggled) { + this->enableEachSideIndependent = toggled; + rightStrokeView->setDisabled(!toggled); + }); + return w; } QWidget* StrokeElementLayerStyle::getListDisplayWidget() const @@ -47,14 +115,16 @@ QWidget* StrokeElementLayerStyle::getListDisplayWidget() const StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& other) { - materialStyles = std::vector>(other.materialStyles.size()); - for (size_t i = 0; i < other.materialStyles.size(); i++) - { - materialStyles[i] = std::make_shared(*other.materialStyles[i]); - } + strokePair.first = std::dynamic_pointer_cast( + std::shared_ptr(std::move(other.strokePair.first->clone())) + ); + strokePair.second = std::dynamic_pointer_cast( + std::shared_ptr(std::move(other.strokePair.second->clone())) + ); + enableEachSideIndependent = other.enableEachSideIndependent; } -std::unique_ptr StrokeElementLayerStyle::clonePtr() const +std::unique_ptr StrokeElementLayerStyle::clone() const { return std::make_unique(StrokeElementLayerStyle(*this)); } @@ -69,7 +139,7 @@ QString FillElementLayerStyle::getStyleName() const return QStringLiteral("填充"); } -QWidget* FillElementLayerStyle::getInputWidget() const +QWidget* FillElementLayerStyle::getInputWidget() { // TODO QLineEdit* name = new QLineEdit; @@ -97,7 +167,7 @@ FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other) } } -std::unique_ptr FillElementLayerStyle::clonePtr() const +std::unique_ptr FillElementLayerStyle::clone() const { return std::make_unique(FillElementLayerStyle(*this)); } diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index 79a49ec..7d5fb25 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -9,6 +9,9 @@ #include "../Renderer/Painting/MaterialStyleStroke.h" #include "../Renderer/Painting/MaterialStyleFill.h" +using Renderer::MaterialStyle; +using Renderer::MaterialStyleStroke; + /** * 在进行Style的添加时,首先创建空对象,然后直接调用getInputWidget()方法 * 在进行Style的修改时,直接调用getInputWidget()方法 @@ -16,41 +19,45 @@ * 对于LayerStyle的实现类,应该同时实现ElementStyle,并将相同种类的(如描边或填充)的style整合成一个类, * 对于相同的类,一个图层应该只拥有一个 */ -class LayerStyle +class LayerStyle : public Renderer::ElementStyle { public: const static std::vector()>>> types; virtual QString getStyleName() const = 0; - virtual QWidget* getInputWidget() const = 0; + virtual QWidget* getInputWidget() = 0; virtual QWidget* getListDisplayWidget() const = 0; virtual ~LayerStyle() {}; - virtual std::unique_ptr clonePtr() const = 0; + virtual std::unique_ptr clone() const = 0; }; -class StrokeElementLayerStyle : public Renderer::ElementStyle, public LayerStyle +class StrokeElementLayerStyle : public LayerStyle { +private: + std::pair, std::shared_ptr> strokePair; + public: std::vector toBaseStyles() const override; QString getStyleName() const override; - QWidget* getInputWidget() const override; + QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; StrokeElementLayerStyle() = default; StrokeElementLayerStyle(const StrokeElementLayerStyle& other); ~StrokeElementLayerStyle() = default; - std::vector> materialStyles; - std::unique_ptr clonePtr() const override; + std::unique_ptr clone() const override; + + bool enableEachSideIndependent = false; }; -class FillElementLayerStyle : public Renderer::ElementStyle, public LayerStyle +class FillElementLayerStyle : public LayerStyle { public: std::vector toBaseStyles() const override; QString getStyleName() const override; - QWidget* getInputWidget() const override; + QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; FillElementLayerStyle() = default; FillElementLayerStyle(const FillElementLayerStyle& other); ~FillElementLayerStyle() = default; std::vector> materialStyles; - std::unique_ptr clonePtr() const override; + std::unique_ptr clone() const override; }; \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp index 8af376d..371cb86 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp @@ -25,6 +25,7 @@ std::unique_ptr Renderer::StrokePlain::clone() const std::vector Renderer::StrokePlain::encoded() const { + qDebug() << material.color; return { glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(material.toVec().second, 0.f, 0.f))), glm::uintBitsToFloat(glm::packUnorm4x8(material.toVec().first)) }; } diff --git a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp index 471d931..45b700a 100644 --- a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp @@ -75,6 +75,7 @@ std::vector generateStyleBuffer(const std::vector& styles) styleBuffer.push_back(style.transform->scale.y); styleBuffer.push_back(style.transform->rotation); styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip))); + auto encoded = style.material->encoded(); styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end()); qDebug() << "style size" << styleBuffer.size(); From 3b87644e21f40f0a90cf998d4e6e1e7acfbe9e2d Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Wed, 15 Mar 2023 16:16:59 +0800 Subject: [PATCH 10/40] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86PixelPath?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/EditorWidgetItem.cpp | 2 +- .../src/Editor/GraphicElement.cpp | 15 +++++++-- .../src/Editor/GraphicElement.h | 2 +- .../src/Editor/LayerWrapper.cpp | 3 ++ .../src/Editor/PixelPath.cpp | 2 ++ .../src/Editor/PixelPath.h | 2 +- .../src/Editor/util/PaintingUtil.cpp | 14 +++++++-- .../src/Renderer/Model.cpp | 2 +- svg/4_L0.svg | 5 +++ svg/ex.json | 31 +++++++++++++++++++ 10 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 svg/4_L0.svg create mode 100644 svg/ex.json diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp index 0a3f01b..ab1f096 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp @@ -41,7 +41,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p layerManager = new LayerManager(source, elementManager); elementInfoDisplayWidget->setElementManager(elementManager); treeWidget->elementManager = elementManager; - qDebug() << layerManager->toJson(); + //qDebug() << layerManager->toJson(); previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toDouble(),jsonDoc.object().value("height").toDouble())); diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 2775fe5..6be59ff 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -1,11 +1,14 @@ #include "GraphicElement.h" #include "util/SvgFileLoader.h" +#include +#include using namespace std; PixelPath SimpleElement::getPaintObject() const { PixelPath result; result.addPath(painterPath); + qDebug() << result.getPainterPath(); return result; } @@ -48,7 +51,7 @@ PixelPath SimpleElement::getPaintObject(std::vector> std::shared_ptr style; if ((*styles).empty()) { - style = std::make_shared(2); + return this->getPaintObject(); } else { @@ -63,6 +66,7 @@ PixelPath SimpleElement::getPaintObject(std::vector> auto [img, mov] = renderer->drawElement(painterPath, *style, 1.0); //qDebug() << img << " ------"; result.addImage(img, mov); + result.addPath(painterPath); //result.addPath(painterPath); // QImage img(80,80,QImage::Format_ARGB32); // QPainter pt(&img); @@ -124,8 +128,15 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke )->materialMap[1.0].color;*/ } - auto [img, mov] = renderer->drawElement(painterPath, *style, 1.0); + QVector2D scale(transform.m11(), transform.m22()); + scale /= transform.m33(); + double maxScale = std::max(scale.x(), scale.y()); + double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio(); + auto [img, mov] = renderer->drawElement(painterPath, *style, pixelRatio); + painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio)); + //img = img.scaled(img.width() / pixelRatio, img.height() / pixelRatio, Qt::KeepAspectRatio, Qt::SmoothTransformation); painter->drawImage(mov, img); + } painter->restore(); diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index ce54ad7..6e63e92 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -33,7 +33,7 @@ public: class SimpleElement : public GraphicElement { -private: +public: QJsonObject jsonSource; // TODO: 改为ComposedPainterPath QPainterPath painterPath; diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index d5f28e7..8b07e72 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -26,6 +26,7 @@ FolderLayerWrapper*LayerWrapper::getParent() const PixelPath LayerWrapper::getCache(LayerWrapper* selectedLayer) { this->refresh(selectedLayer); + qDebug() << cache.painterPath; if (selectedLayer == this) { this->cache.highLight(); @@ -130,7 +131,9 @@ void LeafLayerWrapper::refresh(LayerWrapper* layer) cache.clear(); if (wrappedElement != nullptr) { + qDebug() << cache.painterPath; cache.addPath(wrappedElement->getPaintObject(&(this->styles))); + qDebug() << cache.painterPath; } LayerWrapper::refresh(); } diff --git a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp index 89f4bbc..c770411 100644 --- a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp +++ b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp @@ -66,6 +66,7 @@ void PixelPath::clear() { pixmap.fill(Qt::transparent); boundingRect = QRectF(0, 0, 0, 0); + painterPath.clear(); } PixelPath PixelPath::trans(QTransform& mat)const @@ -76,6 +77,7 @@ PixelPath PixelPath::trans(QTransform& mat)const painter.setRenderHint(QPainter::HighQualityAntialiasing); painter.setTransform(mat); painter.drawPixmap(0, 0, pixmap); + result.addPath(this->painterPath); result.boundingRect = mat.mapRect(boundingRect); return result; } diff --git a/ArchitectureColoredPainting/src/Editor/PixelPath.h b/ArchitectureColoredPainting/src/Editor/PixelPath.h index a764ce8..ced76ff 100644 --- a/ArchitectureColoredPainting/src/Editor/PixelPath.h +++ b/ArchitectureColoredPainting/src/Editor/PixelPath.h @@ -7,7 +7,7 @@ class PixelPath { -private: +public: QRectF boundingRect; QPixmap pixmap; QPainterPath painterPath; diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp index 07e0224..b863fcd 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp @@ -27,8 +27,15 @@ Painting PaintingUtil::transfromToPainting(QString jsonFilePath) { QTransform transform; glm::bvec2 flip(0, 0); QJsonObject jsonObj = readJsonFile(jsonFilePath); + qDebug() << jsonObj; ElementManager *elementManager = new ElementManager(jsonObj, Renderer::ElementRenderer::instance()); LayerManager* layerManager = new LayerManager(jsonObj, elementManager); + //qDebug() << elementManager->toJson(); + //qDebug() << layerManager->toJson(); + qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath; + qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath; + + traverseLayTree(layerManager->getRoot(), transform, flip, painting); return painting; } @@ -43,6 +50,7 @@ void PaintingUtil::traverseLayTree(LayerWrapper* nowLayer, QTransform transform, transform = nowLayer->property.transform * transform; if (leafLayer != nullptr) { + qDebug() << leafLayer<<"------" << painterPath; Element element; ElementTransform elementTrans; element.ratio = bound.width() / bound.height(); @@ -52,10 +60,10 @@ void PaintingUtil::traverseLayTree(LayerWrapper* nowLayer, QTransform transform, trans.scale(1 / bound.width(), 1 / bound.height()); trans.translate(-bound.center().x(), -bound.center().y()); - element.contour.reset(new vector >(PainterPathUtil::transformToLines(trans.map(painterPath)))); + element.contour = std::make_shared >>(PainterPathUtil::transformToLines(trans.map(painterPath))); QSize screenSize = pixelPath.getPixmap().size(); - //element.style.reset(new Renderer::ElementStyleStrokeDemo(0.06)); - + element.style = std::make_shared(0.06); + painterPath = transform.map(painterPath); bound = painterPath.boundingRect(); diff --git a/ArchitectureColoredPainting/src/Renderer/Model.cpp b/ArchitectureColoredPainting/src/Renderer/Model.cpp index 7496155..917ecc9 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Model.cpp @@ -229,7 +229,7 @@ GLuint Renderer::Model::loadPainting(std::string path) if (iter != paintingLoaded.end()) return iter->second; - Painting painting = PaintingUtil::transfromToPainting("D:\\BigC\\Project\\ArchitectureColoredPainting\\data.json"); + Painting painting = PaintingUtil::transfromToPainting("../data.json"); painting.generateBuffers(glFunc); diff --git a/svg/4_L0.svg b/svg/4_L0.svg new file mode 100644 index 0000000..58facaf --- /dev/null +++ b/svg/4_L0.svg @@ -0,0 +1,5 @@ + + 4_L0 + + + diff --git a/svg/ex.json b/svg/ex.json new file mode 100644 index 0000000..9b3f948 --- /dev/null +++ b/svg/ex.json @@ -0,0 +1,31 @@ +{ + "height": 1080, + "width": 1080, + "elements": [ + { + "name": "ababa", + "type": "svg-file", + "data": { + "include": "./svg/0.svg" + } + } + ], + "root-layer": { + "name": "root", + "transform": { + "offset": { + "x": 0, + "y": 0 + }, + "scale": { + "x": 1.0, + "y": 1.0 + }, + "rotation": 0.0 + }, + "effects": [], + "is-folder": true, + "referenced-by": null, + "children":[] + } +} \ No newline at end of file From fa91d80b709d2ea1b4c908727bcf2f43a84334a8 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Wed, 15 Mar 2023 16:36:46 +0800 Subject: [PATCH 11/40] =?UTF-8?q?=E5=AE=8C=E5=96=84Element=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/GraphicElement.cpp | 20 +++++++++++++++++-- .../src/Editor/GraphicElement.h | 5 ++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 6be59ff..02af86d 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -23,6 +23,7 @@ void SimpleElement::loadSvgFile(const QString& filePath) SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource) { painterPath.clear(); + filePath = jsonSource["data"].toObject()["include"].toString(); //loadSvgFile("D:\\Projects\\BigC\\svg\\3.svg"); loadSvgFile("../"/*TODO: 改成json文件所在文件夹路径*/ + jsonSource.value("data").toObject().value("include").toString()); } @@ -95,10 +96,25 @@ PixelPath GroupElement::getPaintObject(std::vector>* // } //} //TODO : 添加细节 -QJsonObject GraphicElement::toJson() const +QJsonObject SimpleElement::toJson() const { QJsonObject result; - result.insert("name", name); + QJsonObject data; + data["include"] = filePath; + result["type"] = "svg-file"; + result["data"] = data; + result["name"] = name; + return result; +} + +QJsonObject GroupElement::toJson() const +{ + QJsonObject result; + QJsonObject data; + data["reference-layer"] = "0.0"; + result["type"] = "group"; + result["data"] = data; + result["name"] = name; return result; } diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index 6e63e92..f375c63 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -25,7 +25,7 @@ public: QString name = ""; int index; // TODO: 改为BitmapPath - virtual QJsonObject toJson() const; + virtual QJsonObject toJson() const = 0; virtual PixelPath getPaintObject() const = 0; virtual PixelPath getPaintObject(std::vector>*) const = 0; virtual void paint(QPainter* painter, QTransform transform, const std::vector> &styles) = 0; @@ -37,9 +37,11 @@ public: QJsonObject jsonSource; // TODO: 改为ComposedPainterPath QPainterPath painterPath; + QString filePath; void loadSvgFile(const QString& filePath); public: + QJsonObject toJson() const override; SimpleElement(QJsonObject jsonSource); SimpleElement(QString filePath); ~SimpleElement() = default; @@ -54,6 +56,7 @@ public: FolderLayerWrapper* sourceLayer; public: + QJsonObject toJson() const override; GroupElement() = default; GroupElement(FolderLayerWrapper* mSourceLayer); ~GroupElement() = default; From 5d88ddf0ca42cf5af8324c1b6f478fb99aad549f Mon Sep 17 00:00:00 2001 From: "yang.yongquan" <3395816735@qq.com> Date: Wed, 15 Mar 2023 17:37:12 +0800 Subject: [PATCH 12/40] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E7=9A=84=E6=A7=BD=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/ElementPoolWidget.cpp | 10 +++ .../src/Editor/ElementPoolWidget.h | 1 + .../src/Editor/util/PaintingUtil.cpp | 81 +++++++++++++------ .../src/Editor/util/PaintingUtil.h | 2 +- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp index 64fadfd..1c5dc3c 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp @@ -78,4 +78,14 @@ void ElementPoolWidget::setElementManager(ElementManager* element) void ElementPoolWidget::refresh() { this->setElementList(this->elementManager->elements); // update(); +} + +void ElementPoolWidget::refreshPicture(GraphicElement* element) { + for (int i = 0; i < elements.size(); i++) { + if (element == elements[i]) { + pictureList->item(i)->setIcon(element->getPaintObject().getDetail().scaled(QSize(iconWidth - 25, iconHeight - 25))); + // update(); + return; + } + } } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h index 2a880a7..f6c253e 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h @@ -28,5 +28,6 @@ signals: public slots: int pictureItemClicked(QListWidgetItem* item); void refresh(); + void refreshPicture(GraphicElement* element); }; diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp index b863fcd..7c66c24 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp @@ -2,16 +2,26 @@ #include #include #include "PainterPathUtil.h" +#include using Renderer::Painting; using Renderer::Element; using Renderer::ElementTransform; using glm::bvec2; using std::max; +using std::shared_ptr; +using std::make_shared; using std::min; +using std::queue; const double PaintingUtil::pi = acos(-1); +struct LayerNode { + LayerWrapper* nowLayer; + QTransform transfrom; + bvec2 flip; +}; + QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) { QFile jsonFile(jsonFilePath); jsonFile.open(QFile::ReadOnly); @@ -28,29 +38,47 @@ Painting PaintingUtil::transfromToPainting(QString jsonFilePath) { glm::bvec2 flip(0, 0); QJsonObject jsonObj = readJsonFile(jsonFilePath); qDebug() << jsonObj; - ElementManager *elementManager = new ElementManager(jsonObj, Renderer::ElementRenderer::instance()); - LayerManager* layerManager = new LayerManager(jsonObj, elementManager); + shared_ptr elementManager = make_shared(jsonObj, Renderer::ElementRenderer::instance()); + shared_ptr layerManager = make_shared(jsonObj, elementManager.get()); //qDebug() << elementManager->toJson(); //qDebug() << layerManager->toJson(); - qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath; - qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath; - - - traverseLayTree(layerManager->getRoot(), transform, flip, painting); + //qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath; + //qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath; + queue layerQueue; + LayerWrapper* root = layerManager->getRoot(); + root->getCache(); + layerQueue.push({ root, transform, flip }); + while (!layerQueue.empty()) { + auto layerNode = layerQueue.front(); + layerQueue.pop(); + FolderLayerWrapper* nowLayer = handleLayerWrapper(layerNode.nowLayer, layerNode.transfrom, layerNode.flip, painting); + if (nowLayer != nullptr) { + for (auto sonLayer : nowLayer->children) { + layerQueue.push({ sonLayer.get(), layerNode.transfrom, layerNode.flip}); + } + } + } + return painting; } -void PaintingUtil::traverseLayTree(LayerWrapper* nowLayer, QTransform transform, bvec2 flip, Painting& painting) { +FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTransform& transform, bvec2& flip, Painting& painting) { LeafLayerWrapper* leafLayer = dynamic_cast(nowLayer); - PixelPath pixelPath = nowLayer->getCache(); - QPainterPath painterPath = pixelPath.getPainterPath(); - QRectF bound = painterPath.boundingRect(); flip ^= bvec2(nowLayer->property.flipHorizontally, nowLayer->property.flipVertically); transform = nowLayer->property.transform * transform; if (leafLayer != nullptr) { - qDebug() << leafLayer<<"------" << painterPath; + + GroupElement* wrapperElement = dynamic_cast(leafLayer->wrappedElement); + if (wrapperElement != nullptr) + return wrapperElement->sourceLayer; + + PixelPath pixelPath = nowLayer->getCache(); + QPainterPath painterPath = pixelPath.getPainterPath(); + QRectF bound = painterPath.boundingRect(); + //qDebug() << leafLayer<<"------" << painterPath; + //qDebug() << transform; Element element; ElementTransform elementTrans; element.ratio = bound.width() / bound.height(); @@ -60,36 +88,40 @@ void PaintingUtil::traverseLayTree(LayerWrapper* nowLayer, QTransform transform, trans.scale(1 / bound.width(), 1 / bound.height()); trans.translate(-bound.center().x(), -bound.center().y()); + qDebug() << trans.map(painterPath); element.contour = std::make_shared >>(PainterPathUtil::transformToLines(trans.map(painterPath))); QSize screenSize = pixelPath.getPixmap().size(); element.style = std::make_shared(0.06); painterPath = transform.map(painterPath); + qDebug() << painterPath; bound = painterPath.boundingRect(); + qDebug() << bound; elementTrans.center = glm::vec2( - (bound.center().x() - screenSize.width()) / screenSize.width(), - (bound.center().y() - screenSize.height()) / screenSize.height() + (2 * bound.center().x() - screenSize.width()) / screenSize.width(), + (2 * bound.center().y() - screenSize.height()) / screenSize.height() ); + qDebug() << elementTrans.center.x << elementTrans.center.y; decomposeTransform(transform, elementTrans.rotation, elementTrans.scale); + elementTrans.scale = glm::vec2( + bound.width() / screenSize.width(), + bound.height() / screenSize.height() + ); elementTrans.flip = glm::bvec2( nowLayer->property.flipHorizontally, nowLayer->property.flipVertically ); + qDebug() << elementTrans.scale.x << elementTrans.scale.y; painting.addElement(element, elementTrans); - return; + return nullptr; } FolderLayerWrapper* folderLayer = dynamic_cast(nowLayer); - if (folderLayer != nullptr) { - for (auto sonLayer : folderLayer->children) { - traverseLayTree(sonLayer.get(), transform, flip, painting); - } - } - return; + return folderLayer; } void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2& scale) { - qDebug() << trans; + //qDebug() << trans; trans.setMatrix( trans.m11(), trans.m12(), trans.m13(), trans.m21(), trans.m22(), trans.m23(), @@ -134,7 +166,8 @@ void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2& angle = 360 - angle; } qDebug() << angle; - R = R.inverted() * trans; - scale = glm::vec2(R.m11(), R.m22()); + //R = R.inverted() * trans; + //scale = glm::vec2(R.m11(), R.m22()); + //qDebug() << scale.x << scale.y; return; } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h index 35ebe03..77e6ea2 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.h @@ -7,7 +7,7 @@ class PaintingUtil private: static const double pi; static QJsonObject readJsonFile(QString jsonFilePath); - static void traverseLayTree(LayerWrapper* nowLayer, QTransform transform, glm::bvec2 flip, Renderer::Painting& painting); + static FolderLayerWrapper* handleLayerWrapper(LayerWrapper* nowLayer, QTransform& transform, glm::bvec2& flip, Renderer::Painting& painting); public: static Renderer::Painting transfromToPainting(QString jsonFilePath); static void decomposeTransform(QTransform trans, float& angle, glm::vec2& scale); From 3abc0d9bcdf5858c5c12f698022e4b347642b823 Mon Sep 17 00:00:00 2001 From: wuyize Date: Wed, 15 Mar 2023 19:24:33 +0800 Subject: [PATCH 13/40] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90json?= =?UTF-8?q?=E5=88=B0Painting=E7=9A=84=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/Shaders/painting.comp | 6 +++--- .../res/Shaders/painting.vert | 1 + .../src/Editor/util/PaintingUtil.cpp | 13 +++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp index 50a32b8..c0af01c 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.comp +++ b/ArchitectureColoredPainting/res/Shaders/painting.comp @@ -1352,8 +1352,8 @@ void main() vec3 debugBVH = vec3(0); // bool debugHit = false; - vec4 color = vec4(0.76, 0.33, 0.15, -1); - // vec4 color = vec4(1,1,1, -1); + //vec4 color = vec4(0.76, 0.33, 0.15, -1); + vec4 color = vec4(1,1,1, -1); vec2 metallicRoughness = vec2(0, 0.8); stack.top = 0; uint index = 0, visitTime = 0; @@ -1423,7 +1423,7 @@ void main() imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1)); imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1)); - //return; + return; if (/*color.a!=-1&&*/ debugBVH == vec3(0)) { // imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1)); diff --git a/ArchitectureColoredPainting/res/Shaders/painting.vert b/ArchitectureColoredPainting/res/Shaders/painting.vert index f294dc6..9c5f22f 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.vert +++ b/ArchitectureColoredPainting/res/Shaders/painting.vert @@ -14,6 +14,7 @@ uniform mat4 projection; void main() { TexCoords = aTexCoords; + TexCoords.y = -TexCoords.y; WorldPos = vec3(model * vec4(aPos, 1.0)); Normal = mat3(model) * aNormal; diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp index 7c66c24..8c4ec74 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp @@ -34,7 +34,6 @@ QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) { Painting PaintingUtil::transfromToPainting(QString jsonFilePath) { Painting painting; - QTransform transform; glm::bvec2 flip(0, 0); QJsonObject jsonObj = readJsonFile(jsonFilePath); qDebug() << jsonObj; @@ -47,7 +46,7 @@ Painting PaintingUtil::transfromToPainting(QString jsonFilePath) { queue layerQueue; LayerWrapper* root = layerManager->getRoot(); root->getCache(); - layerQueue.push({ root, transform, flip }); + layerQueue.push({ root, root->property.transform, flip }); while (!layerQueue.empty()) { auto layerNode = layerQueue.front(); layerQueue.pop(); @@ -71,8 +70,10 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr if (leafLayer != nullptr) { GroupElement* wrapperElement = dynamic_cast(leafLayer->wrappedElement); - if (wrapperElement != nullptr) + if (wrapperElement != nullptr) { + transform = wrapperElement->sourceLayer->property.transform * transform; return wrapperElement->sourceLayer; + } PixelPath pixelPath = nowLayer->getCache(); QPainterPath painterPath = pixelPath.getPainterPath(); @@ -90,7 +91,7 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr qDebug() << trans.map(painterPath); element.contour = std::make_shared >>(PainterPathUtil::transformToLines(trans.map(painterPath))); - QSize screenSize = pixelPath.getPixmap().size(); + QSize screenSize = QSize(1024, 1024); element.style = std::make_shared(0.06); @@ -105,8 +106,8 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr qDebug() << elementTrans.center.x << elementTrans.center.y; decomposeTransform(transform, elementTrans.rotation, elementTrans.scale); elementTrans.scale = glm::vec2( - bound.width() / screenSize.width(), - bound.height() / screenSize.height() + bound.width() * 2 / screenSize.width(), + bound.height() * 2 / screenSize.height() ); elementTrans.flip = glm::bvec2( nowLayer->property.flipHorizontally, From c234c0e9b321b3598358ef53474c7ebe7e3802b9 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Wed, 15 Mar 2023 20:10:14 +0800 Subject: [PATCH 14/40] =?UTF-8?q?=E5=AE=9E=E7=8E=B0element=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=BB=9A=E5=8A=A8=E6=9D=A1?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E7=A9=BA=E7=99=BD=E6=89=93=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EditorWidgetItem.ui | 98 +++++++++++++++---- .../src/Editor/EditorWidget.cpp | 3 +- .../src/Editor/EditorWidgetItem.cpp | 3 +- .../src/Editor/ElementManager.cpp | 1 + .../src/Editor/ElementPoolWidget.cpp | 53 +++++++++- .../src/Editor/ElementPoolWidget.h | 2 + .../src/Editor/GraphicElement.cpp | 3 +- .../src/Editor/LayerWrapper.cpp | 3 - .../src/Editor/PixelPath.h | 4 +- .../src/Editor/PreviewWindow.cpp | 3 +- .../src/Editor/RightBar/LayerTreeWidget.cpp | 14 +-- data.json | 9 +- 12 files changed, 160 insertions(+), 36 deletions(-) diff --git a/ArchitectureColoredPainting/EditorWidgetItem.ui b/ArchitectureColoredPainting/EditorWidgetItem.ui index aea28b0..73f9357 100644 --- a/ArchitectureColoredPainting/EditorWidgetItem.ui +++ b/ArchitectureColoredPainting/EditorWidgetItem.ui @@ -37,38 +37,87 @@ - - - 0 - - - 0 - - - 0 - - - 0 - + - + + + + 0 + 0 + + - 1080 - 1080 + 0 + 0 - 1080 - 1080 + 10801080 + 10801080 + + true + + + + + 0 + 0 + 1024 + 1024 + + + + + 0 + 0 + + + + + 1024 + 1024 + + + + + 10241024 + 10241024 + + + + + + + + 0 + 0 + + + + + 1024 + 1024 + + + + + 1024 + 1024 + + + + + + @@ -138,6 +187,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp index 2c990de..b51987b 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp @@ -24,7 +24,8 @@ EditorWidget::EditorWidget(QWidget* parent) : QWidget(parent) }); connect(this->openButton, &QPushButton::clicked, this, [this]() { QString fileName = QFileDialog::getOpenFileName(this->saveAsButton, QString::fromLocal8Bit("打开"), "", QString::fromLocal8Bit("JSON文件(*.json)")); - this->tabWidget->addTab(new EditorWidgetItem(fileName, this), fileName); + if(!fileName.isEmpty()) + this->tabWidget->addTab(new EditorWidgetItem(fileName, this), fileName); }); connect(this->closeButton, &QPushButton::clicked, this, [this]() { this->tabWidget->removeTab(this->tabWidget->currentIndex()); diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp index ab1f096..9525287 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp @@ -12,6 +12,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p this->filePath = filePath; layerInfoDisplayWidget = dynamic_cast(tabWidget->widget(0)); elementInfoDisplayWidget = dynamic_cast(tabWidget->widget(1)); + elementInfoDisplayWidget->enableEdit(); qDebug() << layerInfoDisplayWidget; qDebug() << elementInfoDisplayWidget; connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); @@ -37,7 +38,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p qDebug() << jError.errorString(); // end test QJsonObject source = jsonDoc.object(); - elementManager = new ElementManager(source,previewWindow->getRenderer()); + elementManager = new ElementManager(source,Renderer::ElementRenderer::instance()); layerManager = new LayerManager(source, elementManager); elementInfoDisplayWidget->setElementManager(elementManager); treeWidget->elementManager = elementManager; diff --git a/ArchitectureColoredPainting/src/Editor/ElementManager.cpp b/ArchitectureColoredPainting/src/Editor/ElementManager.cpp index daed263..7b5b80c 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementManager.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementManager.cpp @@ -97,6 +97,7 @@ void ElementManager::createSimpleElement(QString name, QString filePath) { data.insert("include", filePath); json.insert("data", data); auto element = new SimpleElement(json); + qDebug() << element->painterPath; element->name = name; addElement(element); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp index 1c5dc3c..0ec51b0 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp @@ -1,11 +1,16 @@ #include "ElementPoolWidget.h" +#include +#include +#include +#include ElementPoolWidget::ElementPoolWidget(QWidget* parent) : QWidget(parent) { elementManager = nullptr; iconWidth = 120, iconHeight = 90; - pictureList = new QListWidget(); + pictureList = new QListWidget(this); + pictureList->setContextMenuPolicy(Qt::CustomContextMenu); pictureList->setIconSize(QSize(iconWidth, iconHeight)); pictureList->setWindowFlags(Qt::FramelessWindowHint); pictureList->setResizeMode(QListWidget::Adjust); @@ -88,4 +93,50 @@ void ElementPoolWidget::refreshPicture(GraphicElement* element) { return; } } +} + +void ElementPoolWidget::enableEdit() +{ + connect(this->pictureList, &QListWidget::customContextMenuRequested, this, &ElementPoolWidget::popMenu); +} + +void ElementPoolWidget::popMenu(const QPoint& pos) +{ + QListWidgetItem* item = pictureList->itemAt(pos); + int currentIndex = -1; + if (item != nullptr) + { + currentIndex = pictureList->row(item); + } + QMenu* menu = new QMenu(this); + if (currentIndex >= 0 && currentIndex < elementManager->elements.size()) + { + auto currentElement = this->elementManager->elements[currentIndex]; + menu->addAction(QString::fromLocal8Bit("重命名"), this, [this, currentElement]() { + bool bOk = false; + QString sName = + QInputDialog::getText(this, QString::fromLocal8Bit("重命名"), QString::fromLocal8Bit("新名称:"), QLineEdit::Normal, currentElement->name, &bOk); + if (bOk && !sName.isEmpty()) + { + currentElement->name = sName; + refresh(); + } + }); + menu->addAction(QString::fromLocal8Bit("删除"), this, [this, currentElement]() { + this->elementManager->removeElement(currentElement); + refresh(); + }); + } + else + { + menu->addAction(QString::fromLocal8Bit("添加元素(从svg导入)"), this, [this]() { + QString filePath = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("打开文件"), "", "SVG Files (*.svg)"); + QFileInfo fileInfo(filePath); + QString fileName = fileInfo.fileName(); + qDebug() << fileName << " " << filePath; + this->elementManager->createSimpleElement(fileName, filePath); + refresh(); + }); + } + menu->popup(mapToGlobal(pos)); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h index f6c253e..d4c9cef 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h @@ -21,6 +21,7 @@ public: void setElementList(std::vector elementList); void setElementManager(ElementManager* element); ~ElementPoolWidget(); + void enableEdit(); signals: void elementSelected(GraphicElement* element); @@ -29,5 +30,6 @@ public slots: int pictureItemClicked(QListWidgetItem* item); void refresh(); void refreshPicture(GraphicElement* element); + void popMenu(const QPoint& pos); }; diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 02af86d..36f81dc 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -25,7 +25,8 @@ SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource) painterPath.clear(); filePath = jsonSource["data"].toObject()["include"].toString(); //loadSvgFile("D:\\Projects\\BigC\\svg\\3.svg"); - loadSvgFile("../"/*TODO: 改成json文件所在文件夹路径*/ + jsonSource.value("data").toObject().value("include").toString()); + QFileInfo info(filePath); + loadSvgFile(filePath); } GroupElement::GroupElement(FolderLayerWrapper* sourceLayer) diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 8b07e72..d5f28e7 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -26,7 +26,6 @@ FolderLayerWrapper*LayerWrapper::getParent() const PixelPath LayerWrapper::getCache(LayerWrapper* selectedLayer) { this->refresh(selectedLayer); - qDebug() << cache.painterPath; if (selectedLayer == this) { this->cache.highLight(); @@ -131,9 +130,7 @@ void LeafLayerWrapper::refresh(LayerWrapper* layer) cache.clear(); if (wrappedElement != nullptr) { - qDebug() << cache.painterPath; cache.addPath(wrappedElement->getPaintObject(&(this->styles))); - qDebug() << cache.painterPath; } LayerWrapper::refresh(); } diff --git a/ArchitectureColoredPainting/src/Editor/PixelPath.h b/ArchitectureColoredPainting/src/Editor/PixelPath.h index ced76ff..5ab8614 100644 --- a/ArchitectureColoredPainting/src/Editor/PixelPath.h +++ b/ArchitectureColoredPainting/src/Editor/PixelPath.h @@ -13,8 +13,8 @@ public: QPainterPath painterPath; int w,h; public: - PixelPath(int w=1080, int h= 1080); - PixelPath(QPainterPath painterPath,int w = 1080, int h = 1080); + PixelPath(int w=1024, int h= 1024); + PixelPath(QPainterPath painterPath,int w = 1024, int h = 1024); ~PixelPath() = default; QRectF getBoundingRect() const; QPixmap getPixmap() const; diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp index 485977d..9fb8060 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp @@ -2,7 +2,8 @@ PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent) { - this->setFixedSize(QSize(1080, 1080)); + //this->setFixedSize(QSize(108, 108)); + this->setStyleSheet("border: 1px solid black"); this->renderer = Renderer::ElementRenderer::instance(); QSurfaceFormat surfaceFormat; surfaceFormat.setSamples(16); diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index 1e84c88..a27da25 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -68,13 +68,6 @@ void LayerTreeWidget::popMenu(const QPoint &pos) }); dialog->exec(); }); - menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() { - auto layer = this->selectedItem->data(0, Qt::UserRole).value(); - layer->delSelf(); - layer->getParent()->removeChild(layer); - this->refresh(); - emit requireRefreshPreview(); - }); } if (layer != root) { menu.addAction(QString::fromLocal8Bit("删除"), this, [this]() { @@ -85,6 +78,13 @@ void LayerTreeWidget::popMenu(const QPoint &pos) emit requireRefreshPreview(); }); menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent); + menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() { + auto layer = this->selectedItem->data(0, Qt::UserRole).value(); + layer->delSelf(); + layer->getParent()->removeChild(layer); + this->refresh(); + emit requireRefreshPreview(); + }); } if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) { menu.addAction(QString::fromLocal8Bit("创建组合元素"), this, [this]() { diff --git a/data.json b/data.json index 150cb6c..4f381cb 100644 --- a/data.json +++ b/data.json @@ -6,7 +6,7 @@ "name": "ababa", "type": "svg-file", "data": { - "include": "./svg/2.svg" + "include": "../svg/2.svg" } }, { @@ -15,6 +15,13 @@ "data": { "reference-layer": "0.0" } + }, + { + "name": "ababa2", + "type": "svg-file", + "data": { + "include": "../svg/0.svg" + } } ], "root-layer": { From 70d5973a90cb50617ffa668bbde367f124130dde Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Wed, 15 Mar 2023 21:04:21 +0800 Subject: [PATCH 15/40] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86yyq=E9=BB=84?= =?UTF-8?q?=E8=89=B2=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ArchitectureColoredPainting/src/Editor/PixelPath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp index c770411..3087f39 100644 --- a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp +++ b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp @@ -77,7 +77,7 @@ PixelPath PixelPath::trans(QTransform& mat)const painter.setRenderHint(QPainter::HighQualityAntialiasing); painter.setTransform(mat); painter.drawPixmap(0, 0, pixmap); - result.addPath(this->painterPath); + result.painterPath.addPath(this->painterPath); result.boundingRect = mat.mapRect(boundingRect); return result; } From 89034197990cc185ea400b48ce5175d3289bc8b1 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Wed, 15 Mar 2023 21:04:21 +0800 Subject: [PATCH 16/40] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86zt=E9=BB=84?= =?UTF-8?q?=E8=89=B2=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ArchitectureColoredPainting/src/Editor/PixelPath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp index c770411..3087f39 100644 --- a/ArchitectureColoredPainting/src/Editor/PixelPath.cpp +++ b/ArchitectureColoredPainting/src/Editor/PixelPath.cpp @@ -77,7 +77,7 @@ PixelPath PixelPath::trans(QTransform& mat)const painter.setRenderHint(QPainter::HighQualityAntialiasing); painter.setTransform(mat); painter.drawPixmap(0, 0, pixmap); - result.addPath(this->painterPath); + result.painterPath.addPath(this->painterPath); result.boundingRect = mat.mapRect(boundingRect); return result; } From 78c24ad373f997f1138c2e2645c253d89aaeb4ae Mon Sep 17 00:00:00 2001 From: wuyize Date: Wed, 15 Mar 2023 22:43:51 +0800 Subject: [PATCH 17/40] =?UTF-8?q?FIX:=20painting=E6=B8=B2=E6=9F=93bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/Shaders/painting.comp | 6 +- .../res/Shaders/painting.frag | 6 -- .../res/Shaders/painting.vert | 1 - .../src/Renderer/Model.cpp | 100 +++++++++++++++++- 4 files changed, 101 insertions(+), 12 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp index c0af01c..3e8ede4 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.comp +++ b/ArchitectureColoredPainting/res/Shaders/painting.comp @@ -1149,7 +1149,7 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point p[2] *= ratio; p[3] *= ratio; - vec2 tangentBeginNext; + vec2 tangentBeginNext = vec2(0); if (contourIterator + 1 < contourIndex + 1 + lineCount) { uint lineIndex = elementIndexs[contourIterator + 1]; @@ -1217,10 +1217,10 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point bool hit = d < minDistance; if (onBegin) hit = - hit && shouldFillBeginCap(localUV, percent[0] < 1e-5, endType, p[0], tangentBegin, p3Last - p2Last); + hit && shouldFillBeginCap(localUV, contourIterator == contourIndex + 1, endType, p[0], tangentBegin, p3Last - p2Last); if (onEnd) hit = hit && - shouldFillEndCap(localUV, percent[1] > 1 - 1e-5, endType, p[3], tangentEnd, tangentBeginNext); + shouldFillEndCap(localUV, tangentBeginNext==vec2(0), endType, p[3], tangentEnd, tangentBeginNext); if (hit) { diff --git a/ArchitectureColoredPainting/res/Shaders/painting.frag b/ArchitectureColoredPainting/res/Shaders/painting.frag index 5fed343..4f69ed9 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.frag +++ b/ArchitectureColoredPainting/res/Shaders/painting.frag @@ -36,11 +36,6 @@ void main() lod++; gMetallicRoughness = mt.rg; -// int pageSize = textureSize(texture_basecolor, levels-1).x; - -// uint pageId = 0; -// for(uint i = 0; i < lodExpect; i++) -// pageId += 1<<(2*(levels-1-i)); uint w = 1<<(levels-1-lodExpect); ivec2 page = ivec2(TexCoords * vec2(w)); page = clamp(page, ivec2(0), ivec2(w-1)); @@ -49,7 +44,6 @@ void main() gPaintingIndex = uvec2(0); else gPaintingIndex = uvec2((paintingId<<4)+lodExpect, (page.y<<8)+page.x); - gPaintingTexCoord = vec2(1., 1.) - TexCoords * 2; return; } \ No newline at end of file diff --git a/ArchitectureColoredPainting/res/Shaders/painting.vert b/ArchitectureColoredPainting/res/Shaders/painting.vert index 9c5f22f..f294dc6 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.vert +++ b/ArchitectureColoredPainting/res/Shaders/painting.vert @@ -14,7 +14,6 @@ uniform mat4 projection; void main() { TexCoords = aTexCoords; - TexCoords.y = -TexCoords.y; WorldPos = vec3(model * vec4(aPos, 1.0)); Normal = mat3(model) * aNormal; diff --git a/ArchitectureColoredPainting/src/Renderer/Model.cpp b/ArchitectureColoredPainting/src/Renderer/Model.cpp index 917ecc9..4f62c3b 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Model.cpp @@ -52,7 +52,7 @@ void Renderer::Model::loadModel(QString path) directory = modelFile.dir(); Assimp::Importer importer; - const aiScene* scene = importer.ReadFile(modelFile.absoluteFilePath().toUtf8(), aiProcess_Triangulate /*| aiProcess_FlipUVs*/); + const aiScene* scene = importer.ReadFile(modelFile.absoluteFilePath().toUtf8(), aiProcess_Triangulate); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { qCritical() << "ERROR::ASSIMP::" << importer.GetErrorString() << endl; @@ -229,8 +229,104 @@ GLuint Renderer::Model::loadPainting(std::string path) if (iter != paintingLoaded.end()) return iter->second; - Painting painting = PaintingUtil::transfromToPainting("../data.json"); + Painting painting; + if (auto file = QFileInfo(QString(path.c_str())); file.isFile()) + painting = PaintingUtil::transfromToPainting(file.path()); + else + { + qDebug() << path.c_str() << "Not Found, Using Default Painting"; + vector, float>> contours; + QPainterPath painterPaths[3]; + QQuickSvgParser::parsePathDataFast("M100,100C-.5,100,0,100.5,0,0L40,.07C40,59.5,39.5,60,100,60Z", + painterPaths[0]); + if (!SvgFileLoader().loadSvgFile("../svg/2.svg", painterPaths[1])) + qCritical() << "load error"; + /*QQuickSvgParser::parsePathDataFast("M292.82,107.78s0,0,0,0,0,3.59,0,7.62c0,3.85,0,5.78.06,6.43a19.94,19.94,0,0,0,2.87,7.58,15.85,15.85,0,0,0,6.61,6.23A14.75,14.75,0,0,0,310,137a11.69,11.69,0,0,0,7.59-2.92,11,11,0,0,0,3.2-6.84c.15-1.27.58-4.84-1.79-7.64a8.54,8.54,0,0,0-3.56-2.44c-1.32-.52-3.32-1.31-5.06-.33a5.41,5.41,0,0,0-2.14,3,3.48,3.48,0,0,0-.16,2.71c.78,1.86,3.36,2.14,3.47,2.15", + painterPaths[1]);*/ + QQuickSvgParser::parsePathDataFast("M377,459.61a11.26,11.26,0,0,1,11.27-11.27H696.12a11.27,11.27,0,0,0,11-8.62A359.84,359.84,0,0,0,708,280.56a11.26,11.26,0,0,0-11-8.73H388.27A11.26,11.26,0,0,1,377,260.57h0a11.26,11.26,0,0,1,11.27-11.26H683.71A11.32,11.32,0,0,0,694.28,234C649.8,113.69,542.57,23.85,412.3,4.12a11.22,11.22,0,0,0-12.76,11.17v158.9a11.26,11.26,0,0,0,11.26,11.27H583.12a11.32,11.32,0,0,0,9.26-17.75c-31.67-46.59-78.51-75.2-109.11-90.07a11.25,11.25,0,0,0-16.13,10.17V115.2a11.24,11.24,0,0,0,6.22,10.07l7.51,3.76a11.28,11.28,0,0,1,5,15.12h0a11.27,11.27,0,0,1-15.11,5l-20-10a11.27,11.27,0,0,1-6.22-10.07V54a11.27,11.27,0,0,1,14.62-10.75c5.11,1.59,125.66,40.35,172.24,149A11.27,11.27,0,0,1,621.11,208H388.27A11.26,11.26,0,0,1,377,196.73V11.36A11.32,11.32,0,0,0,365.89.08C363.34,0,360.79,0,358.22,0s-5.11,0-7.66.08a11.32,11.32,0,0,0-11.11,11.28V196.74A11.26,11.26,0,0,1,328.18,208H95.35A11.27,11.27,0,0,1,85,192.3c46.57-108.67,167.12-147.42,172.23-149A11.26,11.26,0,0,1,271.86,54v75.11a11.25,11.25,0,0,1-6.23,10.07l-20,10a11.27,11.27,0,0,1-15.11-5h0a11.26,11.26,0,0,1,5-15.11l7.52-3.76a11.27,11.27,0,0,0,6.22-10.07V87.82a11.25,11.25,0,0,0-16.14-10.16c-30.6,14.87-77.45,43.48-109.1,90.07a11.3,11.3,0,0,0,9.25,17.74H305.66a11.26,11.26,0,0,0,11.27-11.26V15.31A11.22,11.22,0,0,0,304.17,4.14C173.88,23.86,66.66,113.71,22.17,234a11.32,11.32,0,0,0,10.56,15.29H328.18a11.26,11.26,0,0,1,11.27,11.26v0a11.26,11.26,0,0,1-11.27,11.26H19.52a11.26,11.26,0,0,0-11,8.72,359.84,359.84,0,0,0,.83,159.16,11.26,11.26,0,0,0,11,8.61H328.18a11.26,11.26,0,0,1,11.27,11.27h0a11.26,11.26,0,0,1-11.27,11.26h-294a11.32,11.32,0,0,0-10.53,15.4C69,604.65,175.3,692.78,304.16,712.3a11.21,11.21,0,0,0,12.76-11.16V542.22A11.26,11.26,0,0,0,305.66,531h-166c-9.53,0-14.89,11.22-8.69,18.47,34.09,39.77,74.45,65.66,101.77,80.18a11.25,11.25,0,0,0,16.53-10V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,271.85,591v63.85A11.27,11.27,0,0,1,256.8,665.5c-4.45-1.59-109.58-40-171-139.9a11.27,11.27,0,0,1,9.59-17.17H328.18a11.26,11.26,0,0,1,11.27,11.26V705.08a11.32,11.32,0,0,0,11.11,11.28q3.82.07,7.66.08c2.57,0,5.12,0,7.67-.08A11.32,11.32,0,0,0,377,705.08V519.69a11.25,11.25,0,0,1,11.27-11.26H621.1a11.26,11.26,0,0,1,9.59,17.16c-61.46,99.87-166.59,138.3-171,139.9a11.27,11.27,0,0,1-15-10.61V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,467.14,591v28.6a11.25,11.25,0,0,0,16.53,10c27.33-14.53,67.68-40.42,101.77-80.19,6.2-7.23.85-18.46-8.69-18.46h-166a11.26,11.26,0,0,0-11.26,11.26V701.12a11.21,11.21,0,0,0,12.76,11.17c128.86-19.51,235.14-107.66,280.48-226a11.33,11.33,0,0,0-10.53-15.41h-294A11.25,11.25,0,0,1,377,459.61ZM35.27,399.53V316.9a11.26,11.26,0,0,1,11.27-11.26H669.92a11.25,11.25,0,0,1,11.26,11.26v82.63a11.25,11.25,0,0,1-11.26,11.26H46.54a11.27,11.27,0,0,1-11.27-11.26Z", + painterPaths[2]); + + for (auto& i : painterPaths) + { + auto [contour, ratio] = PainterPathUtil::toNormalizedLines(i); + contours.emplace_back(std::make_shared(contour), ratio); + } + + vector> style = { + std::make_shared(), + std::make_shared(0.02), + std::make_shared(0.2) + }; + + vector> element = { + std::make_shared(Element{ contours[0].first, style[0], contours[0].second}), + std::make_shared(Element{ contours[1].first, style[2], contours[1].second}), + std::make_shared(Element{ contours[2].first, style[0], contours[2].second}), + }; + + if (path == "0.json") + { + painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,-0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); + painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45, 0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); + painting.addElement(*element[2], ElementTransform{ glm::vec2(0.50,-0.45), glm::vec2(0.6,0.7) / 2.f, 0, glm::bvec2(false), 0 }); + } + else if (path == "1.json") + { + float widths[] = { 0.43, 0.43 * 0.25 / 0.15, 0.43 * 0.25 / 0.15 }; + QPainterPath painterPaths[6]; + for (int i = 0; i < 6; i++) + if (!SvgFileLoader().loadSvgFile(QString(std::format("../svg/{}.svg", i + 1).c_str()), painterPaths[i])) + qCritical() << "load error"; + + vector, float>> contours; + for (int i = 0; i < 3; i++) + { + auto [contour, ratio] = PainterPathUtil::toNormalizedLines(painterPaths[i], widths[i]); + contours.emplace_back(std::make_shared(contour), ratio); + } + class StyleStrokeRadialGradient : public Renderer::ElementStyle + { + public: + float width; + StrokeType type; + StyleStrokeRadialGradient(float width, StrokeType type) :width(width), type(type) {}; + virtual std::vector toBaseStyles() const override + { + std::map materialMap = { + {0.09, Material{QColor(255,255,255),0,0.8}}, + {0.63, Material{QColor(165,176,207),0,0.8}}, + {1.00, Material{QColor(58,64,151),0,0.8}} + }; + return { BaseStyle(std::make_shared(), + std::make_shared(width, type, StrokeEndType::kFlat, + std::make_shared(materialMap, false))) }; + } + }; + vector> style = { + std::make_shared(widths[0], StrokeType::kLeftSide), + std::make_shared(widths[1], StrokeType::kRightSide), + std::make_shared(widths[2], StrokeType::kLeftSide), + }; + vector> element = { + std::make_shared(Element{ contours[0].first, style[0], contours[0].second}), + std::make_shared(Element{ contours[1].first, style[1], contours[1].second}), + std::make_shared(Element{ contours[2].first, style[2], contours[2].second}), + }; + painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,0.45), glm::vec2(0.25), 0, glm::bvec2(false), 0 }); + painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.535,0.33), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); + painting.addElement(*element[2], ElementTransform{ glm::vec2(-0.535,0.23), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); + } + else + { + for (int i = 0; i < 1000; i++) + { + float x = (float)rand() / RAND_MAX * 2 - 1; + float y = (float)rand() / RAND_MAX * 2 - 1; + painting.addElement(*element[i % 3], ElementTransform{ glm::vec2(x,y), glm::vec2(0.025), (float)rand() / RAND_MAX * 360, glm::bvec2(false), 0 }); + } + } + } painting.generateBuffers(glFunc); auto index = vtManager->createVirtualTexture(painting); From 03a06ce426232cd28351516ac5012c22dfd9f60e Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Thu, 16 Mar 2023 02:13:25 +0800 Subject: [PATCH 18/40] =?UTF-8?q?[editor/style]=20=E8=BF=9B=E4=B8=80?= =?UTF-8?q?=E6=AD=A5=E5=AE=8C=E5=96=84StrokeStyle=E7=9B=B8=E5=85=B3=20[str?= =?UTF-8?q?oke]=20=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90StrokeStyle=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=20[editor/util]=20=E6=96=B0=E5=A2=9EJsonUtil?= =?UTF-8?q?=20[stroke]=20=E5=AE=8C=E6=88=90=E6=B7=BB=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=B1=82=E6=8F=8F=E8=BE=B9=E5=8A=9F=E8=83=BD=20[stroke]=20?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=AE=BE=E7=BD=AE=E6=8E=A7=E4=BB=B6=20[strok?= =?UTF-8?q?e]=20=E5=B0=86StrokeStyleListView=E4=BF=AE=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BA=86StrokeStyleWidget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 5 +- ...rchitectureColoredPainting.vcxproj.filters | 7 +- .../StrokeStyleWidget.cpp | 216 ++++++++++++++++++ .../EditorWidgetComponent/StrokeStyleWidget.h | 33 +++ .../src/Editor/LayerStyle.cpp | 37 ++- .../src/Editor/LayerStyle.h | 6 + .../src/Editor/LayerWrapper.cpp | 4 + .../src/Editor/LayerWrapper.h | 1 + .../src/Editor/util/JsonUtil.hpp | 14 ++ 9 files changed, 308 insertions(+), 15 deletions(-) create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h create mode 100644 ArchitectureColoredPainting/src/Editor/util/JsonUtil.hpp diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index a0e5563..91c9f62 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -153,7 +153,7 @@ - + @@ -189,7 +189,7 @@ - + @@ -197,6 +197,7 @@ + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index e019bc3..71f1e04 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -216,7 +216,7 @@ Source Files\Editor\Style - + Source Files\Editor\Style @@ -254,7 +254,7 @@ Header Files - + Header Files\Editor\Style @@ -477,6 +477,9 @@ Header Files\Editor\Style + + Header Files\Editor\util + diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp new file mode 100644 index 0000000..00283ca --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp @@ -0,0 +1,216 @@ +#include "StrokeStyleWidget.h" +#include "ColorPicker.h" +#include +#include + +#define radialStroke(stroke) std::dynamic_pointer_cast(stroke->materialStroke) +constexpr int COLUMN_WIDTH = 0; +constexpr int COLUMN_COLOR = 1; +constexpr int COLUMN_METALLIC = 2; +constexpr int COLUMN_ROUGHNESS = 3; +constexpr int COLUMN_OPERATIONS = 4; + +// FIXME: Material的控件有显示bug +StrokeStyleWidget::StrokeStyleWidget( + std::shared_ptr stroke, + QWidget* parent +) : QWidget(parent), stroke(stroke) +{ + QVBoxLayout* viewLayout = new QVBoxLayout(this); + this->setLayout(viewLayout); + + initStrokeSettings(); + QWidget* strokeProperties = new QWidget(this); + QHBoxLayout* strokePropertiesLayout = new QHBoxLayout(strokeProperties); + strokePropertiesLayout->setMargin(0); + + strokeProperties->setLayout(strokePropertiesLayout); + strokePropertiesLayout->addWidget(enableGradual); + strokePropertiesLayout->addWidget(endTypeBox); + + viewLayout->addWidget(strokeProperties); + viewLayout->addWidget(widthField); + + initTable(std::dynamic_pointer_cast(stroke->materialStroke)); + viewLayout->addWidget(strokeTable); + this->adjustSize(); +} + +void StrokeStyleWidget::initStrokeSettings() +{ + this->enableGradual = new QtMaterialCheckBox(this); + enableGradual->setText(QStringLiteral("启用渐变")); + enableGradual->setChecked(radialStroke(stroke)->gradual); + connect(enableGradual, &QtMaterialCheckBox::toggled, [this](bool checked) { + radialStroke(this->stroke)->gradual = checked; + }); + +#define endTypeBoxLabel(start, end) QStringLiteral(start##" -> "##end) + this->endTypeBox = new QComboBox(this); + endTypeBox->addItem(endTypeBoxLabel("圆头", "圆头")); // kRound + endTypeBox->addItem(endTypeBoxLabel("平头", "圆头")); // kFlatRound + endTypeBox->addItem(endTypeBoxLabel("圆头", "平头")); // kRoundFlat + endTypeBox->addItem(endTypeBoxLabel("平头", "平头")); // kFlat + endTypeBox->setCurrentIndex(static_cast(this->stroke->endType)); + connect(endTypeBox, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { + switch (index) + { + case 0: + this->stroke->endType = Renderer::StrokeEndType::kRound; + break; + case 1: + this->stroke->endType = Renderer::StrokeEndType::kFlatRound; + break; + case 2: + this->stroke->endType = Renderer::StrokeEndType::kRoundFlat; + break; + case 3: + this->stroke->endType = Renderer::StrokeEndType::kFlat; + break; + } + }); + + this->widthField = new QtMaterialTextField(this); + widthField->setLabel(QStringLiteral("本侧描边宽度")); + widthField->setText(QString::number(stroke->halfWidth)); + QDoubleValidator* widthValidator = new QDoubleValidator(0.1, std::numeric_limits::max(), 3, widthField); + widthValidator->setNotation(QDoubleValidator::StandardNotation); + widthField->setValidator(widthValidator); + connect(widthField, &QtMaterialTextField::textChanged, [this](const QString& changed) { + if (this->widthField->hasAcceptableInput()) + { + this->stroke->halfWidth = changed.toFloat(); + } + }); +} + +// TODO: 新增时参数校验 +void StrokeStyleWidget::initTable(std::shared_ptr materialStroke) +{ + this->strokeTable = new QTableWidget(this); + strokeTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow); + strokeTable->setColumnCount(5); + strokeTable->setRowCount(materialStroke->materialMap.size() + 1); + QStringList headers; + headers << QStringLiteral("离心距离占比") + << QStringLiteral("颜色") + << QStringLiteral("金属度") + << QStringLiteral("粗糙度") + << QStringLiteral("其他操作"); + strokeTable->setHorizontalHeaderLabels(headers); + int row = 0; + // 内容 + for (auto & strokePair : materialStroke->materialMap) + { + setTableRow(row, strokePair.first, strokePair.second); + row++; + } + // 新增按钮 + QtMaterialRaisedButton* addButton = new QtMaterialRaisedButton("+", strokeTable); + strokeTable->setSpan(row, 0, 1, 5); + strokeTable->setCellWidget(row, 0, addButton); + connect(addButton, &QtMaterialRaisedButton::clicked, [this]() { + handlingRowInsert = true; + auto materialMap = &(radialStroke(this->stroke)->materialMap); + float newWidth = 0; + if (materialMap->size() == 0) + { + newWidth = 0.1; + } + else + { + auto lastPair = materialMap->rbegin(); + newWidth = lastPair->first + 0.01; + } + Renderer::Material newMaterial = { QColor::fromRgb(0,0,0), 0.f, .8f }; + (*materialMap)[newWidth] = newMaterial; + int newRow = this->strokeTable->rowCount() - 1; + this->strokeTable->insertRow(newRow); + setTableRow(newRow, newWidth, (*materialMap)[newWidth]); + this->strokeTable->update(); + handlingRowInsert = false; + }); + + connect(strokeTable, &QTableWidget::currentItemChanged, this, &StrokeStyleWidget::onCurrentItemChanged); + connect(strokeTable, &QTableWidget::cellChanged, this, &StrokeStyleWidget::onCellChanged); +} + +void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& material) +{ + QTableWidgetItem* widthItem = new QTableWidgetItem; + widthItem->setData(Qt::EditRole, width); + strokeTable->setItem(row, COLUMN_WIDTH, widthItem); + + QColor* colorPtr = &(material.color); + QTableWidgetItem* colorItem = new QTableWidgetItem; + colorItem->setData(Qt::DisplayRole, *colorPtr); + strokeTable->setItem(row, COLUMN_COLOR, colorItem); + ColorPicker* colorPicker = new ColorPicker(*colorPtr, strokeTable); + strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker); + connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) { + *colorPtr = color; + this->strokeTable->update(); + }); + + QTableWidgetItem* metallicItem = new QTableWidgetItem; + metallicItem->setData(Qt::EditRole, material.metallic); + strokeTable->setItem(row, COLUMN_METALLIC, metallicItem); + + QTableWidgetItem* roughnessItem = new QTableWidgetItem; + roughnessItem->setData(Qt::EditRole, material.roughness); + strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem); + + QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", strokeTable); + removeButton->setFixedSize(20, 20); + strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton); + connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() { + if (this->strokeTable->rowCount() <= 1) return; + radialStroke(this->stroke)->materialMap.erase(this->strokeTable->item(row, COLUMN_WIDTH)->text().toFloat()); + this->strokeTable->removeRow(row); + }); +} + +void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) +{ + if (!current) return; + int column = current->column(); + if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS) + { + this->currentItemValue = current->data(Qt::EditRole); + } +} + +void StrokeStyleWidget::onCellChanged(int row, int column) +{ + if (handlingRowInsert) return; + auto changedItem = strokeTable->item(row, column); + auto changedItemValue = changedItem->text().toFloat(); + if (changedItemValue < 0 || 1 < changedItemValue) + { + changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat()); + return; + } + auto changedWidth = strokeTable->item(row, COLUMN_WIDTH)->data(Qt::EditRole).toFloat(); + switch (column) + { + case COLUMN_WIDTH: + { + float oldWidth = this->currentItemValue.toFloat(); + auto node = radialStroke(stroke)->materialMap.extract(oldWidth); + node.key() = changedWidth; + radialStroke(stroke)->materialMap.insert(std::move(node)); + strokeTable->sortItems(COLUMN_WIDTH); + break; + } + case COLUMN_METALLIC: + { + radialStroke(stroke)->materialMap[changedWidth].metallic = changedItemValue; + break; + } + case COLUMN_ROUGHNESS: + { + radialStroke(stroke)->materialMap[changedWidth].roughness = changedItemValue; + break; + } + } +} \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h new file mode 100644 index 0000000..6d5dbdd --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h @@ -0,0 +1,33 @@ +#pragma once +#include "LayerStyle.h" +#include "../Renderer/Painting/MaterialStyleStroke.h" +#include +#include +#include +#include +#include +class StrokeStyleWidget : public QWidget +{ + Q_OBJECT +private: + QVariant currentItemValue; + + QtMaterialCheckBox* enableGradual; + QComboBox* endTypeBox; + QtMaterialTextField* widthField; + QTableWidget* strokeTable; + bool handlingRowInsert = false; + + void initStrokeSettings(); + void initTable(std::shared_ptr materialStroke); + void setTableRow(int row, float width, Renderer::Material& material); + +public: + StrokeStyleWidget(std::shared_ptr stroke, QWidget* parent = nullptr); + std::shared_ptr stroke; + +protected slots: + void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous); + void onCellChanged(int row, int column); +}; + diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index e44e855..9b65355 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -1,5 +1,6 @@ #include "LayerStyle.h" -#include "./EditorWidgetComponent/StrokeStyleListView.h" +#include "./EditorWidgetComponent/StrokeStyleWidget.h" +#include "./util/JsonUtil.hpp" #include #include #include @@ -50,8 +51,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget() if (this->strokePair.first == nullptr) { auto materialMap = std::map(); - materialMap[0.3] = Renderer::Material{ QColor(0,255,255), 0.f, .8f }; - materialMap[1.0] = Renderer::Material{ QColor(80,25,255), 0.f, .8f }; + materialMap[1.0] = Renderer::Material{ QColor(0, 0, 0), 0.f, .8f }; this->strokePair.first = std::shared_ptr(new Renderer::MaterialStyleStroke( 15, Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, @@ -63,8 +63,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget() if (this->strokePair.second == nullptr) { auto materialMap = std::map(); - materialMap[0.3] = Renderer::Material{ QColor(0,255,255), 0.f, .8f }; - materialMap[1.0] = Renderer::Material{ QColor(80,25,255), 0.f, .8f }; + materialMap[1.0] = Renderer::Material{ QColor(0, 0, 0), 0.f, .8f }; this->strokePair.second = std::shared_ptr(new Renderer::MaterialStyleStroke( 15, Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, @@ -79,9 +78,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget() QVBoxLayout* layout = new QVBoxLayout(w); layout->setMargin(0); - StrokeStyleListView* leftStrokeView = new StrokeStyleListView( - std::dynamic_pointer_cast(this->strokePair.first->materialStroke), w - ); + StrokeStyleWidget* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w); layout->addWidget(leftStrokeView); QtMaterialCheckBox* checkEachSideIndependent = new QtMaterialCheckBox(w); @@ -89,9 +86,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget() checkEachSideIndependent->setChecked(enableEachSideIndependent); layout->addWidget(checkEachSideIndependent); - StrokeStyleListView* rightStrokeView = new StrokeStyleListView( - std::dynamic_pointer_cast(this->strokePair.second->materialStroke), w - ); + StrokeStyleWidget* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w); layout->addWidget(rightStrokeView); rightStrokeView->setDisabled(!this->enableEachSideIndependent); @@ -124,6 +119,16 @@ StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& enableEachSideIndependent = other.enableEachSideIndependent; } +QJsonObject StrokeElementLayerStyle::toJson() const +{ + QJsonObject json; + json.insert("type", "stroke"); + json.insert("enableEachSideIndependent", enableEachSideIndependent); + json.insert("left", JsonUtil::toQJsonArray(strokePair.first->encoded())); + json.insert("right", JsonUtil::toQJsonArray(strokePair.second->encoded())); + return json; +} + std::unique_ptr StrokeElementLayerStyle::clone() const { return std::make_unique(StrokeElementLayerStyle(*this)); @@ -167,7 +172,17 @@ FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other) } } +QJsonObject FillElementLayerStyle::toJson() const +{ + return QJsonObject(); +} + std::unique_ptr FillElementLayerStyle::clone() const { return std::make_unique(FillElementLayerStyle(*this)); } + +std::unique_ptr LayerStyle::fromJson(const QJsonObject& json) +{ + return std::unique_ptr(); +} diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index 7d5fb25..6717299 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "../Renderer/Painting/ElementStyle.h" #include "../Renderer/Painting/MaterialStyleStroke.h" #include "../Renderer/Painting/MaterialStyleFill.h" @@ -23,10 +24,13 @@ class LayerStyle : public Renderer::ElementStyle { public: const static std::vector()>>> types; + static std::unique_ptr fromJson(const QJsonObject& json); + virtual QString getStyleName() const = 0; virtual QWidget* getInputWidget() = 0; virtual QWidget* getListDisplayWidget() const = 0; virtual ~LayerStyle() {}; + virtual QJsonObject toJson() const = 0; virtual std::unique_ptr clone() const = 0; }; @@ -43,6 +47,7 @@ public: StrokeElementLayerStyle() = default; StrokeElementLayerStyle(const StrokeElementLayerStyle& other); ~StrokeElementLayerStyle() = default; + QJsonObject toJson() const override; std::unique_ptr clone() const override; bool enableEachSideIndependent = false; @@ -59,5 +64,6 @@ public: FillElementLayerStyle(const FillElementLayerStyle& other); ~FillElementLayerStyle() = default; std::vector> materialStyles; + QJsonObject toJson() const override; std::unique_ptr clone() const override; }; \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 4c73d5d..0e9b8f4 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -240,6 +240,10 @@ QJsonObject LeafLayerWrapper::toJson() const QJsonObject json = LayerWrapper::toJson(); json.insert("element", wrappedElement->index); json.insert("is-folder", false); + QJsonArray stylesJson; + for (auto& style : styles) + stylesJson.push_back(style->toJson()); + json.insert("styles", stylesJson); return json; } diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 7df5d13..f753dcb 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/ArchitectureColoredPainting/src/Editor/util/JsonUtil.hpp b/ArchitectureColoredPainting/src/Editor/util/JsonUtil.hpp new file mode 100644 index 0000000..e393f38 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/util/JsonUtil.hpp @@ -0,0 +1,14 @@ +#pragma once +#include + +namespace JsonUtil +{ +#include + template + QJsonArray toQJsonArray(const std::vector& vec) + { + QJsonArray array; + std::copy(vec.begin(), vec.end(), std::back_inserter(array)); + return array; + } +} From 15a41d61a53dc0a53a6cb370cb88c6e0a2da4b32 Mon Sep 17 00:00:00 2001 From: wuyize Date: Thu, 16 Mar 2023 14:48:28 +0800 Subject: [PATCH 19/40] =?UTF-8?q?=E5=AE=9E=E7=8E=B0MaterialStyle=E7=9A=84d?= =?UTF-8?q?ecoded=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Renderer/Painting/BaseStyle.cpp | 86 ++++++++++++++++++- .../src/Renderer/Painting/BaseStyle.h | 13 ++- .../Renderer/Painting/MaterialStyleFill.cpp | 16 ++-- .../src/Renderer/Painting/MaterialStyleFill.h | 5 +- .../Renderer/Painting/MaterialStyleStroke.cpp | 6 +- UnitTest/ElementRendererTest.cpp | 14 +-- UnitTest/StyleTest.cpp | 54 ++++++++++++ UnitTest/UnitTest.vcxproj | 1 + UnitTest/UnitTest.vcxproj.filters | 3 + 9 files changed, 176 insertions(+), 22 deletions(-) create mode 100644 UnitTest/StyleTest.cpp diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.cpp index f1b2088..a22470c 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.cpp @@ -1,6 +1,43 @@ #include "BaseStyle.h" +#include "MaterialStyleFill.h" +#include "MaterialStyleStroke.h" using namespace Renderer; +using namespace glm; + +Renderer::Material::Material(const QColor& color, float metallic, float roughness) + : color(color) +{ + setMetallicF(metallic); + setRoughnessF(roughness); +} + +Renderer::Material::Material(const glm::vec4& color, const glm::vec2& metallicRoughness) + : color(QColor::fromRgbF(color.r, color.g, color.b, color.a)) +{ + setMetallicF(metallicRoughness.r); + setRoughnessF(metallicRoughness.g); +} + +float Renderer::Material::metallicF() const +{ + return metallic / 255.f; +} + +float Renderer::Material::roughnessF() const +{ + return roughness / 255.f; +} + +void Renderer::Material::setMetallicF(float metallic) +{ + this->metallic = metallic * 255; +} + +void Renderer::Material::setRoughnessF(float roughness) +{ + this->roughness = roughness * 255; +} bool Renderer::Material::operator==(const Material& m) const { @@ -9,5 +46,52 @@ bool Renderer::Material::operator==(const Material& m) const std::pair Renderer::Material::toVec() const { - return { glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()), glm::vec2(metallic, roughness)}; + return { glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()), glm::vec2(metallicF(), roughnessF())}; +} + +std::unique_ptr Renderer::MaterialStyle::decoded(const std::vector& encoded) +{ + if (encoded[0] <= 0) /// MaterialStyleFill + { + std::unique_ptr materiallFill; + glm::vec4 head = glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[0])); + if (head.z == 0) + { + materiallFill = std::make_unique(Material(glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[1])), glm::vec2(head.r, head.g))); + } + return std::make_unique(std::move(materiallFill)); + } + else /// MaterialStyleStroke + { + std::unique_ptr materialStroke; + uint headUint = floatBitsToUint(encoded[1]); + vec4 head = unpackUnorm4x8(headUint); + StrokeType strokeType = (StrokeType)floor(head.b * 10); + StrokeEndType endType = (StrokeEndType)(int(round(head.b * 100)) % 10); + switch (int(head.a * 100) % 10) + { + /// Plain + case 0: { + materialStroke = std::make_unique(Material(glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[2])), glm::vec2(head.r, head.g))); + break; + } + /// RadialGradient + case 1: { + uint size = headUint % (1 << 15); + bool gradual = (headUint & (1 << 15)) != 0; + std::map materialMap; + for (uint i = 0; i < size; i++) + { + auto data = floatBitsToUint(encoded[2 + i * 2]); + auto level = unpackUnorm2x16(data).y; + auto color = unpackUnorm4x8(floatBitsToUint(encoded[3 + i * 2])); + auto metallicRoughness = unpackUnorm4x8(data); + materialMap.emplace(level, Material(color, glm::vec2(metallicRoughness.r, metallicRoughness.g))); + } + materialStroke = std::make_unique(materialMap, gradual); + break; + } + } + return std::make_unique(encoded[0], strokeType, endType, std::move(materialStroke)); + } } diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.h b/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.h index 6a1e7a8..051221f 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/BaseStyle.h @@ -25,6 +25,7 @@ namespace Renderer virtual std::vector encoded() const = 0; virtual std::unique_ptr clone() const = 0; virtual bool operator==(const MaterialStyle&) const = 0; + static std::unique_ptr decoded(const std::vector& encoded); }; struct BaseStyle @@ -36,8 +37,16 @@ namespace Renderer struct Material { QColor color; - float metallic; - float roughness; + std::uint8_t metallic; + std::uint8_t roughness; + + Material() = default; + Material(const QColor& color, float metallic = 0, float roughness = 0.5); + Material(const glm::vec4& color, const glm::vec2& metallicRoughness); + float metallicF() const; + float roughnessF() const; + void setMetallicF(float metallic); + void setRoughnessF(float roughness); bool operator==(const Material&) const; std::pair toVec() const; }; diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.cpp index 318895c..ec29f9b 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.cpp @@ -3,7 +3,12 @@ using namespace Renderer; Renderer::FillPlain::FillPlain(QColor color, float metallic, float roughness) - : color(color), metallic(metallic), roughness(roughness) + : material(color, metallic, roughness) +{ +} + +Renderer::FillPlain::FillPlain(const Material& material) + : material(material) { } @@ -14,8 +19,9 @@ MaterialFillType Renderer::FillPlain::type() const std::vector Renderer::FillPlain::encoded() const { - return { glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(metallic, roughness, 0, 1))), - glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF())))}; + auto pair = material.toVec(); + return { glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(pair.second, 0, 1))), + glm::uintBitsToFloat(glm::packUnorm4x8(pair.first))}; } std::unique_ptr Renderer::FillPlain::clone() const @@ -26,9 +32,7 @@ std::unique_ptr Renderer::FillPlain::clone() const bool Renderer::FillPlain::operator==(const MaterialFill& m) const { return type() == m.type() - && color == static_cast(m).color - && metallic == static_cast(m).metallic - && roughness == static_cast(m).roughness; + && material == static_cast(m).material; } diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.h b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.h index e3c1001..1910c65 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleFill.h @@ -18,14 +18,13 @@ namespace Renderer { public: FillPlain(QColor color, float metallic, float roughness); + FillPlain(const Material& material); virtual MaterialFillType type() const override; virtual std::vector encoded() const override; virtual std::unique_ptr clone() const override; virtual bool operator==(const MaterialFill&) const override; - QColor color; - float metallic; - float roughness; + Material material; }; class MaterialStyleFill : public MaterialStyle diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp index 371cb86..3c8686b 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp @@ -76,8 +76,8 @@ bool Renderer::StrokeRadialGradient::operator==(const MaterialStroke& m) const && materialMap == static_cast(m).materialMap; } -Renderer::MaterialStyleStroke::MaterialStyleStroke(float width, StrokeType strokeType, StrokeEndType endType, std::shared_ptr materialStroke) - : halfWidth(width/2), strokeType(strokeType), endType(endType), materialStroke(materialStroke) +Renderer::MaterialStyleStroke::MaterialStyleStroke(float halfWidth, StrokeType strokeType, StrokeEndType endType, std::shared_ptr materialStroke) + : halfWidth(halfWidth), strokeType(strokeType), endType(endType), materialStroke(materialStroke) { } @@ -100,7 +100,7 @@ std::vector Renderer::MaterialStyleStroke::encoded() const std::unique_ptr Renderer::MaterialStyleStroke::clone() const { - return std::make_unique(halfWidth*2, strokeType, endType, materialStroke->clone()); + return std::make_unique(halfWidth, strokeType, endType, materialStroke->clone()); } bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const diff --git a/UnitTest/ElementRendererTest.cpp b/UnitTest/ElementRendererTest.cpp index 7a0c035..ca1fbca 100644 --- a/UnitTest/ElementRendererTest.cpp +++ b/UnitTest/ElementRendererTest.cpp @@ -40,7 +40,7 @@ namespace UnitTest {1.00, Material{QColor(58,64,151)}} }; return { BaseStyle(std::make_shared(), - std::make_shared(60, StrokeType::kBothSides, StrokeEndType::kRound, + std::make_shared(30, StrokeType::kBothSides, StrokeEndType::kRound, std::make_shared(materialMap, false))) }; } } style; @@ -61,7 +61,7 @@ namespace UnitTest {1.00, Material{QColor(58,64,151)}} }; return { BaseStyle(std::make_shared(), - std::make_shared(60, StrokeType::kBothSides, StrokeEndType::kFlat, + std::make_shared(30, StrokeType::kBothSides, StrokeEndType::kFlat, std::make_shared(materialMap, false))) }; } } style; @@ -82,7 +82,7 @@ namespace UnitTest {1.00, Material{QColor(58,64,151)}} }; return { BaseStyle(std::make_shared(), - std::make_shared(60, StrokeType::kLeftSide, StrokeEndType::kRound, + std::make_shared(30, StrokeType::kLeftSide, StrokeEndType::kRound, std::make_shared(materialMap, false))) }; } } style; @@ -103,7 +103,7 @@ namespace UnitTest {1.00, Material{QColor(58,64,151)}} }; return { BaseStyle(std::make_shared(), - std::make_shared(60, StrokeType::kLeftSide, StrokeEndType::kFlat, + std::make_shared(30, StrokeType::kLeftSide, StrokeEndType::kFlat, std::make_shared(materialMap, false))) }; } } style; @@ -124,7 +124,7 @@ namespace UnitTest {1.00, Material{QColor(58,64,151)}} }; return { BaseStyle(std::make_shared(), - std::make_shared(160, StrokeType::kRightSide, StrokeEndType::kFlatRound, + std::make_shared(80, StrokeType::kRightSide, StrokeEndType::kFlatRound, std::make_shared(materialMap, false))) }; } } style; @@ -149,7 +149,7 @@ namespace UnitTest virtual std::vector toBaseStyles() const override { return { BaseStyle(std::make_shared(), - std::make_shared(60, StrokeType::kBothSides, StrokeEndType::kRound, + std::make_shared(30, StrokeType::kBothSides, StrokeEndType::kRound, std::make_shared(QColor(255,255,255),1,1))) }; } } style; @@ -170,7 +170,7 @@ namespace UnitTest {1.00, Material{QColor(58,64,151)}} }; return { BaseStyle(std::make_shared(), - std::make_shared(60, StrokeType::kBothSides, StrokeEndType::kRound, + std::make_shared(30, StrokeType::kBothSides, StrokeEndType::kRound, std::make_shared(materialMap, false))) }; } } style; diff --git a/UnitTest/StyleTest.cpp b/UnitTest/StyleTest.cpp new file mode 100644 index 0000000..f3bf969 --- /dev/null +++ b/UnitTest/StyleTest.cpp @@ -0,0 +1,54 @@ +#include "CppUnitTest.h" +#include +#include +#include "Renderer/Painting/ElementStyle.h" +#include + + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; +using namespace Renderer; + +namespace UnitTest +{ + TEST_CLASS(StyleTest) + { + public: + TEST_METHOD(TestEncodeDecode) + { + std::map materialMap = { + {0.20, Material{QColor(255,255,255)}}, + {0.60, Material{QColor(165,176,207)}}, + {1.00, Material{QColor(58,64,151)}} + }; + auto style = std::make_unique( + 30, StrokeType::kBothSides, StrokeEndType::kRound, + std::make_shared(materialMap, false) + ); + /* auto style = std::make_shared( + 30, StrokeType::kBothSides, StrokeEndType::kRound, + std::make_shared(Material(QColor(255, 255, 255))) + );*/ + std::shared_ptr decoded = MaterialStyle::decoded(style->encoded()); + /* Assert::IsTrue(decoded->type() == MaterialStyleType::kStroke); + Assert::IsTrue(std::static_pointer_cast(decoded)->halfWidth == 30); + Assert::IsTrue(std::static_pointer_cast(decoded)->strokeType == StrokeType::kBothSides); + Assert::IsTrue(std::static_pointer_cast(decoded)->endType == StrokeEndType::kRound); + std::shared_ptr materialStroke = std::static_pointer_cast(decoded)->materialStroke; + Assert::IsTrue(materialStroke->type() == MaterialStrokeType::kPlain); + Material material = std::static_pointer_cast(materialStroke)->material; + Assert::IsTrue(material == Material(QColor(255, 255, 255))); + Logger::WriteMessage(std::format("({} {} {} {}), ({} {})\n", + material.color.red(), + material.color.green(), + material.color.blue(), + material.color.alpha(), + material.metallic, + material.roughness + ).c_str());*/ + + + Assert::IsTrue(*style == *decoded); + + } + }; +} \ No newline at end of file diff --git a/UnitTest/UnitTest.vcxproj b/UnitTest/UnitTest.vcxproj index 402f061..3c5c76d 100644 --- a/UnitTest/UnitTest.vcxproj +++ b/UnitTest/UnitTest.vcxproj @@ -117,6 +117,7 @@ input %(Filename).moc + diff --git a/UnitTest/UnitTest.vcxproj.filters b/UnitTest/UnitTest.vcxproj.filters index 2a74cbc..2265b74 100644 --- a/UnitTest/UnitTest.vcxproj.filters +++ b/UnitTest/UnitTest.vcxproj.filters @@ -48,5 +48,8 @@ Source Files + + Source Files + \ No newline at end of file From a9fb9197e6b1ba97e00bac29733acaa1c210cbf4 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Thu, 16 Mar 2023 14:51:28 +0800 Subject: [PATCH 20/40] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=86=97=E4=BD=99?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=EF=BC=8C=E9=87=8D=E5=86=99=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BF=AE=E5=A4=8DBoundRect=EF=BC=8C?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A2=84=E8=A7=88=E5=88=B7=E6=96=B0=E8=A7=A6?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/EditorWidgetItem.cpp | 1 + .../src/Editor/ElementManager.cpp | 5 -- .../src/Editor/ElementPoolWidget.cpp | 27 +++---- .../src/Editor/ElementPoolWidget.h | 1 + .../src/Editor/GraphicElement.cpp | 79 ++++++++----------- .../src/Editor/GraphicElement.h | 3 + .../src/Editor/LayerWrapper.cpp | 16 ++-- .../src/Editor/LayerWrapper.h | 6 +- .../src/Editor/PixelPath.h | 4 +- .../src/Editor/PreviewWindow.cpp | 11 ++- .../src/Editor/PreviewWindow.h | 2 + 11 files changed, 72 insertions(+), 83 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp index 9525287..41d175f 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp @@ -15,6 +15,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p elementInfoDisplayWidget->enableEdit(); qDebug() << layerInfoDisplayWidget; qDebug() << elementInfoDisplayWidget; + connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex); connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged); connect(treeWidget, &LayerTreeWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh); diff --git a/ArchitectureColoredPainting/src/Editor/ElementManager.cpp b/ArchitectureColoredPainting/src/Editor/ElementManager.cpp index 7b5b80c..b711794 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementManager.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementManager.cpp @@ -2,7 +2,6 @@ ElementManager::ElementManager(QJsonObject source,Renderer::ElementRenderer* renderer) { auto elementsJson = source.value("elements").toArray(); - qDebug() << elementsJson.size(); int index = 0; for (auto elementJson : elementsJson) { @@ -68,9 +67,6 @@ int ElementManager::getLayerReferencedBy(const FolderLayerWrapper* layer) { for (int i = 0; i < elements.size(); i++) if (typeid(*elements[i]) == typeid(GroupElement)) { - qDebug() << ((GroupElement*)elements[i])->sourceLayer; - qDebug() << layer; - qDebug() << "------------"; if (((GroupElement*)elements[i])->sourceLayer == layer) return i; } @@ -97,7 +93,6 @@ void ElementManager::createSimpleElement(QString name, QString filePath) { data.insert("include", filePath); json.insert("data", data); auto element = new SimpleElement(json); - qDebug() << element->painterPath; element->name = name; addElement(element); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp index 0ec51b0..e1a4f76 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp @@ -37,23 +37,8 @@ void ElementPoolWidget::setElementList(std::vector elements) { pictureList->clear(); this->elements = elements; for (int index = 0; index < elements.size(); index++) { - // - //QString strPath = QString("C:\\Users\\86177\\Pictures\\Screenshots\\test.png"); - //QPixmap itemPixmap(strPath); - //QPixmap itemPixmap(QSize(200, 200)); - //itemPixmap.fill(Qt::red); - QPixmap itemPixmap = elements[index]->getPaintObject().getDetail(); - qDebug() << this->parentWidget()->size(); - //auto p = new QWidget(); - //auto lb = new QLabel(p); - //lb->setPixmap(itemPixmap); - //lb->setFixedSize(1920, 1080); - //p->setFixedSize(1920, 1080); - //lb->show(); - //p->show(); - QListWidgetItem* pItem = new QListWidgetItem( - itemPixmap.scaled(QSize(iconWidth - 25, iconHeight - 25)), + elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25)), elements[index]->name); pItem->setSizeHint(QSize(iconWidth, iconHeight)); pictureList->insertItem(index, pItem); @@ -88,13 +73,21 @@ void ElementPoolWidget::refresh() { void ElementPoolWidget::refreshPicture(GraphicElement* element) { for (int i = 0; i < elements.size(); i++) { if (element == elements[i]) { - pictureList->item(i)->setIcon(element->getPaintObject().getDetail().scaled(QSize(iconWidth - 25, iconHeight - 25))); + pictureList->item(i)->setIcon(elements[i]->getPreview(QSize(iconWidth - 25, iconHeight - 25))); // update(); return; } } } +void ElementPoolWidget::refreshPictureByIndex(int index) { + if (index >= 0 && index < elements.size()) + { + pictureList->item(index)->setIcon(elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25))); + // update(); + } +} + void ElementPoolWidget::enableEdit() { connect(this->pictureList, &QListWidget::customContextMenuRequested, this, &ElementPoolWidget::popMenu); diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h index d4c9cef..66129b9 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h @@ -30,6 +30,7 @@ public slots: int pictureItemClicked(QListWidgetItem* item); void refresh(); void refreshPicture(GraphicElement* element); + void refreshPictureByIndex(int index); void popMenu(const QPoint& pos); }; diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 38e6612..6823669 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -49,35 +49,7 @@ PixelPath GroupElement::getPaintObject() const //TODO: apply styles and send back PixelPath SimpleElement::getPaintObject(std::vector>* styles) const { - PixelPath result; - std::shared_ptr style; - if ((*styles).empty()) - { - return this->getPaintObject(); - } - else - { - style = (*styles)[0]; - /*qDebug() << std::dynamic_pointer_cast( - std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke - )->material.color.name();*/ - /*qDebug() << std::dynamic_pointer_cast( - std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke - )->materialMap[1.0].color;*/ - } - - auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, *style, 1.0); - //qDebug() << img << " ------"; - result.addImage(img, mov); - result.addPath(painterPath); - //result.addPath(painterPath); - // QImage img(80,80,QImage::Format_ARGB32); - // QPainter pt(&img); - //pt.setPen(QPen(Qt::red, 2)); - //pt.drawLine(0, 0, 80, 80); - //pt.end(); - //result.addImage(img, QPoint(0, 0)); - return result; + return this->getPaintObject(); } PixelPath GroupElement::getPaintObject(std::vector>* styles) const { @@ -132,35 +104,48 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< { Renderer::ElementStyleStrokeDemo demo(2); std::shared_ptr style; - if (styles.empty()) - { - style = std::make_shared(2); - } - else - { - style = styles[0]; - /*qDebug() << std::dynamic_pointer_cast( - std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke - )->material.color.name();*/ - /*qDebug() << std::dynamic_pointer_cast( - std::dynamic_pointer_cast(style)->materialStyles[0]->materialStroke - )->materialMap[1.0].color;*/ - } + style = styles[0]; QVector2D scale(transform.m11(), transform.m22()); scale /= transform.m33(); double maxScale = std::max(scale.x(), scale.y()); double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio(); auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, *style, pixelRatio); + transform.translate(mov.x(), mov.y()); painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio)); - //img = img.scaled(img.width() / pixelRatio, img.height() / pixelRatio, Qt::KeepAspectRatio, Qt::SmoothTransformation); - painter->drawImage(mov, img); - + painter->drawImage(0, 0, img); } - painter->restore(); } void GroupElement::paint(QPainter* painter, QTransform transform, const vector> &styles) { sourceLayer->paint(painter, transform); +} + + +QPixmap SimpleElement::getPreview(QSize size) +{ + QPixmap result(size + QSize(5,5)); + QPainter painter(&result); + painter.setRenderHint(QPainter::Antialiasing); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + painter.scale(size.width() / painterPath.boundingRect().width(), size.height() / painterPath.boundingRect().height()); + painter.drawPath(painterPath); + return result; +} + +QPixmap GroupElement::getPreview(QSize size) +{ + auto cache = sourceLayer->getCache(); + QPixmap result(QSize(1024, 1024)); + QPainter painter(&result); + painter.setRenderHint(QPainter::Antialiasing); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + sourceLayer->paint(&painter, QTransform(), true); + painter.end(); + QRect rect (cache.getBoundingRect().toRect()); + rect.setTopLeft(rect.topLeft() - QPoint(5, 5)); + rect.setBottomRight(rect.bottomRight() + QPoint(5, 5)); + result = result.copy(rect); + return result.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index f375c63..d417e7e 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -29,6 +29,7 @@ public: virtual PixelPath getPaintObject() const = 0; virtual PixelPath getPaintObject(std::vector>*) const = 0; virtual void paint(QPainter* painter, QTransform transform, const std::vector> &styles) = 0; + virtual QPixmap getPreview(QSize size) = 0; }; class SimpleElement : public GraphicElement @@ -48,6 +49,7 @@ public: PixelPath getPaintObject() const override; PixelPath getPaintObject(std::vector>*) const override; void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; + QPixmap getPreview(QSize size) override; }; class GroupElement : public GraphicElement @@ -64,6 +66,7 @@ public: PixelPath getPaintObject(std::vector>*) const override; void setSourceLayer(FolderLayerWrapper* sourceLayer); void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; + QPixmap getPreview(QSize size) override; }; //******************************** BitmapPath ********************************// diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 4c73d5d..4119277 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -251,12 +251,12 @@ int FolderLayerWrapper::getReferencedBy()const return -1; } -void LayerWrapper::paint(QPainter* painter, QTransform transform) +void LayerWrapper::paint(QPainter* painter, QTransform transform, bool ignoreSelected) { - if (this->selected) + if (!ignoreSelected && this->selected) { painter->save(); - painter->setTransform(transform); + painter->setTransform(transform, ignoreSelected); painter->setPen(QPen(Qt::gray, 2)); painter->setPen(Qt::DashLine); painter->drawRect(cache.getBoundingRect()); @@ -264,18 +264,18 @@ void LayerWrapper::paint(QPainter* painter, QTransform transform) } } -void FolderLayerWrapper::paint(QPainter* painter, QTransform transform) +void FolderLayerWrapper::paint(QPainter* painter, QTransform transform, bool ignoreSelected) { - LayerWrapper::paint(painter, transform); + LayerWrapper::paint(painter, transform, ignoreSelected); transform = property.transform * transform; //qDebug() << transform; for (auto& child : children) - child->paint(painter, transform); + child->paint(painter, transform, ignoreSelected); } -void LeafLayerWrapper::paint(QPainter* painter, QTransform transform) +void LeafLayerWrapper::paint(QPainter* painter, QTransform transform, bool ignoreSelected) { - LayerWrapper::paint(painter, transform); + LayerWrapper::paint(painter, transform, ignoreSelected); transform = property.transform * transform; //qDebug() << transform; if (wrappedElement != nullptr) diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 7df5d13..ef825df 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -57,7 +57,7 @@ class LayerWrapper FolderLayerWrapper*getParent() const; // invoke by manager, then invoke parent's applyStyles LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementManager* elementManager=nullptr); LayerWrapper() = default; - virtual void paint(QPainter* painter, QTransform transform=QTransform()); + virtual void paint(QPainter* painter, QTransform transform=QTransform(), bool ignoreSelected = false); // TODO : export Function // virtual LayerWrapper *addChild() = 0; // Leaf Child Only // virtual LayerWrapper *addParent() = 0; // Folder Parent Only @@ -90,7 +90,7 @@ class FolderLayerWrapper : public LayerWrapper QTreeWidgetItem* getQTreeItem() override; QJsonObject toJson() const override; int getReferencedBy()const; - void paint(QPainter* painter, QTransform transform = QTransform()) override; + void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; }; class LeafLayerWrapper : public LayerWrapper @@ -106,7 +106,7 @@ class LeafLayerWrapper : public LayerWrapper LeafLayerWrapper() = default; LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); QJsonObject toJson() const override; - void paint(QPainter* painter, QTransform transform = QTransform()) override; + void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; }; Q_DECLARE_METATYPE(LayerWrapper *) diff --git a/ArchitectureColoredPainting/src/Editor/PixelPath.h b/ArchitectureColoredPainting/src/Editor/PixelPath.h index 5ab8614..c3dc704 100644 --- a/ArchitectureColoredPainting/src/Editor/PixelPath.h +++ b/ArchitectureColoredPainting/src/Editor/PixelPath.h @@ -13,8 +13,8 @@ public: QPainterPath painterPath; int w,h; public: - PixelPath(int w=1024, int h= 1024); - PixelPath(QPainterPath painterPath,int w = 1024, int h = 1024); + PixelPath(int w=16, int h= 16); + PixelPath(QPainterPath painterPath,int w = 16, int h = 16); ~PixelPath() = default; QRectF getBoundingRect() const; QPixmap getPixmap() const; diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp index 9fb8060..05b05e5 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp @@ -87,13 +87,22 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event) // 如果按下的是左键,那么平移图形 currentLayer->property.offset.setX(currentLayer->property.offset.x() + dx); currentLayer->property.offset.setY(currentLayer->property.offset.y() + dy); - qDebug() << dx << "----" << dy; } else if (event->buttons() & Qt::RightButton) { // 如果按下的是右键,那么旋转图形 qreal angle = dx; currentLayer->property.rotation += angle; } + auto layer = currentLayer; + while (layer != nullptr) + { + auto index = -1; + if (typeid(*layer) == typeid(FolderLayerWrapper)) + index = dynamic_cast(layer)->getReferencedBy(); + if (index != -1) + emit refreshElementPreviewByIndex(index); + layer = layer->getParent(); + } } // 更新上一次的位置 m_lastPos = event->pos(); diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.h b/ArchitectureColoredPainting/src/Editor/PreviewWindow.h index 66f4a52..70a033b 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.h +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.h @@ -42,4 +42,6 @@ class PreviewWindow : public QOpenGLWidget, protected QOpenGLFunctions signals: void layerInfoChanged(); + void refreshElementPreview(GraphicElement*); + void refreshElementPreviewByIndex(int); }; From 4ff5406acc199351670261fbbd298bd54bd0bebd Mon Sep 17 00:00:00 2001 From: wuyize Date: Thu, 16 Mar 2023 19:29:38 +0800 Subject: [PATCH 21/40] =?UTF-8?q?FIX:=20qt-material-widgets=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E6=9C=AA=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/util/PainterPathUtil.cpp | 4 ++-- .../src/Editor/util/PainterPathUtil.h | 2 +- .../src/Renderer/Painting/MaterialStyleStroke.cpp | 2 +- .../src/Renderer/Preview/ElementRenderer.cpp | 6 ++++-- ArchitectureColoredPainting/src/main.cpp | 1 + 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp index e7d3b49..104abb6 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.cpp @@ -15,7 +15,7 @@ vector> PainterPathUtil::transformToLines(const QPainterPath& pai for (int elementIndex = 0; elementIndex < painterPath.elementCount(); elementIndex++) { auto element = painterPath.elementAt(elementIndex); point = element; - qDebug() << element; + //qDebug() << element; if (element.isMoveTo()) { if (line.size() >= 2) { lines.push_back(line); @@ -43,7 +43,7 @@ vector> PainterPathUtil::transformToLines(const QPainterPath& pai return lines; } -QPainterPath PainterPathUtil::monotonization(QPainterPath& painterPath) { +QPainterPath PainterPathUtil::monotonization(const QPainterPath& painterPath) { QPainterPath resPath; vector > lines = transformToLines(painterPath); vector> linePtrVector; diff --git a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h index f6fabcb..196142c 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h +++ b/ArchitectureColoredPainting/src/Editor/util/PainterPathUtil.h @@ -7,7 +7,7 @@ class PainterPathUtil { public: static std::vector> transformToLines(const QPainterPath& painterPath); - static QPainterPath monotonization(QPainterPath& painterPath); + static QPainterPath monotonization(const QPainterPath& painterPath); static std::pair normalized(const QPainterPath& path, float width = 0); static std::pair>, float> toNormalizedLines(const QPainterPath& path, float width = 0); }; diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp index 3c8686b..0d72542 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/MaterialStyleStroke.cpp @@ -59,7 +59,7 @@ std::vector Renderer::StrokeRadialGradient::encoded() const v.y = pair.first; result.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(v))); result.push_back(glm::uintBitsToFloat(glm::packUnorm4x8(color))); - qDebug() << pair.first; + //qDebug() << pair.first; } return result; } diff --git a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp index 45b700a..3be860f 100644 --- a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp @@ -10,6 +10,7 @@ #include "../Painting/Element.h" #include "../Painting/Painting.h" #include "../Painting/MaterialStyleStroke.h" +#include using namespace Renderer; std::vector generatePathBuffer(const QPainterPath& path) @@ -78,7 +79,7 @@ std::vector generateStyleBuffer(const std::vector& styles) auto encoded = style.material->encoded(); styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end()); - qDebug() << "style size" << styleBuffer.size(); + //qDebug() << "style size" << styleBuffer.size(); } return styleBuffer; } @@ -199,7 +200,8 @@ std::pair Renderer::ElementRenderer::drawElement(const QPainter std::unique_lock lock(drawMutex); draw.wait(lock, [&] {return drawFinished; }); drawFinished = false; - this->path = &path; + QPainterPath monotonized = PainterPathUtil::monotonization(path); + this->path = &monotonized; this->style = &style; this->pixelRatio = pixelRatio; needDraw = true; diff --git a/ArchitectureColoredPainting/src/main.cpp b/ArchitectureColoredPainting/src/main.cpp index e43c971..6ef683c 100644 --- a/ArchitectureColoredPainting/src/main.cpp +++ b/ArchitectureColoredPainting/src/main.cpp @@ -49,6 +49,7 @@ int main(int argc, char* argv[]) //QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QApplication a(argc, argv); + Q_INIT_RESOURCE(resources); //FramelessHelper::Core::setApplicationOSThemeAware(); FramelessConfig::instance()->set(Global::Option::ForceNonNativeBackgroundBlur); //FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); From 81bb1b4b86fc0b6e8c46d3213af6ecdb071732c3 Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Thu, 16 Mar 2023 20:22:03 +0800 Subject: [PATCH 22/40] =?UTF-8?q?[editor/style]=20=E5=AE=8C=E6=88=90Stroke?= =?UTF-8?q?Style=E7=9A=84=E5=BA=8F=E5=88=97=E5=8C=96=E5=92=8C=E5=8F=8D?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=20[stroke]=20=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E5=88=9B=E5=BB=BAStrokeStyle=E6=97=B6=E7=9A=84=E5=88=9D?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 1 + ...rchitectureColoredPainting.vcxproj.filters | 3 ++ .../StrokeStyleWidget.cpp | 12 +++-- .../src/Editor/LayerStyle.cpp | 44 +++++++++++++++---- .../src/Editor/LayerStyle.h | 16 +++++-- .../src/Editor/LayerWrapper.cpp | 5 +++ .../src/Editor/util/EncodeUtil.hpp | 25 +++++++++++ 7 files changed, 87 insertions(+), 19 deletions(-) create mode 100644 ArchitectureColoredPainting/src/Editor/util/EncodeUtil.hpp diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index 91c9f62..6b49ff0 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -197,6 +197,7 @@ + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index 71f1e04..d32b61b 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -480,6 +480,9 @@ Header Files\Editor\util + + Header Files\Editor\util + diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp index 00283ca..7e014db 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp @@ -10,7 +10,6 @@ constexpr int COLUMN_METALLIC = 2; constexpr int COLUMN_ROUGHNESS = 3; constexpr int COLUMN_OPERATIONS = 4; -// FIXME: Material的控件有显示bug StrokeStyleWidget::StrokeStyleWidget( std::shared_ptr stroke, QWidget* parent @@ -122,7 +121,7 @@ void StrokeStyleWidget::initTable(std::shared_ptrrbegin(); newWidth = lastPair->first + 0.01; } - Renderer::Material newMaterial = { QColor::fromRgb(0,0,0), 0.f, .8f }; + Renderer::Material newMaterial(QColor::fromRgb(0, 0, 0)); (*materialMap)[newWidth] = newMaterial; int newRow = this->strokeTable->rowCount() - 1; this->strokeTable->insertRow(newRow); @@ -153,18 +152,17 @@ void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& ma }); QTableWidgetItem* metallicItem = new QTableWidgetItem; - metallicItem->setData(Qt::EditRole, material.metallic); + metallicItem->setData(Qt::EditRole, material.metallicF()); strokeTable->setItem(row, COLUMN_METALLIC, metallicItem); QTableWidgetItem* roughnessItem = new QTableWidgetItem; - roughnessItem->setData(Qt::EditRole, material.roughness); + roughnessItem->setData(Qt::EditRole, material.roughnessF()); strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem); QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", strokeTable); removeButton->setFixedSize(20, 20); strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton); connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() { - if (this->strokeTable->rowCount() <= 1) return; radialStroke(this->stroke)->materialMap.erase(this->strokeTable->item(row, COLUMN_WIDTH)->text().toFloat()); this->strokeTable->removeRow(row); }); @@ -204,12 +202,12 @@ void StrokeStyleWidget::onCellChanged(int row, int column) } case COLUMN_METALLIC: { - radialStroke(stroke)->materialMap[changedWidth].metallic = changedItemValue; + radialStroke(stroke)->materialMap[changedWidth].setMetallicF(changedItemValue); break; } case COLUMN_ROUGHNESS: { - radialStroke(stroke)->materialMap[changedWidth].roughness = changedItemValue; + radialStroke(stroke)->materialMap[changedWidth].setRoughnessF(changedItemValue); break; } } diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 9b65355..215ec15 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -1,6 +1,6 @@ #include "LayerStyle.h" #include "./EditorWidgetComponent/StrokeStyleWidget.h" -#include "./util/JsonUtil.hpp" +#include "./util/EncodeUtil.hpp" #include #include #include @@ -51,7 +51,6 @@ QWidget* StrokeElementLayerStyle::getInputWidget() if (this->strokePair.first == nullptr) { auto materialMap = std::map(); - materialMap[1.0] = Renderer::Material{ QColor(0, 0, 0), 0.f, .8f }; this->strokePair.first = std::shared_ptr(new Renderer::MaterialStyleStroke( 15, Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, @@ -63,7 +62,6 @@ QWidget* StrokeElementLayerStyle::getInputWidget() if (this->strokePair.second == nullptr) { auto materialMap = std::map(); - materialMap[1.0] = Renderer::Material{ QColor(0, 0, 0), 0.f, .8f }; this->strokePair.second = std::shared_ptr(new Renderer::MaterialStyleStroke( 15, Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, @@ -108,6 +106,14 @@ QWidget* StrokeElementLayerStyle::getListDisplayWidget() const return w; } +StrokeElementLayerStyle::StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right) +{ + this->strokePair.first = left; + this->strokePair.second = right ? right : std::dynamic_pointer_cast( + std::shared_ptr(std::move(left->clone())) + ); +} + StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& other) { strokePair.first = std::dynamic_pointer_cast( @@ -121,11 +127,12 @@ StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& QJsonObject StrokeElementLayerStyle::toJson() const { + // todo: 修改打开逻辑 QJsonObject json; - json.insert("type", "stroke"); - json.insert("enableEachSideIndependent", enableEachSideIndependent); - json.insert("left", JsonUtil::toQJsonArray(strokePair.first->encoded())); - json.insert("right", JsonUtil::toQJsonArray(strokePair.second->encoded())); + json["type"] = getTypeName(); + json["enableEachSideIndependent"] = enableEachSideIndependent; + json["left"] = EncodeUtil::toBase64(strokePair.first->encoded()); + json["right"] = EncodeUtil::toBase64(strokePair.second->encoded()); return json; } @@ -184,5 +191,26 @@ std::unique_ptr FillElementLayerStyle::clone() const std::unique_ptr LayerStyle::fromJson(const QJsonObject& json) { - return std::unique_ptr(); + QString type = json["type"].toString(); + if (type == StrokeElementLayerStyle::getTypeName()) + { + auto ptr = std::make_unique( + std::dynamic_pointer_cast( + std::shared_ptr(std::move(Renderer::MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString())))) + ), + std::dynamic_pointer_cast( + std::shared_ptr(std::move(Renderer::MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString())))) + ) + ); + ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool(); + return ptr; + } + else if (type == FillElementLayerStyle::getTypeName()) + { + return std::make_unique(); + } + else + { + return nullptr; + } } diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index 6717299..636201d 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -13,6 +13,8 @@ using Renderer::MaterialStyle; using Renderer::MaterialStyleStroke; +#define STYLE_TYPENAME(name) static QString getTypeName() { return name; } + /** * 在进行Style的添加时,首先创建空对象,然后直接调用getInputWidget()方法 * 在进行Style的修改时,直接调用getInputWidget()方法 @@ -36,17 +38,22 @@ public: class StrokeElementLayerStyle : public LayerStyle { + using PMaterialStyleStroke = std::shared_ptr; private: - std::pair, std::shared_ptr> strokePair; + std::pair strokePair; public: + STYLE_TYPENAME("stroke") + + StrokeElementLayerStyle() = default; + StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right = nullptr); + StrokeElementLayerStyle(const StrokeElementLayerStyle& other); + ~StrokeElementLayerStyle() = default; + std::vector toBaseStyles() const override; QString getStyleName() const override; QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; - StrokeElementLayerStyle() = default; - StrokeElementLayerStyle(const StrokeElementLayerStyle& other); - ~StrokeElementLayerStyle() = default; QJsonObject toJson() const override; std::unique_ptr clone() const override; @@ -56,6 +63,7 @@ public: class FillElementLayerStyle : public LayerStyle { public: + STYLE_TYPENAME("fill") std::vector toBaseStyles() const override; QString getStyleName() const override; QWidget* getInputWidget() override; diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index d5229e9..febc24a 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -79,6 +79,11 @@ LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager *elementMana qDebug() << json.value("name").toString() << " " << this; int elementIndex = json.value("element").toInt(); wrappedElement = elementManager->getElementById(elementIndex); + QJsonArray stylesArray = json.value("styles").toArray(); + for (const auto& style : stylesArray) + { + styles.push_back(LayerStyle::fromJson(style.toObject())); + } } void LayerWrapper::SimpleProperty::apply(PixelPath&cache) diff --git a/ArchitectureColoredPainting/src/Editor/util/EncodeUtil.hpp b/ArchitectureColoredPainting/src/Editor/util/EncodeUtil.hpp new file mode 100644 index 0000000..d9a5d01 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/util/EncodeUtil.hpp @@ -0,0 +1,25 @@ +#pragma once +#include + +namespace EncodeUtil +{ +#include + template + QString toBase64(const std::vector& vec) + { + QByteArray ba; + ba.resize(vec.size() * sizeof(S)); + memcpy_s(ba.data(), ba.size(), vec.data(), vec.size() * sizeof(S)); + return ba.toBase64(); + } + + template + std::vector fromBase64(const QString& str) + { + QByteArray ba = QByteArray::fromBase64(str.toUtf8()); + std::vector vec; + vec.resize(ba.size() / sizeof(T)); + memcpy_s(vec.data(), vec.size() * sizeof(T), ba.data(), ba.size()); + return vec; + } +} From 2569b07233b96d8b886d7698cdc4c92e6b71bde9 Mon Sep 17 00:00:00 2001 From: wuyize Date: Fri, 17 Mar 2023 11:54:43 +0800 Subject: [PATCH 23/40] =?UTF-8?q?Renderer=E9=83=A8=E5=88=86Painting?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AE=BE=E7=BD=AE=E8=83=8C=E6=99=AF=E9=A2=9C?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ArchitectureColoredPainting/res/Shaders/painting.comp | 7 ++++++- ArchitectureColoredPainting/src/Renderer/Model.cpp | 3 ++- .../src/Renderer/Painting/Painting.cpp | 7 +++++-- .../src/Renderer/Painting/Painting.h | 5 +++-- .../src/Renderer/VirtualTextureManager.cpp | 4 +++- .../src/Renderer/VirtualTextureManager.h | 2 +- ArchitectureColoredPainting/src/main.cpp | 4 ++++ 7 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp index 3e8ede4..7324942 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.comp +++ b/ArchitectureColoredPainting/res/Shaders/painting.comp @@ -4,6 +4,11 @@ layout(local_size_x = 8, local_size_y = 8) in; layout(location = 0) uniform ivec2 pixelOffset; +layout(std140, binding = 1) uniform ubo +{ + vec3 backgroundColor; +}; + layout(rgba8, binding = 0) uniform image2D gBaseColor; layout(rg8, binding = 1) uniform image2D gMetallicRoughness; @@ -1353,7 +1358,7 @@ void main() vec3 debugBVH = vec3(0); // bool debugHit = false; //vec4 color = vec4(0.76, 0.33, 0.15, -1); - vec4 color = vec4(1,1,1, -1); + vec4 color = vec4(backgroundColor, -1); vec2 metallicRoughness = vec2(0, 0.8); stack.top = 0; uint index = 0, visitTime = 0; diff --git a/ArchitectureColoredPainting/src/Renderer/Model.cpp b/ArchitectureColoredPainting/src/Renderer/Model.cpp index 4f62c3b..e96d36a 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Model.cpp @@ -273,7 +273,8 @@ GLuint Renderer::Model::loadPainting(std::string path) } else if (path == "1.json") { - float widths[] = { 0.43, 0.43 * 0.25 / 0.15, 0.43 * 0.25 / 0.15 }; + painting.backgroundColor = QColor(196, 81, 35); + float widths[] = { 0.22, 0.22 * 0.25 / 0.15, 0.22 * 0.25 / 0.15 }; QPainterPath painterPaths[6]; for (int i = 0; i < 6; i++) if (!SvgFileLoader().loadSvgFile(QString(std::format("../svg/{}.svg", i + 1).c_str()), painterPaths[i])) diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp index 3d1fb2a..afd7e04 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp @@ -9,7 +9,7 @@ using namespace Renderer; constexpr int kMaxLineCount = 20; -Painting::Painting() +Painting::Painting(QColor backgroundColor) : backgroundColor(backgroundColor) { } @@ -171,18 +171,21 @@ void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc) //std::cout << std::format("{} {} {} {}\n", contourBuffer->bvhOffset, stylePool[i.first->style], contourBuffer->pointsOffset, contourBuffer->linesOffset); } - glFunc->glCreateBuffers(5, buffers.data()); + glFunc->glCreateBuffers(6, buffers.data()); GLuint& bvhSSBO = buffers[0]; GLuint& bvhBoundSSBO = buffers[1]; GLuint& elementOffsetSSBO = buffers[2]; GLuint& elementIndexSSBO = buffers[3]; GLuint& elementDataSSBO = buffers[4]; + GLuint& backgroundColorUBO = buffers[5]; glFunc->glNamedBufferData(buffers[0], bvhChildren.size() * sizeof(bvhChildren[0]), bvhChildren.data(), GL_STATIC_READ); glFunc->glNamedBufferData(buffers[1], bvhBounds.size() * sizeof(bvhBounds[0]), bvhBounds.data(), GL_STATIC_READ); glFunc->glNamedBufferData(buffers[2], elementOffsets.size() * sizeof(elementOffsets[0]), elementOffsets.data(), GL_STATIC_READ); glFunc->glNamedBufferData(buffers[3], elementIndex.size() * sizeof(elementIndex[0]), elementIndex.data(), GL_STATIC_READ); glFunc->glNamedBufferData(buffers[4], elementData.size() * sizeof(elementData[0]), elementData.data(), GL_STATIC_READ); + glm::vec3 color(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF()); + glFunc->glNamedBufferData(buffers[5], sizeof(glm::vec3), &color, GL_STATIC_READ); } GLuint Renderer::Painting::getElementCount() diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h index ab8f31a..9194040 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h @@ -64,9 +64,10 @@ namespace Renderer std::vector elementIndex; std::vector elementData; int paintingId = 0; - std::array buffers; + std::array buffers; + QColor backgroundColor; - Painting(); + Painting(QColor backgroundColor = Qt::white); void addElement(const Element& element, const ElementTransform& transform); void addElement(std::shared_ptr element, QVector4D bound, float rotation, int zIndex); void generateBuffers(QOpenGLFunctions_4_5_Core* glFunc); diff --git a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp index eeba398..b926ad4 100644 --- a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp +++ b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp @@ -126,6 +126,7 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai for (int i = 0; i < 5; i++) glMain->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]); + glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[5]); for (auto level = levels - 1; level < levels; ++level) { @@ -143,7 +144,7 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai GL_TRUE); program.bind(); - glMain->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast(pageSize) * i, static_cast(pageSize) * j); + glMain->Uniform2i(0 /*pixelOffset*/, static_cast(pageSize) * i, static_cast(pageSize) * j); glMain->BindImageTexture(0, baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); glMain->BindImageTexture(1, metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8); glMain->DispatchCompute(pageSize / 8, pageSize / 8, 1); @@ -190,6 +191,7 @@ void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pag program.bind(); for (int i = 0; i < 5; i++) gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]); + glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[5]); gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast(pageSize) * page.x, static_cast(pageSize) * page.y); gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8); diff --git a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h index e1d3a03..520800b 100644 --- a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h +++ b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h @@ -15,7 +15,7 @@ namespace Renderer { GLuint baseColor; GLuint metallicRoughness; - std::array buffers; + std::array buffers; }; class VirtualTextureManager diff --git a/ArchitectureColoredPainting/src/main.cpp b/ArchitectureColoredPainting/src/main.cpp index 6ef683c..5bf6bbe 100644 --- a/ArchitectureColoredPainting/src/main.cpp +++ b/ArchitectureColoredPainting/src/main.cpp @@ -5,6 +5,7 @@ #include #include #include "consoleapi2.h" +#include extern "C" { @@ -50,6 +51,9 @@ int main(int argc, char* argv[]) QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QApplication a(argc, argv); Q_INIT_RESOURCE(resources); + QtMaterialTheme theme; + theme.setColor("primary1", QColor(0, 90, 158)); + QtMaterialStyle::instance().setTheme(&theme); //FramelessHelper::Core::setApplicationOSThemeAware(); FramelessConfig::instance()->set(Global::Option::ForceNonNativeBackgroundBlur); //FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); From 6a09bdd32c2b59456fa353937dd4dbfcd8f1d2bc Mon Sep 17 00:00:00 2001 From: wuyize Date: Fri, 17 Mar 2023 12:29:31 +0800 Subject: [PATCH 24/40] =?UTF-8?q?FIX:=20GraphicElement=E4=B8=ADpixelRatio?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/GraphicElement.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 6823669..f515210 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -92,7 +92,7 @@ QJsonObject GroupElement::toJson() const return result; } -void SimpleElement::paint(QPainter* painter, QTransform transform, const vector> &styles) +void SimpleElement::paint(QPainter* painter, QTransform transform, const vector>& styles) { painter->save(); painter->setTransform(transform); @@ -102,12 +102,15 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< } else { - Renderer::ElementStyleStrokeDemo demo(2); std::shared_ptr style; style = styles[0]; - QVector2D scale(transform.m11(), transform.m22()); - scale /= transform.m33(); - double maxScale = std::max(scale.x(), scale.y()); + + double angle = atan(transform.m12() / transform.m11()); + double maxScale; + if (fabs(cos(angle))>1e-5) + maxScale = std::max(fabs(transform.m11() / cos(angle)), fabs(transform.m22() / cos(angle))); + else + maxScale = std::max(fabs(transform.m12() / sin(angle)), fabs(transform.m21() / sin(angle))); double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio(); auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, *style, pixelRatio); transform.translate(mov.x(), mov.y()); @@ -117,7 +120,7 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< painter->restore(); } -void GroupElement::paint(QPainter* painter, QTransform transform, const vector> &styles) +void GroupElement::paint(QPainter* painter, QTransform transform, const vector>& styles) { sourceLayer->paint(painter, transform); } @@ -125,7 +128,7 @@ void GroupElement::paint(QPainter* painter, QTransform transform, const vectorpaint(&painter, QTransform(), true); painter.end(); - QRect rect (cache.getBoundingRect().toRect()); + QRect rect(cache.getBoundingRect().toRect()); rect.setTopLeft(rect.topLeft() - QPoint(5, 5)); rect.setBottomRight(rect.bottomRight() + QPoint(5, 5)); result = result.copy(rect); From 9e4cdb3a63c1a9c56a275b69d13be258799bb7e8 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Fri, 17 Mar 2023 14:14:07 +0800 Subject: [PATCH 25/40] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E5=92=8C=E8=83=8C=E6=99=AF=E9=A2=9C=E8=89=B2?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 3 + ...rchitectureColoredPainting.vcxproj.filters | 9 +++ ArchitectureColoredPainting/EditorSetting.ui | 32 ++++++++++ .../EditorSettingWidget.ui | 63 +++++++++++++++++++ .../EditorWidgetItem.ui | 13 +++- .../src/Editor/EditorWidget.cpp | 8 +++ .../src/Editor/EditorWidget.h | 2 +- .../src/Editor/EditorWidgetItem.cpp | 34 ++++++++++ .../src/Editor/EditorWidgetItem.h | 11 +++- .../src/Editor/PreviewWindow.cpp | 9 ++- .../src/Editor/PreviewWindow.h | 2 + .../Editor/RightBar/EditorSettingWidget.cpp | 21 +++++++ .../src/Editor/RightBar/EditorSettingWidget.h | 21 +++++++ data.json | 2 + 14 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 ArchitectureColoredPainting/EditorSetting.ui create mode 100644 ArchitectureColoredPainting/EditorSettingWidget.ui create mode 100644 ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.cpp create mode 100644 ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.h diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index 6b49ff0..ac1871e 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -104,6 +104,7 @@ + @@ -154,6 +155,7 @@ + @@ -197,6 +199,7 @@ + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index d32b61b..f60bea2 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -82,6 +82,9 @@ Form Files + + Form Files + @@ -234,6 +237,9 @@ Source Files\Editor + + Source Files + @@ -281,6 +287,9 @@ Header Files\Editor + + Header Files + diff --git a/ArchitectureColoredPainting/EditorSetting.ui b/ArchitectureColoredPainting/EditorSetting.ui new file mode 100644 index 0000000..3680069 --- /dev/null +++ b/ArchitectureColoredPainting/EditorSetting.ui @@ -0,0 +1,32 @@ + + + EditorSettingWidget + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + 璁剧疆鑳屾櫙棰滆壊 + + + + + + + + + + diff --git a/ArchitectureColoredPainting/EditorSettingWidget.ui b/ArchitectureColoredPainting/EditorSettingWidget.ui new file mode 100644 index 0000000..fc73390 --- /dev/null +++ b/ArchitectureColoredPainting/EditorSettingWidget.ui @@ -0,0 +1,63 @@ + + + EditorSettingWidget + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + + 0 + 0 + + + + + 120 + 16777215 + + + + 璁剧疆鑳屾櫙棰滆壊 + + + + + + + + 0 + 0 + + + + + 120 + 16777215 + + + + 璁剧疆椤圭洰鍚嶇О + + + + + + + + + + diff --git a/ArchitectureColoredPainting/EditorWidgetItem.ui b/ArchitectureColoredPainting/EditorWidgetItem.ui index 73f9357..63fbd7d 100644 --- a/ArchitectureColoredPainting/EditorWidgetItem.ui +++ b/ArchitectureColoredPainting/EditorWidgetItem.ui @@ -147,7 +147,7 @@ - 1 + 2 @@ -159,6 +159,11 @@ 鍥惧厓姹 + + + 璁剧疆 + + @@ -229,6 +234,12 @@
ElementPoolWidget.h
1 + + EditorSettingWidget + QWidget +
EditorSettingWidget.h
+ 1 +
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp index b51987b..97898fb 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp @@ -47,3 +47,11 @@ EditorWidget::EditorWidget(QWidget* parent) : QWidget(parent) }); } +void EditorWidget::renameTab(QWidget* target, QString name) +{ + int index = this->tabWidget->indexOf(target); + if (index != -1) + { + this->tabWidget->setTabText(index, name); + } +} \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidget.h index b0cfe2f..0986609 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidget.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidget.h @@ -18,6 +18,6 @@ private: public: EditorWidget(QWidget* parent = nullptr); ~EditorWidget()=default; - + void renameTab(QWidget* target, QString name); }; diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp index 41d175f..8f6afc9 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp @@ -1,8 +1,11 @@ #include "EditorWidgetItem.h" +#include "EditorWidget.h" +#include EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(parent) { QImage x; + this->parent = parent; displayLayer = nullptr; displayElement = nullptr; ui.setupUi(this); @@ -12,9 +15,12 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p this->filePath = filePath; layerInfoDisplayWidget = dynamic_cast(tabWidget->widget(0)); elementInfoDisplayWidget = dynamic_cast(tabWidget->widget(1)); + editorSettingWidget = dynamic_cast(tabWidget->widget(2)); elementInfoDisplayWidget->enableEdit(); qDebug() << layerInfoDisplayWidget; qDebug() << elementInfoDisplayWidget; + connect(editorSettingWidget, &EditorSettingWidget::backgroundColorChanged, this, &EditorWidgetItem::handleBackgroundColorChange); + connect(editorSettingWidget, &EditorSettingWidget::projectNameChanged, this, &EditorWidgetItem::handleProjectNameChange); connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex); connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged); @@ -53,6 +59,15 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p treeWidget->refresh(); treeWidget->addTopLevelItem(treeWidget->root->getQTreeItem()); } + this->backgroundColor = source.value("background-color").toVariant().value(); + this->projectName = source.value("project-name").toString(); + qDebug() << this->backgroundColor; + qDebug() << this->projectName; + QTimer::singleShot(300, this, [this]() { + handleBackgroundColorChange(this->backgroundColor); + handleProjectNameChange(this->projectName); + }); + } EditorWidgetItem::~EditorWidgetItem() @@ -100,9 +115,28 @@ void EditorWidgetItem::saveImpl(QString filePath) const json.insert("height", 1080); json.insert("root-layer", source1.value("root-layer")); json.insert("elements", source2.value("elements")); + json.insert("project-name", this->projectName); + json.insert("background-color", QJsonValue::fromVariant(QVariant::fromValue(this->backgroundColor))); QJsonDocument doc(json); QFile file(filePath); file.open(QIODevice::WriteOnly); file.write(doc.toJson()); file.close(); +} + +void EditorWidgetItem::handleBackgroundColorChange(QColor color) +{ + this->backgroundColor = color; + previewWindow->setBackgroundColor(color); +} + +void EditorWidgetItem::handleProjectNameChange(QString name) +{ + this->projectName = name; + auto parent = dynamic_cast(this->parent); + qDebug() << name << " " << parent<<" "<renameTab(this, name); + } } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h index 9fc5be8..409374a 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h @@ -6,6 +6,7 @@ #include "LayerManager.h" #include "LayerTreeWidget.h" #include "PreviewWindow.h" +#include "EditorSettingWidget.h" #include "ui_EditorWidgetItem.h" #include #include @@ -26,11 +27,17 @@ class EditorWidgetItem : public QWidget QTabWidget *tabWidget; InfoDisplayWidget* layerInfoDisplayWidget; ElementPoolWidget* elementInfoDisplayWidget; + EditorSettingWidget* editorSettingWidget; // QT DATA PART LayerWrapper *displayLayer; GraphicElement *displayElement; - QString filePath; + QWidget* parent; void saveImpl(QString filePath)const; +public: + // PROJECT INFO + QString filePath; + QString projectName; + QColor backgroundColor; public: EditorWidgetItem(QString filePath, QWidget *parent = nullptr); @@ -38,6 +45,8 @@ class EditorWidgetItem : public QWidget void paintEvent(QPaintEvent *event) override; void save() const; void saveAs(QString filePath)const; + void handleBackgroundColorChange(QColor color); + void handleProjectNameChange(QString name); private slots: void onLayerChange(LayerWrapper *layer); diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp index 05b05e5..c4a03b5 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.cpp @@ -13,6 +13,7 @@ PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent) painter->setRenderHint(QPainter::HighQualityAntialiasing); layerManager = nullptr; currentLayer = nullptr; + backgroundColor = QColor(255, 255, 255, 255); } void PreviewWindow::initialize(LayerManager *layerManager,QSize windowSize) @@ -44,7 +45,7 @@ void PreviewWindow::initializeGL() void PreviewWindow::paintGL() { - glClearColor(1.0, 1.0, 1.0, 1.0); + glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), backgroundColor.alphaF()); glClear(GL_COLOR_BUFFER_BIT); painter->begin(this); painter->setRenderHint(QPainter::Antialiasing); @@ -112,4 +113,10 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event) void PreviewWindow::mouseReleaseEvent(QMouseEvent* event) { emit layerInfoChanged(); +} + +void PreviewWindow::setBackgroundColor(QColor color) +{ + this->backgroundColor = color; + this->repaint(); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/PreviewWindow.h b/ArchitectureColoredPainting/src/Editor/PreviewWindow.h index 70a033b..9f9d07c 100644 --- a/ArchitectureColoredPainting/src/Editor/PreviewWindow.h +++ b/ArchitectureColoredPainting/src/Editor/PreviewWindow.h @@ -23,6 +23,7 @@ class PreviewWindow : public QOpenGLWidget, protected QOpenGLFunctions QRectF viewportRect; LayerWrapper* currentLayer; QPointF m_lastPos; + QColor backgroundColor; void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; @@ -35,6 +36,7 @@ class PreviewWindow : public QOpenGLWidget, protected QOpenGLFunctions void paintGL() override; void resizeGL(int w, int h) override; Renderer::ElementRenderer* const getRenderer()const; + void setBackgroundColor(QColor color); public slots: void currentLayerChanged(LayerWrapper*); diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.cpp new file mode 100644 index 0000000..2f54a22 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.cpp @@ -0,0 +1,21 @@ +#include "EditorSettingWidget.h" +#include +#include +#include + +EditorSettingWidget::EditorSettingWidget(QWidget* parent) + : QWidget(parent) +{ + ui.setupUi(this); + connect(ui.backgroundColorButton, &QPushButton::clicked, this, [this]() { + QColor color = QColorDialog::getColor(Qt::white, this, QString::fromLocal8Bit("选择背景颜色")); + if (color.isValid()) + { + emit backgroundColorChanged(color); + } + }); + connect(ui.renameButton, &QPushButton::clicked, this, [this]() { + QString name = QInputDialog::getText(this, QString::fromLocal8Bit("重命名"), QString::fromLocal8Bit("请输入新的项目名称")); + emit projectNameChanged(name); + }); +} \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.h b/ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.h new file mode 100644 index 0000000..ba0166c --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/RightBar/EditorSettingWidget.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include "ui_EditorSettingWidget.h" + +class EditorSettingWidget : + public QWidget +{ + Q_OBJECT; + + private: + Ui::EditorSettingWidget ui; + + public: + EditorSettingWidget(QWidget* parent = nullptr); + + signals: + void backgroundColorChanged(QColor); + void projectNameChanged(QString); + +}; + diff --git a/data.json b/data.json index 4f381cb..93398a4 100644 --- a/data.json +++ b/data.json @@ -1,4 +1,6 @@ { + "project-name": "鏍蜂緥1", + "background-color": "#ffffff", "height": 1080, "width": 1080, "elements": [ From 24f8daf1fd5450a131d46375e6451f752ec5a968 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Fri, 17 Mar 2023 17:14:09 +0800 Subject: [PATCH 26/40] =?UTF-8?q?=E8=8F=9C=E5=8D=95=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/RightBar/InfoDisplayWidget.cpp | 4 ++-- .../src/Editor/RightBar/LayerTreeWidget.cpp | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp index d41d374..aeaa652 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp @@ -61,13 +61,13 @@ void InfoDisplayWidget::generateLayerForm() emit requireRefreshElementWidget(); emit requireRefreshPreview(); }); - scaleX->setValidator(new QDoubleValidator(0.001, 1000, 4, this)); + scaleX->setValidator(new QDoubleValidator(-1000, 1000, 4, this)); connect(scaleX, &QLineEdit::textChanged, [=](QString content) { this->displayLayer->property.scale = {content.toDouble(), this->displayLayer->property.scale.y()}; emit requireRefreshElementWidget(); emit requireRefreshPreview(); }); - scaleY->setValidator(new QDoubleValidator(0.001, 1000, 4, this)); + scaleY->setValidator(new QDoubleValidator(-1000, 1000, 4, this)); connect(scaleY, &QLineEdit::textChanged, [=](QString content) { this->displayLayer->property.scale = {this->displayLayer->property.scale.x(), content.toDouble()}; emit requireRefreshElementWidget(); diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index a27da25..13f8e4e 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -78,13 +78,14 @@ void LayerTreeWidget::popMenu(const QPoint &pos) emit requireRefreshPreview(); }); menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent); - menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() { - auto layer = this->selectedItem->data(0, Qt::UserRole).value(); - layer->delSelf(); - layer->getParent()->removeChild(layer); - this->refresh(); - emit requireRefreshPreview(); - }); + if(typeid(*layer) == typeid(FolderLayerWrapper)) + menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() { + auto layer = this->selectedItem->data(0, Qt::UserRole).value(); + layer->delSelf(); + layer->getParent()->removeChild(layer); + this->refresh(); + emit requireRefreshPreview(); + }); } if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) { menu.addAction(QString::fromLocal8Bit("创建组合元素"), this, [this]() { From c15e8c3a5ba9629aaaf54cf19afeb26cd2a3e286 Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Sat, 18 Mar 2023 03:51:47 +0800 Subject: [PATCH 27/40] =?UTF-8?q?[style]=20=E9=87=8D=E6=96=B0=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E4=BA=86LayerStyle=E5=9C=A8Layer=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E5=BD=A2=E5=BC=8F=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=BA=86LayerStyleContainer=E7=B1=BB=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BA=86=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E9=83=A8=E5=88=86bad=20smells?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LayerStyleDialog.cpp | 48 ++-- .../EditorWidgetComponent/LayerStyleDialog.h | 10 +- .../StrokeStyleWidget.cpp | 30 +- .../src/Editor/GraphicElement.cpp | 13 +- .../src/Editor/GraphicElement.h | 13 +- .../src/Editor/LayerStyle.cpp | 264 ++++++++++++------ .../src/Editor/LayerStyle.h | 72 +++-- .../src/Editor/LayerWrapper.cpp | 12 +- .../src/Editor/LayerWrapper.h | 3 +- .../src/Editor/RightBar/InfoDisplayWidget.cpp | 75 ++--- 10 files changed, 330 insertions(+), 210 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp index 478301a..33a3568 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp @@ -3,20 +3,18 @@ #include #include #include -#include -#include LayerStyleDialog::LayerStyleDialog( - QWidget* parent, - std::shared_ptr existedStyle, - std::vector>* excludeStyles -) : QDialog(parent) + LayerStyleContainer& styles, + std::shared_ptr existedStyle, + QWidget* parent +) : QDialog(parent), styles(&styles) { - QVBoxLayout* dialogLayout = new QVBoxLayout(this); + auto* dialogLayout = new QVBoxLayout(this); dialogLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter); this->setLayout(dialogLayout); - if (existedStyle) + if (existedStyle) { this->modifyingStyle = existedStyle->clone(); @@ -28,28 +26,14 @@ LayerStyleDialog::LayerStyleDialog( } else { - std::unordered_set excludeStyleNames; - for(auto &style : *excludeStyles) - { - excludeStyleNames.insert(style->getStyleName()); - } + QStringList unusedStyleNames = styles.unusedStyleNames(); + auto* typeSelector = new QComboBox(this); - QComboBox* typeSelector = new QComboBox(this); - - for (auto& pair : LayerStyle::types) + if (!unusedStyleNames.empty()) { - if (!excludeStyleNames.contains(pair.first)) - { - typeSelector->addItem(pair.first); - if (!this->modifyingStyle) - { - this->modifyingStyle = std::move(pair.second()); - } - } - } + typeSelector->addItems(unusedStyleNames); + this->modifyingStyle = std::move(styles.makeUnusedStyle(unusedStyleNames[0])); - if (typeSelector->count() > 0) - { dialogLayout->addWidget(typeSelector); this->styleContainer = new QGridLayout(this); dialogLayout->addLayout(styleContainer); @@ -57,11 +41,11 @@ LayerStyleDialog::LayerStyleDialog( this->styleWidget = this->modifyingStyle->getInputWidget(); this->styleWidget->setParent(this); this->styleContainer->addWidget(styleWidget); - connect(typeSelector, QOverload::of(&QComboBox::currentIndexChanged), + connect(typeSelector, &QComboBox::currentTextChanged, this, &LayerStyleDialog::onStyleTypeSelectorChanged); } } - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttonBox, &QDialogButtonBox::accepted, this, &LayerStyleDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &LayerStyleDialog::reject); dialogLayout->addWidget(buttonBox); @@ -73,7 +57,7 @@ void LayerStyleDialog::accept() QDialog::accept(); } -void LayerStyleDialog::onStyleTypeSelectorChanged(int index) +void LayerStyleDialog::onStyleTypeSelectorChanged(const QString& current) { if (this->styleWidget) { @@ -81,8 +65,10 @@ void LayerStyleDialog::onStyleTypeSelectorChanged(int index) this->styleWidget->setParent(nullptr); delete styleWidget; } - this->modifyingStyle = std::move(LayerStyle::types[index].second()); + this->modifyingStyle = std::move(styles->makeUnusedStyle(current)); this->styleWidget = this->modifyingStyle->getInputWidget(); this->styleWidget->setParent(this); this->styleContainer->addWidget(styleWidget, 0, 0, 1, 1); + this->styleWidget->adjustSize(); + this->adjustSize(); } diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h index 8246cca..b703e80 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h @@ -9,15 +9,17 @@ class LayerStyleDialog : public QDialog private: QWidget* styleWidget; QGridLayout* styleContainer; + LayerStyleContainer* styles; std::unique_ptr modifyingStyle; public: LayerStyleDialog( - QWidget* parent = nullptr, - std::shared_ptr existedStyle = nullptr, - std::vector>* excludeStyles = nullptr); + LayerStyleContainer& styles, + std::shared_ptr existedStyle = nullptr, + QWidget* parent = nullptr + ); std::shared_ptr layerStyle; private slots: - void onStyleTypeSelectorChanged(int index); + void onStyleTypeSelectorChanged(const QString& current); void accept() override; }; diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp index 7e014db..670e185 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp @@ -2,8 +2,8 @@ #include "ColorPicker.h" #include #include +#include -#define radialStroke(stroke) std::dynamic_pointer_cast(stroke->materialStroke) constexpr int COLUMN_WIDTH = 0; constexpr int COLUMN_COLOR = 1; constexpr int COLUMN_METALLIC = 2; @@ -15,12 +15,12 @@ StrokeStyleWidget::StrokeStyleWidget( QWidget* parent ) : QWidget(parent), stroke(stroke) { - QVBoxLayout* viewLayout = new QVBoxLayout(this); + auto* viewLayout = new QVBoxLayout(this); this->setLayout(viewLayout); initStrokeSettings(); - QWidget* strokeProperties = new QWidget(this); - QHBoxLayout* strokePropertiesLayout = new QHBoxLayout(strokeProperties); + auto* strokeProperties = new QWidget(this); + auto* strokePropertiesLayout = new QHBoxLayout(strokeProperties); strokePropertiesLayout->setMargin(0); strokeProperties->setLayout(strokePropertiesLayout); @@ -38,7 +38,7 @@ StrokeStyleWidget::StrokeStyleWidget( void StrokeStyleWidget::initStrokeSettings() { this->enableGradual = new QtMaterialCheckBox(this); - enableGradual->setText(QStringLiteral("启用渐变")); + enableGradual->setText(QStringLiteral("渐变")); enableGradual->setChecked(radialStroke(stroke)->gradual); connect(enableGradual, &QtMaterialCheckBox::toggled, [this](bool checked) { radialStroke(this->stroke)->gradual = checked; @@ -72,7 +72,7 @@ void StrokeStyleWidget::initStrokeSettings() this->widthField = new QtMaterialTextField(this); widthField->setLabel(QStringLiteral("本侧描边宽度")); widthField->setText(QString::number(stroke->halfWidth)); - QDoubleValidator* widthValidator = new QDoubleValidator(0.1, std::numeric_limits::max(), 3, widthField); + auto* widthValidator = new QDoubleValidator(0.1, std::numeric_limits::max(), 3, widthField); widthValidator->setNotation(QDoubleValidator::StandardNotation); widthField->setValidator(widthValidator); connect(widthField, &QtMaterialTextField::textChanged, [this](const QString& changed) { @@ -106,8 +106,12 @@ void StrokeStyleWidget::initTable(std::shared_ptrsetBackgroundColor(QtMaterialStyle::instance().themeColor("primary1")); strokeTable->setSpan(row, 0, 1, 5); strokeTable->setCellWidget(row, 0, addButton); + strokeTable->setMinimumHeight(strokeTable->rowHeight(row) * 5); + strokeTable->setMinimumWidth(strokeTable->sizeHint().width()); + addButton->setFixedHeight(strokeTable->rowHeight(row)); connect(addButton, &QtMaterialRaisedButton::clicked, [this]() { handlingRowInsert = true; auto materialMap = &(radialStroke(this->stroke)->materialMap); @@ -129,37 +133,37 @@ void StrokeStyleWidget::initTable(std::shared_ptrstrokeTable->update(); handlingRowInsert = false; }); - connect(strokeTable, &QTableWidget::currentItemChanged, this, &StrokeStyleWidget::onCurrentItemChanged); connect(strokeTable, &QTableWidget::cellChanged, this, &StrokeStyleWidget::onCellChanged); } void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& material) { - QTableWidgetItem* widthItem = new QTableWidgetItem; + auto* widthItem = new QTableWidgetItem; widthItem->setData(Qt::EditRole, width); strokeTable->setItem(row, COLUMN_WIDTH, widthItem); QColor* colorPtr = &(material.color); - QTableWidgetItem* colorItem = new QTableWidgetItem; + auto* colorItem = new QTableWidgetItem; colorItem->setData(Qt::DisplayRole, *colorPtr); strokeTable->setItem(row, COLUMN_COLOR, colorItem); - ColorPicker* colorPicker = new ColorPicker(*colorPtr, strokeTable); + auto* colorPicker = new ColorPicker(*colorPtr, strokeTable); strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker); connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) { *colorPtr = color; this->strokeTable->update(); }); - QTableWidgetItem* metallicItem = new QTableWidgetItem; + auto* metallicItem = new QTableWidgetItem; metallicItem->setData(Qt::EditRole, material.metallicF()); strokeTable->setItem(row, COLUMN_METALLIC, metallicItem); - QTableWidgetItem* roughnessItem = new QTableWidgetItem; + auto* roughnessItem = new QTableWidgetItem; roughnessItem->setData(Qt::EditRole, material.roughnessF()); strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem); - QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", strokeTable); + auto* removeButton = new QtMaterialRaisedButton("-", strokeTable); + removeButton->setBackgroundColor(QtMaterialStyle::instance().themeColor("primary1")); removeButton->setFixedSize(20, 20); strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton); connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() { diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index f515210..8896f9e 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -48,11 +48,11 @@ PixelPath GroupElement::getPaintObject() const } //TODO: apply styles and send back -PixelPath SimpleElement::getPaintObject(std::vector>* styles) const { +PixelPath SimpleElement::getPaintObject(const LayerStyleContainer& styles) const { return this->getPaintObject(); } -PixelPath GroupElement::getPaintObject(std::vector>* styles) const { +PixelPath GroupElement::getPaintObject(const LayerStyleContainer& styles) const { return getPaintObject(); } @@ -92,7 +92,7 @@ QJsonObject GroupElement::toJson() const return result; } -void SimpleElement::paint(QPainter* painter, QTransform transform, const vector>& styles) +void SimpleElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) { painter->save(); painter->setTransform(transform); @@ -102,9 +102,6 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< } else { - std::shared_ptr style; - style = styles[0]; - double angle = atan(transform.m12() / transform.m11()); double maxScale; if (fabs(cos(angle))>1e-5) @@ -112,7 +109,7 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< else maxScale = std::max(fabs(transform.m12() / sin(angle)), fabs(transform.m21() / sin(angle))); double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio(); - auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, *style, pixelRatio); + auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, styles, pixelRatio); transform.translate(mov.x(), mov.y()); painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio)); painter->drawImage(0, 0, img); @@ -120,7 +117,7 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< painter->restore(); } -void GroupElement::paint(QPainter* painter, QTransform transform, const vector>& styles) +void GroupElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) { sourceLayer->paint(painter, transform); } diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index d417e7e..12e2cfa 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -2,7 +2,6 @@ #include "LayerWrapper.h" #include "LayerStyle.h" -#include #include #include #include @@ -27,8 +26,8 @@ public: // TODO: 改为BitmapPath virtual QJsonObject toJson() const = 0; virtual PixelPath getPaintObject() const = 0; - virtual PixelPath getPaintObject(std::vector>*) const = 0; - virtual void paint(QPainter* painter, QTransform transform, const std::vector> &styles) = 0; + virtual PixelPath getPaintObject(const LayerStyleContainer& styles) const = 0; + virtual void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) = 0; virtual QPixmap getPreview(QSize size) = 0; }; @@ -47,8 +46,8 @@ public: SimpleElement(QString filePath); ~SimpleElement() = default; PixelPath getPaintObject() const override; - PixelPath getPaintObject(std::vector>*) const override; - void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; + PixelPath getPaintObject(const LayerStyleContainer& styles) const override; + void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; QPixmap getPreview(QSize size) override; }; @@ -63,9 +62,9 @@ public: GroupElement(FolderLayerWrapper* mSourceLayer); ~GroupElement() = default; PixelPath getPaintObject() const override; - PixelPath getPaintObject(std::vector>*) const override; + PixelPath getPaintObject(const LayerStyleContainer& styles) const override; void setSourceLayer(FolderLayerWrapper* sourceLayer); - void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; + void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; QPixmap getPreview(QSize size) override; }; diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 215ec15..5be1b72 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -9,31 +9,29 @@ #include #include #include - -const std::vector()>>> LayerStyle::types = { - { - QStringLiteral("描边"), - []() { return std::make_unique(); } - }, - { - QStringLiteral("填充"), - []() { return std::make_unique(); } - } -}; +#define _USE_JOIN_VIEW_INPUT_RANGE +#include +#include std::vector StrokeElementLayerStyle::toBaseStyles() const { std::vector baseStyles; if (enableEachSideIndependent) { - baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), - strokePair.first)); - baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), - strokePair.second)); + if (!radialStroke(strokePair.first)->materialMap.empty()) + { + baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), + strokePair.first)); + } + if (!radialStroke(strokePair.second)->materialMap.empty()) + { + baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), + strokePair.second)); + } } - else + else if (!radialStroke(strokePair.first)->materialMap.empty()) { - auto material = std::shared_ptr(std::move(strokePair.first->clone())); + const auto material = std::shared_ptr(std::move(strokePair.first->clone())); std::dynamic_pointer_cast(material)->strokeType = Renderer::StrokeType::kBothSides; baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), material)); @@ -41,50 +39,23 @@ std::vector StrokeElementLayerStyle::toBaseStyles() const return baseStyles; } -QString StrokeElementLayerStyle::getStyleName() const -{ - return QStringLiteral("描边"); -} - QWidget* StrokeElementLayerStyle::getInputWidget() { - if (this->strokePair.first == nullptr) - { - auto materialMap = std::map(); - this->strokePair.first = std::shared_ptr(new Renderer::MaterialStyleStroke( - 15, - Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, - std::shared_ptr(new Renderer::StrokeRadialGradient( - materialMap, false - )) - )); - } - if (this->strokePair.second == nullptr) - { - auto materialMap = std::map(); - this->strokePair.second = std::shared_ptr(new Renderer::MaterialStyleStroke( - 15, - Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, - std::shared_ptr(new Renderer::StrokeRadialGradient( - materialMap, false - )) - )); - } - QWidget* w = new QWidget; - QListView* materialList = new QListView; + auto* w = new QWidget; + auto* materialList = new QListView; - QVBoxLayout* layout = new QVBoxLayout(w); + auto* layout = new QVBoxLayout(w); layout->setMargin(0); - StrokeStyleWidget* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w); + auto* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w); layout->addWidget(leftStrokeView); - - QtMaterialCheckBox* checkEachSideIndependent = new QtMaterialCheckBox(w); - checkEachSideIndependent->setText(QStringLiteral("启用两侧独立描边")); + + auto* checkEachSideIndependent = new QtMaterialCheckBox(w); + checkEachSideIndependent->setText(QStringLiteral("右侧独立描边")); checkEachSideIndependent->setChecked(enableEachSideIndependent); layout->addWidget(checkEachSideIndependent); - StrokeStyleWidget* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w); + auto* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w); layout->addWidget(rightStrokeView); rightStrokeView->setDisabled(!this->enableEachSideIndependent); @@ -97,39 +68,180 @@ QWidget* StrokeElementLayerStyle::getInputWidget() QWidget* StrokeElementLayerStyle::getListDisplayWidget() const { - QWidget* w = new QWidget; - QLabel* name = new QLabel(w); + auto* w = new QWidget; + auto* name = new QLabel(w); name->setText(QStringLiteral("描边")); - QHBoxLayout* layout = new QHBoxLayout(w); + auto* layout = new QHBoxLayout(w); layout->setMargin(0); layout->addWidget(name); return w; } +void LayerStyleContainer::computeNewHash() +{ + hash = 0; + for (auto& f : styles + | std::views::values + | std::views::transform(&LayerStyle::toBaseStyles) + | std::views::join + | std::views::transform(&Renderer::BaseStyle::material) + | std::views::transform(&MaterialStyle::encoded) + | std::views::join) + { + const unsigned int u = *reinterpret_cast(&f); + hash ^= u + 0x9e3779b9 + (hash << 6) + (hash >> 2); + } +} + +LayerStyleContainer LayerStyleContainer::fromJson(const QJsonArray& jsonArray) +{ + LayerStyleContainer container; + for (const auto& style : jsonArray) + { + container.useStyle(LayerStyle::fromJson(style.toObject())); + } + return container; +} + +LayerStyleContainer::LayerStyleContainer() : hash(0) +{ + unusedStyles = { { + StrokeElementLayerStyle::displayName(), + [] { return std::make_unique(); } + }, + { + FillElementLayerStyle::displayName(), + [] { return std::make_unique(); } + } }; +} + +std::vector LayerStyleContainer::toBaseStyles() const +{ + std::vector result; + for (const auto& style : styles | std::views::values) + { + auto baseStyles = style->toBaseStyles(); + result.insert(result.end(), + std::make_move_iterator(baseStyles.begin()), + std::make_move_iterator(baseStyles.end())); + } + return result; +} + +QJsonArray LayerStyleContainer::toJson() const +{ + QJsonArray json; + for (const auto& style : styles | std::views::values) + { + json.append(style->toJson()); + } + return json; +} + +QStringList LayerStyleContainer::unusedStyleNames() const +{ + QStringList result; + for(const auto& name : unusedStyles | std::views::keys) + { + result << name; + } + return result; +} + +std::unique_ptr LayerStyleContainer::makeUnusedStyle(const QString& styleName) const +{ + return unusedStyles.at(styleName)(); +} + +bool LayerStyleContainer::empty() const +{ + return styles.empty(); +} + +bool LayerStyleContainer::full() const +{ + return unusedStyles.empty(); +} + +std::map>::iterator LayerStyleContainer::begin() +{ + return styles.begin(); +} + +std::map>::iterator LayerStyleContainer::end() +{ + return styles.end(); +} + +bool LayerStyleContainer::useStyle(const std::shared_ptr& style) +{ + auto styleNode = unusedStyles.extract(style->getDisplayName()); + if (styleNode.empty()) + { + return false; + } + styles[styleNode.key()] = style; + usedStyles.insert(std::move(styleNode)); + return true; +} + +bool LayerStyleContainer::dropStyle(const QString& styleName) +{ + auto styleNode = usedStyles.extract(styleName); + if (styleNode.empty()) + { + return false; + } + styles.erase(styleName); + unusedStyles.insert(std::move(styleNode)); + return true; +} + +inline size_t LayerStyleContainer::getHash() const +{ + return hash; +} + +StrokeElementLayerStyle::StrokeElementLayerStyle() +{ + const auto materialMap = std::map(); + this->strokePair.first = std::make_shared( + 7, + Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, + std::make_shared(materialMap, false) + ); + + this->strokePair.second = std::make_shared( + 7, + Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, + std::make_shared(materialMap, false) + ); + +} + StrokeElementLayerStyle::StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right) { this->strokePair.first = left; - this->strokePair.second = right ? right : std::dynamic_pointer_cast( - std::shared_ptr(std::move(left->clone())) + this->strokePair.second = right ? right : std::static_pointer_cast( + std::shared_ptr(std::move(left->clone())) ); } StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& other) { - strokePair.first = std::dynamic_pointer_cast( - std::shared_ptr(std::move(other.strokePair.first->clone())) + strokePair.first = std::static_pointer_cast( + std::shared_ptr(std::move(other.strokePair.first->clone())) ); - strokePair.second = std::dynamic_pointer_cast( - std::shared_ptr(std::move(other.strokePair.second->clone())) + strokePair.second = std::static_pointer_cast( + std::shared_ptr(std::move(other.strokePair.second->clone())) ); enableEachSideIndependent = other.enableEachSideIndependent; } QJsonObject StrokeElementLayerStyle::toJson() const { - // todo: 修改打开逻辑 QJsonObject json; - json["type"] = getTypeName(); + json["type"] = typeName(); json["enableEachSideIndependent"] = enableEachSideIndependent; json["left"] = EncodeUtil::toBase64(strokePair.first->encoded()); json["right"] = EncodeUtil::toBase64(strokePair.second->encoded()); @@ -143,28 +255,24 @@ std::unique_ptr StrokeElementLayerStyle::clone() const std::vector FillElementLayerStyle::toBaseStyles() const { + // TODO: implement return std::vector(); } -QString FillElementLayerStyle::getStyleName() const -{ - return QStringLiteral("填充"); -} - QWidget* FillElementLayerStyle::getInputWidget() { // TODO - QLineEdit* name = new QLineEdit; + auto* name = new QLineEdit; name->setText(QStringLiteral("填充")); return name; } QWidget* FillElementLayerStyle::getListDisplayWidget() const { - QWidget* w = new QWidget; - QLabel* name = new QLabel(w); + auto* w = new QWidget; + auto* name = new QLabel(w); name->setText(QStringLiteral("填充")); - QHBoxLayout* layout = new QHBoxLayout(w); + auto* layout = new QHBoxLayout(w); layout->setMargin(0); layout->addWidget(name); return w; @@ -192,20 +300,20 @@ std::unique_ptr FillElementLayerStyle::clone() const std::unique_ptr LayerStyle::fromJson(const QJsonObject& json) { QString type = json["type"].toString(); - if (type == StrokeElementLayerStyle::getTypeName()) + if (type == StrokeElementLayerStyle::typeName()) { auto ptr = std::make_unique( - std::dynamic_pointer_cast( - std::shared_ptr(std::move(Renderer::MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString())))) + std::static_pointer_cast( + std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString())))) ), - std::dynamic_pointer_cast( - std::shared_ptr(std::move(Renderer::MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString())))) + std::static_pointer_cast( + std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString())))) ) ); ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool(); return ptr; } - else if (type == FillElementLayerStyle::getTypeName()) + else if (type == FillElementLayerStyle::typeName()) { return std::make_unique(); } diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index 636201d..a310b6e 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -1,11 +1,11 @@ #pragma once -#include #include #include -#include -#include +#include +#include #include #include +#include #include "../Renderer/Painting/ElementStyle.h" #include "../Renderer/Painting/MaterialStyleStroke.h" #include "../Renderer/Painting/MaterialStyleFill.h" @@ -13,64 +13,90 @@ using Renderer::MaterialStyle; using Renderer::MaterialStyleStroke; -#define STYLE_TYPENAME(name) static QString getTypeName() { return name; } +#define STYLE_NAME(display_name, type_name) \ + static QString displayName() { return QStringLiteral(display_name); } \ + QString getDisplayName() const override { return QStringLiteral(display_name); } \ + static QString typeName() { return type_name; } +#define radialStroke(stroke) std::static_pointer_cast(stroke->materialStroke) -/** - * 在进行Style的添加时,首先创建空对象,然后直接调用getInputWidget()方法 - * 在进行Style的修改时,直接调用getInputWidget()方法 - * - * 对于LayerStyle的实现类,应该同时实现ElementStyle,并将相同种类的(如描边或填充)的style整合成一个类, - * 对于相同的类,一个图层应该只拥有一个 - */ class LayerStyle : public Renderer::ElementStyle { public: - const static std::vector()>>> types; static std::unique_ptr fromJson(const QJsonObject& json); - virtual QString getStyleName() const = 0; + virtual QString getDisplayName() const = 0; virtual QWidget* getInputWidget() = 0; virtual QWidget* getListDisplayWidget() const = 0; - virtual ~LayerStyle() {}; + virtual ~LayerStyle() = default; virtual QJsonObject toJson() const = 0; virtual std::unique_ptr clone() const = 0; }; +class LayerStyleContainer : public Renderer::ElementStyle +{ + using DisplayNameWithSupplier = std::map()>>; +private: + DisplayNameWithSupplier unusedStyles; + DisplayNameWithSupplier usedStyles; + std::map> styles; + size_t hash; +public: + static LayerStyleContainer fromJson(const QJsonArray& jsonArray); + + LayerStyleContainer(); + std::vector toBaseStyles() const override; + QJsonArray toJson() const; + + bool empty() const; + bool full() const; + std::map>::iterator begin(); + std::map>::iterator end(); + + QStringList unusedStyleNames() const; + std::unique_ptr makeUnusedStyle(const QString& styleName) const; + bool useStyle(const std::shared_ptr& style); + bool dropStyle(const QString& styleName); + size_t getHash() const; + + /** + * 需要在每次更改后手动调用 + */ + void computeNewHash(); +}; + class StrokeElementLayerStyle : public LayerStyle { using PMaterialStyleStroke = std::shared_ptr; -private: - std::pair strokePair; public: - STYLE_TYPENAME("stroke") + STYLE_NAME("描边","stroke") - StrokeElementLayerStyle() = default; + StrokeElementLayerStyle(); StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right = nullptr); StrokeElementLayerStyle(const StrokeElementLayerStyle& other); - ~StrokeElementLayerStyle() = default; + ~StrokeElementLayerStyle() override = default; std::vector toBaseStyles() const override; - QString getStyleName() const override; QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; QJsonObject toJson() const override; std::unique_ptr clone() const override; + std::pair strokePair; bool enableEachSideIndependent = false; }; class FillElementLayerStyle : public LayerStyle { public: - STYLE_TYPENAME("fill") + STYLE_NAME("填充","fill") + std::vector toBaseStyles() const override; - QString getStyleName() const override; QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; FillElementLayerStyle() = default; FillElementLayerStyle(const FillElementLayerStyle& other); - ~FillElementLayerStyle() = default; + ~FillElementLayerStyle() override = default; std::vector> materialStyles; QJsonObject toJson() const override; std::unique_ptr clone() const override; diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index febc24a..9281248 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -80,10 +80,7 @@ LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager *elementMana int elementIndex = json.value("element").toInt(); wrappedElement = elementManager->getElementById(elementIndex); QJsonArray stylesArray = json.value("styles").toArray(); - for (const auto& style : stylesArray) - { - styles.push_back(LayerStyle::fromJson(style.toObject())); - } + styles = LayerStyleContainer::fromJson(stylesArray); } void LayerWrapper::SimpleProperty::apply(PixelPath&cache) @@ -135,7 +132,7 @@ void LeafLayerWrapper::refresh(LayerWrapper* layer) cache.clear(); if (wrappedElement != nullptr) { - cache.addPath(wrappedElement->getPaintObject(&(this->styles))); + cache.addPath(wrappedElement->getPaintObject(this->styles)); } LayerWrapper::refresh(); } @@ -245,10 +242,7 @@ QJsonObject LeafLayerWrapper::toJson() const QJsonObject json = LayerWrapper::toJson(); json.insert("element", wrappedElement->index); json.insert("is-folder", false); - QJsonArray stylesJson; - for (auto& style : styles) - stylesJson.push_back(style->toJson()); - json.insert("styles", stylesJson); + json.insert("styles", styles.toJson()); return json; } diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 9a76c3b..dd87c4f 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -98,8 +98,7 @@ class LeafLayerWrapper : public LayerWrapper { public: GraphicElement *wrappedElement; - //const vector styles; - vector> styles; + LayerStyleContainer styles; public: ~LeafLayerWrapper() = default; diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp index d41d374..6e84bd7 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -81,39 +80,40 @@ void InfoDisplayWidget::generateLayerForm() layout->addRow("scale-X:", scaleX); layout->addRow("scale-Y:", scaleY); layout->setRowWrapPolicy(QFormLayout::DontWrapRows); - - LeafLayerWrapper* leafP = dynamic_cast(this->displayLayer); - if (leafP) { - QListWidget* styleList = new QListWidget(this); - QListWidgetItem* header = new QListWidgetItem; - QWidget* headerWidget = new QWidget(styleList); - QHBoxLayout* headerLayout = new QHBoxLayout; + if (auto* leafP = dynamic_cast(this->displayLayer); leafP) { + auto* styleList = new QListWidget(this); - QLabel* headerLabel = new QLabel(headerWidget); + auto* header = new QListWidgetItem; + auto* headerWidget = new QWidget(styleList); + auto* headerLayout = new QHBoxLayout; + + auto* headerLabel = new QLabel(headerWidget); headerLabel->setText("鏍峰紡鍒楄〃"); headerLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); //QtMaterialRaisedButton* addStyleButton = new QtMaterialRaisedButton("+", headerWidget); - QPushButton* addStyleButton = new QPushButton("+", headerWidget); + auto* addStyleButton = new QPushButton("+", headerWidget); addStyleButton->setFixedSize(QSize(20, 20)); - if (leafP->styles.size() >= LayerStyle::types.size()) + if (leafP->styles.full()) { addStyleButton->setDisabled(true); } else { - connect(addStyleButton, &QPushButton::clicked, [&, leafP]() { - LayerStyleDialog* dialog = new LayerStyleDialog(nullptr, nullptr, &(leafP->styles)); - dialog->exec(); - if (dialog->layerStyle) - { - leafP->styles.push_back(dialog->layerStyle); - emit requireRefreshPreview(); - emit requireSelfRefresh(); - emit requireRefreshElementWidget(); - } - dialog->deleteLater(); + connect(addStyleButton, &QPushButton::clicked, [&, leafP] { + auto* dialog = new LayerStyleDialog(leafP->styles); + dialog->exec(); + if (dialog->layerStyle) + { + leafP->styles.useStyle(dialog->layerStyle); + leafP->styles.computeNewHash(); + + emit requireRefreshPreview(); + emit requireSelfRefresh(); + emit requireRefreshElementWidget(); + } + dialog->deleteLater(); }); } @@ -179,32 +179,35 @@ void InfoDisplayWidget::generateLayerForm() { leafP->styles.push_back(std::shared_ptr(new StrokeElementLayerStyle())); }*/ - std::vector>* styles = &(leafP->styles); - for (auto styleIterator = styles->begin(); styleIterator != styles->end(); styleIterator++) + auto* styles = &leafP->styles; + for (auto styleIterator = styles->begin(); styleIterator != styles->end(); ++styleIterator) { - QListWidgetItem* item = new QListWidgetItem; - QWidget* w = new QWidget; + auto* item = new QListWidgetItem; + auto* w = new QWidget(this); item->setSizeHint(QSize(50, 40)); - QHBoxLayout* layout = new QHBoxLayout; + auto* layout = new QHBoxLayout(w); layout->setAlignment(Qt::AlignmentFlag::AlignRight); //QtMaterialFlatButton* detailButton = new QtMaterialFlatButton(w); //QtMaterialFlatButton* removeButton = new QtMaterialFlatButton(w); - QPushButton* detailButton = new QPushButton(w); - QPushButton* removeButton = new QPushButton(w); + auto* detailButton = new QPushButton(w); + auto* removeButton = new QPushButton(w); detailButton->setText("..."); detailButton->setFixedSize(QSize(20, 20)); removeButton->setText("脳"); removeButton->setFixedSize(QSize(20, 20)); connect(detailButton, &QPushButton::clicked, this, - [this, styleIterator]() + [this, styles, styleIterator] { - LayerStyleDialog* dialog = new LayerStyleDialog(nullptr, *styleIterator); + auto* dialog = + new LayerStyleDialog(*styles, styleIterator->second); dialog->exec(); if (dialog->layerStyle) { - (*styleIterator) = dialog->layerStyle; + styleIterator->second = dialog->layerStyle; + styles->computeNewHash(); + emit requireRefreshPreview(); emit requireSelfRefresh(); emit requireRefreshElementWidget(); @@ -213,15 +216,17 @@ void InfoDisplayWidget::generateLayerForm() }); connect(removeButton, &QPushButton::clicked, this, - [this, styleIterator, styles]() + [this, styleIterator, styles] { - styles->erase(styleIterator); + styles->dropStyle(styleIterator->first); + styles->computeNewHash(); + emit requireRefreshPreview(); emit requireSelfRefresh(); emit requireRefreshElementWidget(); }); - QWidget* styleDisplayWidget = (*styleIterator)->getListDisplayWidget(); + QWidget* styleDisplayWidget = styleIterator->second->getListDisplayWidget(); styleDisplayWidget->setParent(w); styleDisplayWidget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); From 31f2c1be8f11e728050cef1b3fe7011787f48320 Mon Sep 17 00:00:00 2001 From: wuyize Date: Sat, 18 Mar 2023 12:17:04 +0800 Subject: [PATCH 28/40] =?UTF-8?q?=E6=89=93=E5=BC=80=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E6=97=B6=E5=8D=B8=E8=BD=BD=E7=8E=B0=E6=9C=89=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ArchitectureColoredPainting/RendererWidget.ui | 18 +++++++- .../src/Renderer/Mesh.h | 2 +- .../src/Renderer/Model.cpp | 43 ++++++++++++------- .../src/Renderer/Model.h | 5 ++- .../src/Renderer/RendererWidget.h | 1 + .../src/Renderer/VirtualTextureManager.cpp | 24 +++++++++-- .../src/Renderer/VirtualTextureManager.h | 5 ++- 7 files changed, 74 insertions(+), 24 deletions(-) diff --git a/ArchitectureColoredPainting/RendererWidget.ui b/ArchitectureColoredPainting/RendererWidget.ui index e116c32..e0d5a12 100644 --- a/ArchitectureColoredPainting/RendererWidget.ui +++ b/ArchitectureColoredPainting/RendererWidget.ui @@ -84,10 +84,26 @@
- + QLayout::SetDefaultConstraint + + + + + 0 + 0 + + + + + 0 + 16777215 + + + + diff --git a/ArchitectureColoredPainting/src/Renderer/Mesh.h b/ArchitectureColoredPainting/src/Renderer/Mesh.h index ec452fd..35348bc 100644 --- a/ArchitectureColoredPainting/src/Renderer/Mesh.h +++ b/ArchitectureColoredPainting/src/Renderer/Mesh.h @@ -18,7 +18,7 @@ namespace Renderer glm::vec3 Position; glm::vec3 Normal; glm::vec2 TexCoords; - Vertex(const aiVector3D& position, const aiVector3D& Normal, const aiVector3D& TexCoords); + Vertex(const aiVector3D& position, const aiVector3D& normal, const aiVector3D& texCoords); }; struct Texture diff --git a/ArchitectureColoredPainting/src/Renderer/Model.cpp b/ArchitectureColoredPainting/src/Renderer/Model.cpp index e96d36a..bcbfbb5 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Model.cpp @@ -32,14 +32,12 @@ Model::Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, } void Model::draw() { - //shaderProgram->bind(); for (auto& mesh : meshes) { mesh->draw(); } } void Model::drawShadow() { - //shaderProgram->bind(); for (auto& mesh : meshes) { mesh->drawShadow(); } @@ -55,7 +53,7 @@ void Renderer::Model::loadModel(QString path) const aiScene* scene = importer.ReadFile(modelFile.absoluteFilePath().toUtf8(), aiProcess_Triangulate); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { - qCritical() << "ERROR::ASSIMP::" << importer.GetErrorString() << endl; + qCritical() << "ERROR::ASSIMP::" << importer.GetErrorString(); return; } qDebug() << modelFile.absoluteFilePath() << "Loaded Successfully"; @@ -63,9 +61,11 @@ void Renderer::Model::loadModel(QString path) qDebug() << "NumMaterials: " << scene->mNumMaterials; qDebug() << "NumTextures: " << scene->mNumTextures; + unloadModel(); + + if (QFile paintingConfigFile(directory.filePath(name + ".txt")); paintingConfigFile.open(QFile::ReadOnly | QIODevice::Text)) { - paintingMap.clear(); QTextStream stream(&paintingConfigFile); while (!stream.atEnd()) { @@ -81,6 +81,30 @@ void Renderer::Model::loadModel(QString path) { qWarning() << "Painting Config Not Found!"; } + + + aiMatrix4x4 transform; + aiMatrix4x4::Scaling(aiVector3D(1 / 0.008), transform); + processNode(scene->mRootNode, scene, transform * scene->mRootNode->mTransformation); + AABB.clear(); + AABB.emplace_back(minX, minY, minZ); + AABB.emplace_back(minX, minY, maxZ); + AABB.emplace_back(minX, maxY, minZ); + AABB.emplace_back(minX, maxY, maxZ); + AABB.emplace_back(maxX, minY, minZ); + AABB.emplace_back(maxX, minY, maxZ); + AABB.emplace_back(maxX, maxY, minZ); + AABB.emplace_back(maxX, maxY, maxZ); +} + +void Renderer::Model::unloadModel() +{ + paintingMap.clear(); + for(auto& i: paintingLoaded) + vtManager->deleteVirtualTexture(i.second); + paintingLoaded.clear(); + texturesLoaded.clear(); + meshes.clear(); minX = std::numeric_limits::max(); maxX = std::numeric_limits::min(); @@ -88,17 +112,6 @@ void Renderer::Model::loadModel(QString path) maxY = std::numeric_limits::min(); minZ = std::numeric_limits::max(); maxZ = std::numeric_limits::min(); - aiMatrix4x4 transform; - aiMatrix4x4::Scaling(aiVector3D(1 / 0.008), transform); - processNode(scene->mRootNode, scene, transform * scene->mRootNode->mTransformation); - AABB.push_back(QVector3D(minX, minY, minZ)); - AABB.push_back(QVector3D(minX, minY, maxZ)); - AABB.push_back(QVector3D(minX, maxY, minZ)); - AABB.push_back(QVector3D(minX, maxY, maxZ)); - AABB.push_back(QVector3D(maxX, minY, minZ)); - AABB.push_back(QVector3D(maxX, minY, maxZ)); - AABB.push_back(QVector3D(maxX, maxY, minZ)); - AABB.push_back(QVector3D(maxX, maxY, maxZ)); } void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4) diff --git a/ArchitectureColoredPainting/src/Renderer/Model.h b/ArchitectureColoredPainting/src/Renderer/Model.h index d9a6bea..d8112f9 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.h +++ b/ArchitectureColoredPainting/src/Renderer/Model.h @@ -15,6 +15,7 @@ namespace Renderer void draw(); void drawShadow(); void loadModel(QString path); + void unloadModel(); Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, VirtualTextureManager* vtManager); private: QOpenGLContext* context = nullptr; @@ -25,8 +26,8 @@ namespace Renderer VirtualTextureManager* vtManager = nullptr; /** - * @param key BaseColor路径 - * @param value json路径, 纹理坐标 + * @brief key BaseColor路径 \n + * value json路径, 纹理坐标 */ std::unordered_map> paintingMap; std::unordered_map paintingLoaded; diff --git a/ArchitectureColoredPainting/src/Renderer/RendererWidget.h b/ArchitectureColoredPainting/src/Renderer/RendererWidget.h index 258a173..d5a3725 100644 --- a/ArchitectureColoredPainting/src/Renderer/RendererWidget.h +++ b/ArchitectureColoredPainting/src/Renderer/RendererWidget.h @@ -13,6 +13,7 @@ namespace Renderer ~RendererWidget(); public slots: void currentTabChanged(int index); + private: Ui::RendererWidgetClass ui; }; diff --git a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp index b926ad4..87888db 100644 --- a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp +++ b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp @@ -76,7 +76,7 @@ Renderer::VirtualTextureManager::VirtualTextureManager(GladGLContext* glMain) pageIdBufferMutex.lock(); currentBuffer = 1 - currentBuffer; pageIdBufferMutex.unlock(); - + gl->BeginQuery(GL_TIME_ELAPSED, pageLoadTimeQuery); updatePages(pageIds); gl->EndQuery(GL_TIME_ELAPSED); @@ -152,8 +152,26 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai } } - paintings.emplace_back(baseColor, metallicRoughness, painting.buffers); - return paintings.size(); + if (const auto it = std::find_if(paintings.begin(), paintings.end(), [](const PaintingHandle& i) { return i.baseColor == 0; }); + it != paintings.end()) + { + *it = { baseColor, metallicRoughness, painting.buffers }; + return it - paintings.begin() + 1; + } + else + { + paintings.emplace_back(baseColor, metallicRoughness, painting.buffers); + return paintings.size(); + } + +} + +void Renderer::VirtualTextureManager::deleteVirtualTexture(std::uint16_t id) +{ + auto& painting = getPaintingHandle(id); + glMain->DeleteTextures(2, (GLuint*)&painting); + painting.baseColor = 0; + painting.metallicRoughness = 0; } Renderer::PaintingHandle& Renderer::VirtualTextureManager::getPaintingHandle(std::uint16_t id) diff --git a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h index 520800b..bd31cbe 100644 --- a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h +++ b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h @@ -24,11 +24,12 @@ namespace Renderer VirtualTextureManager(GladGLContext* glMain); /** - * @brief - * @param painting + * @brief 创建彩绘虚拟纹理 + * @param painting 彩绘 * @return 虚拟纹理id */ std::uint16_t createVirtualTexture(Painting painting); + void deleteVirtualTexture(std::uint16_t id); PaintingHandle& getPaintingHandle(std::uint16_t id); void tryUpdatePages(const std::vector& pageIds); From aeead9d22e08173162dde9e6cb6ddd18d5957cd0 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Sat, 18 Mar 2023 20:12:43 +0800 Subject: [PATCH 29/40] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=97=B6=E9=80=92=E5=BD=92=E7=BA=A6=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LayerCreateWidget.cpp | 49 +++++++++++++++++-- .../EditorWidgetComponent/LayerCreateWidget.h | 5 +- .../src/Editor/GraphicElement.cpp | 8 +++ .../src/Editor/GraphicElement.h | 1 + .../src/Editor/LayerWrapper.cpp | 32 ++++++++++++ .../src/Editor/LayerWrapper.h | 5 +- .../src/Editor/RightBar/LayerTreeWidget.cpp | 4 +- 7 files changed, 98 insertions(+), 6 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp index ed6743a..45d8dfe 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp @@ -1,15 +1,46 @@ #include "LayerCreateWidget.h" #include -LayerCreateWidget::LayerCreateWidget(ElementManager* elementManager, QWidget* parent) : +LayerCreateWidget::LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent) : QDialog(parent) { + this->elementManager = elementManager; ui.setupUi(this); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); elementPool = new ElementPoolWidget(ui.elementPool); - elementPool->setElementList(elementManager->elements); + elements = elementManager->elements; + elementsCheck(folderLayer); + elementPool->setElementList(elements); +} + +void LayerCreateWidget::elementsCheck(FolderLayerWrapper* parent) +{ + std::set upSet, downSet; + parent->collectUpReachable(upSet); + for (auto it = elements.begin(); it != elements.end();) + { + bool valid = true; + auto ele = dynamic_cast(*it); + if (ele != nullptr) + { + downSet.clear(); + ele->collectReachable(downSet); + for (auto& layer : downSet) + { + if (upSet.find(layer) != upSet.end()) + { + valid = false; + break; + } + } + } + if (valid) + ++it; + else + it = elements.erase(it); + } } LayerCreateWidget::~LayerCreateWidget() @@ -21,8 +52,20 @@ void LayerCreateWidget::accept() QJsonObject jsonObj; jsonObj.insert("name", ui.name->text()); if (ui.comboBox->currentIndex() == 0) { + auto currentEle = elements[elementPool->currentIndex]; + int index = -1; + for (int i = 0; i < elementManager->elements.size(); i++) + { + if (elementManager->elements[i] == currentEle) + { + index = i; + break; + } + } + if (index == -1) + return; jsonObj.insert("is-folder", false); - jsonObj.insert("element", elementPool->currentIndex); + jsonObj.insert("element", index); } else { jsonObj.insert("is-folder", true); diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h index c9b7c89..38456b2 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h @@ -11,12 +11,15 @@ class LayerCreateWidget : Q_OBJECT private: + ElementManager* elementManager; + std::vector elements; Ui::LayerCreateWidget ui; ElementPoolWidget* elementPool; + void elementsCheck(FolderLayerWrapper*); public: - LayerCreateWidget(ElementManager* elementManager,QWidget* parent = nullptr); + LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent = nullptr); ~LayerCreateWidget(); void accept() override; diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 8896f9e..5c0acb0 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -148,4 +148,12 @@ QPixmap GroupElement::getPreview(QSize size) rect.setBottomRight(rect.bottomRight() + QPoint(5, 5)); result = result.copy(rect); return result.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); +} + +void GroupElement::collectReachable(std::set& set) const +{ + if (sourceLayer != nullptr) + { + sourceLayer->collectDownReachable(set); + } } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index 12e2cfa..d0500b2 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -66,6 +66,7 @@ public: void setSourceLayer(FolderLayerWrapper* sourceLayer); void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; QPixmap getPreview(QSize size) override; + void collectReachable(std::set& set) const; }; //******************************** BitmapPath ********************************// diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 9281248..e30b068 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -285,4 +285,36 @@ void LeafLayerWrapper::paint(QPainter* painter, QTransform transform, bool ignor { wrappedElement->paint(painter, transform, styles); } +} + +void LayerWrapper::collectUpReachable(std::set& reachable) +{ + auto cPos = this; + while (cPos != nullptr) + { + reachable.insert(cPos); + cPos = cPos->parent; + } +} + +void LayerWrapper::collectDownReachable(std::set& reachable) +{ + reachable.insert(this); +} + +void LeafLayerWrapper::collectDownReachable(std::set& reachable) +{ + LayerWrapper::collectDownReachable(reachable); + auto ele = dynamic_cast(wrappedElement); + if (ele != nullptr) + { + ele->collectReachable(reachable); + } +} + +void FolderLayerWrapper::collectDownReachable(std::set& reachable) +{ + LayerWrapper::collectDownReachable(reachable); + for (auto& child : children) + child->collectDownReachable(reachable); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index dd87c4f..92d82d1 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -68,7 +68,8 @@ class LayerWrapper virtual void delSelf(); virtual QJsonObject toJson() const; ~LayerWrapper() = default; - + virtual void collectUpReachable(std::set& reachable); + virtual void collectDownReachable(std::set& reachable); }; class FolderLayerWrapper : public LayerWrapper @@ -92,6 +93,7 @@ class FolderLayerWrapper : public LayerWrapper QJsonObject toJson() const override; int getReferencedBy()const; void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; + void collectDownReachable(std::set& reachable) override; }; class LeafLayerWrapper : public LayerWrapper @@ -107,6 +109,7 @@ class LeafLayerWrapper : public LayerWrapper LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); QJsonObject toJson() const override; void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; + void collectDownReachable(std::set& reachable) override; }; Q_DECLARE_METATYPE(LayerWrapper *) diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index 13f8e4e..8b85c1a 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -50,7 +50,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos) if (layer != nullptr) { if (typeid(*layer) == typeid(FolderLayerWrapper)) { menu.addAction(QString::fromLocal8Bit("创建子节点"), this, [this, layer]() { - auto dialog = new LayerCreateWidget(elementManager, this); + auto dialog = new LayerCreateWidget(elementManager, dynamic_cast(layer), this); connect(dialog, &LayerCreateWidget::LayerInfoReturned, this, [this, layer](QJsonObject jsonObj) { auto folderLayer = dynamic_cast(layer); LayerWrapper* newLayer; @@ -76,6 +76,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos) layer->getParent()->removeChild(layer); this->refresh(); emit requireRefreshPreview(); + emit requireRefreshElementWidget(); }); menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent); if(typeid(*layer) == typeid(FolderLayerWrapper)) @@ -85,6 +86,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos) layer->getParent()->removeChild(layer); this->refresh(); emit requireRefreshPreview(); + emit requireRefreshElementWidget(); }); } if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) { From fd1baf42f68a8451d453904534dde292a90965fc Mon Sep 17 00:00:00 2001 From: wuyize Date: Sat, 18 Mar 2023 20:13:17 +0800 Subject: [PATCH 30/40] =?UTF-8?q?Renderer=E5=9B=BE=E5=85=83=E5=8F=98?= =?UTF-8?q?=E6=8D=A2=E6=94=B9=E7=94=A8=E7=9F=A9=E9=98=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/Shaders/painting.comp | 109 +++++++---------- .../src/Editor/util/PaintingUtil.cpp | 7 +- .../src/Renderer/Model.cpp | 54 ++++++--- .../src/Renderer/Painting/Element.cpp | 28 ++--- .../src/Renderer/Painting/Element.h | 19 +-- .../src/Renderer/Painting/Painting.cpp | 112 +++++++----------- .../src/Renderer/Painting/Painting.h | 23 +--- .../src/Renderer/Preview/ElementRenderer.cpp | 16 ++- .../src/Renderer/VirtualTextureManager.cpp | 10 +- .../src/Renderer/VirtualTextureManager.h | 2 +- 10 files changed, 182 insertions(+), 198 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp index 7324942..6e166cf 100644 --- a/ArchitectureColoredPainting/res/Shaders/painting.comp +++ b/ArchitectureColoredPainting/res/Shaders/painting.comp @@ -20,22 +20,25 @@ layout(std430, binding = 1) buffer bvhBoundBuffer { vec4 bvhBound[]; }; -layout(std430, binding = 2) buffer elementOffsetBuffer +layout(std430, binding = 2) buffer elementTranformBuffer +{ + mat3x2 elementTranform[]; +}; +layout(std430, binding = 3) buffer elementOffsetBuffer { /** * @[0] elementBvhRoot * @[1] styleOffset * @[2] pointsOffset * @[3] linesOffset - */ - uint elementOffset[][5]; + uint elementOffset[][4]; }; -layout(std430, binding = 3) buffer elementIndexBuffer +layout(std430, binding = 4) buffer elementIndexBuffer { uint elementIndexs[]; // 线和面 }; -layout(std430, binding = 4) buffer elementDataBuffer +layout(std430, binding = 5) buffer elementDataBuffer { float elementData[]; // 点和Style }; @@ -1115,15 +1118,11 @@ bool fillElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsO } bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex, - float widthHeightRatio, inout vec4 elementColor, inout vec2 metallicRoughness) + inout vec4 elementColor, inout vec2 metallicRoughness) { bool hitElement = false; float strokeWidth = elementData[styleIndex]; - vec2 size = normalize(vec2(widthHeightRatio, 1)) + vec2(2 * strokeWidth); - vec2 ratio = widthHeightRatio < 1 ? vec2(widthHeightRatio, 1) : vec2(1, 1 / widthHeightRatio); - localUV *= ratio; - float minDistance = 1e38; uint lineCount = elementIndexs[contourIndex]; vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])); @@ -1149,17 +1148,13 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]); - p[0] *= ratio; - p[1] *= ratio; - p[2] *= ratio; - p[3] *= ratio; vec2 tangentBeginNext = vec2(0); if (contourIterator + 1 < contourIndex + 1 + lineCount) { uint lineIndex = elementIndexs[contourIterator + 1]; uint pLocation = linesOffset + 3 * lineIndex; - //vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]); + // vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]); uvec4 pxIndex = uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF, elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF); @@ -1168,10 +1163,6 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point mat4x2 pNext = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]); - pNext[0] *= ratio; - pNext[1] *= ratio; - pNext[2] *= ratio; - pNext[3] *= ratio; if (pNext[0] == pNext[1] && pNext[2] == pNext[3]) { @@ -1179,8 +1170,8 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point pNext[2] = pNext[1]; } - //if(pNext[0]!=p[3]) - // break; + // if(pNext[0]!=p[3]) + // break; if (pNext[0] != pNext[1]) tangentBeginNext = normalize(pNext[0] - pNext[1]); else @@ -1221,11 +1212,11 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point bool hit = d < minDistance; if (onBegin) - hit = - hit && shouldFillBeginCap(localUV, contourIterator == contourIndex + 1, endType, p[0], tangentBegin, p3Last - p2Last); + hit = hit && shouldFillBeginCap(localUV, contourIterator == contourIndex + 1, endType, p[0], + tangentBegin, p3Last - p2Last); if (onEnd) - hit = hit && - shouldFillEndCap(localUV, tangentBeginNext==vec2(0), endType, p[3], tangentEnd, tangentBeginNext); + hit = hit && shouldFillEndCap(localUV, tangentBeginNext == vec2(0), endType, p[3], tangentEnd, + tangentBeginNext); if (hit) { @@ -1272,7 +1263,7 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point return hitElement; } -bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, out vec2 metallicRoughness, +bool drawElement(uint elementIndex, vec2 localUV, out vec3 color, out vec2 metallicRoughness, inout vec3 debugBVH = vec3(0)) { bool hitElement = false; @@ -1284,7 +1275,7 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou uint styleIndex = currentOffset[1]; uint pointsOffset = currentOffset[2]; uint linesOffset = currentOffset[3]; - float widthHeightRatio = uintBitsToFloat(currentOffset[4]); + // float widthHeightRatio = uintBitsToFloat(currentOffset[4]); elementStack.top = 0; uint elementBvhIndex = 0; @@ -1317,7 +1308,7 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou else // 线 { hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex, - widthHeightRatio, elementColor, metallicRoughness); + elementColor, metallicRoughness); } elementBvhIndex = elementBvhLength; @@ -1357,7 +1348,7 @@ void main() vec3 debugBVH = vec3(0); // bool debugHit = false; - //vec4 color = vec4(0.76, 0.33, 0.15, -1); + // vec4 color = vec4(0.76, 0.33, 0.15, -1); vec4 color = vec4(backgroundColor, -1); vec2 metallicRoughness = vec2(0, 0.8); stack.top = 0; @@ -1371,49 +1362,39 @@ void main() visitTime++; vec4 bound = bvhBound[index]; uint leftChild = bvhChildren[index].x; - if (leftChild >= bvhLength) - { - uint zIndex = bvhChildren[index].y >> 18; - bvec2 flip = bvec2(bvhChildren[index].y & (1 << 16), bvhChildren[index].y & (1 << 17)); - float angle = (float(bvhChildren[index].y & ((1 << 16) - 1)) / 65535.0) * 2 * PI; - mat2 rotation = {{cos(angle), -sin(angle)}, {sin(angle), cos(angle)}}; - vec2 localUV = uv - (bound.xy + bound.zw) / 2; - localUV = rotation * localUV; - vec2 scale = (bound.zw - bound.xy) / 2; - localUV /= scale; - if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex > color.w) - { - // if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005)))) - if (any(greaterThan(vec2(-1) + vec2(0.005), localUV)) || - any(greaterThan(localUV, vec2(1) - vec2(0.005)))) - debugBVH.g += 0.3; - // uint elementIndex = leftChild - bvhLength; - // debugBVH.bg += 0.5 * (localUV + vec2(1)); - // debugBVH = vec3(0); - if (flip.x) - localUV.x = -localUV.x; - if (flip.y) - localUV.y = -localUV.y; + if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw))) + { + if (any(greaterThan(bound.xy + vec2(0.005), uv)) || any(greaterThan(uv, bound.zw - vec2(0.005)))) + debugBVH.g += 0.3; + + if (leftChild >= bvhLength) + { + uint transformIndex = leftChild - 0x80000000; + uint zIndex = bvhChildren[index].y >> 18; + uint elementIndex = bvhChildren[index].y - zIndex; + mat3x2 transform = elementTranform[transformIndex]; + vec2 localUV = + (mat3(vec3(transform[0], 0), vec3(transform[1], 0), vec3(transform[2], 1)) * vec3(uv, 1)).xy; + vec3 elementColor; vec2 elementMetallicRoughness; - if (drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness, + if (drawElement(elementIndex, localUV, elementColor, elementMetallicRoughness, debugBVH)) { color = vec4(elementColor, zIndex); metallicRoughness = elementMetallicRoughness; } - } + //if(elementIndex == 1 && transformIndex==1) + // color = vec4(1,1,0,1); - index = bvhLength; - } - else if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw))) - { - if (any(greaterThan(bound.xy + vec2(0.005), uv)) || any(greaterThan(uv, bound.zw - vec2(0.005)))) - debugBVH.g += 0.3; - // debugBVH.r += 0.02; - stack.push(index); - index = leftChild; + index = bvhLength; + } + else + { + stack.push(index); + index = leftChild; + } } else index = bvhLength; @@ -1428,7 +1409,7 @@ void main() imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1)); imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1)); - return; + //return; if (/*color.a!=-1&&*/ debugBVH == vec3(0)) { // imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1)); diff --git a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp index 8c4ec74..aea42d4 100644 --- a/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp +++ b/ArchitectureColoredPainting/src/Editor/util/PaintingUtil.cpp @@ -99,7 +99,10 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr qDebug() << painterPath; bound = painterPath.boundingRect(); qDebug() << bound; - elementTrans.center = glm::vec2( + + // TODO 改用矩阵 + + /* elementTrans.center = glm::vec2( (2 * bound.center().x() - screenSize.width()) / screenSize.width(), (2 * bound.center().y() - screenSize.height()) / screenSize.height() ); @@ -114,7 +117,7 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr nowLayer->property.flipVertically ); qDebug() << elementTrans.scale.x << elementTrans.scale.y; - painting.addElement(element, elementTrans); + painting.addElement(element, elementTrans);*/ return nullptr; } diff --git a/ArchitectureColoredPainting/src/Renderer/Model.cpp b/ArchitectureColoredPainting/src/Renderer/Model.cpp index bcbfbb5..3510ed7 100644 --- a/ArchitectureColoredPainting/src/Renderer/Model.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Model.cpp @@ -16,6 +16,7 @@ #include #include #include "Painting/MaterialStyleStroke.h" +#include using namespace Renderer; using std::vector; @@ -81,7 +82,7 @@ void Renderer::Model::loadModel(QString path) { qWarning() << "Painting Config Not Found!"; } - + aiMatrix4x4 transform; aiMatrix4x4::Scaling(aiVector3D(1 / 0.008), transform); @@ -100,7 +101,7 @@ void Renderer::Model::loadModel(QString path) void Renderer::Model::unloadModel() { paintingMap.clear(); - for(auto& i: paintingLoaded) + for (auto& i : paintingLoaded) vtManager->deleteVirtualTexture(i.second); paintingLoaded.clear(); texturesLoaded.clear(); @@ -280,13 +281,13 @@ GLuint Renderer::Model::loadPainting(std::string path) if (path == "0.json") { - painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,-0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); - painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45, 0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); - painting.addElement(*element[2], ElementTransform{ glm::vec2(0.50,-0.45), glm::vec2(0.6,0.7) / 2.f, 0, glm::bvec2(false), 0 }); + //painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,-0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); + //painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45, 0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 }); + //painting.addElement(*element[2], ElementTransform{ glm::vec2(0.50,-0.45), glm::vec2(0.6,0.7) / 2.f, 0, glm::bvec2(false), 0 }); } else if (path == "1.json") { - painting.backgroundColor = QColor(196, 81, 35); + //painting.backgroundColor = QColor(196, 81, 35); float widths[] = { 0.22, 0.22 * 0.25 / 0.15, 0.22 * 0.25 / 0.15 }; QPainterPath painterPaths[6]; for (int i = 0; i < 6; i++) @@ -322,14 +323,39 @@ GLuint Renderer::Model::loadPainting(std::string path) std::make_shared(widths[1], StrokeType::kRightSide), std::make_shared(widths[2], StrokeType::kLeftSide), }; - vector> element = { - std::make_shared(Element{ contours[0].first, style[0], contours[0].second}), - std::make_shared(Element{ contours[1].first, style[1], contours[1].second}), - std::make_shared(Element{ contours[2].first, style[2], contours[2].second}), + std::map materialMap = { + {0.09, Material{QColor(255,255,255),0,0.8}}, + {0.63, Material{QColor(165,176,207),0,0.8}}, + {1.00, Material{QColor(58,64,151),0,0.8}} }; - painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,0.45), glm::vec2(0.25), 0, glm::bvec2(false), 0 }); - painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.535,0.33), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); - painting.addElement(*element[2], ElementTransform{ glm::vec2(-0.535,0.23), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); + vector> element = { + std::make_shared(contours[0].first, std::make_shared( + widths[0], StrokeType::kLeftSide, StrokeEndType::kFlat, std::make_shared(materialMap, false))), + std::make_shared(contours[1].first, std::make_shared( + widths[1], StrokeType::kRightSide, StrokeEndType::kFlat, std::make_shared(materialMap, false))), + std::make_shared(contours[2].first, std::make_shared( + widths[2], StrokeType::kLeftSide, StrokeEndType::kFlat, std::make_shared(materialMap, false))), + }; + + QTransform trans = QTransform::fromScale(0.3, 0.3).inverted(); + glm::mat3x2 mat(trans.m11(), trans.m12(), trans.m21(), trans.m22(), trans.m31(), trans.m32()); + + trans = QTransform::fromTranslate(0.5, 0).scale(0.3, 0.3).inverted(); + glm::mat3x2 mat2(trans.m11(), trans.m12(), trans.m21(), trans.m22(), trans.m31(), trans.m32()); + //mat = glm::mat3x2(11, 22, 33, 44, 55, 66); + //mat2 = glm::mat3x2(1, 2, 3, 4, 5, 6); + + qDebug() << std::format("\n{} {} {}\n {} {} {}\n{} {} {}", + trans.m11(), trans.m21(), trans.m31(), + trans.m12(), trans.m22(), trans.m32(), + trans.m13(), trans.m23(), trans.m33()).c_str(); + + //painting.addElement(*element[0], ElementTransform{ glm::vec4(-1,-1,1,1), mat, 0}); + painting.addElement(*element[1], ElementTransform{ glm::vec4(-1,-1,0,1), mat, 0 }); + painting.addElement(*element[2], ElementTransform{ glm::vec4(0,-1,1,1), mat2, 0 }); + //painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,0.45), glm::vec2(0.25), 0, glm::bvec2(false), 0 }); + //painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.535,0.33), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); + //painting.addElement(*element[2], ElementTransform{ glm::vec2(-0.535,0.23), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); } else { @@ -337,7 +363,7 @@ GLuint Renderer::Model::loadPainting(std::string path) { float x = (float)rand() / RAND_MAX * 2 - 1; float y = (float)rand() / RAND_MAX * 2 - 1; - painting.addElement(*element[i % 3], ElementTransform{ glm::vec2(x,y), glm::vec2(0.025), (float)rand() / RAND_MAX * 360, glm::bvec2(false), 0 }); + //painting.addElement(*element[i % 3], ElementTransform{ glm::vec2(x,y), glm::vec2(0.025), (float)rand() / RAND_MAX * 360, glm::bvec2(false), 0 }); } } } diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/Element.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/Element.cpp index 4f2dab0..ce01a11 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/Element.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/Element.cpp @@ -1,16 +1,16 @@ #include "Element.h" -void Renderer::ElementTransform::applyTransformStyle(const TransformStyle& t) -{ - center += t.translation; - scale *= t.scale; - rotation += t.rotation; - flip ^= t.flip; -} - -Renderer::ElementTransform Renderer::ElementTransform::appliedTransformStyle(const TransformStyle& t) const -{ - ElementTransform result = *this; - result.applyTransformStyle(t); - return result; -} +//void Renderer::ElementTransform::applyTransformStyle(const TransformStyle& t) +//{ +// /*center += t.translation; +// scale *= t.scale; +// rotation += t.rotation; +// flip ^= t.flip;*/ +//} +// +//Renderer::ElementTransform Renderer::ElementTransform::appliedTransformStyle(const TransformStyle& t) const +//{ +// ElementTransform result = *this; +// result.applyTransformStyle(t); +// return result; +//} diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/Element.h b/ArchitectureColoredPainting/src/Renderer/Painting/Element.h index 2e5c892..c7655ed 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/Element.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/Element.h @@ -5,7 +5,7 @@ #include "Line.h" #include "ElementStyle.h" -namespace Renderer +namespace Renderer { using Contour = std::vector>; @@ -18,14 +18,15 @@ namespace Renderer struct ElementTransform { - glm::vec2 center; - //glm::vec2 size; - glm::vec2 scale; /// 相对于画布 - float rotation; /// 角度制 - glm::bvec2 flip; + //glm::vec2 center; + //glm::vec2 scale; /// 相对于画布 + //float rotation; /// 角度制 + //glm::bvec2 flip; + glm::vec4 bound; /// 包围盒,不影响变换 + glm::mat3x2 transform; /// 逆变换 GLuint zIndex; - - void applyTransformStyle(const TransformStyle& t); - ElementTransform appliedTransformStyle(const TransformStyle& t) const; + + //void applyTransformStyle(const TransformStyle& t); + //ElementTransform appliedTransformStyle(const TransformStyle& t) const; }; } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp index afd7e04..2fd6d73 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.cpp @@ -53,87 +53,40 @@ void Renderer::Painting::addElement(ElementWithTransform elementWithTransform) elementPool.insert({ element, 0 }); } elements.push_back(elementWithTransform); + elementTransformPool.emplace(elementWithTransform.transform.transform, 0); } -void Renderer::Painting::addElement(const Element& element, const ElementTransform& transform) +void Renderer::Painting::addElement(const BaseElement& element, const ElementTransform& transform) { - auto contour = element.contour; - auto it = elementStyleMap.find(element.style); - if (it == elementStyleMap.end()) - { - std::vector baseStyles; - for (auto& style : element.style->toBaseStyles()) - { - auto [iter, _] = styleSet.insert(style.material); - baseStyles.push_back(BaseStyle{ style.transform, *iter }); - } - it = elementStyleMap.insert({ element.style, baseStyles }).first; - } - for (int i = 0; i < it->second.size(); i++) - { - auto& style = it->second[i]; - ElementTransform trans = transform; - trans.applyTransformStyle(*style.transform); - trans.zIndex = trans.zIndex * 10 + i; - - addElement(ElementWithTransform{ BaseElement{element.contour, style.material, element.ratio}, trans }); - } + addElement({ element , transform }); } -Renderer::BaseTransform::BaseTransform(ElementTransform t) - : bound(glm::vec4(t.center - t.scale, t.center + t.scale)) - , rotation(t.rotation) - , flip(t.flip) - , zIndex(t.zIndex) +BvhTreeData Painting::encodeElementLeaf(const ElementWithTransform& e) { -} - -void Renderer::Painting::addElement(std::shared_ptr element, QVector4D bound, float rotation, int zIndex) -{ - -} - -BvhTreeData Painting::encodeElementLeaf(ElementWithTransform e) -{ - glm::vec4 bound; - switch (e.element.style->type()) - { - case MaterialStyleType::kStroke: - { - auto w = std::static_pointer_cast(e.element.style)->getHalfWidth(); - glm::vec2 size = e.element.ratio < 1 ? glm::vec2(e.element.ratio, 1) : glm::vec2(1, 1 / e.element.ratio); - glm::vec2 scale = size * e.transform.scale; - bound = glm::vec4(e.transform.center - scale, e.transform.center + scale); - break; - } - case MaterialStyleType::kFill: - { - bound = glm::vec4(e.transform.center - e.transform.scale, e.transform.center + e.transform.scale); - break; - } - } - //bound = glm::vec4(e.transform.center - e.transform.scale, e.transform.center + e.transform.scale); - GLuint rightSon = (GLuint)(glm::mod(e.transform.rotation, 360.f) / 360.f * (1 << 16)) - + (e.transform.flip.x << 16) + (e.transform.flip.y << 17) + (e.transform.zIndex << 18); - return BvhTreeData(QVector4D(bound.x, bound.y, bound.z, bound.w), elementPool[e.element], rightSon); + QVector4D bound(e.transform.bound.x, e.transform.bound.y, e.transform.bound.z, e.transform.bound.w); + GLuint rightSon = elementPool[e.element] + (e.transform.zIndex << 18); + return { bound, elementTransformPool[e.transform.transform], rightSon }; } void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc) { qDebug() << "Element Count: " << elementPool.size(); - qDebug() << "Coutour Count: " << contourPool.size(); + qDebug() << "Contour Count: " << contourPool.size(); qDebug() << " Style Count: " << stylePool.size(); bvhChildren.clear(); bvhBounds.clear(); + elementTransform.clear(); elementOffsets.clear(); elementIndex.clear(); elementData.clear(); for (int index = 0; auto & i : elementPool) - { i.second = index++; - } + for (int index = 0; auto & i : elementTransformPool) + i.second = index++; + + std::vector rootBvhTreeData; for (auto& i : elements) @@ -162,30 +115,35 @@ void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc) elementData.insert(elementData.end(), encodedStyle.begin(), encodedStyle.end()); } + for (auto & i : elementTransformPool) + elementTransform.emplace_back(i.first); + for (auto& i : elementPool) { //qDebug() <<"element:" << i.second; //std::shared_ptr contourBuffer = i.first.style->type() == MaterialStyleType::kStroke ? contourPool[i.first.contour].second : contourPool[i.first.contour].first; auto& contourBuffer = contourPool[{i.first.contour, i.first.style->type()}]; - elementOffsets.push_back({ contourBuffer.bvhOffset, stylePool[i.first.style], contourBuffer.pointsOffset, contourBuffer.linesOffset, glm::floatBitsToUint(i.first.ratio) }); + elementOffsets.push_back({ contourBuffer.bvhOffset, stylePool[i.first.style], contourBuffer.pointsOffset, contourBuffer.linesOffset }); //std::cout << std::format("{} {} {} {}\n", contourBuffer->bvhOffset, stylePool[i.first->style], contourBuffer->pointsOffset, contourBuffer->linesOffset); } - glFunc->glCreateBuffers(6, buffers.data()); + glFunc->glCreateBuffers(7, buffers.data()); GLuint& bvhSSBO = buffers[0]; GLuint& bvhBoundSSBO = buffers[1]; - GLuint& elementOffsetSSBO = buffers[2]; - GLuint& elementIndexSSBO = buffers[3]; - GLuint& elementDataSSBO = buffers[4]; - GLuint& backgroundColorUBO = buffers[5]; + GLuint& elementTransformSSBO = buffers[2]; + GLuint& elementOffsetSSBO = buffers[3]; + GLuint& elementIndexSSBO = buffers[4]; + GLuint& elementDataSSBO = buffers[5]; + GLuint& backgroundColorUBO = buffers[6]; glFunc->glNamedBufferData(buffers[0], bvhChildren.size() * sizeof(bvhChildren[0]), bvhChildren.data(), GL_STATIC_READ); glFunc->glNamedBufferData(buffers[1], bvhBounds.size() * sizeof(bvhBounds[0]), bvhBounds.data(), GL_STATIC_READ); - glFunc->glNamedBufferData(buffers[2], elementOffsets.size() * sizeof(elementOffsets[0]), elementOffsets.data(), GL_STATIC_READ); - glFunc->glNamedBufferData(buffers[3], elementIndex.size() * sizeof(elementIndex[0]), elementIndex.data(), GL_STATIC_READ); - glFunc->glNamedBufferData(buffers[4], elementData.size() * sizeof(elementData[0]), elementData.data(), GL_STATIC_READ); + glFunc->glNamedBufferData(buffers[2], elementTransform.size() * sizeof(elementTransform[0]), elementTransform.data(), GL_STATIC_READ); + glFunc->glNamedBufferData(buffers[3], elementOffsets.size() * sizeof(elementOffsets[0]), elementOffsets.data(), GL_STATIC_READ); + glFunc->glNamedBufferData(buffers[4], elementIndex.size() * sizeof(elementIndex[0]), elementIndex.data(), GL_STATIC_READ); + glFunc->glNamedBufferData(buffers[5], elementData.size() * sizeof(elementData[0]), elementData.data(), GL_STATIC_READ); glm::vec3 color(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF()); - glFunc->glNamedBufferData(buffers[5], sizeof(glm::vec3), &color, GL_STATIC_READ); + glFunc->glNamedBufferData(buffers[6], sizeof(glm::vec3), &color, GL_STATIC_READ); } GLuint Renderer::Painting::getElementCount() @@ -223,3 +181,17 @@ bool Renderer::Painting::CompareMaterialStyle::operator()(const std::shared_ptr< else return left < right; } + +std::size_t Renderer::Painting::HashMat3x2::operator()(const glm::mat3x2& mat) const +{ + std::size_t result = 0; + constexpr long long P = 998244353; + long long base = 1; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + { + result += base * mat[i][j]; + base *= P; + } + return result; +} diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h index 9194040..cf18500 100644 --- a/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h +++ b/ArchitectureColoredPainting/src/Renderer/Painting/Painting.h @@ -15,24 +15,13 @@ namespace Renderer { std::shared_ptr contour; std::shared_ptr style; - float ratio; /// 宽高比 bool operator<(const BaseElement& e) const; }; - struct BaseTransform - { - glm::vec4 bound; - float rotation; - glm::bvec2 flip; - GLuint zIndex; - BaseTransform(ElementTransform t); - }; - struct ElementWithTransform { BaseElement element; ElementTransform transform; - //BaseTransform transform; }; struct ContourBuffer @@ -52,7 +41,6 @@ namespace Renderer GLuint styleOffset; GLuint pointsOffset; GLuint linesOffset; - GLuint ratio; }; class Painting @@ -60,16 +48,16 @@ namespace Renderer public: std::vector bvhChildren; std::vector bvhBounds; + std::vector elementTransform; std::vector elementOffsets; std::vector elementIndex; std::vector elementData; int paintingId = 0; - std::array buffers; + std::array buffers; QColor backgroundColor; Painting(QColor backgroundColor = Qt::white); - void addElement(const Element& element, const ElementTransform& transform); - void addElement(std::shared_ptr element, QVector4D bound, float rotation, int zIndex); + void addElement(const BaseElement& element, const ElementTransform& transform); void generateBuffers(QOpenGLFunctions_4_5_Core* glFunc); GLuint getElementCount(); private: @@ -77,14 +65,15 @@ namespace Renderer std::unordered_map, MaterialStyleType>, ContourBuffer, ContourHash> contourPool; struct CompareMaterialStyle { bool operator()(const std::shared_ptr&, const std::shared_ptr&) const; }; std::set, CompareMaterialStyle> styleSet; - std::unordered_map, std::vector> elementStyleMap; std::unordered_map, GLuint> stylePool; + struct HashMat3x2 { std::size_t operator()(const glm::mat3x2&) const; }; + std::unordered_map elementTransformPool; std::map elementPool; std::vector elements; void addElement(ElementWithTransform element); void insertContourBuffer(ContourBuffer& buffer); - BvhTreeData encodeElementLeaf(ElementWithTransform e); + BvhTreeData encodeElementLeaf(const ElementWithTransform& e); }; } diff --git a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp index 3be860f..259cc20 100644 --- a/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp +++ b/ArchitectureColoredPainting/src/Renderer/Preview/ElementRenderer.cpp @@ -76,7 +76,7 @@ std::vector generateStyleBuffer(const std::vector& styles) styleBuffer.push_back(style.transform->scale.y); styleBuffer.push_back(style.transform->rotation); styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip))); - + auto encoded = style.material->encoded(); styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end()); //qDebug() << "style size" << styleBuffer.size(); @@ -88,13 +88,23 @@ QRectF calcBoundingRect(const QPainterPath& path, const std::vector& { QRectF bound = path.boundingRect(); - ElementTransform originTransform{ glm::vec2(bound.center().x(), bound.center().y()), glm::vec2(bound.width(), bound.height()), 0, glm::bvec2(false), 0 }; + //ElementTransform originTransform{ glm::vec2(bound.center().x(), bound.center().y()), glm::vec2(bound.width(), bound.height()), 0, glm::bvec2(false), 0 }; glm::vec2 leftTop(std::numeric_limits::max()), rightBottom(std::numeric_limits::min()); for (auto& baseStyle : styles) { - BaseTransform transform(originTransform.appliedTransformStyle(*baseStyle.transform)); + struct BaseTransform + { + glm::vec4 bound; + float rotation = 0; + glm::bvec2 flip = glm::bvec2(false); + GLuint zIndex = 0; + }; + //BaseTransform transform(originTransform.appliedTransformStyle(*baseStyle.transform)); + glm::vec2 center(bound.center().x(), bound.center().y()); + glm::vec2 scale(bound.width(), bound.height()); + BaseTransform transform{ glm::vec4(center - scale, center + scale) }; if (baseStyle.material->type() == MaterialStyleType::kStroke) { float halfWidth = std::static_pointer_cast(baseStyle.material)->getHalfWidth(); diff --git a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp index 87888db..55a2c01 100644 --- a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp +++ b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp @@ -124,9 +124,9 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glMain->TextureStorage2D(metallicRoughness, levels, GL_RG8, GLsizei(textureSize), GLsizei(textureSize)); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 6; i++) glMain->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]); - glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[5]); + glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[6]); for (auto level = levels - 1; level < levels; ++level) { @@ -170,8 +170,10 @@ void Renderer::VirtualTextureManager::deleteVirtualTexture(std::uint16_t id) { auto& painting = getPaintingHandle(id); glMain->DeleteTextures(2, (GLuint*)&painting); + glMain->DeleteBuffers(7, painting.buffers.data()); painting.baseColor = 0; painting.metallicRoughness = 0; + painting.buffers.fill(0); } Renderer::PaintingHandle& Renderer::VirtualTextureManager::getPaintingHandle(std::uint16_t id) @@ -207,9 +209,9 @@ void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pag if (commit) { program.bind(); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 6; i++) gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]); - glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[5]); + glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[6]); gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast(pageSize) * page.x, static_cast(pageSize) * page.y); gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8); diff --git a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h index bd31cbe..e5bbd24 100644 --- a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h +++ b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.h @@ -15,7 +15,7 @@ namespace Renderer { GLuint baseColor; GLuint metallicRoughness; - std::array buffers; + std::array buffers; }; class VirtualTextureManager From 3c2eada43f664ab9163d2c88f65fb1d68ba8d13d Mon Sep 17 00:00:00 2001 From: "yang.yongquan" <3395816735@qq.com> Date: Sat, 18 Mar 2023 20:26:07 +0800 Subject: [PATCH 31/40] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E8=8E=B7?= =?UTF-8?q?=E5=BE=97=E7=BA=BF=E5=AE=BD=E7=9A=84=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/LayerStyle.cpp | 19 +++++++++++++++++++ .../src/Editor/LayerStyle.h | 1 + 2 files changed, 20 insertions(+) diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 5be1b72..5115658 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -197,6 +197,25 @@ bool LayerStyleContainer::dropStyle(const QString& styleName) return true; } +float LayerStyleContainer::boundingBoxAffectValue() { + float maxLineWidth = 0; + auto strokeStyle = styles[StrokeElementLayerStyle::displayName()]; + if (strokeStyle != nullptr) { + auto strokeElementLayerStyle = dynamic_cast(strokeStyle.get()); + if (strokeElementLayerStyle != nullptr) { + auto leftStyleStroke = strokeElementLayerStyle->strokePair.first; + auto rightStyleStroke = strokeElementLayerStyle->strokePair.second; + if (leftStyleStroke != nullptr) { + maxLineWidth = std::max(maxLineWidth, leftStyleStroke->halfWidth); + } + if (rightStyleStroke != nullptr) { + maxLineWidth = std::max(maxLineWidth, rightStyleStroke->halfWidth); + } + } + } + return maxLineWidth; +} + inline size_t LayerStyleContainer::getHash() const { return hash; diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index a310b6e..ed328bb 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -56,6 +56,7 @@ public: std::unique_ptr makeUnusedStyle(const QString& styleName) const; bool useStyle(const std::shared_ptr& style); bool dropStyle(const QString& styleName); + float boundingBoxAffectValue(); size_t getHash() const; /** From 3d8420f6176d84e287a4fa368a62abbecb1a2d89 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Sat, 18 Mar 2023 23:10:16 +0800 Subject: [PATCH 32/40] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=9B=BE=E5=B1=82?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=98=BE=E7=A4=BA=E6=95=88=E6=9E=9C=20|=20#7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EditorWidgetItem.ui | 7 +- .../src/Editor/EditorWidgetItem.cpp | 1 + .../src/Editor/ElementPoolWidget.cpp | 1 + .../src/Editor/ElementPoolWidget.h | 1 + .../src/Editor/LayerWrapper.cpp | 65 +++++++++++++++++-- .../src/Editor/LayerWrapper.h | 4 ++ .../src/Editor/RightBar/LayerTreeWidget.cpp | 8 +-- 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/ArchitectureColoredPainting/EditorWidgetItem.ui b/ArchitectureColoredPainting/EditorWidgetItem.ui index 63fbd7d..e269e9d 100644 --- a/ArchitectureColoredPainting/EditorWidgetItem.ui +++ b/ArchitectureColoredPainting/EditorWidgetItem.ui @@ -182,7 +182,12 @@ - 鍥惧眰鏍 + 鍥惧眰鍚 + + + + + 鍏宠仈鍥惧厓 diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp index 8f6afc9..bef3c7c 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp @@ -32,6 +32,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this, &EditorWidgetItem::triggerRefreshPreview); connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); + connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh); // &EditorWidget::triggerRefreshPreview); // test QFile settingFile; diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp index e1a4f76..17ec55a 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp @@ -67,6 +67,7 @@ void ElementPoolWidget::setElementManager(ElementManager* element) void ElementPoolWidget::refresh() { this->setElementList(this->elementManager->elements); + emit refreshLayerTree(); // update(); } diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h index 66129b9..82ee0ff 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h @@ -25,6 +25,7 @@ public: signals: void elementSelected(GraphicElement* element); + void refreshLayerTree(); public slots: int pictureItemClicked(QListWidgetItem* item); diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index e30b068..e83ae7e 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -192,19 +192,39 @@ void FolderLayerWrapper::delSelf() { QTreeWidgetItem* LayerWrapper::getQTreeItem() { - this->qTreeWidgetItem->setText(0, this->property.name); this->qTreeWidgetItem->setData(0, Qt::UserRole, QVariant::fromValue(this)); return this->qTreeWidgetItem; } +QTreeWidgetItem* LeafLayerWrapper::getQTreeItem() +{ + if (this->qTreeWidgetItem == nullptr) + this->qTreeWidgetItem = new QTreeWidgetItem(); + if (typeid(*wrappedElement) == typeid(GroupElement)) + { + this->qTreeWidgetItem->setText(0, "@ "+this->property.name); + } + else + { + this->qTreeWidgetItem->setText(0, this->property.name); + } + this->qTreeWidgetItem->setText(1,">> "+this->wrappedElement->name); + this->qTreeWidgetItem->setTextColor(1, Qt::blue); + return LayerWrapper::getQTreeItem(); +} + QTreeWidgetItem* FolderLayerWrapper::getQTreeItem() { - while (this->qTreeWidgetItem->childCount() > 0) { - this->qTreeWidgetItem->removeChild(this->qTreeWidgetItem->child(0)); - } - for (auto& child : this->children) { + for (auto& child : this->children) { this->qTreeWidgetItem->addChild(child->getQTreeItem()); } + this->qTreeWidgetItem->setText(0, this->property.name); + auto ele = this->elementManager->getElementById(this->getReferencedBy()); + if (ele != nullptr) + { + this->qTreeWidgetItem->setText(1, "<< " + ele->name); + this->qTreeWidgetItem->setTextColor(1, Qt::darkGreen); + } return LayerWrapper::getQTreeItem(); } @@ -317,4 +337,37 @@ void FolderLayerWrapper::collectDownReachable(std::set& reachable LayerWrapper::collectDownReachable(reachable); for (auto& child : children) child->collectDownReachable(reachable); -} \ No newline at end of file +} + +void LayerWrapper::refreshTreeItem() +{ + +} + +void LeafLayerWrapper::refreshTreeItem() +{ + if (typeid(*wrappedElement) == typeid(GroupElement)) + { + this->qTreeWidgetItem->setText(0, "@ " + this->property.name); + } + else + { + this->qTreeWidgetItem->setText(0, this->property.name); + } + this->qTreeWidgetItem->setText(1, ">> " + this->wrappedElement->name); + this->qTreeWidgetItem->setTextColor(1, Qt::blue); +} + +void FolderLayerWrapper::refreshTreeItem() +{ + for (auto& child : this->children) { + child->refreshTreeItem(); + } + this->qTreeWidgetItem->setText(0, this->property.name); + auto ele = this->elementManager->getElementById(this->getReferencedBy()); + if (ele != nullptr) + { + this->qTreeWidgetItem->setText(1, "<< " + ele->name); + this->qTreeWidgetItem->setTextColor(1, Qt::darkGreen); + } +} diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 92d82d1..b767d35 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -70,6 +70,7 @@ class LayerWrapper ~LayerWrapper() = default; virtual void collectUpReachable(std::set& reachable); virtual void collectDownReachable(std::set& reachable); + virtual void refreshTreeItem(); }; class FolderLayerWrapper : public LayerWrapper @@ -94,6 +95,7 @@ class FolderLayerWrapper : public LayerWrapper int getReferencedBy()const; void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; void collectDownReachable(std::set& reachable) override; + void refreshTreeItem() override; }; class LeafLayerWrapper : public LayerWrapper @@ -110,6 +112,8 @@ class LeafLayerWrapper : public LayerWrapper QJsonObject toJson() const override; void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; void collectDownReachable(std::set& reachable) override; + QTreeWidgetItem* getQTreeItem() override; + void refreshTreeItem() override; }; Q_DECLARE_METATYPE(LayerWrapper *) diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index 8b85c1a..69a67b9 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -9,7 +9,7 @@ LayerTreeWidget::LayerTreeWidget(QWidget *parent) this->selectedItem = nullptr; this->copiedItem = nullptr; this->setContextMenuPolicy(Qt::CustomContextMenu); - this->setHeaderLabel("Layer Content"); + this->setColumnWidth(0, 240); connect(this, &QTreeWidget::customContextMenuRequested, this, &LayerTreeWidget::popMenu); connect(this, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *currentItem) { if (this->selectedItem != nullptr) { @@ -126,9 +126,5 @@ void LayerTreeWidget::onRenameEvent() } void LayerTreeWidget::refresh() { - // if(this->root!=nullptr) - //{ - // this->clear(); - // this->addTopLevelItem(this->root->getQTreeItem()); - //} + this->root->refreshTreeItem(); } \ No newline at end of file From 0e62672b58456f0ffd51628a59d3b0b45b7fc728 Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Sun, 19 Mar 2023 01:27:42 +0800 Subject: [PATCH 33/40] =?UTF-8?q?[editor/style]=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86FillElementLayerStyle=20|=20#2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 2 + ...rchitectureColoredPainting.vcxproj.filters | 6 + .../EditorWidgetComponent/ColorPicker.h | 2 +- .../EditorWidgetComponent/FillStyleWidget.cpp | 48 +++++++ .../EditorWidgetComponent/FillStyleWidget.h | 12 ++ .../StrokeStyleWidget.cpp | 2 +- .../src/Editor/LayerStyle.cpp | 125 +++++++++++------- .../src/Editor/LayerStyle.h | 37 ++++-- .../src/Editor/RightBar/InfoDisplayWidget.cpp | 59 +-------- 9 files changed, 174 insertions(+), 119 deletions(-) create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.cpp create mode 100644 ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.h diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index ac1871e..948b53b 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -104,6 +104,7 @@ + @@ -200,6 +201,7 @@ + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index f60bea2..c738e52 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -240,6 +240,9 @@ Source Files + + Source Files + @@ -290,6 +293,9 @@ Header Files + + Header Files + diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h index aca00ea..a8edd67 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h @@ -6,7 +6,7 @@ class ColorPicker : public QPushButton private: QColor color; public: - ColorPicker(const QColor& color, QWidget* parent = nullptr); + ColorPicker(const QColor& color = QColor::fromRgb(0, 0, 0), QWidget* parent = nullptr); QColor getColor() const; public slots: void onClicked(); diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.cpp new file mode 100644 index 0000000..bf78dbc --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.cpp @@ -0,0 +1,48 @@ +#include "FillStyleWidget.h" +#include "ColorPicker.h" +#include +#include +#include + +FillStyleWidget::FillStyleWidget(std::shared_ptr fill, QWidget* parent) +: QWidget(parent), fill(fill) +{ + auto* layout = new QGridLayout(this); + this->setLayout(layout); + + // 颜色 + auto* material = &plainFill(fill)->material; + auto* colorLabel = new QLabel(QStringLiteral("颜色"), this); + layout->addWidget(colorLabel, 0, 0); + auto* colorPicker = new ColorPicker(material->color); + connect(colorPicker, &ColorPicker::colorChanged, + [material](QColor color) + { + material->color = color; + }); + layout->addWidget(colorPicker, 0, 1); + + // 金属度 + auto* metallicLabel = new QLabel(QStringLiteral("金属度"), this); + layout->addWidget(metallicLabel, 1, 0); + auto* metallicInput = new QtMaterialTextField(this); + metallicInput->setText(QString::number(material->metallicF(), 'g', 3)); + connect(metallicInput, &QtMaterialTextField::textChanged, + [material](const QString& text) + { + material->setMetallicF(text.toFloat()); + }); + layout->addWidget(metallicInput, 1, 1); + + // 粗糙度 + auto* roughnessLabel = new QLabel(QStringLiteral("粗糙度"), this); + layout->addWidget(roughnessLabel, 2, 0); + auto* roughnessInput = new QtMaterialTextField(this); + roughnessInput->setText(QString::number(material->roughnessF(), 'g', 3)); + connect(roughnessInput, &QtMaterialTextField::textChanged, + [material](const QString& text) + { + material->setRoughnessF(text.toFloat()); + }); + layout->addWidget(roughnessInput, 2, 1); +} diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.h new file mode 100644 index 0000000..bff2724 --- /dev/null +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.h @@ -0,0 +1,12 @@ +#pragma once +#include "../Renderer/Painting/MaterialStyleFill.h" +#include "LayerStyle.h" +#include +class FillStyleWidget : public QWidget +{ + Q_OBJECT +public: + FillStyleWidget(std::shared_ptr fill, QWidget* parent = nullptr); + std::shared_ptr fill; +}; + diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp index 670e185..e2c9ce7 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp @@ -11,7 +11,7 @@ constexpr int COLUMN_ROUGHNESS = 3; constexpr int COLUMN_OPERATIONS = 4; StrokeStyleWidget::StrokeStyleWidget( - std::shared_ptr stroke, + std::shared_ptr stroke, QWidget* parent ) : QWidget(parent), stroke(stroke) { diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 5115658..7240d46 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -1,12 +1,11 @@ #include "LayerStyle.h" #include "./EditorWidgetComponent/StrokeStyleWidget.h" +#include "./EditorWidgetComponent/FillStyleWidget.h" #include "./util/EncodeUtil.hpp" #include #include -#include #include #include -#include #include #include #define _USE_JOIN_VIEW_INPUT_RANGE @@ -20,21 +19,19 @@ std::vector StrokeElementLayerStyle::toBaseStyles() const { if (!radialStroke(strokePair.first)->materialMap.empty()) { - baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), - strokePair.first)); + baseStyles.push_back({ std::make_shared(), strokePair.first }); } if (!radialStroke(strokePair.second)->materialMap.empty()) { - baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), - strokePair.second)); + baseStyles.push_back({ std::make_shared(), strokePair.second }); } } else if (!radialStroke(strokePair.first)->materialMap.empty()) { const auto material = std::shared_ptr(std::move(strokePair.first->clone())); - std::dynamic_pointer_cast(material)->strokeType = Renderer::StrokeType::kBothSides; + std::static_pointer_cast(material)->strokeType = Renderer::StrokeType::kBothSides; - baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), material)); + baseStyles.push_back({ std::make_shared(), material }); } return baseStyles; } @@ -197,18 +194,23 @@ bool LayerStyleContainer::dropStyle(const QString& styleName) return true; } -float LayerStyleContainer::boundingBoxAffectValue() { +float LayerStyleContainer::boundingBoxAffectValue() const { float maxLineWidth = 0; - auto strokeStyle = styles[StrokeElementLayerStyle::displayName()]; - if (strokeStyle != nullptr) { - auto strokeElementLayerStyle = dynamic_cast(strokeStyle.get()); - if (strokeElementLayerStyle != nullptr) { - auto leftStyleStroke = strokeElementLayerStyle->strokePair.first; - auto rightStyleStroke = strokeElementLayerStyle->strokePair.second; - if (leftStyleStroke != nullptr) { + const auto strokeStyle = styles.at(StrokeElementLayerStyle::displayName()); + if (strokeStyle != nullptr) + { + if (const auto strokeElementLayerStyle = + std::dynamic_pointer_cast(strokeStyle); + strokeElementLayerStyle != nullptr) + { + const auto& leftStyleStroke = strokeElementLayerStyle->strokePair.first; + const auto& rightStyleStroke = strokeElementLayerStyle->strokePair.second; + if (leftStyleStroke != nullptr) + { maxLineWidth = std::max(maxLineWidth, leftStyleStroke->halfWidth); } - if (rightStyleStroke != nullptr) { + if (rightStyleStroke != nullptr) + { maxLineWidth = std::max(maxLineWidth, rightStyleStroke->halfWidth); } } @@ -216,11 +218,25 @@ float LayerStyleContainer::boundingBoxAffectValue() { return maxLineWidth; } -inline size_t LayerStyleContainer::getHash() const +size_t LayerStyleContainer::getHash() const { return hash; } +std::unique_ptr StrokeElementLayerStyle::fromJson(const QJsonObject& json) +{ + auto ptr = std::make_unique( + std::static_pointer_cast( + std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString())))) + ), + std::static_pointer_cast( + std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString())))) + ) + ); + ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool(); + return ptr; +} + StrokeElementLayerStyle::StrokeElementLayerStyle() { const auto materialMap = std::map(); @@ -238,7 +254,7 @@ StrokeElementLayerStyle::StrokeElementLayerStyle() } -StrokeElementLayerStyle::StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right) +StrokeElementLayerStyle::StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right) { this->strokePair.first = left; this->strokePair.second = right ? right : std::static_pointer_cast( @@ -259,8 +275,7 @@ StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& QJsonObject StrokeElementLayerStyle::toJson() const { - QJsonObject json; - json["type"] = typeName(); + auto json = LayerStyle::toJson(); json["enableEachSideIndependent"] = enableEachSideIndependent; json["left"] = EncodeUtil::toBase64(strokePair.first->encoded()); json["right"] = EncodeUtil::toBase64(strokePair.second->encoded()); @@ -272,18 +287,24 @@ std::unique_ptr StrokeElementLayerStyle::clone() const return std::make_unique(StrokeElementLayerStyle(*this)); } +std::unique_ptr FillElementLayerStyle::fromJson(const QJsonObject& json) +{ + auto ptr = std::make_unique( + std::static_pointer_cast( + std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["material"].toString())))) + ) + ); + return ptr; +} + std::vector FillElementLayerStyle::toBaseStyles() const { - // TODO: implement - return std::vector(); + return { {std::make_shared(), fillMaterialStyle} }; } QWidget* FillElementLayerStyle::getInputWidget() { - // TODO - auto* name = new QLineEdit; - name->setText(QStringLiteral("填充")); - return name; + return new FillStyleWidget(fillMaterialStyle); } QWidget* FillElementLayerStyle::getListDisplayWidget() const @@ -297,18 +318,29 @@ QWidget* FillElementLayerStyle::getListDisplayWidget() const return w; } +FillElementLayerStyle::FillElementLayerStyle(const PMaterialStyleFill& fillMaterialStyle) + : fillMaterialStyle(fillMaterialStyle) +{ + if (!fillMaterialStyle) + { + this->fillMaterialStyle = std::make_shared( + std::make_shared(Renderer::Material(QColor::fromRgb(0, 0, 0))) + ); + } +} + FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other) { - materialStyles = std::vector>(other.materialStyles.size()); - for (size_t i = 0; i < other.materialStyles.size(); i++) - { - materialStyles[i] = std::make_shared(*other.materialStyles[i]); - } + this->fillMaterialStyle = std::static_pointer_cast( + std::shared_ptr(std::move(other.fillMaterialStyle->clone())) + ); } QJsonObject FillElementLayerStyle::toJson() const { - return QJsonObject(); + auto json = LayerStyle::toJson(); + json["material"] = EncodeUtil::toBase64(fillMaterialStyle->encoded()); + return json; } std::unique_ptr FillElementLayerStyle::clone() const @@ -321,23 +353,18 @@ std::unique_ptr LayerStyle::fromJson(const QJsonObject& json) QString type = json["type"].toString(); if (type == StrokeElementLayerStyle::typeName()) { - auto ptr = std::make_unique( - std::static_pointer_cast( - std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString())))) - ), - std::static_pointer_cast( - std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString())))) - ) - ); - ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool(); - return ptr; + return StrokeElementLayerStyle::fromJson(json); } - else if (type == FillElementLayerStyle::typeName()) + if (type == FillElementLayerStyle::typeName()) { - return std::make_unique(); - } - else - { - return nullptr; + return FillElementLayerStyle::fromJson(json); } + return nullptr; +} + +QJsonObject LayerStyle::toJson() const +{ + QJsonObject json; + json["type"] = this->getTypeName(); + return json; } diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index ed328bb..3d9b023 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -12,26 +12,35 @@ using Renderer::MaterialStyle; using Renderer::MaterialStyleStroke; +using Renderer::MaterialStyleFill; #define STYLE_NAME(display_name, type_name) \ static QString displayName() { return QStringLiteral(display_name); } \ QString getDisplayName() const override { return QStringLiteral(display_name); } \ - static QString typeName() { return type_name; } + static QString typeName() { return type_name; } \ + QString getTypeName() const override { return type_name; } #define radialStroke(stroke) std::static_pointer_cast(stroke->materialStroke) +#define plainFill(fill) std::static_pointer_cast(fill->materialFill) class LayerStyle : public Renderer::ElementStyle { public: static std::unique_ptr fromJson(const QJsonObject& json); + virtual ~LayerStyle() = default; virtual QString getDisplayName() const = 0; + virtual QString getTypeName() const = 0; + virtual QWidget* getInputWidget() = 0; virtual QWidget* getListDisplayWidget() const = 0; - virtual ~LayerStyle() = default; - virtual QJsonObject toJson() const = 0; + + virtual QJsonObject toJson() const; virtual std::unique_ptr clone() const = 0; }; +/** + * LayerStyle的容器,在每次数据变更时需要手动调用computeNewHash()方法,否则哈希值不会更新 + */ class LayerStyleContainer : public Renderer::ElementStyle { using DisplayNameWithSupplier = std::map()>>; @@ -56,7 +65,7 @@ public: std::unique_ptr makeUnusedStyle(const QString& styleName) const; bool useStyle(const std::shared_ptr& style); bool dropStyle(const QString& styleName); - float boundingBoxAffectValue(); + float boundingBoxAffectValue() const; size_t getHash() const; /** @@ -70,10 +79,11 @@ class StrokeElementLayerStyle : public LayerStyle using PMaterialStyleStroke = std::shared_ptr; public: - STYLE_NAME("描边","stroke") + STYLE_NAME("描边", "stroke") + static std::unique_ptr fromJson(const QJsonObject& json); StrokeElementLayerStyle(); - StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right = nullptr); + StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right = nullptr); StrokeElementLayerStyle(const StrokeElementLayerStyle& other); ~StrokeElementLayerStyle() override = default; @@ -89,16 +99,21 @@ public: class FillElementLayerStyle : public LayerStyle { + using PMaterialStyleFill = std::shared_ptr; + public: - STYLE_NAME("填充","fill") + STYLE_NAME("填充", "fill") + static std::unique_ptr fromJson(const QJsonObject& json); + + FillElementLayerStyle(const PMaterialStyleFill& fillMaterialStyle = nullptr); + FillElementLayerStyle(const FillElementLayerStyle& other); + ~FillElementLayerStyle() override = default; std::vector toBaseStyles() const override; QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; - FillElementLayerStyle() = default; - FillElementLayerStyle(const FillElementLayerStyle& other); - ~FillElementLayerStyle() override = default; - std::vector> materialStyles; QJsonObject toJson() const override; std::unique_ptr clone() const override; + + PMaterialStyleFill fillMaterialStyle; }; \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp index ca1e2ca..1db2940 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp @@ -102,7 +102,7 @@ void InfoDisplayWidget::generateLayerForm() else { connect(addStyleButton, &QPushButton::clicked, [&, leafP] { - auto* dialog = new LayerStyleDialog(leafP->styles); + auto* dialog = new LayerStyleDialog(leafP->styles, nullptr, this); dialog->exec(); if (dialog->layerStyle) { @@ -113,7 +113,6 @@ void InfoDisplayWidget::generateLayerForm() emit requireSelfRefresh(); emit requireRefreshElementWidget(); } - dialog->deleteLater(); }); } @@ -125,60 +124,7 @@ void InfoDisplayWidget::generateLayerForm() header->setFlags(Qt::NoItemFlags); styleList->addItem(header); styleList->setItemWidget(header, headerWidget); - //static vector styleNames = { "鏍蜂緥1", "鏍蜂緥2", "鏍蜂緥3" }; - // auto createStyleItem = [this, styleList](int index) { - // QListWidgetItem* item = new QListWidgetItem; - // QWidget* w = new QWidget; - // item->setSizeHint(QSize(50, 40)); - // QHBoxLayout* layout = new QHBoxLayout; - // QPushButton* deleteButton = new QPushButton(w); - // QPushButton* detailButton = new QPushButton(w); - // QLabel* name = new QLabel(w); - // name->setText(styleNames[index]); - // detailButton->setText("..."); - // detailButton->setFixedSize(QSize(20, 20)); - // deleteButton->setText("脳"); - // deleteButton->setFixedSize(QSize(20, 20)); - // connect(detailButton, &QPushButton::clicked, [styleList, item, this, index]() { - // QDialog dlg(this); - // dlg.setWindowTitle("鏍峰紡璇︽儏"); - // dlg.resize(400, 200); - // QGridLayout *contentLayout = new QGridLayout(&dlg); - // QLineEdit* name = new QLineEdit(styleNames[index], &dlg); - // auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel); - // contentLayout->addWidget(buttonBox); - // connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept); - // connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject); - // bool updateStyle = dlg.exec(); - // if (updateStyle) { - // styleNames[index] = name->text(); - // qDebug() << name->text(); - // // 鍦ㄦ澶勪慨鏀规柊鏍峰紡淇℃伅鑷冲唴瀛 - // emit requireRefreshPreview(); - // emit requireSelfRefresh(); - // } - // }); - // connect(deleteButton, &QPushButton::clicked, [styleList,item,this]() { - // styleList->removeItemWidget(item); - // delete item; - // // 鍒犻櫎layer瀵瑰簲鏍峰紡 - // emit requireRefreshPreview(); - // emit requireSelfRefresh(); - // }); - // layout->addWidget(name); - // layout->addWidget(detailButton); - // layout->addWidget(deleteButton); - // w->setLayout(layout); - // styleList->addItem(item); - // styleList->setItemWidget(item, w); - // }; - // for (int i = 0; i < styleNames.size(); i++) - // createStyleItem(i); - /*if (leafP->styles.empty()) - { - leafP->styles.push_back(std::shared_ptr(new StrokeElementLayerStyle())); - }*/ auto* styles = &leafP->styles; for (auto styleIterator = styles->begin(); styleIterator != styles->end(); ++styleIterator) { @@ -200,7 +146,7 @@ void InfoDisplayWidget::generateLayerForm() [this, styles, styleIterator] { auto* dialog = - new LayerStyleDialog(*styles, styleIterator->second); + new LayerStyleDialog(*styles, styleIterator->second, this); dialog->exec(); if (dialog->layerStyle) @@ -212,7 +158,6 @@ void InfoDisplayWidget::generateLayerForm() emit requireSelfRefresh(); emit requireRefreshElementWidget(); } - dialog->deleteLater(); }); connect(removeButton, &QPushButton::clicked, this, From 12b62bf0397ec862710099d6a18d81d7e9726a5b Mon Sep 17 00:00:00 2001 From: wuyize Date: Sun, 19 Mar 2023 12:17:35 +0800 Subject: [PATCH 34/40] =?UTF-8?q?Fix:=20element.comp=E5=A1=AB=E5=85=85?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E6=B8=B2=E6=9F=93=E9=94=99=E8=AF=AF=20|#13?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/Shaders/element.comp | 6 +- UnitTest/ElementRendererTest.cpp | 79 ++++++++++++++++--- UnitTest/ElementRendererTest.h | 16 ++-- 3 files changed, 77 insertions(+), 24 deletions(-) diff --git a/ArchitectureColoredPainting/res/Shaders/element.comp b/ArchitectureColoredPainting/res/Shaders/element.comp index b44b514..fd09af8 100644 --- a/ArchitectureColoredPainting/res/Shaders/element.comp +++ b/ArchitectureColoredPainting/res/Shaders/element.comp @@ -1071,15 +1071,15 @@ void main() if (num_its % 2 == 1) { hitElement = true; - elementColor = vec4(1, 1, 0, 0); vec4 head = unpackUnorm4x8(floatBitsToUint(style[styleIndex])); if (head.z == 0) { - elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1); + elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[styleIndex+1])).rgb, 1); } + } - + styleIndex += 2; } else // Stroke { diff --git a/UnitTest/ElementRendererTest.cpp b/UnitTest/ElementRendererTest.cpp index ca1fbca..aba0474 100644 --- a/UnitTest/ElementRendererTest.cpp +++ b/UnitTest/ElementRendererTest.cpp @@ -3,7 +3,7 @@ #include #include "ElementRendererTest.h" #include "Renderer/Painting/ElementStyle.h" - +#include "Renderer/Painting/MaterialStyleFill.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Renderer; @@ -12,13 +12,63 @@ namespace UnitTest { void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); + TEST_CLASS(ElementRendererFillTest) + { + private: + char* argv[1]; + int argc; + QPainterPath path; + public: + ElementRendererFillTest() :argv{ (char*)"" }, argc(1) + { + QQuickSvgParser::parsePathDataFast("M100,100C-.5,100,0,100.5,0,0L40,.07C40,59.5,39.5,60,100,60Z", + path); + QTransform transform; + //transform.scale(10, 10); + path = transform.map(path); + } + + TEST_METHOD_INITIALIZE(initialize) + { + qInstallMessageHandler(messageHandler); + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); + } + TEST_METHOD(TestFillPlain) + { + QApplication a(argc, argv); + class Style : public Renderer::ElementStyle + { + virtual std::vector toBaseStyles() const override + { + + return { BaseStyle(std::make_shared(), + std::make_shared( + std::make_shared(Material(QColor(255,255,0))))) }; + } + } style; + TestGLWidget w(style, path); + w.show(); + a.exec(); + } + + }; + TEST_CLASS(ElementRendererStokeTypeTest) { private: char* argv[1]; int argc; + QPainterPath path; public: - ElementRendererStokeTypeTest() :argv{ (char*)"" }, argc(1) {} + ElementRendererStokeTypeTest() :argv{ (char*)"" }, argc(1) + { + QQuickSvgParser::parsePathDataFast("M292.82,107.78s0,0,0,0,0,3.59,0,7.62c0,3.85,0,5.78.06,6.43a19.94,19.94,0,0,0,2.87,7.58,15.85,15.85,0,0,0,6.61,6.23A14.75,14.75,0,0,0,310,137a11.69,11.69,0,0,0,7.59-2.92,11,11,0,0,0,3.2-6.84c.15-1.27.58-4.84-1.79-7.64a8.54,8.54,0,0,0-3.56-2.44c-1.32-.52-3.32-1.31-5.06-.33a5.41,5.41,0,0,0-2.14,3,3.48,3.48,0,0,0-.16,2.71c.78,1.86,3.36,2.14,3.47,2.15", path); + QTransform transform; + transform.scale(10, 10); + path = transform.map(path); + } TEST_METHOD_INITIALIZE(initialize) { @@ -44,7 +94,7 @@ namespace UnitTest std::make_shared(materialMap, false))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } @@ -65,7 +115,7 @@ namespace UnitTest std::make_shared(materialMap, false))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } @@ -86,7 +136,7 @@ namespace UnitTest std::make_shared(materialMap, false))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } @@ -107,7 +157,7 @@ namespace UnitTest std::make_shared(materialMap, false))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } @@ -128,7 +178,7 @@ namespace UnitTest std::make_shared(materialMap, false))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } @@ -139,8 +189,15 @@ namespace UnitTest private: char* argv[1]; int argc; + QPainterPath path; public: - ElementRendererStokeMaterialTest() :argv{ (char*)"" }, argc(1) {} + ElementRendererStokeMaterialTest() :argv{ (char*)"" }, argc(1) + { + QQuickSvgParser::parsePathDataFast("M292.82,107.78s0,0,0,0,0,3.59,0,7.62c0,3.85,0,5.78.06,6.43a19.94,19.94,0,0,0,2.87,7.58,15.85,15.85,0,0,0,6.61,6.23A14.75,14.75,0,0,0,310,137a11.69,11.69,0,0,0,7.59-2.92,11,11,0,0,0,3.2-6.84c.15-1.27.58-4.84-1.79-7.64a8.54,8.54,0,0,0-3.56-2.44c-1.32-.52-3.32-1.31-5.06-.33a5.41,5.41,0,0,0-2.14,3,3.48,3.48,0,0,0-.16,2.71c.78,1.86,3.36,2.14,3.47,2.15", path); + QTransform transform; + transform.scale(10, 10); + path = transform.map(path); + } TEST_METHOD(TestStrokePlain) { QApplication a(argc, argv); @@ -153,7 +210,7 @@ namespace UnitTest std::make_shared(QColor(255,255,255),1,1))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } @@ -174,7 +231,7 @@ namespace UnitTest std::make_shared(materialMap, false))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } @@ -195,7 +252,7 @@ namespace UnitTest std::make_shared(materialMap, true))) }; } } style; - TestGLWidget w(style); + TestGLWidget w(style, path); w.show(); a.exec(); } diff --git a/UnitTest/ElementRendererTest.h b/UnitTest/ElementRendererTest.h index 9271821..d709bfe 100644 --- a/UnitTest/ElementRendererTest.h +++ b/UnitTest/ElementRendererTest.h @@ -16,29 +16,25 @@ namespace UnitTest private: Renderer::ElementRenderer& renderer; Renderer::ElementStyle& style; + QPainterPath& path; public: - TestGLWidget(Renderer::ElementStyle& style, QWidget* parent = nullptr) - : QOpenGLWidget(parent), renderer(*Renderer::ElementRenderer::instance()), style(style) {}; + TestGLWidget(Renderer::ElementStyle& style, QPainterPath& path, QWidget* parent = nullptr) + : QOpenGLWidget(parent), renderer(*Renderer::ElementRenderer::instance()), style(style), path(path) {}; void initializeGL() override { initializeOpenGLFunctions(); }; void paintGL() override { - glClearColor(219/255., 78/255., 32/255., 1.0); + glClearColor(219 / 255., 78 / 255., 32 / 255., 1.0); glClear(GL_COLOR_BUFFER_BIT); - QPainterPath path; - QQuickSvgParser::parsePathDataFast("M292.82,107.78s0,0,0,0,0,3.59,0,7.62c0,3.85,0,5.78.06,6.43a19.94,19.94,0,0,0,2.87,7.58,15.85,15.85,0,0,0,6.61,6.23A14.75,14.75,0,0,0,310,137a11.69,11.69,0,0,0,7.59-2.92,11,11,0,0,0,3.2-6.84c.15-1.27.58-4.84-1.79-7.64a8.54,8.54,0,0,0-3.56-2.44c-1.32-.52-3.32-1.31-5.06-.33a5.41,5.41,0,0,0-2.14,3,3.48,3.48,0,0,0-.16,2.71c.78,1.86,3.36,2.14,3.47,2.15", path); - path = PainterPathUtil::monotonization(path); - QTransform transform; - transform.scale(10, 10); - path = transform.map(path); + float pixelRatio = devicePixelRatioF(); auto [img, pos] = renderer.drawElement(path, style, pixelRatio); QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setRenderHint(QPainter::HighQualityAntialiasing); - painter.drawImage(QRectF(QPointF(0, 0), img.size()/pixelRatio), img); + painter.drawImage(QRectF(QPointF(0, 0), img.size() / pixelRatio), img); }; void resizeGL(int w, int h) override {}; }; From 4c95d6e36251bd664bd3ddbd62bb79936dfe8daf Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Sun, 19 Mar 2023 13:29:52 +0800 Subject: [PATCH 35/40] =?UTF-8?q?=E5=BE=AE=E8=B0=83=E4=BA=86=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 1 + ...rchitectureColoredPainting.vcxproj.filters | 113 ++++++++++-------- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index 948b53b..c403fad 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -202,6 +202,7 @@ + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index c738e52..5610888 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -71,6 +71,18 @@ {b9732a33-aa2e-4f8d-886f-1b1730c66519} + + {8d846557-8fd5-47d5-8edf-eb3eb77c226b} + + + {22d7f3ef-8185-476e-8fe1-aea24c4faacc} + + + {6fc32493-d5a2-44c3-a283-d2d3181330fb} + + + {e6de889e-8313-4846-8bdf-125b766eef59} + @@ -141,18 +153,6 @@ Source Files\Renderer\Painting - - Source Files\Editor - - - Source Files\Editor - - - Source Files\Editor - - - Source Files\Editor - Source Files\Editor @@ -201,12 +201,6 @@ Source Files\Editor - - Source Files - - - Source Files\Editor - Source Files @@ -225,23 +219,41 @@ Source Files\Editor - - Source Files\Editor - - - Source Files\Editor - Source Files\Editor Source Files\Editor + + Source Files\Editor + - Source Files + Source Files\Editor - Source Files + Source Files\Editor\Style + + + Source Files\Editor\Element + + + Source Files\Editor\Element + + + Source Files\Editor\Element + + + Source Files\Editor\Layer + + + Source Files\Editor\Layer + + + Source Files\Editor\Layer + + + Source Files\Editor\Layer @@ -257,9 +269,6 @@ Header Files\Editor - - Header Files\Editor - Header Files @@ -272,15 +281,9 @@ Header Files\Editor - - Header Files\Editor - Header Files\Editor - - Header Files\Editor - Header Files\Editor @@ -291,10 +294,19 @@ Header Files\Editor
- Header Files + Header Files\Editor - Header Files + Header Files\Editor\Style + + + Header Files\Editor\Element + + + Header Files\Editor\Layer + + + Header Files\Editor\Layer @@ -426,15 +438,6 @@ Header Files\Renderer\Painting - - Header Files\Editor - - - Header Files\Editor - - - Header Files\Editor - Header Files\Renderer\Painting @@ -474,9 +477,6 @@ Header Files\Renderer\Preview - - Header Files - Header Files\Renderer @@ -498,6 +498,21 @@ Header Files\Editor\util + + Header Files\Editor\Element + + + Header Files\Editor\Element + + + Header Files\Editor\Layer + + + Header Files\Editor + + + Header Files\Editor\Layer + From 66cde802ecfbd64b5c919667048c930d3326e7b3 Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Sun, 19 Mar 2023 14:12:44 +0800 Subject: [PATCH 36/40] =?UTF-8?q?=E4=B8=BAGraphicElement=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BA=86isClosed=E6=8E=A5=E5=8F=A3=20|=20#11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/GraphicElement.cpp | 15 ++++++++++++++- .../src/Editor/GraphicElement.h | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index 5c0acb0..4cc2ef3 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -17,7 +17,10 @@ void SimpleElement::loadSvgFile(const QString& filePath) // TODO 样式问题 SvgFileLoader loader; loader.loadSvgFile(filePath, painterPath); - qDebug() << "load svg file success " << painterPath.elementCount(); + auto startPoint = static_cast(painterPath.elementAt(0)); + auto endPoint = static_cast(painterPath.elementAt(painterPath.elementCount() - 1)); + this->closed = startPoint == endPoint; + qDebug() << "load svg file success " << painterPath.elementCount() << (isClosed() ? "is" : "not") << "closed"; } SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource) @@ -117,11 +120,21 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const LayerSt painter->restore(); } +bool SimpleElement::isClosed() const +{ + return closed; +} + void GroupElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) { sourceLayer->paint(painter, transform); } +bool GroupElement::isClosed() const +{ + return false; +} + QPixmap SimpleElement::getPreview(QSize size) { diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index d0500b2..377b9e5 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -28,11 +28,14 @@ public: virtual PixelPath getPaintObject() const = 0; virtual PixelPath getPaintObject(const LayerStyleContainer& styles) const = 0; virtual void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) = 0; + virtual bool isClosed() const = 0; virtual QPixmap getPreview(QSize size) = 0; }; class SimpleElement : public GraphicElement { +private: + bool closed; public: QJsonObject jsonSource; // TODO: 改为ComposedPainterPath @@ -48,6 +51,7 @@ public: PixelPath getPaintObject() const override; PixelPath getPaintObject(const LayerStyleContainer& styles) const override; void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; + bool isClosed() const override; QPixmap getPreview(QSize size) override; }; @@ -65,6 +69,7 @@ public: PixelPath getPaintObject(const LayerStyleContainer& styles) const override; void setSourceLayer(FolderLayerWrapper* sourceLayer); void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; + bool isClosed() const override; QPixmap getPreview(QSize size) override; void collectReachable(std::set& set) const; }; From 587c09115aaef9fc460fb004118c95e63355026b Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Sun, 19 Mar 2023 14:43:25 +0800 Subject: [PATCH 37/40] =?UTF-8?q?[editor/style]=20=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E5=8C=BA=E5=88=86=E5=B0=81=E9=97=AD=E4=B8=8E=E9=9D=9E?= =?UTF-8?q?=E5=B0=81=E9=97=AD=E5=9B=BE=E5=85=83=20|=20#12=20=20*=20LayerSt?= =?UTF-8?q?yleContainer=E7=9A=84=E6=9E=84=E9=80=A0=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86isClosedElement=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...rchitectureColoredPainting.vcxproj.filters | 6 ++ .../src/Editor/LayerStyle.cpp | 30 ++++--- .../src/Editor/LayerStyle.h | 83 +++++++++++-------- .../src/Editor/LayerWrapper.cpp | 10 +-- .../src/Editor/LayerWrapper.h | 1 - 5 files changed, 77 insertions(+), 53 deletions(-) diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index 5610888..e198184 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -255,6 +255,9 @@ Source Files\Editor\Layer + + Source Files + @@ -308,6 +311,9 @@ Header Files\Editor\Layer + + Header Files + diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 7240d46..3351b34 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -90,9 +90,9 @@ void LayerStyleContainer::computeNewHash() } } -LayerStyleContainer LayerStyleContainer::fromJson(const QJsonArray& jsonArray) +LayerStyleContainer LayerStyleContainer::fromJson(bool isClosedElement, const QJsonArray& jsonArray) { - LayerStyleContainer container; + LayerStyleContainer container(isClosedElement); for (const auto& style : jsonArray) { container.useStyle(LayerStyle::fromJson(style.toObject())); @@ -100,16 +100,26 @@ LayerStyleContainer LayerStyleContainer::fromJson(const QJsonArray& jsonArray) return container; } -LayerStyleContainer::LayerStyleContainer() : hash(0) +LayerStyleContainer::LayerStyleContainer(bool isClosedElement) : hash(0) { - unusedStyles = { { - StrokeElementLayerStyle::displayName(), - [] { return std::make_unique(); } - }, + for (const auto& style : commonStyles) { - FillElementLayerStyle::displayName(), - [] { return std::make_unique(); } - } }; + unusedStyles.insert(style); + } + if (isClosedElement) + { + for (const auto& style : closedOnlyStyles) + { + unusedStyles.insert(style); + } + } + else + { + for (const auto& style : unclosedOnlyStyles) + { + unusedStyles.insert(style); + } + } } std::vector LayerStyleContainer::toBaseStyles() const diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index 3d9b023..9274732 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -38,42 +38,6 @@ public: virtual std::unique_ptr clone() const = 0; }; -/** - * LayerStyle的容器,在每次数据变更时需要手动调用computeNewHash()方法,否则哈希值不会更新 - */ -class LayerStyleContainer : public Renderer::ElementStyle -{ - using DisplayNameWithSupplier = std::map()>>; -private: - DisplayNameWithSupplier unusedStyles; - DisplayNameWithSupplier usedStyles; - std::map> styles; - size_t hash; -public: - static LayerStyleContainer fromJson(const QJsonArray& jsonArray); - - LayerStyleContainer(); - std::vector toBaseStyles() const override; - QJsonArray toJson() const; - - bool empty() const; - bool full() const; - std::map>::iterator begin(); - std::map>::iterator end(); - - QStringList unusedStyleNames() const; - std::unique_ptr makeUnusedStyle(const QString& styleName) const; - bool useStyle(const std::shared_ptr& style); - bool dropStyle(const QString& styleName); - float boundingBoxAffectValue() const; - size_t getHash() const; - - /** - * 需要在每次更改后手动调用 - */ - void computeNewHash(); -}; - class StrokeElementLayerStyle : public LayerStyle { using PMaterialStyleStroke = std::shared_ptr; @@ -116,4 +80,51 @@ public: std::unique_ptr clone() const override; PMaterialStyleFill fillMaterialStyle; +}; + +/** + * LayerStyle的容器,在每次数据变更时需要手动调用computeNewHash()方法,否则哈希值不会更新 + */ +class LayerStyleContainer : public Renderer::ElementStyle +{ + using DisplayNameWithSupplier = std::map()>>; +private: + + inline const static DisplayNameWithSupplier commonStyles = { { + StrokeElementLayerStyle::displayName(), + [] { return std::make_unique(); } + } }; + inline const static DisplayNameWithSupplier closedOnlyStyles = { { + FillElementLayerStyle::displayName(), + [] { return std::make_unique(); } + } }; + inline const static DisplayNameWithSupplier unclosedOnlyStyles = { }; + + DisplayNameWithSupplier unusedStyles; + DisplayNameWithSupplier usedStyles; + std::map> styles; + size_t hash; +public: + static LayerStyleContainer fromJson(bool isClosedElement, const QJsonArray& jsonArray); + + LayerStyleContainer(bool isClosedElement); + std::vector toBaseStyles() const override; + QJsonArray toJson() const; + + bool empty() const; + bool full() const; + std::map>::iterator begin(); + std::map>::iterator end(); + + QStringList unusedStyleNames() const; + std::unique_ptr makeUnusedStyle(const QString& styleName) const; + bool useStyle(const std::shared_ptr& style); + bool dropStyle(const QString& styleName); + float boundingBoxAffectValue() const; + size_t getHash() const; + + /** + * 需要在每次更改后手动调用 + */ + void computeNewHash(); }; \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index e83ae7e..f131f27 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -73,14 +73,12 @@ FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *element } } -LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent) - : LayerWrapper(json, parent) +LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager* elementManager, FolderLayerWrapper* parent) + : LayerWrapper(json, parent), + wrappedElement(elementManager->getElementById(json.value("element").toInt())), + styles(LayerStyleContainer::fromJson(wrappedElement->isClosed(), json.value("styles").toArray())) { qDebug() << json.value("name").toString() << " " << this; - int elementIndex = json.value("element").toInt(); - wrappedElement = elementManager->getElementById(elementIndex); - QJsonArray stylesArray = json.value("styles").toArray(); - styles = LayerStyleContainer::fromJson(stylesArray); } void LayerWrapper::SimpleProperty::apply(PixelPath&cache) diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index b767d35..3b82b86 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -107,7 +107,6 @@ class LeafLayerWrapper : public LayerWrapper public: ~LeafLayerWrapper() = default; void refresh(LayerWrapper* layer = nullptr) override; - LeafLayerWrapper() = default; LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); QJsonObject toJson() const override; void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; From 3904ff0b61ad2d86ab2dab5198a3dfafc460b719 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Sun, 19 Mar 2023 15:33:55 +0800 Subject: [PATCH 38/40] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E6=A3=80=E6=B5=8B=20|=20#9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/ElementPoolWidget.cpp | 1 + .../src/Editor/GraphicElement.h | 1 + .../src/Editor/LayerWrapper.cpp | 45 +++++++++++++++++++ .../src/Editor/LayerWrapper.h | 6 ++- .../src/Editor/RightBar/LayerTreeWidget.cpp | 14 +++--- 5 files changed, 61 insertions(+), 6 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp index 17ec55a..ff166f0 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp @@ -120,6 +120,7 @@ void ElementPoolWidget::popMenu(const QPoint& pos) this->elementManager->removeElement(currentElement); refresh(); }); + menu->actions().last()->setDisabled(currentElement->referencedCount > 0); } else { diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index 377b9e5..8ce9bf2 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -20,6 +20,7 @@ class ComposedPainterPath; class GraphicElement { public: + size_t referencedCount = 0; Renderer::ElementRenderer *renderer; QString name = ""; int index; diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index f131f27..770c45d 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -79,6 +79,14 @@ LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager* elementMana styles(LayerStyleContainer::fromJson(wrappedElement->isClosed(), json.value("styles").toArray())) { qDebug() << json.value("name").toString() << " " << this; + if(wrappedElement != nullptr) + wrappedElement->referencedCount++; +} + +LeafLayerWrapper::~LeafLayerWrapper() +{ + if (wrappedElement != nullptr) + wrappedElement->referencedCount--; } void LayerWrapper::SimpleProperty::apply(PixelPath&cache) @@ -368,4 +376,41 @@ void FolderLayerWrapper::refreshTreeItem() this->qTreeWidgetItem->setText(1, "<< " + ele->name); this->qTreeWidgetItem->setTextColor(1, Qt::darkGreen); } + if (this->referencedCount() > 0) + { + this->qTreeWidgetItem->setToolTip(0,QString::fromLocal8Bit("子树被引用计数:") + QString::number(this->referencedCount(true)) + "\n" + + QString::fromLocal8Bit("当前节点被引用计数:") + QString::number(this->getReferencedBy() != -1)); + } + else + { + this->qTreeWidgetItem->setToolTip(0, ""); + } } + +size_t LayerWrapper::referencedCount(bool excludeSelf) const +{ + return 0; +} + +size_t FolderLayerWrapper::referencedCount(bool excludeSelf) const +{ + size_t count = 0; + for (auto& child : children) + count += child->referencedCount(); + if (!excludeSelf && this->getReferencedBy() != -1) + count++; + return count; +} + +bool LayerWrapper::deleteable(bool excludeSubTree) const +{ + return true; +} + +bool FolderLayerWrapper::deleteable(bool excludeSubTree) const +{ + if (excludeSubTree) + return this->getReferencedBy() == -1; + else + return this->referencedCount() == 0; +} \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 3b82b86..b62d685 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -71,6 +71,8 @@ class LayerWrapper virtual void collectUpReachable(std::set& reachable); virtual void collectDownReachable(std::set& reachable); virtual void refreshTreeItem(); + virtual size_t referencedCount(bool excludeSelf = false) const; + virtual bool deleteable(bool excludeSubTree = false) const; }; class FolderLayerWrapper : public LayerWrapper @@ -96,6 +98,8 @@ class FolderLayerWrapper : public LayerWrapper void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; void collectDownReachable(std::set& reachable) override; void refreshTreeItem() override; + size_t referencedCount(bool excludeSelf = false) const override; + bool deleteable(bool excludeSubTree = false) const override; }; class LeafLayerWrapper : public LayerWrapper @@ -105,7 +109,7 @@ class LeafLayerWrapper : public LayerWrapper LayerStyleContainer styles; public: - ~LeafLayerWrapper() = default; + ~LeafLayerWrapper(); void refresh(LayerWrapper* layer = nullptr) override; LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); QJsonObject toJson() const override; diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index 69a67b9..dba5943 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -78,16 +78,20 @@ void LayerTreeWidget::popMenu(const QPoint &pos) emit requireRefreshPreview(); emit requireRefreshElementWidget(); }); + menu.actions().last()->setEnabled(layer->deleteable()); menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent); if(typeid(*layer) == typeid(FolderLayerWrapper)) + { menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() { auto layer = this->selectedItem->data(0, Qt::UserRole).value(); - layer->delSelf(); - layer->getParent()->removeChild(layer); - this->refresh(); - emit requireRefreshPreview(); - emit requireRefreshElementWidget(); + layer->delSelf(); + layer->getParent()->removeChild(layer); + this->refresh(); + emit requireRefreshPreview(); + emit requireRefreshElementWidget(); }); + menu.actions().last()->setEnabled(layer->deleteable(true)); + } } if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) { menu.addAction(QString::fromLocal8Bit("创建组合元素"), this, [this]() { From 8bf6835c234cced8f7efe0401685d66efef3915b Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Sun, 19 Mar 2023 15:48:42 +0800 Subject: [PATCH 39/40] =?UTF-8?q?=E6=B7=BB=E5=8A=A0LayerWrapper=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/LayerWrapper.cpp | 15 +++++++++++++++ .../src/Editor/LayerWrapper.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 770c45d..bf0222b 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -413,4 +413,19 @@ bool FolderLayerWrapper::deleteable(bool excludeSubTree) const return this->getReferencedBy() == -1; else return this->referencedCount() == 0; +} + +bool LayerWrapper::referencingGroupElement() const +{ + return false; +} + +bool LeafLayerWrapper::referencingGroupElement() const +{ + return typeid(*wrappedElement) == typeid(GroupElement); +} + +bool LayerWrapper::canApplyStyles() const +{ + return typeid(*this) == typeid(LeafLayerWrapper) && !referencingGroupElement(); } \ No newline at end of file diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index b62d685..947d90c 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -73,6 +73,8 @@ class LayerWrapper virtual void refreshTreeItem(); virtual size_t referencedCount(bool excludeSelf = false) const; virtual bool deleteable(bool excludeSubTree = false) const; + virtual bool referencingGroupElement() const; + bool canApplyStyles() const; }; class FolderLayerWrapper : public LayerWrapper @@ -117,6 +119,7 @@ class LeafLayerWrapper : public LayerWrapper void collectDownReachable(std::set& reachable) override; QTreeWidgetItem* getQTreeItem() override; void refreshTreeItem() override; + bool referencingGroupElement() const override; }; Q_DECLARE_METATYPE(LayerWrapper *) From b3bbf6c1bee75caeaaad05e7f4c300125c4f6f93 Mon Sep 17 00:00:00 2001 From: karlis <2995621482@qq.com> Date: Sun, 19 Mar 2023 16:07:35 +0800 Subject: [PATCH 40/40] =?UTF-8?q?=E9=87=8D=E5=86=99=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E4=BF=A1=E5=8F=B7=E5=8F=8A=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Editor/EditorWidgetItem.cpp | 9 +++++ .../src/Editor/ElementPoolWidget.cpp | 7 ++-- .../src/Editor/ElementPoolWidget.h | 1 + .../src/Editor/RightBar/InfoDisplayWidget.cpp | 36 ++++++++----------- .../src/Editor/RightBar/InfoDisplayWidget.h | 4 ++- .../src/Editor/RightBar/LayerTreeWidget.cpp | 16 +++------ .../src/Editor/RightBar/LayerTreeWidget.h | 1 + 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp index bef3c7c..eb5f228 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp @@ -19,6 +19,15 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p elementInfoDisplayWidget->enableEdit(); qDebug() << layerInfoDisplayWidget; qDebug() << elementInfoDisplayWidget; + auto centralRefresh = [this]() { + layerInfoDisplayWidget->refresh(); + elementInfoDisplayWidget->refresh(); + treeWidget->refresh(); + previewWindow->refresh(); + }; + connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh); + connect(elementInfoDisplayWidget, &ElementPoolWidget::triggerCentralRefresh, centralRefresh); + connect(treeWidget, &LayerTreeWidget::triggerCentralRefresh, centralRefresh); connect(editorSettingWidget, &EditorSettingWidget::backgroundColorChanged, this, &EditorWidgetItem::handleBackgroundColorChange); connect(editorSettingWidget, &EditorSettingWidget::projectNameChanged, this, &EditorWidgetItem::handleProjectNameChange); connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex); diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp index ff166f0..74453d0 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp @@ -67,7 +67,6 @@ void ElementPoolWidget::setElementManager(ElementManager* element) void ElementPoolWidget::refresh() { this->setElementList(this->elementManager->elements); - emit refreshLayerTree(); // update(); } @@ -113,12 +112,12 @@ void ElementPoolWidget::popMenu(const QPoint& pos) if (bOk && !sName.isEmpty()) { currentElement->name = sName; - refresh(); + emit triggerCentralRefresh(); } }); menu->addAction(QString::fromLocal8Bit("删除"), this, [this, currentElement]() { this->elementManager->removeElement(currentElement); - refresh(); + emit triggerCentralRefresh(); }); menu->actions().last()->setDisabled(currentElement->referencedCount > 0); } @@ -130,7 +129,7 @@ void ElementPoolWidget::popMenu(const QPoint& pos) QString fileName = fileInfo.fileName(); qDebug() << fileName << " " << filePath; this->elementManager->createSimpleElement(fileName, filePath); - refresh(); + emit triggerCentralRefresh(); }); } menu->popup(mapToGlobal(pos)); diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h index 82ee0ff..472b1ba 100644 --- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h +++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h @@ -26,6 +26,7 @@ public: signals: void elementSelected(GraphicElement* element); void refreshLayerTree(); + void triggerCentralRefresh(); public slots: int pictureItemClicked(QListWidgetItem* item); diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp index 1db2940..6869729 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp @@ -45,32 +45,27 @@ void InfoDisplayWidget::generateLayerForm() rotation->setValidator(new QIntValidator(-10000, 10000, this)); connect(rotation, &QLineEdit::textChanged, [=](QString content) { this->displayLayer->property.rotation = content.toDouble(); - emit requireRefreshElementWidget(); - emit requireRefreshPreview(); + emit triggerCentralRefresh(); }); offsetX->setValidator(new QIntValidator(-10000, 10000, this)); connect(offsetX, &QLineEdit::textChanged, [=](QString content) { this->displayLayer->property.offset = {content.toDouble(), this->displayLayer->property.offset.y()}; - emit requireRefreshElementWidget(); - emit requireRefreshPreview(); + emit triggerCentralRefresh(); }); offsetY->setValidator(new QIntValidator(-10000, 10000, this)); connect(offsetY, &QLineEdit::textChanged, [=](QString content) { this->displayLayer->property.offset = {this->displayLayer->property.offset.x(), content.toDouble()}; - emit requireRefreshElementWidget(); - emit requireRefreshPreview(); + emit triggerCentralRefresh(); }); scaleX->setValidator(new QDoubleValidator(-1000, 1000, 4, this)); connect(scaleX, &QLineEdit::textChanged, [=](QString content) { this->displayLayer->property.scale = {content.toDouble(), this->displayLayer->property.scale.y()}; - emit requireRefreshElementWidget(); - emit requireRefreshPreview(); + emit triggerCentralRefresh(); }); scaleY->setValidator(new QDoubleValidator(-1000, 1000, 4, this)); connect(scaleY, &QLineEdit::textChanged, [=](QString content) { this->displayLayer->property.scale = {this->displayLayer->property.scale.x(), content.toDouble()}; - emit requireRefreshElementWidget(); - emit requireRefreshPreview(); + emit triggerCentralRefresh(); }); layout->addRow("layer name:", name); @@ -108,10 +103,7 @@ void InfoDisplayWidget::generateLayerForm() { leafP->styles.useStyle(dialog->layerStyle); leafP->styles.computeNewHash(); - - emit requireRefreshPreview(); - emit requireSelfRefresh(); - emit requireRefreshElementWidget(); + emit triggerCentralRefresh(); } }); } @@ -153,10 +145,7 @@ void InfoDisplayWidget::generateLayerForm() { styleIterator->second = dialog->layerStyle; styles->computeNewHash(); - - emit requireRefreshPreview(); - emit requireSelfRefresh(); - emit requireRefreshElementWidget(); + emit triggerCentralRefresh(); } }); @@ -165,10 +154,7 @@ void InfoDisplayWidget::generateLayerForm() { styles->dropStyle(styleIterator->first); styles->computeNewHash(); - - emit requireRefreshPreview(); - emit requireSelfRefresh(); - emit requireRefreshElementWidget(); + emit triggerCentralRefresh(); }); QWidget* styleDisplayWidget = styleIterator->second->getListDisplayWidget(); @@ -190,6 +176,12 @@ void InfoDisplayWidget::generateLayerForm() } void InfoDisplayWidget::triggerSelfRefresh() +{ + if (this->displayLayer != nullptr) + this->generateLayerForm(); +} + +void InfoDisplayWidget::refresh() { if (this->displayLayer != nullptr) this->generateLayerForm(); diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.h b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.h index 37b259c..da314f5 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.h +++ b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.h @@ -16,11 +16,13 @@ class InfoDisplayWidget : public QWidget public: void setLayer(LayerWrapper *layer); void generateLayerForm(); + void refresh(); public slots: void triggerSelfRefresh(); - signals: +signals: + void triggerCentralRefresh(); void requireRefreshPreview(); void requireSelfRefresh(); void requireRefreshElementWidget(); diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp index dba5943..a8ba44e 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.cpp @@ -24,7 +24,7 @@ LayerTreeWidget::LayerTreeWidget(QWidget *parent) else { emit displayLayerChange(nullptr); } - emit requireRefreshPreview(); + emit triggerCentralRefresh(); }); // connect(this, &QTreeWidget::itemDoubleClicked, this, &LayerTreeWidget::onItemDoubleClicked); } @@ -62,9 +62,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos) folderLayer->addChild(std::shared_ptr(newLayer)); folderLayer->qTreeWidgetItem->addChild(newLayer->getQTreeItem()); qDebug() << jsonObj<<"----------------------"; - this->refresh(); - emit requireRefreshPreview(); - emit requireRefreshElementWidget(); + emit triggerCentralRefresh(); }); dialog->exec(); }); @@ -74,9 +72,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos) auto layer = this->selectedItem->data(0, Qt::UserRole).value(); layer->del(); layer->getParent()->removeChild(layer); - this->refresh(); - emit requireRefreshPreview(); - emit requireRefreshElementWidget(); + emit triggerCentralRefresh(); }); menu.actions().last()->setEnabled(layer->deleteable()); menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent); @@ -86,9 +82,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos) auto layer = this->selectedItem->data(0, Qt::UserRole).value(); layer->delSelf(); layer->getParent()->removeChild(layer); - this->refresh(); - emit requireRefreshPreview(); - emit requireRefreshElementWidget(); + emit triggerCentralRefresh(); }); menu.actions().last()->setEnabled(layer->deleteable(true)); } @@ -103,7 +97,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos) "", &ok); if (ok && !name.isEmpty()) { elementManager->createGroupElement(name, layer); - emit requireRefreshElementWidget(); + emit triggerCentralRefresh(); } } }); diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.h b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.h index e7472dd..a7f4c93 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.h +++ b/ArchitectureColoredPainting/src/Editor/RightBar/LayerTreeWidget.h @@ -21,6 +21,7 @@ class LayerTreeWidget : public QTreeWidget // void onItemDoubleClicked(QTreeWidgetItem *item, int column = 0); signals: + void triggerCentralRefresh(); void displayLayerChange(LayerWrapper *); void requireRefreshPreview(); void requireRefreshElementWidget();