Compare commits

...

17 Commits

Author SHA1 Message Date
ArgonarioD f109ed7d62 merge 2023-03-16 02:05:29 +08:00
ArgonarioD 257868fd4c [style] 初步完成LayerStyle序列化 2023-03-16 01:56:05 +08:00
ArgonarioD 8809daaddd [stroke] fix: 新增描边时无法正确应用颜色修改的问题 2023-03-16 01:54:50 +08:00
ArgonarioD e72ba7ebbd [editor/util] 添加了JsonUtil 2023-03-16 01:53:28 +08:00
wuyize 78c24ad373 FIX: painting渲染bug 2023-03-15 22:43:51 +08:00
karlis 627b947738 Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-15 21:10:19 +08:00
karlis 8903419799 修复了zt黄色的问题 2023-03-15 21:10:05 +08:00
karlis 70d5973a90 修复了yyq黄色的问题 2023-03-15 21:04:21 +08:00
karlis 6c86403c4a Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-15 20:22:26 +08:00
karlis b9c8624dae Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-15 20:22:17 +08:00
karlis 153f6bdd8e Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-15 20:10:18 +08:00
karlis c234c0e9b3 实现element导入,添加滚动条,修复空白打开 2023-03-15 20:10:14 +08:00
wuyize 3abc0d9bcd 初步完成json到Painting的转换 2023-03-15 19:24:33 +08:00
yang.yongquan 5d88ddf0ca 增加图片刷新的槽函数 2023-03-15 17:37:12 +08:00
karlis fa91d80b70 完善Element序列化 2023-03-15 16:36:46 +08:00
karlis 3b87644e21 修改了PixelPath 2023-03-15 16:16:59 +08:00
ArgonarioD 073f68e360 初步实现了编辑器中的StrokeStyle
[style/stroke] 实现了行删除
[style/stroke] 基本稳定了strokeStyle的修改
[paint] 令drawElement时会应用style
[style] 修改了LayerStyle
[editor] 新增了ColorPicker类和StrokeStyleListView类
2023-03-15 11:43:16 +08:00
31 changed files with 606 additions and 88 deletions

View File

@ -197,6 +197,7 @@
<QtMoc Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.h" /> <QtMoc Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.h" />
<QtMoc Include="src\Editor\EditorWidgetComponent\LayerStyleDialog.h" /> <QtMoc Include="src\Editor\EditorWidgetComponent\LayerStyleDialog.h" />
<QtMoc Include="src\Editor\EditorWidgetComponent\ColorPicker.h" /> <QtMoc Include="src\Editor\EditorWidgetComponent\ColorPicker.h" />
<ClInclude Include="src\Editor\util\JsonUtil.hpp" />
<ClInclude Include="src\Editor\ElementManager.h" /> <ClInclude Include="src\Editor\ElementManager.h" />
<QtMoc Include="src\Editor\ElementPoolWidget.h" /> <QtMoc Include="src\Editor\ElementPoolWidget.h" />
<ClInclude Include="src\Editor\GraphicElement.h" /> <ClInclude Include="src\Editor\GraphicElement.h" />

View File

@ -477,6 +477,9 @@
<ClInclude Include="src\Editor\LayerStyle.h"> <ClInclude Include="src\Editor\LayerStyle.h">
<Filter>Header Files\Editor\Style</Filter> <Filter>Header Files\Editor\Style</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Editor\util\JsonUtil.hpp">
<Filter>Header Files\Editor\util</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtRcc Include="res\MainWindow.qrc"> <QtRcc Include="res\MainWindow.qrc">

View File

@ -37,38 +37,87 @@
</property> </property>
<item> <item>
<widget class="QWidget" name="MainWindow" native="true"> <widget class="QWidget" name="MainWindow" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="30"> <layout class="QVBoxLayout" name="verticalLayout_2" stretch="20,1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,12,5"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,12,5">
<item> <item>
<widget class="QWidget" name="LeftBar" native="true"/> <widget class="QWidget" name="LeftBar" native="true"/>
</item> </item>
<item> <item>
<widget class="PreviewWindow" name="Preview"> <widget class="QScrollArea" name="scrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>1080</width> <width>0</width>
<height>1080</height> <height>0</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>1080</width> <width>10801080</width>
<height>1080</height> <height>10801080</height>
</size> </size>
</property> </property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1024</width>
<height>1024</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1024</width>
<height>1024</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>10241024</width>
<height>10241024</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="PreviewWindow" name="Preview">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1024</width>
<height>1024</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>1024</width>
<height>1024</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
<item> <item>
@ -138,6 +187,19 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -1149,7 +1149,7 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
p[2] *= ratio; p[2] *= ratio;
p[3] *= ratio; p[3] *= ratio;
vec2 tangentBeginNext; vec2 tangentBeginNext = vec2(0);
if (contourIterator + 1 < contourIndex + 1 + lineCount) if (contourIterator + 1 < contourIndex + 1 + lineCount)
{ {
uint lineIndex = elementIndexs[contourIterator + 1]; uint lineIndex = elementIndexs[contourIterator + 1];
@ -1217,10 +1217,10 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
bool hit = d < minDistance; bool hit = d < minDistance;
if (onBegin) if (onBegin)
hit = 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) if (onEnd)
hit = hit && 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) if (hit)
{ {
@ -1352,8 +1352,8 @@ void main()
vec3 debugBVH = vec3(0); vec3 debugBVH = vec3(0);
// bool debugHit = false; // 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(1,1,1, -1); vec4 color = vec4(1,1,1, -1);
vec2 metallicRoughness = vec2(0, 0.8); vec2 metallicRoughness = vec2(0, 0.8);
stack.top = 0; stack.top = 0;
uint index = 0, visitTime = 0; uint index = 0, visitTime = 0;
@ -1423,7 +1423,7 @@ void main()
imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1)); imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1));
imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1)); imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1));
//return; return;
if (/*color.a!=-1&&*/ debugBVH == vec3(0)) if (/*color.a!=-1&&*/ debugBVH == vec3(0))
{ {
// imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1)); // imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1));

View File

@ -36,11 +36,6 @@ void main()
lod++; lod++;
gMetallicRoughness = mt.rg; 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); uint w = 1<<(levels-1-lodExpect);
ivec2 page = ivec2(TexCoords * vec2(w)); ivec2 page = ivec2(TexCoords * vec2(w));
page = clamp(page, ivec2(0), ivec2(w-1)); page = clamp(page, ivec2(0), ivec2(w-1));
@ -49,7 +44,6 @@ void main()
gPaintingIndex = uvec2(0); gPaintingIndex = uvec2(0);
else else
gPaintingIndex = uvec2((paintingId<<4)+lodExpect, (page.y<<8)+page.x); gPaintingIndex = uvec2((paintingId<<4)+lodExpect, (page.y<<8)+page.x);
gPaintingTexCoord = vec2(1., 1.) - TexCoords * 2;
return; return;
} }

View File

@ -24,7 +24,8 @@ EditorWidget::EditorWidget(QWidget* parent) : QWidget(parent)
}); });
connect(this->openButton, &QPushButton::clicked, this, [this]() { connect(this->openButton, &QPushButton::clicked, this, [this]() {
QString fileName = QFileDialog::getOpenFileName(this->saveAsButton, QString::fromLocal8Bit("´ò¿ª"), "", QString::fromLocal8Bit("JSONÎļþ(*.json)")); 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]() { connect(this->closeButton, &QPushButton::clicked, this, [this]() {
this->tabWidget->removeTab(this->tabWidget->currentIndex()); this->tabWidget->removeTab(this->tabWidget->currentIndex());

View File

@ -0,0 +1,108 @@
#include "StrokeStyleListView.h"
#include "ColorPicker.h"
#include <qtmaterialraisedbutton.h>
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<Renderer::StrokeRadialGradient> 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;
}
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "LayerStyle.h"
#include "../Renderer/Painting/MaterialStyleStroke.h"
#include <QListView>
#include <QListWidget>
#include <QTableWidget>
class StrokeStyleListView : public QTableWidget
{
Q_OBJECT
private:
QString currentItemValue;
public:
StrokeStyleListView(std::shared_ptr<Renderer::StrokeRadialGradient> stroke, QWidget* parent = nullptr);
std::shared_ptr<Renderer::StrokeRadialGradient> stroke;
protected slots:
void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
void onCellChanged(int row, int column);
};

View File

@ -126,7 +126,7 @@ void StrokeStyleWidget::initTable(std::shared_ptr<Renderer::StrokeRadialGradient
(*materialMap)[newWidth] = newMaterial; (*materialMap)[newWidth] = newMaterial;
int newRow = this->strokeTable->rowCount() - 1; int newRow = this->strokeTable->rowCount() - 1;
this->strokeTable->insertRow(newRow); this->strokeTable->insertRow(newRow);
setTableRow(newRow, newWidth, newMaterial); setTableRow(newRow, newWidth, (*materialMap)[newWidth]);
this->strokeTable->update(); this->strokeTable->update();
handlingRowInsert = false; handlingRowInsert = false;
}); });
@ -149,7 +149,7 @@ void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& ma
strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker); strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker);
connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) { connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) {
*colorPtr = color; *colorPtr = color;
this->strokeTable->update(); this->strokeTable->update();
}); });
QTableWidgetItem* metallicItem = new QTableWidgetItem; QTableWidgetItem* metallicItem = new QTableWidgetItem;
@ -176,7 +176,7 @@ void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWi
int column = current->column(); int column = current->column();
if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS) if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS)
{ {
this->currentItemValue = current->text(); this->currentItemValue = current->data(Qt::EditRole);
} }
} }
@ -190,7 +190,7 @@ void StrokeStyleWidget::onCellChanged(int row, int column)
changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat()); changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat());
return; return;
} }
auto changedWidth = strokeTable->item(row, COLUMN_WIDTH)->text().toFloat(); auto changedWidth = strokeTable->item(row, COLUMN_WIDTH)->data(Qt::EditRole).toFloat();
switch (column) switch (column)
{ {
case COLUMN_WIDTH: case COLUMN_WIDTH:

View File

@ -10,7 +10,7 @@ class StrokeStyleWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
private: private:
QString currentItemValue; QVariant currentItemValue;
QtMaterialCheckBox* enableGradual; QtMaterialCheckBox* enableGradual;
QComboBox* endTypeBox; QComboBox* endTypeBox;

View File

@ -12,6 +12,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
this->filePath = filePath; this->filePath = filePath;
layerInfoDisplayWidget = dynamic_cast<InfoDisplayWidget *>(tabWidget->widget(0)); layerInfoDisplayWidget = dynamic_cast<InfoDisplayWidget *>(tabWidget->widget(0));
elementInfoDisplayWidget = dynamic_cast<ElementPoolWidget *>(tabWidget->widget(1)); elementInfoDisplayWidget = dynamic_cast<ElementPoolWidget *>(tabWidget->widget(1));
elementInfoDisplayWidget->enableEdit();
qDebug() << layerInfoDisplayWidget; qDebug() << layerInfoDisplayWidget;
qDebug() << elementInfoDisplayWidget; qDebug() << elementInfoDisplayWidget;
connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
@ -37,11 +38,11 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
qDebug() << jError.errorString(); qDebug() << jError.errorString();
// end test // end test
QJsonObject source = jsonDoc.object(); QJsonObject source = jsonDoc.object();
elementManager = new ElementManager(source,previewWindow->getRenderer()); elementManager = new ElementManager(source,Renderer::ElementRenderer::instance());
layerManager = new LayerManager(source, elementManager); layerManager = new LayerManager(source, elementManager);
elementInfoDisplayWidget->setElementManager(elementManager); elementInfoDisplayWidget->setElementManager(elementManager);
treeWidget->elementManager = elementManager; treeWidget->elementManager = elementManager;
qDebug() << layerManager->toJson(); //qDebug() << layerManager->toJson();
previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toDouble(),jsonDoc.object().value("height").toDouble())); previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toDouble(),jsonDoc.object().value("height").toDouble()));

