scene: Add support for item transformations
This commit is contained in:
parent
9e70c2a21c
commit
f6b605daf2
8 changed files with 71 additions and 48 deletions
|
@ -208,7 +208,7 @@ void EffectWindow::addRepaintFull()
|
|||
|
||||
void EffectWindow::addLayerRepaint(const QRect &r)
|
||||
{
|
||||
d->m_windowItem->scheduleRepaint(d->m_windowItem->mapFromGlobal(r));
|
||||
d->m_windowItem->scheduleRepaint(d->m_windowItem->mapFromScene(r));
|
||||
}
|
||||
|
||||
const EffectWindowGroup *EffectWindow::group() const
|
||||
|
|
|
@ -82,6 +82,7 @@ void Item::setParentItem(Item *item)
|
|||
Q_ASSERT(m_parentItem->m_scene == m_scene);
|
||||
m_parentItem->addChild(this);
|
||||
}
|
||||
updateItemToSceneTransform();
|
||||
updateEffectiveVisibility();
|
||||
}
|
||||
|
||||
|
@ -93,7 +94,7 @@ void Item::addChild(Item *item)
|
|||
markSortedChildItemsDirty();
|
||||
|
||||
updateBoundingRect();
|
||||
scheduleRepaint(item->boundingRect().translated(item->position()));
|
||||
scheduleRepaint(item->transform().mapRect(item->boundingRect()).translated(item->position()));
|
||||
|
||||
Q_EMIT childAdded(item);
|
||||
}
|
||||
|
@ -101,7 +102,7 @@ void Item::addChild(Item *item)
|
|||
void Item::removeChild(Item *item)
|
||||
{
|
||||
Q_ASSERT(m_childItems.contains(item));
|
||||
scheduleRepaint(item->boundingRect().translated(item->position()));
|
||||
scheduleRepaint(item->transform().mapRect(item->boundingRect()).translated(item->position()));
|
||||
|
||||
m_childItems.removeOne(item);
|
||||
markSortedChildItemsDirty();
|
||||
|
@ -124,6 +125,7 @@ void Item::setPosition(const QPointF &point)
|
|||
if (m_position != point) {
|
||||
scheduleRepaint(boundingRect());
|
||||
m_position = point;
|
||||
updateItemToSceneTransform();
|
||||
if (m_parentItem) {
|
||||
m_parentItem->updateBoundingRect();
|
||||
}
|
||||
|
@ -163,7 +165,7 @@ void Item::updateBoundingRect()
|
|||
{
|
||||
QRectF boundingRect = rect();
|
||||
for (Item *item : std::as_const(m_childItems)) {
|
||||
boundingRect |= item->boundingRect().translated(item->position());
|
||||
boundingRect |= item->transform().mapRect(item->boundingRect()).translated(item->position());
|
||||
}
|
||||
if (m_boundingRect != boundingRect) {
|
||||
m_boundingRect = boundingRect;
|
||||
|
@ -184,51 +186,63 @@ QRegion Item::opaque() const
|
|||
return QRegion();
|
||||
}
|
||||
|
||||
QPointF Item::rootPosition() const
|
||||
{
|
||||
QPointF ret = position();
|
||||
|
||||
Item *parent = parentItem();
|
||||
while (parent) {
|
||||
ret += parent->position();
|
||||
parent = parent->parentItem();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QMatrix4x4 Item::transform() const
|
||||
QTransform Item::transform() const
|
||||
{
|
||||
return m_transform;
|
||||
}
|
||||
|
||||
void Item::setTransform(const QMatrix4x4 &transform)
|
||||
void Item::setTransform(const QTransform &transform)
|
||||
{
|
||||
if (m_transform == transform) {
|
||||
return;
|
||||
}
|
||||
scheduleRepaint(boundingRect());
|
||||
m_transform = transform;
|
||||
updateItemToSceneTransform();
|
||||
if (m_parentItem) {
|
||||
m_parentItem->updateBoundingRect();
|
||||
}
|
||||
scheduleRepaint(boundingRect());
|
||||
}
|
||||
|
||||
QRegion Item::mapToGlobal(const QRegion ®ion) const
|
||||
void Item::updateItemToSceneTransform()
|
||||
{
|
||||
m_itemToSceneTransform = m_transform;
|
||||
if (!m_position.isNull()) {
|
||||
m_itemToSceneTransform *= QTransform::fromTranslate(m_position.x(), m_position.y());
|
||||
}
|
||||
if (m_parentItem) {
|
||||
m_itemToSceneTransform *= m_parentItem->m_itemToSceneTransform;
|
||||
}
|
||||
m_sceneToItemTransform = m_itemToSceneTransform.inverted();
|
||||
|
||||
for (Item *childItem : std::as_const(m_childItems)) {
|
||||
childItem->updateItemToSceneTransform();
|
||||
}
|
||||
}
|
||||
|
||||
QRegion Item::mapToScene(const QRegion ®ion) const
|
||||
{
|
||||
if (region.isEmpty()) {
|
||||
return QRegion();
|
||||
}
|
||||
return region.translated(rootPosition().toPoint());
|
||||
return m_itemToSceneTransform.map(region);
|
||||
}
|
||||
|
||||
QRectF Item::mapToGlobal(const QRectF &rect) const
|
||||
QRectF Item::mapToScene(const QRectF &rect) const
|
||||
{
|
||||
if (rect.isEmpty()) {
|
||||
return QRect();
|
||||
}
|
||||
return rect.translated(rootPosition());
|
||||
return m_itemToSceneTransform.mapRect(rect);
|
||||
}
|
||||
|
||||
QRectF Item::mapFromGlobal(const QRectF &rect) const
|
||||
QRectF Item::mapFromScene(const QRectF &rect) const
|
||||
{
|
||||
if (rect.isEmpty()) {
|
||||
return QRect();
|
||||
}
|
||||
return rect.translated(-rootPosition());
|
||||
return m_sceneToItemTransform.mapRect(rect);
|
||||
}
|
||||
|
||||
void Item::stackBefore(Item *sibling)
|
||||
|
@ -303,7 +317,7 @@ void Item::scheduleRepaint(SceneDelegate *delegate, const QRegion ®ion)
|
|||
|
||||
void Item::scheduleRepaintInternal(const QRegion ®ion)
|
||||
{
|
||||
const QRegion globalRegion = mapToGlobal(region);
|
||||
const QRegion globalRegion = mapToScene(region);
|
||||
const QList<SceneDelegate *> delegates = m_scene->delegates();
|
||||
for (SceneDelegate *delegate : delegates) {
|
||||
const QRegion dirtyRegion = globalRegion & delegate->viewport();
|
||||
|
@ -316,7 +330,7 @@ void Item::scheduleRepaintInternal(const QRegion ®ion)
|
|||
|
||||
void Item::scheduleRepaintInternal(SceneDelegate *delegate, const QRegion ®ion)
|
||||
{
|
||||
const QRegion globalRegion = mapToGlobal(region);
|
||||
const QRegion globalRegion = mapToScene(region);
|
||||
const QRegion dirtyRegion = globalRegion & delegate->viewport();
|
||||
if (!dirtyRegion.isEmpty()) {
|
||||
m_repaints[delegate] += dirtyRegion;
|
||||
|
@ -329,7 +343,7 @@ void Item::scheduleFrame()
|
|||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
const QRect geometry = mapToGlobal(rect()).toRect();
|
||||
const QRect geometry = mapToScene(rect()).toRect();
|
||||
const QList<SceneDelegate *> delegates = m_scene->delegates();
|
||||
for (SceneDelegate *delegate : delegates) {
|
||||
if (delegate->viewport().intersects(geometry)) {
|
||||
|
@ -412,7 +426,7 @@ void Item::updateEffectiveVisibility()
|
|||
|
||||
m_effectiveVisible = effectiveVisible;
|
||||
if (!m_effectiveVisible) {
|
||||
m_scene->addRepaint(mapToGlobal(boundingRect()).toAlignedRect());
|
||||
m_scene->addRepaint(mapToScene(boundingRect()).toAlignedRect());
|
||||
} else {
|
||||
scheduleRepaintInternal(boundingRect().toAlignedRect());
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
#include "scene/itemgeometry.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QMatrix4x4>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QTransform>
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
@ -69,26 +69,24 @@ public:
|
|||
QList<Item *> childItems() const;
|
||||
QList<Item *> sortedChildItems() const;
|
||||
|
||||
QPointF rootPosition() const;
|
||||
|
||||
QMatrix4x4 transform() const;
|
||||
void setTransform(const QMatrix4x4 &transform);
|
||||
QTransform transform() const;
|
||||
void setTransform(const QTransform &transform);
|
||||
|
||||
/**
|
||||
* Maps the given @a region from the item's coordinate system to the scene's coordinate
|
||||
* system.
|
||||
*/
|
||||
QRegion mapToGlobal(const QRegion ®ion) const;
|
||||
QRegion mapToScene(const QRegion ®ion) const;
|
||||
/**
|
||||
* Maps the given @a rect from the item's coordinate system to the scene's coordinate
|
||||
* system.
|
||||
*/
|
||||
QRectF mapToGlobal(const QRectF &rect) const;
|
||||
QRectF mapToScene(const QRectF &rect) const;
|
||||
/**
|
||||
* Maps the given @a rect from the scene's coordinate system to the item's coordinate
|
||||
* system.
|
||||
*/
|
||||
QRectF mapFromGlobal(const QRectF &rect) const;
|
||||
QRectF mapFromScene(const QRectF &rect) const;
|
||||
|
||||
/**
|
||||
* Moves this item right before the specified @a sibling in the parent's children list.
|
||||
|
@ -142,6 +140,7 @@ private:
|
|||
void addChild(Item *item);
|
||||
void removeChild(Item *item);
|
||||
void updateBoundingRect();
|
||||
void updateItemToSceneTransform();
|
||||
void scheduleRepaintInternal(const QRegion ®ion);
|
||||
void scheduleRepaintInternal(SceneDelegate *delegate, const QRegion ®ion);
|
||||
void markSortedChildItemsDirty();
|
||||
|
@ -153,7 +152,9 @@ private:
|
|||
Scene *m_scene;
|
||||
QPointer<Item> m_parentItem;
|
||||
QList<Item *> m_childItems;
|
||||
QMatrix4x4 m_transform;
|
||||
QTransform m_transform;
|
||||
QTransform m_itemToSceneTransform;
|
||||
QTransform m_sceneToItemTransform;
|
||||
QRectF m_boundingRect;
|
||||
QPointF m_position;
|
||||
QSizeF m_size = QSize(0, 0);
|
||||
|
|
|
@ -139,11 +139,19 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context)
|
|||
{
|
||||
const QList<Item *> sortedChildItems = item->sortedChildItems();
|
||||
|
||||
QMatrix4x4 matrix;
|
||||
const auto logicalPosition = QVector2D(item->position().x(), item->position().y());
|
||||
const auto scale = context->renderTargetScale;
|
||||
|
||||
QMatrix4x4 matrix;
|
||||
matrix.translate(roundVector(logicalPosition * scale).toVector3D());
|
||||
matrix *= item->transform();
|
||||
if (context->transformStack.size() == 1) {
|
||||
matrix *= context->rootTransform;
|
||||
}
|
||||
if (!item->transform().isIdentity()) {
|
||||
matrix.scale(scale, scale);
|
||||
matrix *= item->transform();
|
||||
matrix.scale(1 / scale, 1 / scale);
|
||||
}
|
||||
context->transformStack.push(context->transformStack.top() * matrix);
|
||||
|
||||
context->opacityStack.push(context->opacityStack.top() * item->opacity());
|
||||
|
@ -261,6 +269,7 @@ void ItemRendererOpenGL::renderItem(const RenderTarget &renderTarget, const Rend
|
|||
|
||||
RenderContext renderContext{
|
||||
.projectionMatrix = viewport.projectionMatrix(),
|
||||
.rootTransform = data.toMatrix(viewport.scale()), // TODO: unify transforms
|
||||
.clip = region,
|
||||
.hardwareClipping = region != infiniteRegion() && ((mask & Scene::PAINT_WINDOW_TRANSFORMED) || (mask & Scene::PAINT_SCREEN_TRANSFORMED)),
|
||||
.renderTargetScale = viewport.scale(),
|
||||
|
@ -269,8 +278,6 @@ void ItemRendererOpenGL::renderItem(const RenderTarget &renderTarget, const Rend
|
|||
renderContext.transformStack.push(QMatrix4x4());
|
||||
renderContext.opacityStack.push(data.opacity());
|
||||
|
||||
item->setTransform(data.toMatrix(renderContext.renderTargetScale));
|
||||
|
||||
createRenderNode(item, &renderContext);
|
||||
|
||||
int totalVertexCount = 0;
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
QStack<QMatrix4x4> transformStack;
|
||||
QStack<qreal> opacityStack;
|
||||
const QMatrix4x4 projectionMatrix;
|
||||
const QMatrix4x4 rootTransform;
|
||||
const QRegion clip;
|
||||
const bool hardwareClipping;
|
||||
const qreal renderTargetScale;
|
||||
|
|
|
@ -61,7 +61,7 @@ void ItemRendererQPainter::renderItem(const RenderTarget &renderTarget, const Re
|
|||
{
|
||||
QRegion region = _region;
|
||||
|
||||
const QRect boundingRect = item->mapToGlobal(item->boundingRect()).toAlignedRect();
|
||||
const QRect boundingRect = item->mapToScene(item->boundingRect()).toAlignedRect();
|
||||
if (!(mask & (Scene::PAINT_WINDOW_TRANSFORMED | Scene::PAINT_SCREEN_TRANSFORMED))) {
|
||||
region &= boundingRect;
|
||||
}
|
||||
|
|
|
@ -320,12 +320,12 @@ void WorkspaceScene::preparePaintSimpleScreen()
|
|||
if (window->opacity() == 1.0) {
|
||||
const SurfaceItem *surfaceItem = windowItem->surfaceItem();
|
||||
if (Q_LIKELY(surfaceItem)) {
|
||||
data.opaque = surfaceItem->mapToGlobal(surfaceItem->opaque());
|
||||
data.opaque = surfaceItem->mapToScene(surfaceItem->opaque());
|
||||
}
|
||||
|
||||
const DecorationItem *decorationItem = windowItem->decorationItem();
|
||||
if (decorationItem) {
|
||||
data.opaque += decorationItem->mapToGlobal(decorationItem->opaque());
|
||||
data.opaque += decorationItem->mapToScene(decorationItem->opaque());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,7 @@ void WorkspaceScene::paintSimpleScreen(const RenderTarget &renderTarget, const R
|
|||
data->region = visible;
|
||||
|
||||
if (!(data->mask & PAINT_WINDOW_TRANSFORMED)) {
|
||||
data->region &= data->item->mapToGlobal(data->item->boundingRect()).toAlignedRect();
|
||||
data->region &= data->item->mapToScene(data->item->boundingRect()).toAlignedRect();
|
||||
|
||||
if (!(data->mask & PAINT_WINDOW_TRANSLUCENT)) {
|
||||
visible -= data->opaque;
|
||||
|
@ -433,7 +433,7 @@ void WorkspaceScene::paintSimpleScreen(const RenderTarget &renderTarget, const R
|
|||
}
|
||||
|
||||
if (m_dndIcon) {
|
||||
const QRegion repaint = region & m_dndIcon->mapToGlobal(m_dndIcon->boundingRect()).toRect();
|
||||
const QRegion repaint = region & m_dndIcon->mapToScene(m_dndIcon->boundingRect()).toRect();
|
||||
if (!repaint.isEmpty()) {
|
||||
m_renderer->renderItem(renderTarget, viewport, m_dndIcon.get(), 0, repaint, WindowPaintData{});
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ QDebug operator<<(QDebug debug, const Window *window)
|
|||
QRectF Window::visibleGeometry() const
|
||||
{
|
||||
if (const WindowItem *item = windowItem()) {
|
||||
return item->mapToGlobal(item->boundingRect());
|
||||
return item->mapToScene(item->boundingRect());
|
||||
}
|
||||
return QRectF();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue