1
0
Fork 0

Work on clipping in remote canvas

Different canvas clip reference frames are handled now, and updating
the clip nodes should not longer crash. Unfortunately, clips set
on groups don't work yet, further work is needed here.
This commit is contained in:
James Turner 2018-06-17 16:54:09 +01:00
parent c82a725e47
commit 8f205040dc
7 changed files with 156 additions and 57 deletions

View file

@ -51,52 +51,148 @@ void CanvasItem::setTransform(const QMatrix4x4 &mat)
m_localTransform->setTransform(mat);
}
void CanvasItem::setGlobalClip(const QRectF &clip)
void CanvasItem::setClip(const QRectF &clip, ReferenceFrame rf)
{
if (m_hasClip && (clip == m_clipRect) && (rf == m_clipReferenceFrame)) {
return;
}
m_hasClip = true;
m_globalClipRect = clip;
m_clipRect = clip;
m_clipReferenceFrame = rf;
update();
}
void CanvasItem::setClipReferenceFrameItem(QQuickItem *refItem)
{
m_clipReferenceFrameItem = refItem;
}
void CanvasItem::clearClip()
{
m_hasClip = false;
update();
}
QSGNode *CanvasItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
QSGNode *CanvasItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *d)
{
if (m_hasClip && oldNode && (oldNode->type() == QSGNode::BasicNodeType)) {
delete oldNode;
QSGNode* realOldNode = oldNode;
QSGClipNode* oldClip = nullptr;
if (oldNode && (oldNode->type() == QSGNode::ClipNodeType)) {
Q_ASSERT(oldNode->childCount() == 1);
realOldNode = oldNode->childAtIndex(0);
oldClip = static_cast<QSGClipNode*>(oldNode);
}
if (!m_hasClip && m_clipNode) {
oldNode = new QSGNode;
}
updateClipNode();
return m_hasClip ? m_clipNode : oldNode;
}
QSGClipNode *CanvasItem::updateClipNode()
{
if (!m_hasClip) {
if (m_clipNode) {
delete m_clipNode;
m_clipNode = nullptr;
}
QSGNode* contentNode = updateRealPaintNode(realOldNode, d);
if (!contentNode) {
return nullptr;
}
if (!m_clipNode) {
m_clipNode = new QSGClipNode();
QSGNode* clipNode = updateClipNode(oldClip, contentNode);
return clipNode ? clipNode : contentNode;
}
QSGNode *CanvasItem::updateRealPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *d)
{
if (oldNode) {
return oldNode;
}
// transform global rect to local
QRectF localRect(mapFromGlobal(m_globalClipRect.topLeft()),
mapFromGlobal(m_globalClipRect.bottomRight()));
m_clipNode->setClipRect(localRect);
return m_clipNode;
return new QSGNode();
}
QRectF checkRectangularClip(QPointF* vertices)
{
// order is TL / BL / TR / BR to match updateRectGeometry
const double top = vertices[0].y();
const double left = vertices[0].x();
const double bottom = vertices[1].y();
const double right = vertices[2].x();
if (vertices[1].x() != left) return {};
if (vertices[2].y() != top) return {};
if ((vertices[3].x() != right) || (vertices[3].y() != bottom))
return {};
return QRectF(vertices[0], vertices[3]);
}
QSGClipNode* CanvasItem::updateClipNode(QSGClipNode* oldClipNode, QSGNode* contentNode)
{
Q_ASSERT(contentNode);
if (!m_hasClip) {
return nullptr;
}
QSGGeometry* clipGeometry = nullptr;
QSGClipNode* clipNode = oldClipNode;
if (!clipNode) {
clipNode = new QSGClipNode();
clipGeometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4);
clipGeometry->setDrawingMode(GL_TRIANGLE_STRIP);
clipNode->setGeometry(clipGeometry);
clipNode->setFlag(QSGNode::OwnsGeometry);
clipNode->appendChildNode(contentNode);
} else {
if (clipNode->childCount() == 1) {
const auto existingChild = clipNode->childAtIndex(0);
if (existingChild == contentNode) {
qInfo() << "optimise for this case!";
}
}
clipNode->removeAllChildNodes();
clipNode->appendChildNode(contentNode);
clipGeometry = clipNode->geometry();
Q_ASSERT(clipGeometry);
}
QPointF clipVertices[4],
inVertices[4] = {m_clipRect.topLeft(), m_clipRect.bottomLeft(),
m_clipRect.topRight(), m_clipRect.bottomRight()};
QRectF rectClip;
switch (m_clipReferenceFrame) {
case ReferenceFrame::GLOBAL:
case ReferenceFrame::PARENT:
Q_ASSERT(m_clipReferenceFrameItem);
for (int i=0; i<4; ++i) {
clipVertices[i] = mapFromItem(m_clipReferenceFrameItem, inVertices[i]);
}
rectClip = checkRectangularClip(clipVertices);
break;
case ReferenceFrame::LOCAL:
// local ref-frame clip is always rectangular
rectClip = m_clipRect;
for (int i=0; i<4; ++i) {
clipVertices[i] = inVertices[i];
}
break;
}
clipNode->setIsRectangular(!rectClip.isNull());
qInfo() << "\nobj:" << objectName();
if (!rectClip.isNull()) {
qInfo() << "have rectangular clip for:" << m_clipRect << (int) m_clipReferenceFrame << rectClip;
clipNode->setClipRect(rectClip);
} else {
qInfo() << "haved rotated clip" << m_clipRect << (int) m_clipReferenceFrame;
qInfo() << "final local clip points:" << clipVertices[0] << clipVertices[1]
<< clipVertices[2] << clipVertices[3];
}
QSGGeometry::Point2D *v = clipGeometry->vertexDataAsPoint2D();
for (int i=0; i<4; ++i) {
v[i].x = clipVertices[i].x();
v[i].y = clipVertices[i].y();
}
clipGeometry->markVertexDataDirty();
clipNode->markDirty(QSGNode::DirtyGeometry);
return clipNode;
}
#include "canvasitem.moc"

View file

@ -19,6 +19,7 @@
#define CANVASITEM_H
#include <QQuickItem>
#include "fgcanvaselement.h"
class LocalTransform;
class QSGClipNode;
@ -31,23 +32,28 @@ public:
void setTransform(const QMatrix4x4& mat);
void setGlobalClip(const QRectF &clip);
void setClip(const QRectF &clip, ReferenceFrame rf);
void setClipReferenceFrameItem(QQuickItem* refItem);
void clearClip();
QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *) override final;
signals:
public slots:
protected:
QSGClipNode* updateClipNode();
virtual QSGNode *updateRealPaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *d);
private:
QSGClipNode* updateClipNode(QSGClipNode* oldClipNode, QSGNode* contentNode);
LocalTransform* m_localTransform;
QRectF m_globalClipRect;
QRectF m_clipRect;
bool m_hasClip = false;
QSGClipNode* m_clipNode = nullptr;
ReferenceFrame m_clipReferenceFrame = ReferenceFrame::GLOBAL;
QQuickItem* m_clipReferenceFrameItem = nullptr;
};
#endif // CANVASITEM_H