View File

@ -97,6 +97,7 @@ void ElementManager::createSimpleElement(QString name, QString filePath) {
data.insert("include", filePath); data.insert("include", filePath);
json.insert("data", data); json.insert("data", data);
auto element = new SimpleElement(json); auto element = new SimpleElement(json);
qDebug() << element->painterPath;
element->name = name; element->name = name;
addElement(element); addElement(element);
} }

View File

@ -1,11 +1,16 @@
#include "ElementPoolWidget.h" #include "ElementPoolWidget.h"
#include <QMenu>
#include <QInputDialog>
#include <QFileDialog>
#include <QDialogButtonBox>
ElementPoolWidget::ElementPoolWidget(QWidget* parent) ElementPoolWidget::ElementPoolWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
{ {
elementManager = nullptr; elementManager = nullptr;
iconWidth = 120, iconHeight = 90; iconWidth = 120, iconHeight = 90;
pictureList = new QListWidget(); pictureList = new QListWidget(this);
pictureList->setContextMenuPolicy(Qt::CustomContextMenu);
pictureList->setIconSize(QSize(iconWidth, iconHeight)); pictureList->setIconSize(QSize(iconWidth, iconHeight));
pictureList->setWindowFlags(Qt::FramelessWindowHint); pictureList->setWindowFlags(Qt::FramelessWindowHint);
pictureList->setResizeMode(QListWidget::Adjust); pictureList->setResizeMode(QListWidget::Adjust);
@ -79,3 +84,59 @@ void ElementPoolWidget::refresh() {
this->setElementList(this->elementManager->elements); this->setElementList(this->elementManager->elements);
// update(); // 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;
}
}
}
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));
}

View File

@ -21,6 +21,7 @@ public:
void setElementList(std::vector<GraphicElement*> elementList); void setElementList(std::vector<GraphicElement*> elementList);
void setElementManager(ElementManager* element); void setElementManager(ElementManager* element);
~ElementPoolWidget(); ~ElementPoolWidget();
void enableEdit();
signals: signals:
void elementSelected(GraphicElement* element); void elementSelected(GraphicElement* element);
@ -28,5 +29,7 @@ signals:
public slots: public slots:
int pictureItemClicked(QListWidgetItem* item); int pictureItemClicked(QListWidgetItem* item);
void refresh(); void refresh();
void refreshPicture(GraphicElement* element);
void popMenu(const QPoint& pos);
}; };

View File

@ -1,11 +1,14 @@
#include "GraphicElement.h" #include "GraphicElement.h"
#include "util/SvgFileLoader.h" #include "util/SvgFileLoader.h"
#include <QGuiApplication>
#include <QScreen>
using namespace std; using namespace std;
PixelPath SimpleElement::getPaintObject() const PixelPath SimpleElement::getPaintObject() const
{ {
PixelPath result; PixelPath result;
result.addPath(painterPath); result.addPath(painterPath);
//qDebug() << result.getPainterPath();
return result; return result;
} }
@ -20,8 +23,10 @@ void SimpleElement::loadSvgFile(const QString& filePath)
SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource) SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource)
{ {
painterPath.clear(); painterPath.clear();
filePath = jsonSource["data"].toObject()["include"].toString();
//loadSvgFile("D:\\Projects\\BigC\\svg\\3.svg"); //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) GroupElement::GroupElement(FolderLayerWrapper* sourceLayer)
@ -48,7 +53,7 @@ PixelPath SimpleElement::getPaintObject(std::vector<std::shared_ptr<LayerStyle>>
std::shared_ptr<Renderer::ElementStyle> style; std::shared_ptr<Renderer::ElementStyle> style;
if ((*styles).empty()) if ((*styles).empty())
{ {
style = std::make_shared<Renderer::ElementStyleStrokeDemo>(2); return this->getPaintObject();
} }
else else
{ {
@ -60,9 +65,11 @@ PixelPath SimpleElement::getPaintObject(std::vector<std::shared_ptr<LayerStyle>>
std::dynamic_pointer_cast<StrokeElementLayerStyle>(style)->materialStyles[0]->materialStroke std::dynamic_pointer_cast<StrokeElementLayerStyle>(style)->materialStyles[0]->materialStroke
)->materialMap[1.0].color;*/ )->materialMap[1.0].color;*/
} }
auto [img, mov] = renderer->drawElement(painterPath, *style, 1.0);
auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, *style, 1.0);
//qDebug() << img << " ------"; //qDebug() << img << " ------";
result.addImage(img, mov); result.addImage(img, mov);
result.addPath(painterPath);
//result.addPath(painterPath); //result.addPath(painterPath);
// QImage img(80,80,QImage::Format_ARGB32); // QImage img(80,80,QImage::Format_ARGB32);
// QPainter pt(&img); // QPainter pt(&img);
@ -91,10 +98,25 @@ PixelPath GroupElement::getPaintObject(std::vector<std::shared_ptr<LayerStyle>>*
// } // }
//} //}
//TODO : Ìí¼Óϸ½Ú //TODO : Ìí¼Óϸ½Ú
QJsonObject GraphicElement::toJson() const QJsonObject SimpleElement::toJson() const
{ {
QJsonObject result; 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; return result;
} }
@ -124,8 +146,15 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector<
std::dynamic_pointer_cast<StrokeElementLayerStyle>(style)->materialStyles[0]->materialStroke std::dynamic_pointer_cast<StrokeElementLayerStyle>(style)->materialStyles[0]->materialStroke
)->materialMap[1.0].color;*/ )->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::ElementRenderer::instance()->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->drawImage(mov, img);
} }
painter->restore(); painter->restore();

View File

@ -25,7 +25,7 @@ public:
QString name = ""; QString name = "";
int index; int index;
// TODO: ¸ÄΪBitmapPath // TODO: ¸ÄΪBitmapPath
virtual QJsonObject toJson() const; virtual QJsonObject toJson() const = 0;
virtual PixelPath getPaintObject() const = 0; virtual PixelPath getPaintObject() const = 0;
virtual PixelPath getPaintObject(std::vector<std::shared_ptr<LayerStyle>>*) const = 0; virtual PixelPath getPaintObject(std::vector<std::shared_ptr<LayerStyle>>*) const = 0;
virtual void paint(QPainter* painter, QTransform transform, const std::vector<std::shared_ptr<LayerStyle>> &styles) = 0; virtual void paint(QPainter* painter, QTransform transform, const std::vector<std::shared_ptr<LayerStyle>> &styles) = 0;
@ -33,13 +33,15 @@ public:
class SimpleElement : public GraphicElement class SimpleElement : public GraphicElement
{ {
private: public:
QJsonObject jsonSource; QJsonObject jsonSource;
// TODO: ¸ÄΪComposedPainterPath // TODO: ¸ÄΪComposedPainterPath
QPainterPath painterPath; QPainterPath painterPath;
QString filePath;
void loadSvgFile(const QString& filePath); void loadSvgFile(const QString& filePath);
public: public:
QJsonObject toJson() const override;
SimpleElement(QJsonObject jsonSource); SimpleElement(QJsonObject jsonSource);
SimpleElement(QString filePath); SimpleElement(QString filePath);
~SimpleElement() = default; ~SimpleElement() = default;
@ -54,6 +56,7 @@ public:
FolderLayerWrapper* sourceLayer; FolderLayerWrapper* sourceLayer;
public: public:
QJsonObject toJson() const override;
GroupElement() = default; GroupElement() = default;
GroupElement(FolderLayerWrapper* mSourceLayer); GroupElement(FolderLayerWrapper* mSourceLayer);
~GroupElement() = default; ~GroupElement() = default;

View File

@ -1,5 +1,6 @@
#include "LayerStyle.h" #include "LayerStyle.h"
#include "./EditorWidgetComponent/StrokeStyleWidget.h" #include "./EditorWidgetComponent/StrokeStyleWidget.h"
#include "./util/JsonUtil.hpp"
#include <qtmaterialcheckbox.h> #include <qtmaterialcheckbox.h>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QDialogButtonBox> #include <QDialogButtonBox>
@ -118,6 +119,16 @@ StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle&
enableEachSideIndependent = other.enableEachSideIndependent; enableEachSideIndependent = other.enableEachSideIndependent;
} }
QJsonObject StrokeElementLayerStyle::toJson() const
{
QJsonObject json;
json.insert("type", "stroke");
json.insert("enableEachSideIndependent", enableEachSideIndependent);
json.insert("left", JsonUtil::toQJsonArray<GLfloat>(strokePair.first->encoded()));
json.insert("right", JsonUtil::toQJsonArray<GLfloat>(strokePair.second->encoded()));
return json;
}
std::unique_ptr<LayerStyle> StrokeElementLayerStyle::clone() const std::unique_ptr<LayerStyle> StrokeElementLayerStyle::clone() const
{ {
return std::make_unique<StrokeElementLayerStyle>(StrokeElementLayerStyle(*this)); return std::make_unique<StrokeElementLayerStyle>(StrokeElementLayerStyle(*this));
@ -161,7 +172,17 @@ FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other)
} }
} }
QJsonObject FillElementLayerStyle::toJson() const
{
return QJsonObject();
}
std::unique_ptr<LayerStyle> FillElementLayerStyle::clone() const std::unique_ptr<LayerStyle> FillElementLayerStyle::clone() const
{ {
return std::make_unique<FillElementLayerStyle>(FillElementLayerStyle(*this)); return std::make_unique<FillElementLayerStyle>(FillElementLayerStyle(*this));
} }
std::unique_ptr<LayerStyle> LayerStyle::fromJson(const QJsonObject& json)
{
return std::unique_ptr<LayerStyle>();
}

