yang.yongquan 2023-03-18 20:30:31 +08:00
commit e48954175d
22 changed files with 362 additions and 235 deletions

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,17 +1148,13 @@ 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)
{ {
uint lineIndex = elementIndexs[contourIterator + 1]; uint lineIndex = elementIndexs[contourIterator + 1];
uint pLocation = linesOffset + 3 * lineIndex; uint pLocation = linesOffset + 3 * lineIndex;
//vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]); // vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
uvec4 pxIndex = uvec4(pointsOffset) + uvec4 pxIndex = uvec4(pointsOffset) +
2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF, 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF); elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
@ -1168,10 +1163,6 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
mat4x2 pNext = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], 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])
{ {
@ -1179,8 +1170,8 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
pNext[2] = pNext[1]; pNext[2] = pNext[1];
} }
//if(pNext[0]!=p[3]) // if(pNext[0]!=p[3])
// break; // break;
if (pNext[0] != pNext[1]) if (pNext[0] != pNext[1])
tangentBeginNext = normalize(pNext[0] - pNext[1]); tangentBeginNext = normalize(pNext[0] - pNext[1]);
else else
@ -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;
@ -1357,7 +1348,7 @@ 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(backgroundColor, -1); vec4 color = vec4(backgroundColor, -1);
vec2 metallicRoughness = vec2(0, 0.8); vec2 metallicRoughness = vec2(0, 0.8);
stack.top = 0; stack.top = 0;
@ -1371,49 +1362,39 @@ void main()
visitTime++; visitTime++;
vec4 bound = bvhBound[index]; vec4 bound = bvhBound[index];
uint leftChild = bvhChildren[index].x; uint leftChild = bvhChildren[index].x;
if (leftChild >= bvhLength)
{
uint zIndex = bvhChildren[index].y >> 18;
bvec2 flip = bvec2(bvhChildren[index].y & (1 << 16), bvhChildren[index].y & (1 << 17));
float angle = (float(bvhChildren[index].y & ((1 << 16) - 1)) / 65535.0) * 2 * PI;
mat2 rotation = {{cos(angle), -sin(angle)}, {sin(angle), cos(angle)}};
vec2 localUV = uv - (bound.xy + bound.zw) / 2;
localUV = rotation * localUV;
vec2 scale = (bound.zw - bound.xy) / 2;
localUV /= scale;
if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex > color.w)
{
// if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005))))
if (any(greaterThan(vec2(-1) + vec2(0.005), localUV)) ||
any(greaterThan(localUV, vec2(1) - vec2(0.005))))
debugBVH.g += 0.3;
// uint elementIndex = leftChild - bvhLength;
// debugBVH.bg += 0.5 * (localUV + vec2(1));
// debugBVH = vec3(0); if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw)))
if (flip.x) {
localUV.x = -localUV.x; if (any(greaterThan(bound.xy + vec2(0.005), uv)) || any(greaterThan(uv, bound.zw - vec2(0.005))))
if (flip.y) debugBVH.g += 0.3;
localUV.y = -localUV.y;
if (leftChild >= bvhLength)
{
uint transformIndex = leftChild - 0x80000000;
uint zIndex = bvhChildren[index].y >> 18;
uint elementIndex = bvhChildren[index].y - zIndex;
mat3x2 transform = elementTranform[transformIndex];
vec2 localUV =
(mat3(vec3(transform[0], 0), vec3(transform[1], 0), vec3(transform[2], 1)) * vec3(uv, 1)).xy;
vec3 elementColor; 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)))) stack.push(index);
debugBVH.g += 0.3; index = leftChild;
// debugBVH.r += 0.02; }
stack.push(index);
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

@ -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

@ -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

@ -286,3 +286,35 @@ 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);
}

View File

@ -68,7 +68,8 @@ 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);
}; };
class FolderLayerWrapper : public LayerWrapper class FolderLayerWrapper : public LayerWrapper
@ -92,6 +93,7 @@ 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;
}; };
class LeafLayerWrapper : public LayerWrapper class LeafLayerWrapper : public LayerWrapper
@ -107,6 +109,7 @@ 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;
}; };
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();

View File

@ -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,15 +76,18 @@ 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);
menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() { if(typeid(*layer) == typeid(FolderLayerWrapper))
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>(); menu.addAction(QString::fromLocal8Bit("ɾ³ý£¨±£Áô×ӽڵ㣩"), this, [this]() {
layer->delSelf(); auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
layer->getParent()->removeChild(layer); layer->delSelf();
this->refresh(); layer->getParent()->removeChild(layer);
emit requireRefreshPreview(); this->refresh();
}); emit requireRefreshPreview();
emit requireRefreshElementWidget();
});
} }
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

@ -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,8 +152,28 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
} }
} }
paintings.emplace_back(baseColor, metallicRoughness, painting.buffers); if (const auto it = std::find_if(paintings.begin(), paintings.end(), [](const PaintingHandle& i) { return i.baseColor == 0; });
return paintings.size(); it != paintings.end())
{
*it = { baseColor, metallicRoughness, painting.buffers };
return it - paintings.begin() + 1;
}
else
{
paintings.emplace_back(baseColor, metallicRoughness, painting.buffers);
return paintings.size();
}
}
void Renderer::VirtualTextureManager::deleteVirtualTexture(std::uint16_t id)
{
auto& painting = getPaintingHandle(id);
glMain->DeleteTextures(2, (GLuint*)&painting);
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)
@ -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);