From c60fbae0b920b86e8c39e241c9a3e838e1c53388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Thu, 26 Sep 2024 12:16:46 +0200 Subject: [PATCH] Added composition mode to layer TODO: * Serialization in XML, JSON and Lua formats * Decide which modes to support * Consider what should happen when set on group layers --- src/libtiled/layer.h | 15 ++++++++++++ src/libtiled/mapwriter.cpp | 3 +++ src/tiled/changeevents.h | 3 ++- src/tiled/changelayer.cpp | 22 +++++++++++++++++ src/tiled/changelayer.h | 19 +++++++++++++++ src/tiled/imagelayeritem.cpp | 1 + src/tiled/mapitem.cpp | 10 ++++---- src/tiled/mapitem.h | 2 +- src/tiled/mapobjectitem.cpp | 2 ++ src/tiled/propertieswidget.cpp | 43 ++++++++++++++++++++++++++++++++++ src/tiled/tilelayeritem.cpp | 1 + src/tiled/undocommands.h | 1 + 12 files changed, 116 insertions(+), 6 deletions(-) diff --git a/src/libtiled/layer.h b/src/libtiled/layer.h index ae6881e5b0..f739799a9d 100644 --- a/src/libtiled/layer.h +++ b/src/libtiled/layer.h @@ -32,6 +32,7 @@ #include "object.h" #include "tileset.h" +#include #include #include #include @@ -192,6 +193,9 @@ class TILEDSHARED_EXPORT Layer : public Object QPointF parallaxFactor() const; QPointF effectiveParallaxFactor() const; + QPainter::CompositionMode compositionMode() const; + void setCompositionMode(QPainter::CompositionMode compositionMode); + bool canMergeDown() const; virtual bool isEmpty() const = 0; @@ -263,6 +267,7 @@ class TILEDSHARED_EXPORT Layer : public Object int mY = 0; QPointF mOffset; QPointF mParallaxFactor = { 1.0, 1.0 }; + QPainter::CompositionMode mCompositionMode = QPainter::CompositionMode_SourceOver; qreal mOpacity = 1.0; QColor mTintColor; bool mVisible = true; @@ -307,6 +312,16 @@ inline QPointF Layer::parallaxFactor() const return mParallaxFactor; } +inline QPainter::CompositionMode Layer::compositionMode() const +{ + return mCompositionMode; +} + +inline void Layer::setCompositionMode(QPainter::CompositionMode compositionMode) +{ + mCompositionMode = compositionMode; +} + /** * An iterator for iterating over the layers of a map, in the order in which diff --git a/src/libtiled/mapwriter.cpp b/src/libtiled/mapwriter.cpp index d6c4f3265d..cf678471eb 100644 --- a/src/libtiled/mapwriter.cpp +++ b/src/libtiled/mapwriter.cpp @@ -677,6 +677,9 @@ void MapWriterPrivate::writeLayerAttributes(QXmlStreamWriter &w, w.writeAttribute(QStringLiteral("parallaxx"), QString::number(parallaxFactor.x())); if (parallaxFactor.y() != 1.0) w.writeAttribute(QStringLiteral("parallaxy"), QString::number(parallaxFactor.y())); + + if (layer.compositionMode() != QPainter::CompositionMode_SourceOver) + w.writeAttribute(QStringLiteral("blend"), QStringLiteral("TODO: Convert composition mode to/from string")); } void MapWriterPrivate::writeObjectGroup(QXmlStreamWriter &w, diff --git a/src/tiled/changeevents.h b/src/tiled/changeevents.h index 313bb36dfa..71c155d812 100644 --- a/src/tiled/changeevents.h +++ b/src/tiled/changeevents.h @@ -128,7 +128,8 @@ class LayerChangeEvent : public ChangeEvent LockedProperty = 1 << 3, OffsetProperty = 1 << 4, ParallaxFactorProperty = 1 << 5, - TintColorProperty = 1 << 6, + CompositionModeProperty = 1 << 6, + TintColorProperty = 1 << 7, PositionProperties = OffsetProperty | ParallaxFactorProperty, AllProperties = 0xFF }; diff --git a/src/tiled/changelayer.cpp b/src/tiled/changelayer.cpp index 39427fb664..c9818dfc30 100644 --- a/src/tiled/changelayer.cpp +++ b/src/tiled/changelayer.cpp @@ -190,6 +190,28 @@ void SetLayerParallaxFactor::setValue(Layer *layer, const QPointF &value) const } +SetLayerCompositionMode::SetLayerCompositionMode(Document *document, + QList layers, + QPainter::CompositionMode compositionMode, + QUndoCommand *parent) + : ChangeValue(document, std::move(layers), compositionMode, parent) +{ + setText(QCoreApplication::translate("Undo Commands", + "Change Layer Composition Mode")); +} + +QPainter::CompositionMode SetLayerCompositionMode::getValue(const Layer *layer) const +{ + return layer->compositionMode(); +} + +void SetLayerCompositionMode::setValue(Layer *layer, const QPainter::CompositionMode &value) const +{ + layer->setCompositionMode(value); + emit document()->changed(LayerChangeEvent(layer, LayerChangeEvent::CompositionModeProperty)); +} + + SetTileLayerSize::SetTileLayerSize(Document *document, TileLayer *tileLayer, QSize size, diff --git a/src/tiled/changelayer.h b/src/tiled/changelayer.h index a86c98b3ec..57a6af4502 100644 --- a/src/tiled/changelayer.h +++ b/src/tiled/changelayer.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace Tiled { @@ -153,6 +154,24 @@ class SetLayerParallaxFactor : public ChangeValue void setValue(Layer *layer, const QPointF &value) const override; }; +/** + * Used for changing the layer parallax factor. + */ +class SetLayerCompositionMode : public ChangeValue +{ +public: + SetLayerCompositionMode(Document *document, + QList layers, + QPainter::CompositionMode compositionMode, + QUndoCommand *parent = nullptr); + + int id() const override { return Cmd_ChangeLayerCompositionMode; } + +private: + QPainter::CompositionMode getValue(const Layer *layer) const override; + void setValue(Layer *layer, const QPainter::CompositionMode &value) const override; +}; + /** * Used for changing the tile layer size. * diff --git a/src/tiled/imagelayeritem.cpp b/src/tiled/imagelayeritem.cpp index d2ddef5333..899591110a 100644 --- a/src/tiled/imagelayeritem.cpp +++ b/src/tiled/imagelayeritem.cpp @@ -55,5 +55,6 @@ void ImageLayerItem::paint(QPainter *painter, { // TODO: Display a border around the layer when selected MapRenderer *renderer = mMapDocument->renderer(); + painter->setCompositionMode(layer()->compositionMode()); renderer->drawImageLayer(painter, imageLayer(), option->exposedRect); } diff --git a/src/tiled/mapitem.cpp b/src/tiled/mapitem.cpp index 27f0f1f4a9..db6682ba6f 100644 --- a/src/tiled/mapitem.cpp +++ b/src/tiled/mapitem.cpp @@ -548,8 +548,10 @@ void MapItem::layerChanged(const LayerChangeEvent &change) QGraphicsItem *layerItem = mLayerItems.value(layer); Q_ASSERT(layerItem); - if (change.properties & LayerChangeEvent::TintColorProperty) - layerTintColorChanged(layer); + if (change.properties & (LayerChangeEvent::TintColorProperty | + LayerChangeEvent::CompositionModeProperty)) { + updateLayerItems(layer); + } layerItem->setVisible(layer->isVisible()); @@ -584,7 +586,7 @@ void MapItem::layerChanged(const LayerChangeEvent &change) updateBoundingRect(); // possible layer offset change } -void MapItem::layerTintColorChanged(Layer *layer) +void MapItem::updateLayerItems(Layer *layer) { switch (layer->layerType()) { case Layer::TileLayerType: @@ -600,7 +602,7 @@ void MapItem::layerTintColorChanged(Layer *layer) case Layer::GroupLayerType: // Recurse into group layers since tint color is inherited for (auto childLayer : static_cast(layer)->layers()) - layerTintColorChanged(childLayer); + updateLayerItems(childLayer); break; } } diff --git a/src/tiled/mapitem.h b/src/tiled/mapitem.h index 04fefd1d67..fd651b1e25 100644 --- a/src/tiled/mapitem.h +++ b/src/tiled/mapitem.h @@ -107,7 +107,7 @@ class MapItem : public QGraphicsObject void layerAboutToBeRemoved(GroupLayer *parentLayer, int index); void layerRemoved(Layer *layer); void layerChanged(const LayerChangeEvent &change); - void layerTintColorChanged(Layer *layer); + void updateLayerItems(Layer *layer); void imageLayerChanged(ImageLayer *imageLayer); diff --git a/src/tiled/mapobjectitem.cpp b/src/tiled/mapobjectitem.cpp index 70c679fecb..959bbb1563 100644 --- a/src/tiled/mapobjectitem.cpp +++ b/src/tiled/mapobjectitem.cpp @@ -145,6 +145,8 @@ void MapObjectItem::paint(QPainter *painter, const QPointF pixelPos = renderer->pixelToScreenCoords(mObject->position()); painter->translate(-pixelPos); + if (ObjectGroup *objectGroup = mObject->objectGroup()) + painter->setCompositionMode(objectGroup->compositionMode()); renderer->drawMapObject(painter, mObject, mColors); painter->translate(pixelPos); diff --git a/src/tiled/propertieswidget.cpp b/src/tiled/propertieswidget.cpp index b2f5890cac..d171bb85aa 100644 --- a/src/tiled/propertieswidget.cpp +++ b/src/tiled/propertieswidget.cpp @@ -195,6 +195,38 @@ template<> EnumData enumData() return { names, {}, icons }; } +template<> EnumData enumData() +{ + const QStringList names { + QStringLiteral("SourceOver"), + QStringLiteral("DestinationOver"), + QStringLiteral("Clear"), + QStringLiteral("Source"), + QStringLiteral("Destination"), + QStringLiteral("SourceIn"), + QStringLiteral("DestinationIn"), + QStringLiteral("SourceOut"), + QStringLiteral("DestinationOut"), + QStringLiteral("SourceAtop"), + QStringLiteral("DestinationAtop"), + QStringLiteral("Xor"), + QStringLiteral("Plus"), + QStringLiteral("Multiply"), + QStringLiteral("Screen"), + QStringLiteral("Overlay"), + QStringLiteral("Darken"), + QStringLiteral("Lighten"), + QStringLiteral("ColorDodge"), + QStringLiteral("ColorBurn"), + QStringLiteral("HardLight"), + QStringLiteral("SoftLight"), + QStringLiteral("Difference"), + QStringLiteral("Exclusion"), + }; + + return { names }; +} + class FlippingProperty : public IntProperty { @@ -1037,6 +1069,15 @@ class LayerProperties : public ObjectProperties }); mParallaxFactorProperty->setSingleStep(0.1); + mCompositionModeProperty = new EnumProperty( + tr("Composition Mode"), + [this] { return layer()->compositionMode(); }, + [this](QPainter::CompositionMode mode) { + push(new SetLayerCompositionMode(mapDocument(), + mapDocument()->selectedLayers(), + mode)); + }); + mLayerProperties = new GroupProperty(tr("Layer")); mLayerProperties->addProperty(mIdProperty); mLayerProperties->addProperty(mNameProperty); @@ -1048,6 +1089,7 @@ class LayerProperties : public ObjectProperties mLayerProperties->addProperty(mTintColorProperty); mLayerProperties->addProperty(mOffsetProperty); mLayerProperties->addProperty(mParallaxFactorProperty); + mLayerProperties->addProperty(mCompositionModeProperty); addProperty(mLayerProperties); @@ -1114,6 +1156,7 @@ class LayerProperties : public ObjectProperties Property *mTintColorProperty; Property *mOffsetProperty; PointFProperty *mParallaxFactorProperty; + BaseEnumProperty *mCompositionModeProperty; }; class ImageLayerProperties : public LayerProperties diff --git a/src/tiled/tilelayeritem.cpp b/src/tiled/tilelayeritem.cpp index 16f1585712..b968898675 100644 --- a/src/tiled/tilelayeritem.cpp +++ b/src/tiled/tilelayeritem.cpp @@ -68,5 +68,6 @@ void TileLayerItem::paint(QPainter *painter, { MapRenderer *renderer = mMapDocument->renderer(); // TODO: Display a border around the layer when selected + painter->setCompositionMode(layer()->compositionMode()); renderer->drawTileLayer(painter, tileLayer(), option->exposedRect); } diff --git a/src/tiled/undocommands.h b/src/tiled/undocommands.h index 2627662510..3f8e2198f3 100644 --- a/src/tiled/undocommands.h +++ b/src/tiled/undocommands.h @@ -32,6 +32,7 @@ enum UndoCommands { Cmd_ChangeClassName, Cmd_ChangeImageLayerRepeatX, Cmd_ChangeImageLayerRepeatY, + Cmd_ChangeLayerCompositionMode, Cmd_ChangeLayerLocked, Cmd_ChangeLayerName, Cmd_ChangeLayerOffset,