View File

@ -5,6 +5,7 @@
#include <QWidget> #include <QWidget>
#include <QObject> #include <QObject>
#include <QListWidget> #include <QListWidget>
#include <QJsonObject>
#include "../Renderer/Painting/ElementStyle.h" #include "../Renderer/Painting/ElementStyle.h"
#include "../Renderer/Painting/MaterialStyleStroke.h" #include "../Renderer/Painting/MaterialStyleStroke.h"
#include "../Renderer/Painting/MaterialStyleFill.h" #include "../Renderer/Painting/MaterialStyleFill.h"
@ -23,10 +24,13 @@ class LayerStyle : public Renderer::ElementStyle
{ {
public: public:
const static std::vector<std::pair<QString, std::function<std::unique_ptr<LayerStyle>()>>> types; const static std::vector<std::pair<QString, std::function<std::unique_ptr<LayerStyle>()>>> types;
static std::unique_ptr<LayerStyle> fromJson(const QJsonObject& json);
virtual QString getStyleName() const = 0; virtual QString getStyleName() const = 0;
virtual QWidget* getInputWidget() = 0; virtual QWidget* getInputWidget() = 0;
virtual QWidget* getListDisplayWidget() const = 0; virtual QWidget* getListDisplayWidget() const = 0;
virtual ~LayerStyle() {}; virtual ~LayerStyle() {};
virtual QJsonObject toJson() const = 0;
virtual std::unique_ptr<LayerStyle> clone() const = 0; virtual std::unique_ptr<LayerStyle> clone() const = 0;
}; };
@ -43,6 +47,7 @@ public:
StrokeElementLayerStyle() = default; StrokeElementLayerStyle() = default;
StrokeElementLayerStyle(const StrokeElementLayerStyle& other); StrokeElementLayerStyle(const StrokeElementLayerStyle& other);
~StrokeElementLayerStyle() = default; ~StrokeElementLayerStyle() = default;
QJsonObject toJson() const override;
std::unique_ptr<LayerStyle> clone() const override; std::unique_ptr<LayerStyle> clone() const override;
bool enableEachSideIndependent = false; bool enableEachSideIndependent = false;
@ -59,5 +64,6 @@ public:
FillElementLayerStyle(const FillElementLayerStyle& other); FillElementLayerStyle(const FillElementLayerStyle& other);
~FillElementLayerStyle() = default; ~FillElementLayerStyle() = default;
std::vector<std::shared_ptr<Renderer::MaterialStyleFill>> materialStyles; std::vector<std::shared_ptr<Renderer::MaterialStyleFill>> materialStyles;
QJsonObject toJson() const override;
std::unique_ptr<LayerStyle> clone() const override; std::unique_ptr<LayerStyle> clone() const override;
}; };

View File

