Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per-object opacity #4031

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# General build artifacts
default/
build/

# clangd cache
.cache/
Expand Down
8 changes: 8 additions & 0 deletions docs/reference/json-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ Object
polyline, array, "Array of :ref:`Points <json-point>`, in case the object is a polyline"
properties, array, "Array of :ref:`Properties <json-property>`"
rotation, double, "Angle in degrees clockwise"
opacity, double, "The opacity of the object as a value from 0 to 1. Defaults to 1."
template, string, "Reference to a template file, in case object is a :doc:`template instance </manual/using-templates>`"
text, :ref:`json-object-text`, "Only used for text objects"
type, string, "The class of the object (was saved as ``class`` in 1.9, optional)"
Expand All @@ -241,6 +242,7 @@ Object Example
"value":12
}],
"rotation":0,
"opacity":1,
"type":"npc",
"visible":true,
"width":0,
Expand All @@ -259,6 +261,7 @@ Ellipse Example
"id":13,
"name":"",
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":248,
Expand All @@ -276,6 +279,7 @@ Rectangle Example
"id":14,
"name":"",
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":368,
Expand All @@ -294,6 +298,7 @@ Point Example
"name":"",
"point":true,
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":0,
Expand Down Expand Up @@ -332,6 +337,7 @@ Polygon Example
"y":-288
}],
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":0,
Expand Down Expand Up @@ -374,6 +380,7 @@ Polyline Example
"y":0
}],
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":0,
Expand All @@ -396,6 +403,7 @@ Text Example
"wrap":true
},
"rotation":0,
"opacity":1,
"type":"",
"visible":true,
"width":248,
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/tmx-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,8 @@ Can contain any number: :ref:`tmx-object`
- **height:** The height of the object in pixels. (defaults to 0)
- **rotation:** The rotation of the object in degrees clockwise around (x, y).
(defaults to 0)
- **opacity:** The opacity of the object as a value from 0 to 1. (defaults
to 1)
- **gid:** A reference to a tile. (optional)
- **visible:** Whether the object is shown (1) or hidden (0). (defaults to
1)
Expand Down
7 changes: 7 additions & 0 deletions src/libtiled/mapobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ QVariant MapObject::mapObjectProperty(Property property) const
case PositionProperty: return mPos;
case SizeProperty: return mSize;
case RotationProperty: return mRotation;
case OpacityProperty: return mOpacity;
case CellProperty: Q_ASSERT(false); break;
case ShapeProperty: return mShape;
case TemplateProperty: Q_ASSERT(false); break;
Expand All @@ -334,6 +335,7 @@ void MapObject::setMapObjectProperty(Property property, const QVariant &value)
case PositionProperty: setPosition(value.toPointF()); break;
case SizeProperty: setSize(value.toSizeF()); break;
case RotationProperty: setRotation(value.toReal()); break;
case OpacityProperty: setOpacity(value.toReal()); break;
case CellProperty: Q_ASSERT(false); break;
case ShapeProperty: setShape(value.value<Shape>()); break;
case TemplateProperty: Q_ASSERT(false); break;
Expand Down Expand Up @@ -374,6 +376,7 @@ MapObject *MapObject::clone() const
o->setShape(mShape);
o->setCell(mCell);
o->setRotation(mRotation);
o->setOpacity(mOpacity);
o->setVisible(mVisible);
o->setChangedProperties(mChangedProperties);
o->setObjectTemplate(mObjectTemplate);
Expand All @@ -389,6 +392,7 @@ void MapObject::copyPropertiesFrom(const MapObject *object)
setShape(object->shape());
setCell(object->cell());
setRotation(object->rotation());
setOpacity(object->opacity());
setVisible(object->isVisible());
setProperties(object->properties());
setChangedProperties(object->changedProperties());
Expand Down Expand Up @@ -428,6 +432,9 @@ void MapObject::syncWithTemplate()
if (!propertyChanged(MapObject::RotationProperty))
setRotation(base->rotation());

if (!propertyChanged(MapObject::OpacityProperty))
setOpacity(base->opacity());

if (!propertyChanged(MapObject::VisibleProperty))
setVisible(base->isVisible());
}
Expand Down
25 changes: 21 additions & 4 deletions src/libtiled/mapobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,11 @@ class TILEDSHARED_EXPORT MapObject : public Object
PositionProperty = 1 << 7,
SizeProperty = 1 << 8,
RotationProperty = 1 << 9,
CellProperty = 1 << 10,
ShapeProperty = 1 << 11,
TemplateProperty = 1 << 12,
CustomProperties = 1 << 13,
OpacityProperty = 1 << 10,
CellProperty = 1 << 11,
ShapeProperty = 1 << 12,
TemplateProperty = 1 << 13,
CustomProperties = 1 << 14,
AllProperties = 0xFF
};

