Compare commits

...

17 Commits

Author SHA1 Message Date
ArgonarioD adb28a67e8 将一些可以改成引用传参的地方改成了引用 2023-03-19 01:25:31 +08:00
ArgonarioD 47ada04c3a 优化了bad smells
LayerStyleContainer::boundingBoxAffectedValue()
2023-03-19 01:20:32 +08:00
ArgonarioD 1378997f64 merge 2023-03-19 01:13:02 +08:00
ArgonarioD 1650404bb9 [fill] 实现FillElementLayerStyle 2023-03-19 01:06:51 +08:00
karlis 69422ba96a Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-18 23:10:34 +08:00
karlis 3d8420f617 优化图层列表显示效果 | #7 2023-03-18 23:10:16 +08:00
yang.yongquan e48954175d Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-18 20:30:31 +08:00
yang.yongquan 3c2eada43f 添加了获得线宽的函数 2023-03-18 20:26:07 +08:00
karlis 6494c2b9af Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-18 20:20:25 +08:00
wuyize fd1baf42f6 Renderer图元变换改用矩阵 2023-03-18 20:17:12 +08:00
karlis aeead9d22e 添加创建时递归约束 2023-03-18 20:12:43 +08:00
ArgonarioD f42868cf3f merge 2023-03-18 18:19:27 +08:00
ArgonarioD d40796abb0 为LayerStyleContainer添加了文档注释 2023-03-18 18:16:11 +08:00
karlis 84bddf4447 Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-18 16:26:51 +08:00
wuyize 31f2c1be8f 打开模型时卸载现有模型 2023-03-18 12:18:38 +08:00
ArgonarioD c15e8c3a5b [style] 重新设计了LayerStyle在Layer中的存储形式
新增了LayerStyleContainer类,修改了相关代码
修改了部分bad smells
2023-03-18 03:51:47 +08:00
karlis 24f8daf1fd 菜单优化 2023-03-17 17:14:09 +08:00
34 changed files with 620 additions and 357 deletions

View File

@ -104,6 +104,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Editor\EditorWidgetComponent\FillStyleWidget.cpp" />
<ClCompile Include="src\Editor\RightBar\EditorSettingWidget.cpp" /> <ClCompile Include="src\Editor\RightBar\EditorSettingWidget.cpp" />
<ClCompile Include="src\Editor\EditorWidgetComponent\ColorPicker.cpp" /> <ClCompile Include="src\Editor\EditorWidgetComponent\ColorPicker.cpp" />
<ClCompile Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.cpp" /> <ClCompile Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.cpp" />
@ -200,6 +201,7 @@
<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" />
<QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h" /> <QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h" />
<QtMoc Include="src\Editor\EditorWidgetComponent\FillStyleWidget.h" />
<ClInclude Include="src\Editor\util\EncodeUtil.hpp" /> <ClInclude Include="src\Editor\util\EncodeUtil.hpp" />
<ClInclude Include="src\Editor\util\JsonUtil.hpp" /> <ClInclude Include="src\Editor\util\JsonUtil.hpp" />
<ClInclude Include="src\Editor\ElementManager.h" /> <ClInclude Include="src\Editor\ElementManager.h" />

View File

@ -240,6 +240,9 @@
<ClCompile Include="src\Editor\RightBar\EditorSettingWidget.cpp"> <ClCompile Include="src\Editor\RightBar\EditorSettingWidget.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Editor\EditorWidgetComponent\FillStyleWidget.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="src\Renderer\RendererGLWidget.h"> <QtMoc Include="src\Renderer\RendererGLWidget.h">
@ -290,6 +293,9 @@
<QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h"> <QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="src\Editor\EditorWidgetComponent\FillStyleWidget.h">
<Filter>Header Files</Filter>
</QtMoc>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\data.json" /> <None Include="..\data.json" />

View File

@ -182,7 +182,12 @@
</property> </property>
<column> <column>
<property name="text"> <property name="text">
<string>图层树</string> <string>图层名</string>
</property>
</column>
<column>
<property name="text">
<string>关联图元</string>
</property> </property>
</column> </column>
</widget> </widget>

View File

@ -84,10 +84,26 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0">
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum> <enum>QLayout::SetDefaultConstraint</enum>
</property> </property>
<item>
<widget class="QListWidget" name="textureListWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>0</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item> <item>
<widget class="Renderer::RendererGLWidget" name="openGLWidget"> <widget class="Renderer::RendererGLWidget" name="openGLWidget">
<property name="sizePolicy"> <property name="sizePolicy">

View File

@ -20,22 +20,25 @@ layout(std430, binding = 1) buffer bvhBoundBuffer
{ {
vec4 bvhBound[]; vec4 bvhBound[];
}; };
layout(std430, binding = 2) buffer elementOffsetBuffer layout(std430, binding = 2) buffer elementTranformBuffer
{
mat3x2 elementTranform[];
};
layout(std430, binding = 3) buffer elementOffsetBuffer
{ {
/** /**
* @[0] elementBvhRoot * @[0] elementBvhRoot
* @[1] styleOffset * @[1] styleOffset
* @[2] pointsOffset * @[2] pointsOffset
* @[3] linesOffset * @[3] linesOffset
*/ */
uint elementOffset[][5]; uint elementOffset[][4];
}; };
layout(std430, binding = 3) buffer elementIndexBuffer layout(std430, binding = 4) buffer elementIndexBuffer
{ {
uint elementIndexs[]; // ÏߺÍÃæ uint elementIndexs[]; // ÏߺÍÃæ
}; };
layout(std430, binding = 4) buffer elementDataBuffer layout(std430, binding = 5) buffer elementDataBuffer
{ {
float elementData[]; // µãºÍStyle 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, 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; bool hitElement = false;
float strokeWidth = elementData[styleIndex]; 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; float minDistance = 1e38;
uint lineCount = elementIndexs[contourIndex]; uint lineCount = elementIndexs[contourIndex];
vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])); vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1]));
@ -1149,10 +1148,6 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
mat4x2 p = mat4x2 p =
mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]], 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]]); 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); vec2 tangentBeginNext = vec2(0);
if (contourIterator + 1 < contourIndex + 1 + lineCount) if (contourIterator + 1 < contourIndex + 1 + lineCount)
@ -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]], mat4x2 pNext = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]],
elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]],
elementData[pxIndex[3]], elementData[pyIndex[3]]); 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]) if (pNext[0] == pNext[1] && pNext[2] == pNext[3])
{ {
@ -1221,11 +1212,11 @@ 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, contourIterator == contourIndex + 1, endType, p[0],
hit && shouldFillBeginCap(localUV, contourIterator == contourIndex + 1, endType, p[0], tangentBegin, p3Last - p2Last); tangentBegin, p3Last - p2Last);
if (onEnd) if (onEnd)
hit = hit && hit = hit && shouldFillEndCap(localUV, tangentBeginNext == vec2(0), endType, p[3], tangentEnd,
shouldFillEndCap(localUV, tangentBeginNext==vec2(0), endType, p[3], tangentEnd, tangentBeginNext); tangentBeginNext);
if (hit) if (hit)
{ {
@ -1272,7 +1263,7 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
return hitElement; 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)) inout vec3 debugBVH = vec3(0))
{ {
bool hitElement = false; bool hitElement = false;
@ -1284,7 +1275,7 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
uint styleIndex = currentOffset[1]; uint styleIndex = currentOffset[1];
uint pointsOffset = currentOffset[2]; uint pointsOffset = currentOffset[2];
uint linesOffset = currentOffset[3]; uint linesOffset = currentOffset[3];
float widthHeightRatio = uintBitsToFloat(currentOffset[4]); // float widthHeightRatio = uintBitsToFloat(currentOffset[4]);
elementStack.top = 0; elementStack.top = 0;
uint elementBvhIndex = 0; uint elementBvhIndex = 0;
@ -1317,7 +1308,7 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
else // Ïß else // Ïß
{ {
hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex, hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex,
widthHeightRatio, elementColor, metallicRoughness); elementColor, metallicRoughness);
} }
elementBvhIndex = elementBvhLength; elementBvhIndex = elementBvhLength;
@ -1371,50 +1362,40 @@ void main()
visitTime++; visitTime++;
vec4 bound = bvhBound[index]; vec4 bound = bvhBound[index];
uint leftChild = bvhChildren[index].x; uint leftChild = bvhChildren[index].x;
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) if (leftChild >= bvhLength)
{ {
uint transformIndex = leftChild - 0x80000000;
uint zIndex = bvhChildren[index].y >> 18; uint zIndex = bvhChildren[index].y >> 18;
bvec2 flip = bvec2(bvhChildren[index].y & (1 << 16), bvhChildren[index].y & (1 << 17)); uint elementIndex = bvhChildren[index].y - zIndex;
float angle = (float(bvhChildren[index].y & ((1 << 16) - 1)) / 65535.0) * 2 * PI; mat3x2 transform = elementTranform[transformIndex];
mat2 rotation = {{cos(angle), -sin(angle)}, {sin(angle), cos(angle)}}; vec2 localUV =
vec2 localUV = uv - (bound.xy + bound.zw) / 2; (mat3(vec3(transform[0], 0), vec3(transform[1], 0), vec3(transform[2], 1)) * vec3(uv, 1)).xy;
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; vec3 elementColor;
vec2 elementMetallicRoughness; vec2 elementMetallicRoughness;
if (drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness, if (drawElement(elementIndex, localUV, elementColor, elementMetallicRoughness,
debugBVH)) debugBVH))
{ {
color = vec4(elementColor, zIndex); color = vec4(elementColor, zIndex);
metallicRoughness = elementMetallicRoughness; metallicRoughness = elementMetallicRoughness;
} }
} //if(elementIndex == 1 && transformIndex==1)
// color = vec4(1,1,0,1);
index = bvhLength; index = bvhLength;
} }
else if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw))) else
{ {
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); stack.push(index);
index = leftChild; index = leftChild;
} }
}
else else
index = bvhLength; index = bvhLength;
} }
@ -1428,7 +1409,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

@ -6,7 +6,7 @@ class ColorPicker : public QPushButton
private: private:
QColor color; QColor color;
public: public:
ColorPicker(const QColor& color, QWidget* parent = nullptr); ColorPicker(const QColor& color = QColor::fromRgb(0, 0, 0), QWidget* parent = nullptr);
QColor getColor() const; QColor getColor() const;
public slots: public slots:
void onClicked(); void onClicked();

View File

@ -0,0 +1,48 @@
#include "FillStyleWidget.h"
#include "ColorPicker.h"
#include <QGridLayout>
#include <QLabel>
#include <qtmaterialtextfield.h>
FillStyleWidget::FillStyleWidget(std::shared_ptr<Renderer::MaterialStyleFill> 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);
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "../Renderer/Painting/MaterialStyleFill.h"
#include "LayerStyle.h"
#include <QWidget>
class FillStyleWidget : public QWidget
{
Q_OBJECT
public:
FillStyleWidget(std::shared_ptr<Renderer::MaterialStyleFill> fill, QWidget* parent = nullptr);
std::shared_ptr<Renderer::MaterialStyleFill> fill;
};

View File

@ -1,15 +1,46 @@
#include "LayerCreateWidget.h" #include "LayerCreateWidget.h"
#include <QComboBox> #include <QComboBox>
LayerCreateWidget::LayerCreateWidget(ElementManager* elementManager, QWidget* parent) : LayerCreateWidget::LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent) :
QDialog(parent) QDialog(parent)
{ {
this->elementManager = elementManager;
ui.setupUi(this); ui.setupUi(this);
connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
elementPool = new ElementPoolWidget(ui.elementPool); elementPool = new ElementPoolWidget(ui.elementPool);
elementPool->setElementList(elementManager->elements); elements = elementManager->elements;
elementsCheck(folderLayer);
elementPool->setElementList(elements);
}
void LayerCreateWidget::elementsCheck(FolderLayerWrapper* parent)
{
std::set<LayerWrapper*> upSet, downSet;
parent->collectUpReachable(upSet);
for (auto it = elements.begin(); it != elements.end();)
{
bool valid = true;
auto ele = dynamic_cast<GroupElement*>(*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() LayerCreateWidget::~LayerCreateWidget()
@ -21,8 +52,20 @@ void LayerCreateWidget::accept()
QJsonObject jsonObj; QJsonObject jsonObj;
jsonObj.insert("name", ui.name->text()); jsonObj.insert("name", ui.name->text());
if (ui.comboBox->currentIndex() == 0) { 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("is-folder", false);
jsonObj.insert("element", elementPool->currentIndex); jsonObj.insert("element", index);
} }
else { else {
jsonObj.insert("is-folder", true); jsonObj.insert("is-folder", true);

View File

@ -11,12 +11,15 @@ class LayerCreateWidget :
Q_OBJECT Q_OBJECT
private: private:
ElementManager* elementManager;
std::vector<GraphicElement*> elements;
Ui::LayerCreateWidget ui; Ui::LayerCreateWidget ui;
ElementPoolWidget* elementPool; ElementPoolWidget* elementPool;
void elementsCheck(FolderLayerWrapper*);
public: public:
LayerCreateWidget(ElementManager* elementManager,QWidget* parent = nullptr); LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent = nullptr);
~LayerCreateWidget(); ~LayerCreateWidget();
void accept() override; void accept() override;

View File

@ -11,7 +11,7 @@ constexpr int COLUMN_ROUGHNESS = 3;
constexpr int COLUMN_OPERATIONS = 4; constexpr int COLUMN_OPERATIONS = 4;
StrokeStyleWidget::StrokeStyleWidget( StrokeStyleWidget::StrokeStyleWidget(
std::shared_ptr<Renderer::MaterialStyleStroke> stroke, std::shared_ptr<MaterialStyleStroke> stroke,
QWidget* parent QWidget* parent
) : QWidget(parent), stroke(stroke) ) : QWidget(parent), stroke(stroke)
{ {

View File

@ -32,6 +32,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this, connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this,
&EditorWidgetItem::triggerRefreshPreview); &EditorWidgetItem::triggerRefreshPreview);
connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh);
// &EditorWidget::triggerRefreshPreview); // &EditorWidget::triggerRefreshPreview);
// test // test
QFile settingFile; QFile settingFile;

View File

@ -67,6 +67,7 @@ void ElementPoolWidget::setElementManager(ElementManager* element)
void ElementPoolWidget::refresh() { void ElementPoolWidget::refresh() {
this->setElementList(this->elementManager->elements); this->setElementList(this->elementManager->elements);
emit refreshLayerTree();
// update(); // update();
} }

View File

@ -25,6 +25,7 @@ public:
signals: signals:
void elementSelected(GraphicElement* element); void elementSelected(GraphicElement* element);
void refreshLayerTree();
public slots: public slots:
int pictureItemClicked(QListWidgetItem* item); int pictureItemClicked(QListWidgetItem* item);

View File

@ -149,3 +149,11 @@ QPixmap GroupElement::getPreview(QSize size)
result = result.copy(rect); result = result.copy(rect);
return result.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); return result.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
} }
void GroupElement::collectReachable(std::set<LayerWrapper*>& set) const
{
if (sourceLayer != nullptr)
{
sourceLayer->collectDownReachable(set);
}
}