@ -240,6 +240,10 @@ QJsonObject LeafLayerWrapper::toJson() const
QJsonObject json = LayerWrapper::toJson(); QJsonObject json = LayerWrapper::toJson();
json.insert("element", wrappedElement->index); json.insert("element", wrappedElement->index);
json.insert("is-folder", false); json.insert("is-folder", false);
QJsonArray stylesJson;
for (auto& style : styles)
stylesJson.push_back(style->toJson());
json.insert("styles", stylesJson);
return json; return json;
} }
@ -268,7 +272,7 @@ void FolderLayerWrapper::paint(QPainter* painter, QTransform transform)
{ {
LayerWrapper::paint(painter, transform); LayerWrapper::paint(painter, transform);
transform = property.transform * transform; transform = property.transform * transform;
qDebug() << transform; //qDebug() << transform;
for (auto& child : children) for (auto& child : children)
child->paint(painter, transform); child->paint(painter, transform);
} }
@ -277,7 +281,7 @@ void LeafLayerWrapper::paint(QPainter* painter, QTransform transform)
{ {
LayerWrapper::paint(painter, transform); LayerWrapper::paint(painter, transform);
transform = property.transform * transform; transform = property.transform * transform;
qDebug() << transform; //qDebug() << transform;
if (wrappedElement != nullptr) if (wrappedElement != nullptr)
{ {
wrappedElement->paint(painter, transform, styles); wrappedElement->paint(painter, transform, styles);

View File

@ -6,6 +6,7 @@
#include <QGraphicsItemGroup> #include <QGraphicsItemGroup>
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QJSonObject> #include <QJSonObject>
#include <QJsonArray>
#include <QLine> #include <QLine>
#include <QObject> #include <QObject>
#include <QPoint> #include <QPoint>

View File

@ -66,6 +66,7 @@ void PixelPath::clear()
{ {
pixmap.fill(Qt::transparent); pixmap.fill(Qt::transparent);
boundingRect = QRectF(0, 0, 0, 0); boundingRect = QRectF(0, 0, 0, 0);
painterPath.clear();
} }
PixelPath PixelPath::trans(QTransform& mat)const PixelPath PixelPath::trans(QTransform& mat)const
@ -76,6 +77,7 @@ PixelPath PixelPath::trans(QTransform& mat)const
painter.setRenderHint(QPainter::HighQualityAntialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing);
painter.setTransform(mat); painter.setTransform(mat);
painter.drawPixmap(0, 0, pixmap); painter.drawPixmap(0, 0, pixmap);
result.painterPath.addPath(this->painterPath);
result.boundingRect = mat.mapRect(boundingRect); result.boundingRect = mat.mapRect(boundingRect);
return result; return result;
} }

View File

@ -7,14 +7,14 @@
class PixelPath class PixelPath
{ {
private: public:
QRectF boundingRect; QRectF boundingRect;
QPixmap pixmap; QPixmap pixmap;
QPainterPath painterPath; QPainterPath painterPath;
int w,h; int w,h;
public: public:
PixelPath(int w=1080, int h= 1080); PixelPath(int w=1024, int h= 1024);
PixelPath(QPainterPath painterPath,int w = 1080, int h = 1080); PixelPath(QPainterPath painterPath,int w = 1024, int h = 1024);
~PixelPath() = default; ~PixelPath() = default;
QRectF getBoundingRect() const; QRectF getBoundingRect() const;
QPixmap getPixmap() const; QPixmap getPixmap() const;

View File

@ -2,7 +2,8 @@
PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent) 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(); this->renderer = Renderer::ElementRenderer::instance();
QSurfaceFormat surfaceFormat; QSurfaceFormat surfaceFormat;
surfaceFormat.setSamples(16); surfaceFormat.setSamples(16);

View File

@ -68,13 +68,6 @@ void LayerTreeWidget::popMenu(const QPoint &pos)
}); });
dialog->exec(); dialog->exec();
}); });
menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() {
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
layer->delSelf();
layer->getParent()->removeChild(layer);
this->refresh();
emit requireRefreshPreview();
});
} }
if (layer != root) { if (layer != root) {
menu.addAction(QString::fromLocal8Bit("ɾ³ý"), this, [this]() { menu.addAction(QString::fromLocal8Bit("ɾ³ý"), this, [this]() {
@ -85,6 +78,13 @@ void LayerTreeWidget::popMenu(const QPoint &pos)
emit requireRefreshPreview(); emit requireRefreshPreview();
}); });
menu.addAction(QString::fromLocal8Bit("ÖØÃüÃû"), this, &LayerTreeWidget::onRenameEvent); menu.addAction(QString::fromLocal8Bit("ÖØÃüÃû"), this, &LayerTreeWidget::onRenameEvent);
menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() {
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
layer->delSelf();
layer->getParent()->removeChild(layer);
this->refresh();
emit requireRefreshPreview();
});
} }
if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) { if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) {
menu.addAction(QString::fromLocal8Bit("´´½¨×éºÏÔªËØ"), this, [this]() { menu.addAction(QString::fromLocal8Bit("´´½¨×éºÏÔªËØ"), this, [this]() {

View File

@ -0,0 +1,14 @@
#pragma once
#include <QJsonArray>
namespace JsonUtil
{
#include <vector>
template<typename T>
QJsonArray toQJsonArray(const std::vector<T>& vec)
{
QJsonArray array;
std::copy(vec.begin(), vec.end(), std::back_inserter(array));
return array;
}
}

View File

@ -2,16 +2,26 @@
#include <QFile> #include <QFile>
#include <QJsondocument> #include <QJsondocument>
#include "PainterPathUtil.h" #include "PainterPathUtil.h"
#include <queue>
using Renderer::Painting; using Renderer::Painting;
using Renderer::Element; using Renderer::Element;
using Renderer::ElementTransform; using Renderer::ElementTransform;
using glm::bvec2; using glm::bvec2;
using std::max; using std::max;
using std::shared_ptr;
using std::make_shared;
using std::min; using std::min;
using std::queue;
const double PaintingUtil::pi = acos(-1); const double PaintingUtil::pi = acos(-1);
struct LayerNode {
LayerWrapper* nowLayer;
QTransform transfrom;
bvec2 flip;
};
QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) { QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) {
QFile jsonFile(jsonFilePath); QFile jsonFile(jsonFilePath);
jsonFile.open(QFile::ReadOnly); jsonFile.open(QFile::ReadOnly);
@ -24,25 +34,52 @@ QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) {
Painting PaintingUtil::transfromToPainting(QString jsonFilePath) { Painting PaintingUtil::transfromToPainting(QString jsonFilePath) {
Painting painting; Painting painting;
QTransform transform;
glm::bvec2 flip(0, 0); glm::bvec2 flip(0, 0);
QJsonObject jsonObj = readJsonFile(jsonFilePath); QJsonObject jsonObj = readJsonFile(jsonFilePath);
ElementManager *elementManager = new ElementManager(jsonObj, Renderer::ElementRenderer::instance()); qDebug() << jsonObj;
LayerManager* layerManager = new LayerManager(jsonObj, elementManager); shared_ptr<ElementManager> elementManager = make_shared<ElementManager>(jsonObj, Renderer::ElementRenderer::instance());
traverseLayTree(layerManager->getRoot(), transform, flip, painting); shared_ptr<LayerManager> layerManager = make_shared<LayerManager>(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;
queue<LayerNode> layerQueue;
LayerWrapper* root = layerManager->getRoot();
root->getCache();
layerQueue.push({ root, root->property.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; 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<LeafLayerWrapper*>(nowLayer); LeafLayerWrapper* leafLayer = dynamic_cast<LeafLayerWrapper*>(nowLayer);
PixelPath pixelPath = nowLayer->getCache();
QPainterPath painterPath = pixelPath.getPainterPath();
QRectF bound = painterPath.boundingRect();
flip ^= bvec2(nowLayer->property.flipHorizontally, nowLayer->property.flipVertically); flip ^= bvec2(nowLayer->property.flipHorizontally, nowLayer->property.flipVertically);
transform = nowLayer->property.transform * transform; transform = nowLayer->property.transform * transform;
if (leafLayer != nullptr) { if (leafLayer != nullptr) {
GroupElement* wrapperElement = dynamic_cast<GroupElement*>(leafLayer->wrappedElement);
if (wrapperElement != nullptr) {
transform = wrapperElement->sourceLayer->property.transform * transform;
return wrapperElement->sourceLayer;
}
PixelPath pixelPath = nowLayer->getCache();
QPainterPath painterPath = pixelPath.getPainterPath();
QRectF bound = painterPath.boundingRect();
//qDebug() << leafLayer<<"------" << painterPath;
//qDebug() << transform;
Element element; Element element;
ElementTransform elementTrans; ElementTransform elementTrans;
element.ratio = bound.width() / bound.height(); element.ratio = bound.width() / bound.height();
@ -52,36 +89,40 @@ void PaintingUtil::traverseLayTree(LayerWrapper* nowLayer, QTransform transform,
trans.scale(1 / bound.width(), 1 / bound.height()); trans.scale(1 / bound.width(), 1 / bound.height());
trans.translate(-bound.center().x(), -bound.center().y()); trans.translate(-bound.center().x(), -bound.center().y());
element.contour.reset(new vector<vector<Renderer::Point> >(PainterPathUtil::transformToLines(trans.map(painterPath)))); qDebug() << trans.map(painterPath);
QSize screenSize = pixelPath.getPixmap().size(); element.contour = std::make_shared<vector<vector<Renderer::Point> >>(PainterPathUtil::transformToLines(trans.map(painterPath)));
//element.style.reset(new Renderer::ElementStyleStrokeDemo(0.06)); QSize screenSize = QSize(1024, 1024);
element.style = std::make_shared<Renderer::ElementStyleStrokeDemo>(0.06);
painterPath = transform.map(painterPath); painterPath = transform.map(painterPath);
qDebug() << painterPath;
bound = painterPath.boundingRect(); bound = painterPath.boundingRect();
qDebug() << bound;
elementTrans.center = glm::vec2( elementTrans.center = glm::vec2(
(bound.center().x() - screenSize.width()) / screenSize.width(), (2 * bound.center().x() - screenSize.width()) / screenSize.width(),
(bound.center().y() - screenSize.height()) / screenSize.height() (2 * bound.center().y() - screenSize.height()) / screenSize.height()
); );
qDebug() << elementTrans.center.x << elementTrans.center.y;
decomposeTransform(transform, elementTrans.rotation, elementTrans.scale); decomposeTransform(transform, elementTrans.rotation, elementTrans.scale);
elementTrans.scale = glm::vec2(
bound.width() * 2 / screenSize.width(),
bound.height() * 2 / screenSize.height()
);
elementTrans.flip = glm::bvec2( elementTrans.flip = glm::bvec2(
nowLayer->property.flipHorizontally, nowLayer->property.flipHorizontally,
nowLayer->property.flipVertically nowLayer->property.flipVertically
); );
qDebug() << elementTrans.scale.x << elementTrans.scale.y;
painting.addElement(element, elementTrans); painting.addElement(element, elementTrans);
return; return nullptr;
} }
FolderLayerWrapper* folderLayer = dynamic_cast<FolderLayerWrapper*>(nowLayer); FolderLayerWrapper* folderLayer = dynamic_cast<FolderLayerWrapper*>(nowLayer);
if (folderLayer != nullptr) { return folderLayer;
for (auto sonLayer : folderLayer->children) {
traverseLayTree(sonLayer.get(), transform, flip, painting);
}
}
return;
} }
void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2& scale) { void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2& scale) {
qDebug() << trans; //qDebug() << trans;
trans.setMatrix( trans.setMatrix(
trans.m11(), trans.m12(), trans.m13(), trans.m11(), trans.m12(), trans.m13(),
trans.m21(), trans.m22(), trans.m23(), trans.m21(), trans.m22(), trans.m23(),
@ -126,7 +167,8 @@ void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2&
angle = 360 - angle; angle = 360 - angle;
} }
qDebug() << angle; qDebug() << angle;
R = R.inverted() * trans; //R = R.inverted() * trans;
scale = glm::vec2(R.m11(), R.m22()); //scale = glm::vec2(R.m11(), R.m22());
//qDebug() << scale.x << scale.y;
return; return;
} }

View File

@ -7,7 +7,7 @@ class PaintingUtil
private: private:
static const double pi; static const double pi;
static QJsonObject readJsonFile(QString jsonFilePath); 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: public:
static Renderer::Painting transfromToPainting(QString jsonFilePath); static Renderer::Painting transfromToPainting(QString jsonFilePath);
static void decomposeTransform(QTransform trans, float& angle, glm::vec2& scale); static void decomposeTransform(QTransform trans, float& angle, glm::vec2& scale);

View File

@ -52,7 +52,7 @@ void Renderer::Model::loadModel(QString path)
directory = modelFile.dir(); directory = modelFile.dir();
Assimp::Importer importer; 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) if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{ {
qCritical() << "ERROR::ASSIMP::" << importer.GetErrorString() << endl; qCritical() << "ERROR::ASSIMP::" << importer.GetErrorString() << endl;
@ -229,8 +229,104 @@ GLuint Renderer::Model::loadPainting(std::string path)
if (iter != paintingLoaded.end()) if (iter != paintingLoaded.end())
return iter->second; return iter->second;
Painting painting = PaintingUtil::transfromToPainting("D:\\BigC\\Project\\ArchitectureColoredPainting\\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<std::pair<std::shared_ptr<Contour>, 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>(contour), ratio);
}
vector<std::shared_ptr<ElementStyle>> style = {
std::make_shared<ElementStyleFillDemo>(),
std::make_shared<ElementStyleStrokeDemo>(0.02),
std::make_shared<ElementStyleStrokeRadialGradientDemo>(0.2)
};
vector<std::shared_ptr<Element>> element = {
std::make_shared<Element>(Element{ contours[0].first, style[0], contours[0].second}),
std::make_shared<Element>(Element{ contours[1].first, style[2], contours[1].second}),
std::make_shared<Element>(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<std::pair<std::shared_ptr<Contour>, 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>(contour), ratio);
}
class StyleStrokeRadialGradient : public Renderer::ElementStyle
{
public:
float width;
StrokeType type;
StyleStrokeRadialGradient(float width, StrokeType type) :width(width), type(type) {};
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override
{
std::map<float, Material> 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<TransformStyle>(),
std::make_shared<MaterialStyleStroke>(width, type, StrokeEndType::kFlat,
std::make_shared<StrokeRadialGradient>(materialMap, false))) };
}
};
vector<std::shared_ptr<ElementStyle>> style = {
std::make_shared<StyleStrokeRadialGradient>(widths[0], StrokeType::kLeftSide),
std::make_shared<StyleStrokeRadialGradient>(widths[1], StrokeType::kRightSide),
std::make_shared<StyleStrokeRadialGradient>(widths[2], StrokeType::kLeftSide),
};
vector<std::shared_ptr<Element>> element = {
std::make_shared<Element>(Element{ contours[0].first, style[0], contours[0].second}),
std::make_shared<Element>(Element{ contours[1].first, style[1], contours[1].second}),
std::make_shared<Element>(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); painting.generateBuffers(glFunc);
auto index = vtManager->createVirtualTexture(painting); auto index = vtManager->createVirtualTexture(painting);

View File

@ -6,7 +6,7 @@
"name": "ababa", "name": "ababa",
"type": "svg-file", "type": "svg-file",
"data": { "data": {
"include": "./svg/2.svg" "include": "../svg/2.svg"
} }
}, },
{ {
@ -15,6 +15,13 @@
"data": { "data": {
"reference-layer": "0.0" "reference-layer": "0.0"
} }
},
{
"name": "ababa2",
"type": "svg-file",
"data": {
"include": "../svg/0.svg"
}
} }
], ],
"root-layer": { "root-layer": {

5
svg/4_L0.svg Normal file
View File

@ -0,0 +1,5 @@
<svg id="万字笔画" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1068 1045">
<title>4_L0</title>
<polyline points="873 0 360 390 427 483 490 439 600 592 690 524 750 608 189 1045" fill="none"/>
<polyline points="1068 830 651 303 566 373 629 455 487 566 538 632 461 696 0 99" fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 307 B

31
svg/ex.json Normal file
View File

@ -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":[]
}
}