Expand Down Expand Up @@ -200,6 +201,9 @@ class TILEDSHARED_EXPORT MapObject : public Object
qreal rotation() const;
void setRotation(qreal rotation);

qreal opacity() const;
void setOpacity(qreal opacity);

Alignment alignment(const Map *map = nullptr) const;

bool isVisible() const;
Expand Down Expand Up @@ -247,6 +251,7 @@ class TILEDSHARED_EXPORT MapObject : public Object
const ObjectTemplate *mObjectTemplate = nullptr;
ObjectGroup *mObjectGroup = nullptr;
qreal mRotation = 0.0;
qreal mOpacity = 1.0;
bool mVisible = true;
bool mTemplateBase = false;
ChangedProperties mChangedProperties;
Expand Down Expand Up @@ -479,6 +484,18 @@ inline qreal MapObject::rotation() const
inline void MapObject::setRotation(qreal rotation)
{ mRotation = rotation; }

/**
* Returns the opacity of the object.
*/
inline qreal MapObject::opacity() const
{ return mOpacity; }

/**
* Sets the opacity of the object.
*/
inline void MapObject::setOpacity(qreal opacity)
{ mOpacity = opacity; }

inline bool MapObject::isVisible() const
{ return mVisible; }

Expand Down
6 changes: 6 additions & 0 deletions src/libtiled/mapreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,12 @@ std::unique_ptr<MapObject> MapReaderPrivate::readObject()
object->setPropertyChanged(MapObject::RotationProperty);
}

const qreal opacity = atts.value(QLatin1String("opacity")).toDouble(&ok);
if (ok) {
object->setOpacity(opacity);
object->setPropertyChanged(MapObject::OpacityProperty);
}