View File

@ -66,6 +66,7 @@ public:
void setSourceLayer(FolderLayerWrapper* sourceLayer); void setSourceLayer(FolderLayerWrapper* sourceLayer);
void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override;
QPixmap getPreview(QSize size) override; QPixmap getPreview(QSize size) override;
void collectReachable(std::set<LayerWrapper*>& set) const;
}; };
//******************************** BitmapPath ********************************// //******************************** BitmapPath ********************************//

View File

@ -1,12 +1,11 @@
#include "LayerStyle.h" #include "LayerStyle.h"
#include "./EditorWidgetComponent/StrokeStyleWidget.h" #include "./EditorWidgetComponent/StrokeStyleWidget.h"
#include "./EditorWidgetComponent/FillStyleWidget.h"
#include "./util/EncodeUtil.hpp" #include "./util/EncodeUtil.hpp"
#include <qtmaterialcheckbox.h> #include <qtmaterialcheckbox.h>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QDialogButtonBox>
#include <QPushButton> #include <QPushButton>
#include <QLabel> #include <QLabel>
#include <QLineEdit>
#include <QObject> #include <QObject>
#include <QDebug> #include <QDebug>
#define _USE_JOIN_VIEW_INPUT_RANGE #define _USE_JOIN_VIEW_INPUT_RANGE
@ -20,21 +19,19 @@ std::vector<Renderer::BaseStyle> StrokeElementLayerStyle::toBaseStyles() const
{ {
if (!radialStroke(strokePair.first)->materialMap.empty()) if (!radialStroke(strokePair.first)->materialMap.empty())
{ {
baseStyles.push_back(Renderer::BaseStyle(std::make_shared<Renderer::TransformStyle>(), baseStyles.push_back({ std::make_shared<Renderer::TransformStyle>(), strokePair.first });
strokePair.first));
} }
if (!radialStroke(strokePair.second)->materialMap.empty()) if (!radialStroke(strokePair.second)->materialMap.empty())
{ {
baseStyles.push_back(Renderer::BaseStyle(std::make_shared<Renderer::TransformStyle>(), baseStyles.push_back({ std::make_shared<Renderer::TransformStyle>(), strokePair.second });
strokePair.second));
} }
} }
else if (!radialStroke(strokePair.first)->materialMap.empty()) else if (!radialStroke(strokePair.first)->materialMap.empty())
{ {
const 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<MaterialStyleStroke>(material)->strokeType = Renderer::StrokeType::kBothSides; std::static_pointer_cast<MaterialStyleStroke>(material)->strokeType = Renderer::StrokeType::kBothSides;
baseStyles.push_back(Renderer::BaseStyle(std::make_shared<Renderer::TransformStyle>(), material)); baseStyles.push_back({ std::make_shared<Renderer::TransformStyle>(), material });
} }
return baseStyles; return baseStyles;
} }
@ -197,11 +194,49 @@ bool LayerStyleContainer::dropStyle(const QString& styleName)
return true; return true;
} }
inline size_t LayerStyleContainer::getHash() const float LayerStyleContainer::boundingBoxAffectValue() const {
float maxLineWidth = 0;
const auto strokeStyle = styles.at(StrokeElementLayerStyle::displayName());
if (strokeStyle != nullptr)
{
if (const auto strokeElementLayerStyle =
std::dynamic_pointer_cast<StrokeElementLayerStyle>(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)
{
maxLineWidth = std::max(maxLineWidth, rightStyleStroke->halfWidth);
}
}
}
return maxLineWidth;
}
size_t LayerStyleContainer::getHash() const
{ {
return hash; return hash;
} }
std::unique_ptr<StrokeElementLayerStyle> StrokeElementLayerStyle::fromJson(const QJsonObject& json)
{
auto ptr = std::make_unique<StrokeElementLayerStyle>(
std::static_pointer_cast<MaterialStyleStroke>(
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["left"].toString()))))
),
std::static_pointer_cast<MaterialStyleStroke>(
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["right"].toString()))))
)
);
ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool();
return ptr;
}
StrokeElementLayerStyle::StrokeElementLayerStyle() StrokeElementLayerStyle::StrokeElementLayerStyle()
{ {
const auto materialMap = std::map<float, Renderer::Material>(); const auto materialMap = std::map<float, Renderer::Material>();
@ -219,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.first = left;
this->strokePair.second = right ? right : std::static_pointer_cast<MaterialStyleStroke>( this->strokePair.second = right ? right : std::static_pointer_cast<MaterialStyleStroke>(
@ -240,8 +275,7 @@ StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle&
QJsonObject StrokeElementLayerStyle::toJson() const QJsonObject StrokeElementLayerStyle::toJson() const
{ {
QJsonObject json; auto json = LayerStyle::toJson();
json["type"] = typeName();
json["enableEachSideIndependent"] = enableEachSideIndependent; json["enableEachSideIndependent"] = enableEachSideIndependent;
json["left"] = EncodeUtil::toBase64<GLfloat>(strokePair.first->encoded()); json["left"] = EncodeUtil::toBase64<GLfloat>(strokePair.first->encoded());
json["right"] = EncodeUtil::toBase64<GLfloat>(strokePair.second->encoded()); json["right"] = EncodeUtil::toBase64<GLfloat>(strokePair.second->encoded());
@ -253,18 +287,24 @@ std::unique_ptr<LayerStyle> StrokeElementLayerStyle::clone() const
return std::make_unique<StrokeElementLayerStyle>(StrokeElementLayerStyle(*this)); return std::make_unique<StrokeElementLayerStyle>(StrokeElementLayerStyle(*this));
} }
std::unique_ptr<FillElementLayerStyle> FillElementLayerStyle::fromJson(const QJsonObject& json)
{
auto ptr = std::make_unique<FillElementLayerStyle>(
std::static_pointer_cast<MaterialStyleFill>(
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["material"].toString()))))
)
);
return ptr;
}
std::vector<Renderer::BaseStyle> FillElementLayerStyle::toBaseStyles() const std::vector<Renderer::BaseStyle> FillElementLayerStyle::toBaseStyles() const
{ {
// TODO: implement return { {std::make_shared<Renderer::TransformStyle>(), fillMaterialStyle} };
return std::vector<Renderer::BaseStyle>();
} }
QWidget* FillElementLayerStyle::getInputWidget() QWidget* FillElementLayerStyle::getInputWidget()
{ {
// TODO return new FillStyleWidget(fillMaterialStyle);
auto* name = new QLineEdit;
name->setText(QStringLiteral("Ìî³ä"));
return name;
} }
QWidget* FillElementLayerStyle::getListDisplayWidget() const QWidget* FillElementLayerStyle::getListDisplayWidget() const
@ -278,18 +318,29 @@ QWidget* FillElementLayerStyle::getListDisplayWidget() const
return w; return w;
} }
FillElementLayerStyle::FillElementLayerStyle(const PMaterialStyleFill& fillMaterialStyle)
: fillMaterialStyle(fillMaterialStyle)
{
if (!fillMaterialStyle)
{
this->fillMaterialStyle = std::make_shared<MaterialStyleFill>(
std::make_shared<Renderer::FillPlain>(Renderer::Material(QColor::fromRgb(0, 0, 0)))
);
}
}
FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other) FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other)
{ {
materialStyles = std::vector<std::shared_ptr<Renderer::MaterialStyleFill>>(other.materialStyles.size()); this->fillMaterialStyle = std::static_pointer_cast<MaterialStyleFill>(
for (size_t i = 0; i < other.materialStyles.size(); i++) std::shared_ptr(std::move(other.fillMaterialStyle->clone()))
{ );
materialStyles[i] = std::make_shared<Renderer::MaterialStyleFill>(*other.materialStyles[i]);
}
} }
QJsonObject FillElementLayerStyle::toJson() const QJsonObject FillElementLayerStyle::toJson() const
{ {
return QJsonObject(); auto json = LayerStyle::toJson();
json["material"] = EncodeUtil::toBase64<GLfloat>(fillMaterialStyle->encoded());
return json;
} }
std::unique_ptr<LayerStyle> FillElementLayerStyle::clone() const std::unique_ptr<LayerStyle> FillElementLayerStyle::clone() const
@ -302,23 +353,18 @@ std::unique_ptr<LayerStyle> LayerStyle::fromJson(const QJsonObject& json)
QString type = json["type"].toString(); QString type = json["type"].toString();
if (type == StrokeElementLayerStyle::typeName()) if (type == StrokeElementLayerStyle::typeName())
{ {
auto ptr = std::make_unique<StrokeElementLayerStyle>( return StrokeElementLayerStyle::fromJson(json);
std::static_pointer_cast<MaterialStyleStroke>(
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["left"].toString()))))
),
std::static_pointer_cast<MaterialStyleStroke>(
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["right"].toString()))))
)
);
ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool();
return ptr;
} }
else if (type == FillElementLayerStyle::typeName()) if (type == FillElementLayerStyle::typeName())
{ {
return std::make_unique<FillElementLayerStyle>(); return FillElementLayerStyle::fromJson(json);
} }
else
{
return nullptr; return nullptr;
} }
QJsonObject LayerStyle::toJson() const
{
QJsonObject json;
json["type"] = this->getTypeName();
return json;
} }

View File

@ -12,26 +12,35 @@
using Renderer::MaterialStyle; using Renderer::MaterialStyle;
using Renderer::MaterialStyleStroke; using Renderer::MaterialStyleStroke;
using Renderer::MaterialStyleFill;
#define STYLE_NAME(display_name, type_name) \ #define STYLE_NAME(display_name, type_name) \
static QString displayName() { return QStringLiteral(display_name); } \ static QString displayName() { return QStringLiteral(display_name); } \
QString getDisplayName() const override { 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<Renderer::StrokeRadialGradient>(stroke->materialStroke) #define radialStroke(stroke) std::static_pointer_cast<Renderer::StrokeRadialGradient>(stroke->materialStroke)
#define plainFill(fill) std::static_pointer_cast<Renderer::FillPlain>(fill->materialFill)
class LayerStyle : public Renderer::ElementStyle class LayerStyle : public Renderer::ElementStyle
{ {
public: public:
static std::unique_ptr<LayerStyle> fromJson(const QJsonObject& json); static std::unique_ptr<LayerStyle> fromJson(const QJsonObject& json);
virtual ~LayerStyle() = default;
virtual QString getDisplayName() const = 0; virtual QString getDisplayName() const = 0;
virtual QString getTypeName() const = 0;
virtual QWidget* getInputWidget() = 0; virtual QWidget* getInputWidget() = 0;
virtual QWidget* getListDisplayWidget() const = 0; virtual QWidget* getListDisplayWidget() const = 0;
virtual ~LayerStyle() = default;
virtual QJsonObject toJson() const = 0; virtual QJsonObject toJson() const;
virtual std::unique_ptr<LayerStyle> clone() const = 0; virtual std::unique_ptr<LayerStyle> clone() const = 0;
}; };
/**
* LayerStylecomputeNewHash()
*/
class LayerStyleContainer : public Renderer::ElementStyle class LayerStyleContainer : public Renderer::ElementStyle
{ {
using DisplayNameWithSupplier = std::map<QString, std::function<std::unique_ptr<LayerStyle>()>>; using DisplayNameWithSupplier = std::map<QString, std::function<std::unique_ptr<LayerStyle>()>>;
@ -56,6 +65,7 @@ public:
std::unique_ptr<LayerStyle> makeUnusedStyle(const QString& styleName) const; std::unique_ptr<LayerStyle> makeUnusedStyle(const QString& styleName) const;
bool useStyle(const std::shared_ptr<LayerStyle>& style); bool useStyle(const std::shared_ptr<LayerStyle>& style);
bool dropStyle(const QString& styleName); bool dropStyle(const QString& styleName);
float boundingBoxAffectValue() const;
size_t getHash() const; size_t getHash() const;
/** /**
@ -70,9 +80,10 @@ class StrokeElementLayerStyle : public LayerStyle
public: public:
STYLE_NAME("Ãè±ß", "stroke") STYLE_NAME("Ãè±ß", "stroke")
static std::unique_ptr<StrokeElementLayerStyle> fromJson(const QJsonObject& json);
StrokeElementLayerStyle(); StrokeElementLayerStyle();
StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right = nullptr); StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right = nullptr);
StrokeElementLayerStyle(const StrokeElementLayerStyle& other); StrokeElementLayerStyle(const StrokeElementLayerStyle& other);
~StrokeElementLayerStyle() override = default; ~StrokeElementLayerStyle() override = default;
@ -88,16 +99,21 @@ public:
class FillElementLayerStyle : public LayerStyle class FillElementLayerStyle : public LayerStyle
{ {
using PMaterialStyleFill = std::shared_ptr<MaterialStyleFill>;
public: public:
STYLE_NAME("Ìî³ä", "fill") STYLE_NAME("Ìî³ä", "fill")
static std::unique_ptr<FillElementLayerStyle> fromJson(const QJsonObject& json);
FillElementLayerStyle(const PMaterialStyleFill& fillMaterialStyle = nullptr);
FillElementLayerStyle(const FillElementLayerStyle& other);
~FillElementLayerStyle() override = default;
std::vector<Renderer::BaseStyle> toBaseStyles() const override; std::vector<Renderer::BaseStyle> toBaseStyles() const override;
QWidget* getInputWidget() override; QWidget* getInputWidget() override;
QWidget* getListDisplayWidget() const override; QWidget* getListDisplayWidget() const override;
FillElementLayerStyle() = default;
FillElementLayerStyle(const FillElementLayerStyle& other);
~FillElementLayerStyle() override = default;
std::vector<std::shared_ptr<Renderer::MaterialStyleFill>> materialStyles;
QJsonObject toJson() const override; QJsonObject toJson() const override;
std::unique_ptr<LayerStyle> clone() const override; std::unique_ptr<LayerStyle> clone() const override;
PMaterialStyleFill fillMaterialStyle;
}; };

View File

@ -192,19 +192,39 @@ void FolderLayerWrapper::delSelf() {
QTreeWidgetItem* LayerWrapper::getQTreeItem() QTreeWidgetItem* LayerWrapper::getQTreeItem()
{ {
this->qTreeWidgetItem->setText(0, this->property.name);
this->qTreeWidgetItem->setData(0, Qt::UserRole, QVariant::fromValue(this)); this->qTreeWidgetItem->setData(0, Qt::UserRole, QVariant::fromValue(this));
return this->qTreeWidgetItem; 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() 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->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(); return LayerWrapper::getQTreeItem();
} }
@ -286,3 +306,68 @@ void LeafLayerWrapper::paint(QPainter* painter, QTransform transform, bool ignor
wrappedElement->paint(painter, transform, styles); wrappedElement->paint(painter, transform, styles);
} }
} }
void LayerWrapper::collectUpReachable(std::set<LayerWrapper*>& reachable)
{
auto cPos = this;
while (cPos != nullptr)
{
reachable.insert(cPos);
cPos = cPos->parent;
}
}
void LayerWrapper::collectDownReachable(std::set<LayerWrapper*>& reachable)
{
reachable.insert(this);
}
void LeafLayerWrapper::collectDownReachable(std::set<LayerWrapper*>& reachable)
{
LayerWrapper::collectDownReachable(reachable);
auto ele = dynamic_cast<GroupElement*>(wrappedElement);
if (ele != nullptr)
{
ele->collectReachable(reachable);
}
}
void FolderLayerWrapper::collectDownReachable(std::set<LayerWrapper*>& reachable)
{
LayerWrapper::collectDownReachable(reachable);
for (auto& child : children)
child->collectDownReachable(reachable);
}
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);
}
}

View File

@ -68,7 +68,9 @@ class LayerWrapper
virtual void delSelf(); virtual void delSelf();
virtual QJsonObject toJson() const; virtual QJsonObject toJson() const;
~LayerWrapper() = default; ~LayerWrapper() = default;
virtual void collectUpReachable(std::set<LayerWrapper*>& reachable);
virtual void collectDownReachable(std::set<LayerWrapper*>& reachable);
virtual void refreshTreeItem();
}; };
class FolderLayerWrapper : public LayerWrapper class FolderLayerWrapper : public LayerWrapper
@ -92,6 +94,8 @@ class FolderLayerWrapper : public LayerWrapper
QJsonObject toJson() const override; QJsonObject toJson() const override;
int getReferencedBy()const; int getReferencedBy()const;
void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override;
void collectDownReachable(std::set<LayerWrapper*>& reachable) override;
void refreshTreeItem() override;
}; };
class LeafLayerWrapper : public LayerWrapper class LeafLayerWrapper : public LayerWrapper
@ -107,6 +111,9 @@ class LeafLayerWrapper : public LayerWrapper
LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent);
QJsonObject toJson() const override; QJsonObject toJson() const override;
void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override;
void collectDownReachable(std::set<LayerWrapper*>& reachable) override;
QTreeWidgetItem* getQTreeItem() override;
void refreshTreeItem() override;
}; };
Q_DECLARE_METATYPE(LayerWrapper *) Q_DECLARE_METATYPE(LayerWrapper *)

View File

@ -60,13 +60,13 @@ void InfoDisplayWidget::generateLayerForm()
emit requireRefreshElementWidget(); emit requireRefreshElementWidget();
emit requireRefreshPreview(); 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) { connect(scaleX, &QLineEdit::textChanged, [=](QString content) {
this->displayLayer->property.scale = {content.toDouble(), this->displayLayer->property.scale.y()}; this->displayLayer->property.scale = {content.toDouble(), this->displayLayer->property.scale.y()};
emit requireRefreshElementWidget(); emit requireRefreshElementWidget();
emit requireRefreshPreview(); 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) { connect(scaleY, &QLineEdit::textChanged, [=](QString content) {
this->displayLayer->property.scale = {this->displayLayer->property.scale.x(), content.toDouble()}; this->displayLayer->property.scale = {this->displayLayer->property.scale.x(), content.toDouble()};
emit requireRefreshElementWidget(); emit requireRefreshElementWidget();
@ -102,7 +102,7 @@ void InfoDisplayWidget::generateLayerForm()
else else
{ {
connect(addStyleButton, &QPushButton::clicked, [&, leafP] { connect(addStyleButton, &QPushButton::clicked, [&, leafP] {
auto* dialog = new LayerStyleDialog(leafP->styles); auto* dialog = new LayerStyleDialog(leafP->styles, nullptr, this);
dialog->exec(); dialog->exec();
if (dialog->layerStyle) if (dialog->layerStyle)
{ {
@ -113,7 +113,6 @@ void InfoDisplayWidget::generateLayerForm()
emit requireSelfRefresh(); emit requireSelfRefresh();
emit requireRefreshElementWidget(); emit requireRefreshElementWidget();
} }
dialog->deleteLater();
}); });
} }
@ -125,60 +124,7 @@ void InfoDisplayWidget::generateLayerForm()
header->setFlags(Qt::NoItemFlags); header->setFlags(Qt::NoItemFlags);
styleList->addItem(header); styleList->addItem(header);
styleList->setItemWidget(header, headerWidget); styleList->setItemWidget(header, headerWidget);
//static vector<QString> 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<LayerStyle>(new StrokeElementLayerStyle()));
}*/
auto* styles = &leafP->styles; auto* styles = &leafP->styles;
for (auto styleIterator = styles->begin(); styleIterator != styles->end(); ++styleIterator) for (auto styleIterator = styles->begin(); styleIterator != styles->end(); ++styleIterator)
{ {
@ -200,7 +146,7 @@ void InfoDisplayWidget::generateLayerForm()
[this, styles, styleIterator] [this, styles, styleIterator]
{ {
auto* dialog = auto* dialog =
new LayerStyleDialog(*styles, styleIterator->second); new LayerStyleDialog(*styles, styleIterator->second, this);
dialog->exec(); dialog->exec();
if (dialog->layerStyle) if (dialog->layerStyle)
@ -212,7 +158,6 @@ void InfoDisplayWidget::generateLayerForm()
emit requireSelfRefresh(); emit requireSelfRefresh();
emit requireRefreshElementWidget(); emit requireRefreshElementWidget();
} }
dialog->deleteLater();
}); });
connect(removeButton, &QPushButton::clicked, this, connect(removeButton, &QPushButton::clicked, this,

View File

@ -9,7 +9,7 @@ LayerTreeWidget::LayerTreeWidget(QWidget *parent)
this->selectedItem = nullptr; this->selectedItem = nullptr;
this->copiedItem = nullptr; this->copiedItem = nullptr;
this->setContextMenuPolicy(Qt::CustomContextMenu); this->setContextMenuPolicy(Qt::CustomContextMenu);
this->setHeaderLabel("Layer Content"); this->setColumnWidth(0, 240);
connect(this, &QTreeWidget::customContextMenuRequested, this, &LayerTreeWidget::popMenu); connect(this, &QTreeWidget::customContextMenuRequested, this, &LayerTreeWidget::popMenu);
connect(this, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *currentItem) { connect(this, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *currentItem) {
if (this->selectedItem != nullptr) { if (this->selectedItem != nullptr) {
@ -50,7 +50,7 @@ void LayerTreeWidget::popMenu(const QPoint &pos)
if (layer != nullptr) { if (layer != nullptr) {
if (typeid(*layer) == typeid(FolderLayerWrapper)) { if (typeid(*layer) == typeid(FolderLayerWrapper)) {
menu.addAction(QString::fromLocal8Bit("创建子节点"), this, [this, layer]() { menu.addAction(QString::fromLocal8Bit("创建子节点"), this, [this, layer]() {
auto dialog = new LayerCreateWidget(elementManager, this); auto dialog = new LayerCreateWidget(elementManager, dynamic_cast<FolderLayerWrapper*>(layer), this);
connect(dialog, &LayerCreateWidget::LayerInfoReturned, this, [this, layer](QJsonObject jsonObj) { connect(dialog, &LayerCreateWidget::LayerInfoReturned, this, [this, layer](QJsonObject jsonObj) {
auto folderLayer = dynamic_cast<FolderLayerWrapper*>(layer); auto folderLayer = dynamic_cast<FolderLayerWrapper*>(layer);
LayerWrapper* newLayer; LayerWrapper* newLayer;
@ -76,14 +76,17 @@ void LayerTreeWidget::popMenu(const QPoint &pos)
layer->getParent()->removeChild(layer); layer->getParent()->removeChild(layer);
this->refresh(); this->refresh();
emit requireRefreshPreview(); emit requireRefreshPreview();
emit requireRefreshElementWidget();
}); });
menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent); menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent);
if(typeid(*layer) == typeid(FolderLayerWrapper))
menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() { menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() {
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>(); auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
layer->delSelf(); layer->delSelf();
layer->getParent()->removeChild(layer); layer->getParent()->removeChild(layer);
this->refresh(); this->refresh();
emit requireRefreshPreview(); emit requireRefreshPreview();
emit requireRefreshElementWidget();
}); });
} }
if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) { if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) {
@ -123,9 +126,5 @@ void LayerTreeWidget::onRenameEvent()
} }
void LayerTreeWidget::refresh() { void LayerTreeWidget::refresh() {
// if(this->root!=nullptr) this->root->refreshTreeItem();
//{
// this->clear();
// this->addTopLevelItem(this->root->getQTreeItem());
//}
} }

View File

@ -99,7 +99,10 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr
qDebug() << painterPath; qDebug() << painterPath;
bound = painterPath.boundingRect(); bound = painterPath.boundingRect();
qDebug() << bound; qDebug() << bound;
elementTrans.center = glm::vec2(
// TODO 改用矩阵
/* elementTrans.center = glm::vec2(
(2 * bound.center().x() - screenSize.width()) / screenSize.width(), (2 * bound.center().x() - screenSize.width()) / screenSize.width(),
(2 * bound.center().y() - screenSize.height()) / screenSize.height() (2 * bound.center().y() - screenSize.height()) / screenSize.height()
); );
@ -114,7 +117,7 @@ FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTr
nowLayer->property.flipVertically nowLayer->property.flipVertically
); );
qDebug() << elementTrans.scale.x << elementTrans.scale.y; qDebug() << elementTrans.scale.x << elementTrans.scale.y;
painting.addElement(element, elementTrans); painting.addElement(element, elementTrans);*/
return nullptr; return nullptr;
} }

View File

@ -18,7 +18,7 @@ namespace Renderer
glm::vec3 Position; glm::vec3 Position;
glm::vec3 Normal; glm::vec3 Normal;
glm::vec2 TexCoords; 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 struct Texture

View File

@ -16,6 +16,7 @@
#include <ThirdPartyLib/qquick/qquicksvgparser_p.h> #include <ThirdPartyLib/qquick/qquicksvgparser_p.h>
#include <util/PaintingUtil.h> #include <util/PaintingUtil.h>
#include "Painting/MaterialStyleStroke.h" #include "Painting/MaterialStyleStroke.h"
#include <glm/gtc/matrix_transform.hpp>
using namespace Renderer; using namespace Renderer;
using std::vector; using std::vector;
@ -32,14 +33,12 @@ Model::Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram,
} }
void Model::draw() { void Model::draw() {
//shaderProgram->bind();
for (auto& mesh : meshes) { for (auto& mesh : meshes) {
mesh->draw(); mesh->draw();
} }
} }
void Model::drawShadow() { void Model::drawShadow() {
//shaderProgram->bind();
for (auto& mesh : meshes) { for (auto& mesh : meshes) {
mesh->drawShadow(); mesh->drawShadow();
} }
@ -55,7 +54,7 @@ void Renderer::Model::loadModel(QString path)
const aiScene* scene = importer.ReadFile(modelFile.absoluteFilePath().toUtf8(), aiProcess_Triangulate); 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();
return; return;
} }
qDebug() << modelFile.absoluteFilePath() << "Loaded Successfully"; qDebug() << modelFile.absoluteFilePath() << "Loaded Successfully";
@ -63,9 +62,11 @@ void Renderer::Model::loadModel(QString path)
qDebug() << "NumMaterials: " << scene->mNumMaterials; qDebug() << "NumMaterials: " << scene->mNumMaterials;
qDebug() << "NumTextures: " << scene->mNumTextures; qDebug() << "NumTextures: " << scene->mNumTextures;
unloadModel();
if (QFile paintingConfigFile(directory.filePath(name + ".txt")); paintingConfigFile.open(QFile::ReadOnly | QIODevice::Text)) if (QFile paintingConfigFile(directory.filePath(name + ".txt")); paintingConfigFile.open(QFile::ReadOnly | QIODevice::Text))
{ {
paintingMap.clear();
QTextStream stream(&paintingConfigFile); QTextStream stream(&paintingConfigFile);
while (!stream.atEnd()) while (!stream.atEnd())
{ {
@ -82,23 +83,36 @@ void Renderer::Model::loadModel(QString path)
qWarning() << "Painting Config Not Found!"; 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<float>::max(); minX = std::numeric_limits<float>::max();
maxX = std::numeric_limits<float>::min(); maxX = std::numeric_limits<float>::min();
minY = std::numeric_limits<float>::max(); minY = std::numeric_limits<float>::max();
maxY = std::numeric_limits<float>::min(); maxY = std::numeric_limits<float>::min();
minZ = std::numeric_limits<float>::max(); minZ = std::numeric_limits<float>::max();
maxZ = std::numeric_limits<float>::min(); maxZ = std::numeric_limits<float>::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) void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4)
@ -267,13 +281,13 @@ GLuint Renderer::Model::loadPainting(std::string path)
if (path == "0.json") 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[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[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[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") 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 }; float widths[] = { 0.22, 0.22 * 0.25 / 0.15, 0.22 * 0.25 / 0.15 };
QPainterPath painterPaths[6]; QPainterPath painterPaths[6];
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
@ -309,14 +323,39 @@ GLuint Renderer::Model::loadPainting(std::string path)
std::make_shared<StyleStrokeRadialGradient>(widths[1], StrokeType::kRightSide), std::make_shared<StyleStrokeRadialGradient>(widths[1], StrokeType::kRightSide),
std::make_shared<StyleStrokeRadialGradient>(widths[2], StrokeType::kLeftSide), std::make_shared<StyleStrokeRadialGradient>(widths[2], StrokeType::kLeftSide),
}; };
vector<std::shared_ptr<Element>> element = { std::map<float, Material> materialMap = {
std::make_shared<Element>(Element{ contours[0].first, style[0], contours[0].second}), {0.09, Material{QColor(255,255,255),0,0.8}},
std::make_shared<Element>(Element{ contours[1].first, style[1], contours[1].second}), {0.63, Material{QColor(165,176,207),0,0.8}},
std::make_shared<Element>(Element{ contours[2].first, style[2], contours[2].second}), {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 }); vector<std::shared_ptr<BaseElement>> element = {
painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.535,0.33), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); std::make_shared<BaseElement>(contours[0].first, std::make_shared<MaterialStyleStroke>(
painting.addElement(*element[2], ElementTransform{ glm::vec2(-0.535,0.23), glm::vec2(0.15), 0, glm::bvec2(false), 0 }); widths[0], StrokeType::kLeftSide, StrokeEndType::kFlat, std::make_shared<StrokeRadialGradient>(materialMap, false))),
std::make_shared<BaseElement>(contours[1].first, std::make_shared<MaterialStyleStroke>(
widths[1], StrokeType::kRightSide, StrokeEndType::kFlat, std::make_shared<StrokeRadialGradient>(materialMap, false))),
std::make_shared<BaseElement>(contours[2].first, std::make_shared<MaterialStyleStroke>(
widths[2], StrokeType::kLeftSide, StrokeEndType::kFlat, std::make_shared<StrokeRadialGradient>(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 else
{ {
@ -324,7 +363,7 @@ GLuint Renderer::Model::loadPainting(std::string path)
{ {
float x = (float)rand() / RAND_MAX * 2 - 1; float x = (float)rand() / RAND_MAX * 2 - 1;
float y = (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 });
} }
} }
} }

View File

@ -15,6 +15,7 @@ namespace Renderer
void draw(); void draw();
void drawShadow(); void drawShadow();
void loadModel(QString path); void loadModel(QString path);
void unloadModel();
Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, VirtualTextureManager* vtManager); Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, VirtualTextureManager* vtManager);
private: private:
QOpenGLContext* context = nullptr; QOpenGLContext* context = nullptr;
@ -25,8 +26,8 @@ namespace Renderer
VirtualTextureManager* vtManager = nullptr; VirtualTextureManager* vtManager = nullptr;
/** /**
* @param key BaseColor * @brief key BaseColor \n
* @param value json, * value json,
*/ */
std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>> paintingMap; std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>> paintingMap;
std::unordered_map<std::string, GLuint> paintingLoaded; std::unordered_map<std::string, GLuint> paintingLoaded;

View File

@ -1,16 +1,16 @@
#include "Element.h" #include "Element.h"
void Renderer::ElementTransform::applyTransformStyle(const TransformStyle& t) //void Renderer::ElementTransform::applyTransformStyle(const TransformStyle& t)
{ //{
center += t.translation; // /*center += t.translation;
scale *= t.scale; // scale *= t.scale;
rotation += t.rotation; // rotation += t.rotation;
flip ^= t.flip; // flip ^= t.flip;*/
} //}
//
Renderer::ElementTransform Renderer::ElementTransform::appliedTransformStyle(const TransformStyle& t) const //Renderer::ElementTransform Renderer::ElementTransform::appliedTransformStyle(const TransformStyle& t) const
{ //{
ElementTransform result = *this; // ElementTransform result = *this;
result.applyTransformStyle(t); // result.applyTransformStyle(t);
return result; // return result;
} //}

View File

@ -18,14 +18,15 @@ namespace Renderer
struct ElementTransform struct ElementTransform
{ {
glm::vec2 center; //glm::vec2 center;
//glm::vec2 size; //glm::vec2 scale; /// 相对于画布
glm::vec2 scale; /// 相对于画布 //float rotation; /// 角度制
float rotation; /// 角度制 //glm::bvec2 flip;
glm::bvec2 flip; glm::vec4 bound; /// 包围盒,不影响变换
glm::mat3x2 transform; /// 逆变换
GLuint zIndex; GLuint zIndex;
void applyTransformStyle(const TransformStyle& t); //void applyTransformStyle(const TransformStyle& t);
ElementTransform appliedTransformStyle(const TransformStyle& t) const; //ElementTransform appliedTransformStyle(const TransformStyle& t) const;
}; };
} }

View File

@ -53,87 +53,40 @@ void Renderer::Painting::addElement(ElementWithTransform elementWithTransform)
elementPool.insert({ element, 0 }); elementPool.insert({ element, 0 });
} }
elements.push_back(elementWithTransform); 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; addElement({ element , transform });
auto it = elementStyleMap.find(element.style);
if (it == elementStyleMap.end())
{
std::vector<BaseStyle> 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 });
}
} }
Renderer::BaseTransform::BaseTransform(ElementTransform t) BvhTreeData Painting::encodeElementLeaf(const ElementWithTransform& e)
: bound(glm::vec4(t.center - t.scale, t.center + t.scale))
, rotation(t.rotation)
, flip(t.flip)
, zIndex(t.zIndex)
{ {
} 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);
void Renderer::Painting::addElement(std::shared_ptr<Element> element, QVector4D bound, float rotation, int zIndex) return { bound, elementTransformPool[e.transform.transform], rightSon };
{
}
BvhTreeData Painting::encodeElementLeaf(ElementWithTransform e)
{
glm::vec4 bound;
switch (e.element.style->type())
{
case MaterialStyleType::kStroke:
{
auto w = std::static_pointer_cast<MaterialStyleStroke>(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);
} }
void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc) void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc)
{ {
qDebug() << "Element Count: " << elementPool.size(); qDebug() << "Element Count: " << elementPool.size();
qDebug() << "Coutour Count: " << contourPool.size(); qDebug() << "Contour Count: " << contourPool.size();
qDebug() << " Style Count: " << stylePool.size(); qDebug() << " Style Count: " << stylePool.size();
bvhChildren.clear(); bvhChildren.clear();
bvhBounds.clear(); bvhBounds.clear();
elementTransform.clear();
elementOffsets.clear(); elementOffsets.clear();
elementIndex.clear(); elementIndex.clear();
elementData.clear(); elementData.clear();
for (int index = 0; auto & i : elementPool) for (int index = 0; auto & i : elementPool)
{
i.second = index++; i.second = index++;
} for (int index = 0; auto & i : elementTransformPool)
i.second = index++;
std::vector<BvhTreeData> rootBvhTreeData; std::vector<BvhTreeData> rootBvhTreeData;
for (auto& i : elements) for (auto& i : elements)
@ -162,30 +115,35 @@ void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc)
elementData.insert(elementData.end(), encodedStyle.begin(), encodedStyle.end()); elementData.insert(elementData.end(), encodedStyle.begin(), encodedStyle.end());
} }
for (auto & i : elementTransformPool)
elementTransform.emplace_back(i.first);
for (auto& i : elementPool) for (auto& i : elementPool)
{ {
//qDebug() <<"element:" << i.second; //qDebug() <<"element:" << i.second;
//std::shared_ptr<ContourBuffer> contourBuffer = i.first.style->type() == MaterialStyleType::kStroke ? contourPool[i.first.contour].second : contourPool[i.first.contour].first; //std::shared_ptr<ContourBuffer> 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()}]; 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); //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& bvhSSBO = buffers[0];
GLuint& bvhBoundSSBO = buffers[1]; GLuint& bvhBoundSSBO = buffers[1];
GLuint& elementOffsetSSBO = buffers[2]; GLuint& elementTransformSSBO = buffers[2];
GLuint& elementIndexSSBO = buffers[3]; GLuint& elementOffsetSSBO = buffers[3];
GLuint& elementDataSSBO = buffers[4]; GLuint& elementIndexSSBO = buffers[4];
GLuint& backgroundColorUBO = buffers[5]; 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[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[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[2], elementTransform.size() * sizeof(elementTransform[0]), elementTransform.data(), GL_STATIC_READ);
glFunc->glNamedBufferData(buffers[3], elementIndex.size() * sizeof(elementIndex[0]), elementIndex.data(), GL_STATIC_READ); glFunc->glNamedBufferData(buffers[3], elementOffsets.size() * sizeof(elementOffsets[0]), elementOffsets.data(), GL_STATIC_READ);
glFunc->glNamedBufferData(buffers[4], elementData.size() * sizeof(elementData[0]), elementData.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()); 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() GLuint Renderer::Painting::getElementCount()
@ -223,3 +181,17 @@ bool Renderer::Painting::CompareMaterialStyle::operator()(const std::shared_ptr<
else else
return left < right; 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;
}

View File

@ -15,24 +15,13 @@ namespace Renderer
{ {
std::shared_ptr<Contour> contour; std::shared_ptr<Contour> contour;
std::shared_ptr<MaterialStyle> style; std::shared_ptr<MaterialStyle> style;
float ratio; /// ¿í¸ß±È
bool operator<(const BaseElement& e) const; bool operator<(const BaseElement& e) const;
}; };
struct BaseTransform
{
glm::vec4 bound;
float rotation;
glm::bvec2 flip;
GLuint zIndex;
BaseTransform(ElementTransform t);
};
struct ElementWithTransform struct ElementWithTransform
{ {
BaseElement element; BaseElement element;
ElementTransform transform; ElementTransform transform;
//BaseTransform transform;
}; };
struct ContourBuffer struct ContourBuffer
@ -52,7 +41,6 @@ namespace Renderer
GLuint styleOffset; GLuint styleOffset;
GLuint pointsOffset; GLuint pointsOffset;
GLuint linesOffset; GLuint linesOffset;
GLuint ratio;
}; };
class Painting class Painting
@ -60,16 +48,16 @@ namespace Renderer
public: public:
std::vector<GLuint> bvhChildren; std::vector<GLuint> bvhChildren;
std::vector<QVector4D> bvhBounds; std::vector<QVector4D> bvhBounds;
std::vector<glm::mat3x2> elementTransform;
std::vector<ElementOffset> elementOffsets; std::vector<ElementOffset> elementOffsets;
std::vector<GLuint> elementIndex; std::vector<GLuint> elementIndex;
std::vector<GLfloat> elementData; std::vector<GLfloat> elementData;
int paintingId = 0; int paintingId = 0;
std::array<GLuint, 6> buffers; std::array<GLuint, 7> buffers;
QColor backgroundColor; QColor backgroundColor;
Painting(QColor backgroundColor = Qt::white); Painting(QColor backgroundColor = Qt::white);
void addElement(const Element& element, const ElementTransform& transform); void addElement(const BaseElement& element, const ElementTransform& transform);
void addElement(std::shared_ptr<Element> element, QVector4D bound, float rotation, int zIndex);
void generateBuffers(QOpenGLFunctions_4_5_Core* glFunc); void generateBuffers(QOpenGLFunctions_4_5_Core* glFunc);
GLuint getElementCount(); GLuint getElementCount();
private: private:
@ -77,14 +65,15 @@ namespace Renderer
std::unordered_map<std::tuple<std::shared_ptr<Contour>, MaterialStyleType>, ContourBuffer, ContourHash> contourPool; std::unordered_map<std::tuple<std::shared_ptr<Contour>, MaterialStyleType>, ContourBuffer, ContourHash> contourPool;
struct CompareMaterialStyle { bool operator()(const std::shared_ptr<MaterialStyle>&, const std::shared_ptr<MaterialStyle>&) const; }; struct CompareMaterialStyle { bool operator()(const std::shared_ptr<MaterialStyle>&, const std::shared_ptr<MaterialStyle>&) const; };
std::set<std::shared_ptr<MaterialStyle>, CompareMaterialStyle> styleSet; std::set<std::shared_ptr<MaterialStyle>, CompareMaterialStyle> styleSet;
std::unordered_map<std::shared_ptr<ElementStyle>, std::vector<BaseStyle>> elementStyleMap;
std::unordered_map<std::shared_ptr<MaterialStyle>, GLuint> stylePool; std::unordered_map<std::shared_ptr<MaterialStyle>, GLuint> stylePool;
struct HashMat3x2 { std::size_t operator()(const glm::mat3x2&) const; };
std::unordered_map<glm::mat3x2, GLuint, HashMat3x2> elementTransformPool;
std::map<BaseElement, GLuint> elementPool; std::map<BaseElement, GLuint> elementPool;
std::vector<ElementWithTransform> elements; std::vector<ElementWithTransform> elements;
void addElement(ElementWithTransform element); void addElement(ElementWithTransform element);
void insertContourBuffer(ContourBuffer& buffer); void insertContourBuffer(ContourBuffer& buffer);
BvhTreeData encodeElementLeaf(ElementWithTransform e); BvhTreeData encodeElementLeaf(const ElementWithTransform& e);
}; };
} }