View file

@ -127,9 +127,15 @@ void FGCanvasElement::polish()
_clipDirty = false;
if (qq) {
if (_hasClip) {
// qq->setGlobalClip(_clipRect);
if (_clipFrame == ReferenceFrame::GLOBAL) {
qq->setClipReferenceFrameItem(rootGroup()->quickItem());
} else if (_clipFrame == ReferenceFrame::PARENT) {
qq->setClipReferenceFrameItem(parentGroup()->quickItem());
}
qq->setObjectName(_propertyRoot->path());
qq->setClip(_clipRect, _clipFrame);
} else {
// qq->clearClip();
qq->clearClip();
}
}
}
@ -244,6 +250,15 @@ const FGCanvasGroup *FGCanvasElement::parentGroup() const
return _parent;
}
const FGCanvasGroup *FGCanvasElement::rootGroup() const
{
if (!_parent) {
return qobject_cast<const FGCanvasGroup*>(this);
}
return _parent->rootGroup();
}
CanvasConnection *FGCanvasElement::connection() const
{
if (_parent)

View file

@ -59,6 +59,8 @@ public:
const FGCanvasGroup* parentGroup() const;
const FGCanvasGroup* rootGroup() const;
CanvasConnection* connection() const;
static bool isStyleProperty(QByteArray name);

View file

@ -61,7 +61,7 @@ public:
update(); // request a paint node update
}
virtual QSGNode* updatePaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintNodeData *)
QSGNode* updateRealPaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintNodeData *) override
{
if (m_path.isEmpty()) {
return nullptr;
@ -169,13 +169,6 @@ public:
strokeGeom->setFlag(QSGNode::OwnsMaterial);
}
QSGClipNode* clip = updateClipNode();
if (clip) {
if (fillGeom) clip->appendChildNode(fillGeom);
if (strokeGeom) clip->appendChildNode(strokeGeom);
return clip;
}
if (fillGeom && strokeGeom) {
QSGNode* groupNode = new QSGNode;
groupNode->appendChildNode(fillGeom);

View file

@ -73,7 +73,7 @@ public:
update();
}
virtual QSGNode* updatePaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintNodeData *data)
QSGNode* updateRealPaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintNodeData *data) override
{
if (!m_textNode) {
@ -88,12 +88,6 @@ public:
m_color,
QQuickText::Normal);
QSGNode* clip = updateClipNode();
if (clip) {
clip->appendChildNode(m_textNode);
return clip;
}
return m_textNode;
}

View file

@ -65,7 +65,7 @@ public:
update();
}
virtual QSGNode* updatePaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintNodeData *data)
QSGNode* updateRealPaintNode(QSGNode* oldNode, QQuickItem::UpdatePaintNodeData *data) override
{
if (m_pixmap.isNull()) {
return nullptr;
@ -85,13 +85,6 @@ public:
}
m_texture = window()->createTextureFromImage(m_pixmap.toImage(), QQuickWindow::TextureCanUseAtlas);
texNode->setTexture(m_texture);
QSGNode* clip = updateClipNode();
if (clip) {
clip->appendChildNode(texNode);
return clip;
}
return texNode;
}