if (gid) {
object->setCell(cellForGid(gid));
object->setPropertyChanged(MapObject::CellProperty);
Expand Down
3 changes: 3 additions & 0 deletions src/libtiled/maptovariantconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,9 @@ QVariant MapToVariantConverter::toVariant(const MapObject &object) const
if (notTemplateInstance || object.propertyChanged(MapObject::RotationProperty))
objectVariant[QStringLiteral("rotation")] = object.rotation();

if (notTemplateInstance || object.propertyChanged(MapObject::OpacityProperty))
objectVariant[QStringLiteral("opacity")] = object.opacity();

if (notTemplateInstance || object.propertyChanged(MapObject::VisibleProperty))
objectVariant[QStringLiteral("visible")] = object.isVisible();

Expand Down
4 changes: 4 additions & 0 deletions src/libtiled/mapwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,10 @@ void MapWriterPrivate::writeObject(QXmlStreamWriter &w,
if (shouldWrite(rotation != 0.0, isTemplateInstance, mapObject.propertyChanged(MapObject::RotationProperty)))
w.writeAttribute(QStringLiteral("rotation"), QString::number(rotation));

const qreal opacity = mapObject.opacity();
if (shouldWrite(opacity != 1.0, isTemplateInstance, mapObject.propertyChanged(MapObject::OpacityProperty)))
w.writeAttribute(QStringLiteral("opacity"), QString::number(opacity));

if (shouldWrite(!mapObject.isVisible(), isTemplateInstance, mapObject.propertyChanged(MapObject::VisibleProperty)))
w.writeAttribute(QStringLiteral("visible"), QLatin1String(mapObject.isVisible() ? "1" : "0"));

Expand Down
2 changes: 2 additions & 0 deletions src/libtiled/minimaprenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ void MiniMapRenderer::renderToImage(QImage &image, RenderFlags renderFlags) cons
painter.translate(-origin);
}

painter.setOpacity(object->opacity());
Copy link
Member

@bjorn bjorn Aug 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to store the above layer->effectiveOpacity() in a variable and set the opacity to layerOpacity * object->opacity() here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow. I don't think I would have even considered that. This is one of my fears of being a contributor. I do not know the full requirements for such a project. I am just learning qt to be honest.


mRenderer->drawMapObject(&painter, object, object->effectiveColors());

if (object->rotation() != qreal(0))
Expand Down
6 changes: 6 additions & 0 deletions src/libtiled/varianttomapconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ std::unique_ptr<MapObject> VariantToMapConverter::toMapObject(const QVariantMap
const qreal width = variantMap[QStringLiteral("width")].toReal();
const qreal height = variantMap[QStringLiteral("height")].toReal();
const qreal rotation = variantMap[QStringLiteral("rotation")].toReal();
const qreal opacity = variantMap[QStringLiteral("opacity")].toReal();

QString className = variantMap[QStringLiteral("class")].toString();
if (className.isEmpty()) // fallback for compatibility
Expand All @@ -738,6 +739,11 @@ std::unique_ptr<MapObject> VariantToMapConverter::toMapObject(const QVariantMap
object->setPropertyChanged(MapObject::RotationProperty);
}

if (variantMap.contains(QLatin1String("opacity"))) {
object->setOpacity(opacity);
object->setPropertyChanged(MapObject::OpacityProperty);
}

if (!templateVariant.isNull()) { // This object is a template instance
QString templateFileName = resolvePath(mDir, templateVariant);
auto objectTemplate = TemplateManager::instance()->loadObjectTemplate(templateFileName);
Expand Down
1 change: 1 addition & 0 deletions src/plugins/lua/luaplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,7 @@ void LuaWriter::writeMapObject(const Tiled::MapObject *mapObject)
mWriter.writeKeyAndValue("width", mapObject->width());
mWriter.writeKeyAndValue("height", mapObject->height());
mWriter.writeKeyAndValue("rotation", mapObject->rotation());
mWriter.writeKeyAndValue("opacity", mapObject->opacity());

if (!mapObject->cell().isEmpty())
mWriter.writeKeyAndValue("gid", mGidMapper.cellToGid(mapObject->cell()));
Expand Down
31 changes: 31 additions & 0 deletions src/plugins/python/pythonbind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6985,6 +6985,18 @@ _wrap_PyTiledMapObject_objectGroup(PyTiledMapObject *self, PyObject *PYBINDGEN_U
}


PyObject *
_wrap_PyTiledMapObject_opacity(PyTiledMapObject *self, PyObject *PYBINDGEN_UNUSED(_args), PyObject *PYBINDGEN_UNUSED(_kwargs))
{
PyObject *py_retval;
double retval;

retval = self->obj->opacity();
py_retval = Py_BuildValue((char *) "d", retval);
return py_retval;
}


PyObject *
_wrap_PyTiledMapObject_rotation(PyTiledMapObject *self, PyObject *PYBINDGEN_UNUSED(_args), PyObject *PYBINDGEN_UNUSED(_kwargs))
{
Expand Down Expand Up @@ -7049,6 +7061,23 @@ _wrap_PyTiledMapObject_setName(PyTiledMapObject *self, PyObject *args, PyObject
}


PyObject *
_wrap_PyTiledMapObject_setOpacity(PyTiledMapObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *py_retval;
double opacity;
const char *keywords[] = {"opacity", NULL};

if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "d", (char **) keywords, &opacity)) {
return NULL;
}
self->obj->setOpacity(opacity);
Py_INCREF(Py_None);
py_retval = Py_None;
return py_retval;
}


PyObject *
_wrap_PyTiledMapObject_setPosition(PyTiledMapObject *self, PyObject *args, PyObject *kwargs)
{
Expand Down Expand Up @@ -7271,10 +7300,12 @@ static PyMethodDef PyTiledMapObject_methods[] = {
{(char *) "isVisible", (PyCFunction) _wrap_PyTiledMapObject_isVisible, METH_NOARGS, "isVisible()\n\n" },
{(char *) "name", (PyCFunction) _wrap_PyTiledMapObject_name, METH_NOARGS, "name()\n\n" },
{(char *) "objectGroup", (PyCFunction) _wrap_PyTiledMapObject_objectGroup, METH_NOARGS, "objectGroup()\n\n" },
{(char *) "opacity", (PyCFunction) _wrap_PyTiledMapObject_opacity, METH_NOARGS, "opacity()\n\n" },
{(char *) "rotation", (PyCFunction) _wrap_PyTiledMapObject_rotation, METH_NOARGS, "rotation()\n\n" },
{(char *) "setCell", (PyCFunction) _wrap_PyTiledMapObject_setCell, METH_KEYWORDS|METH_VARARGS, "setCell(c)\n\ntype: c: Tiled::Cell const" },
{(char *) "setHeight", (PyCFunction) _wrap_PyTiledMapObject_setHeight, METH_KEYWORDS|METH_VARARGS, "setHeight(h)\n\ntype: h: double" },
{(char *) "setName", (PyCFunction) _wrap_PyTiledMapObject_setName, METH_KEYWORDS|METH_VARARGS, "setName(n)\n\ntype: n: QString" },
{(char *) "setOpacity", (PyCFunction) _wrap_PyTiledMapObject_setOpacity, METH_KEYWORDS|METH_VARARGS, "setOpacity(opacity)\n\ntype: opacity: double" },
{(char *) "setPosition", (PyCFunction) _wrap_PyTiledMapObject_setPosition, METH_KEYWORDS|METH_VARARGS, "setPosition(pos)\n\ntype: pos: QPointF" },
{(char *) "setRotation", (PyCFunction) _wrap_PyTiledMapObject_setRotation, METH_KEYWORDS|METH_VARARGS, "setRotation(r)\n\ntype: r: double" },
{(char *) "setShape", (PyCFunction) _wrap_PyTiledMapObject_setShape, METH_KEYWORDS|METH_VARARGS, "setShape(s)\n\ntype: s: Tiled::MapObject::Shape" },
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/python/tiledbinding.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ def _decorate(obj, *args, **kwargs):
cls_mapobject.add_method('objectGroup', retval('Tiled::ObjectGroup*',reference_existing_object=True), [])
cls_mapobject.add_method('rotation', 'double', [])
cls_mapobject.add_method('setRotation', None, [('double','r')])
cls_mapobject.add_method('opacity', 'double', [])
cls_mapobject.add_method('setOpacity', None, [('double','opacity')])
cls_mapobject.add_method('isVisible', 'bool', [])
cls_mapobject.add_method('setVisible', None, [('bool','v')])
cls_mapobject.add_method('name', 'QString', [])
Expand Down
5 changes: 5 additions & 0 deletions src/tiled/editablemapobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ void EditableMapObject::setRotation(qreal rotation)
setMapObjectProperty(MapObject::RotationProperty, rotation);
}

void EditableMapObject::setOpacity(qreal opacity)
{
setMapObjectProperty(MapObject::OpacityProperty, opacity);
}

void EditableMapObject::setVisible(bool visible)
{
setMapObjectProperty(MapObject::VisibleProperty, visible);
Expand Down
8 changes: 8 additions & 0 deletions src/tiled/editablemapobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class EditableMapObject : public EditableObject
Q_PROPERTY(qreal height READ height WRITE setHeight)
Q_PROPERTY(QSizeF size READ size WRITE setSize)
Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible)
Q_PROPERTY(QJSValue polygon READ polygon WRITE setPolygon)
Q_PROPERTY(QString text READ text WRITE setText)
Expand Down Expand Up @@ -114,6 +115,7 @@ class EditableMapObject : public EditableObject
qreal height() const;
QSizeF size() const;
qreal rotation() const;
qreal opacity() const;
bool isVisible() const;
QJSValue polygon() const;
QString text() const;
Expand Down Expand Up @@ -149,6 +151,7 @@ public slots:
void setHeight(qreal height);
void setSize(QSizeF size);
void setRotation(qreal rotation);
void setOpacity(qreal opacity);
void setVisible(bool visible);
void setPolygon(QJSValue polygon);
void setPolygon(const QPolygonF &polygon);
Expand Down Expand Up @@ -219,6 +222,11 @@ inline qreal EditableMapObject::rotation() const
return mapObject()->rotation();
}

inline qreal EditableMapObject::opacity() const
{
return mapObject()->opacity();
}

inline bool EditableMapObject::isVisible() const
{
return mapObject()->isVisible();
Expand Down
1 change: 1 addition & 0 deletions src/tiled/mapobjectitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ void MapObjectItem::syncWithMapObject()

setPos(pixelPos);
setRotation(mObject->rotation());
setOpacity(mObject->opacity());

if (mBoundingRect != bounds) {
// Notify the graphics scene about the geometry change in advance
Expand Down
12 changes: 12 additions & 0 deletions src/tiled/propertybrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,11 @@ void PropertyBrowser::addMapObjectProperties()
bool isPoint = mapObject->shape() == MapObject::Point;
addProperty(RotationProperty, QMetaType::Double, tr("Rotation"), groupProperty)->setEnabled(!isPoint);

QtVariantProperty *opacityProperty = addProperty(OpacityProperty, QMetaType::Double, tr("Opacity"), groupProperty);
opacityProperty->setAttribute(QLatin1String("minimum"), 0.0);
opacityProperty->setAttribute(QLatin1String("maximum"), 1.0);
opacityProperty->setAttribute(QLatin1String("singleStep"), 0.1);

if (mMapObjectFlags & ObjectHasTile) {
QtVariantProperty *flippingProperty =
addProperty(FlippingProperty, VariantPropertyManager::flagTypeId(),
Expand Down Expand Up @@ -1296,6 +1301,12 @@ QUndoCommand *PropertyBrowser::applyMapObjectValueTo(PropertyId id, const QVaria
val.toDouble());
}
break;
case OpacityProperty:{
command = new ChangeMapObject(mDocument, mapObject,
MapObject::OpacityProperty,
val.toReal());
break;
}
case FlippingProperty: {
const int flippingFlags = val.toInt();

Expand Down Expand Up @@ -1905,6 +1916,7 @@ void PropertyBrowser::updateProperties()
}

mIdToProperty[RotationProperty]->setValue(mapObject->rotation());
mIdToProperty[OpacityProperty]->setValue(mapObject->opacity());

if (flags & ObjectHasTile) {
int flippingFlags = 0;
Expand Down
Loading