View File

@ -88,13 +88,23 @@ QRectF calcBoundingRect(const QPainterPath& path, const std::vector<BaseStyle>&
{ {
QRectF bound = path.boundingRect(); 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<float>::max()), rightBottom(std::numeric_limits<float>::min()); glm::vec2 leftTop(std::numeric_limits<float>::max()), rightBottom(std::numeric_limits<float>::min());
for (auto& baseStyle : styles) 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) if (baseStyle.material->type() == MaterialStyleType::kStroke)
{ {
float halfWidth = std::static_pointer_cast<MaterialStyleStroke>(baseStyle.material)->getHalfWidth(); float halfWidth = std::static_pointer_cast<MaterialStyleStroke>(baseStyle.material)->getHalfWidth();

View File

@ -13,6 +13,7 @@ namespace Renderer
~RendererWidget(); ~RendererWidget();
public slots: public slots:
void currentTabChanged(int index); void currentTabChanged(int index);
private: private:
Ui::RendererWidgetClass ui; Ui::RendererWidgetClass ui;
}; };

View File

@ -124,9 +124,9 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glMain->TextureStorage2D(metallicRoughness, levels, GL_RG8, GLsizei(textureSize), GLsizei(textureSize)); 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_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) for (auto level = levels - 1; level < levels; ++level)
{ {
@ -152,10 +152,30 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
} }
} }
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); paintings.emplace_back(baseColor, metallicRoughness, painting.buffers);
return paintings.size(); return paintings.size();
} }
}
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) Renderer::PaintingHandle& Renderer::VirtualTextureManager::getPaintingHandle(std::uint16_t id)
{ {
return paintings[id - 1]; return paintings[id - 1];
@ -189,9 +209,9 @@ void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pag
if (commit) if (commit)
{ {
program.bind(); 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]); 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<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y); gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y);
gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); 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); gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);

View File

@ -15,7 +15,7 @@ namespace Renderer
{ {
GLuint baseColor; GLuint baseColor;
GLuint metallicRoughness; GLuint metallicRoughness;
std::array<GLuint, 6> buffers; std::array<GLuint, 7> buffers;
}; };
class VirtualTextureManager class VirtualTextureManager
@ -24,11 +24,12 @@ namespace Renderer
VirtualTextureManager(GladGLContext* glMain); VirtualTextureManager(GladGLContext* glMain);
/** /**
* @brief * @brief
* @param painting * @param painting
* @return ÐéÄâÎÆÀíid * @return ÐéÄâÎÆÀíid
*/ */
std::uint16_t createVirtualTexture(Painting painting); std::uint16_t createVirtualTexture(Painting painting);
void deleteVirtualTexture(std::uint16_t id);
PaintingHandle& getPaintingHandle(std::uint16_t id); PaintingHandle& getPaintingHandle(std::uint16_t id);
void tryUpdatePages(const std::vector<glm::u16vec2>& pageIds); void tryUpdatePages(const std::vector<glm::u16vec2>& pageIds);