Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAnimatedTransformMaskParamsHolder.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2016 Jouni Pentikäinen <joupent@gmail.com>
3 * SPDX-FileCopyrightText: 2021 Eoin O'Neill<eoinoneill1991@gmail.com>
4 * SPDX-FileCopyrightText: 2021 Emmet O'Neill <emmetoneill.pdx@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
11#include "tool_transform_args.h"
12#include "kis_time_span.h"
13#include "kis_transform_mask.h"
14#include "kis_image.h"
15#include "kis_transform_utils.h"
16#include <QHash>
17
18#include <kis_lod_transform.h>
21
23{
24template<>
30} // namespace KisLodSwitchingWrapperDetail
31
33
35{
36 using TransformChannels = QHash<QString, QSharedPointer<KisScalarKeyframeChannel>>;
37
39 : baseArgs(_defaultBounds)
40 , defaultBounds(_defaultBounds)
41 {
42 }
43
45 : baseArgs(rhs.baseArgs)
47 , isHidden(rhs.isHidden)
49 {
50
51 Q_FOREACH(QString otherKey, rhs.transformChannels.keys()) {
52 if (rhs.transformChannels[otherKey]){
53 transformChannels.insert(otherKey, toQShared(new KisScalarKeyframeChannel(*rhs.transformChannels[otherKey])));
54 }
55 }
56
57 }
58
62 bool isHidden {false};
63 bool isInitialized {false};
64};
65
66namespace {
67QPointF centerOffsetCurvesToArgs(const ToolTransformArgs &args)
68{
70
71 QTransform t = m.TS * m.SC * m.S * m.projectedP;
72
73
74 const QPointF calculatedOffset = t.map(args.originalCenter() + args.rotationCenterOffset());
75
82 return (args.transformedCenter() + args.rotationCenterOffset()) - calculatedOffset;
83}
84
85QPointF centerOffsetArgsToCurves(const ToolTransformArgs &args)
86{
88
89 const QPointF expectedCurveOffset =
90 m.finalTransform().map(args.originalCenter() + args.rotationCenterOffset());
91
98 return expectedCurveOffset - args.rotationCenterOffset();
99}
100
101} // namespace
102
107
112
116
118{
119 return !m_d->transformChannels.isEmpty();
120}
121
123{
125
126 if (m_d->transformChannels.isEmpty()) return args;
127 if (m_d->defaultBounds->currentLevelOfDetail() > 0) return args;
128 if (args->mode() != ToolTransformArgs::FREE_TRANSFORM) return args;
129
130
131 auto channelFor = [this] (const QString &id) -> KisScalarKeyframeChannel* {
132 KisScalarKeyframeChannel *channel = this->m_d->transformChannels.value(id, nullptr).data();
133
134 if (channel && channel->keyframeCount() > 0) {
135 return channel;
136 }
137
138 return nullptr;
139 };
140
141 {
142 // Position
143
144 KisScalarKeyframeChannel *posXChannel = channelFor(KisKeyframeChannel::PositionX.id());
145 KisScalarKeyframeChannel *posYChannel = channelFor(KisKeyframeChannel::PositionY.id());
146
147 if (posXChannel || posYChannel) {
148 qreal xPosition = posXChannel ? posXChannel->currentValue() : args->transformedCenter().x();
149 qreal yPosition = posYChannel ? posYChannel->currentValue() : args->transformedCenter().y();
150
151 args->setTransformedCenter(QPointF(xPosition, yPosition));
152 }
153 }
154
155 {
156 // Scale
157
158 KisScalarKeyframeChannel *scaleXChannel = channelFor(KisKeyframeChannel::ScaleX.id());
159 KisScalarKeyframeChannel *scaleYChannel = channelFor(KisKeyframeChannel::ScaleY.id());
160
161 if (scaleXChannel || scaleYChannel) {
162 qreal xScale = scaleXChannel ? scaleXChannel->currentValue() : args->scaleX();
163 qreal yScale = scaleYChannel ? scaleYChannel->currentValue() : args->scaleY();
164
165 args->setScaleX(xScale);
166 args->setScaleY(yScale);
167 }
168 }
169
170 {
171 // Shear
172
173 KisScalarKeyframeChannel *shearXChannel = channelFor(KisKeyframeChannel::ShearX.id());
174 KisScalarKeyframeChannel *shearYChannel = channelFor(KisKeyframeChannel::ShearY.id());
175
176 if (shearXChannel || shearYChannel) {
177 qreal xShear = shearXChannel ? shearXChannel->currentValue() : args->shearX();
178 qreal yShear = shearYChannel ? shearYChannel->currentValue() : args->shearY();
179
180 args->setShearX(xShear);
181 args->setShearY(yShear);
182 }
183 }
184
185 {
186 // Rotation
187
188 KisScalarKeyframeChannel *rotationXChannel = channelFor(KisKeyframeChannel::RotationX.id());
189 KisScalarKeyframeChannel *rotationYChannel = channelFor(KisKeyframeChannel::RotationY.id());
190 KisScalarKeyframeChannel *rotationZChannel = channelFor(KisKeyframeChannel::RotationZ.id());
191
192 if (rotationXChannel || rotationYChannel || rotationZChannel) {
193 qreal xRotation = rotationXChannel ? kisDegreesToRadians(rotationXChannel->currentValue()) : args->aX();
194 qreal yRotation = rotationYChannel ? kisDegreesToRadians(rotationYChannel->currentValue()) : args->aY();
195 qreal zRotation = rotationZChannel ? kisDegreesToRadians(rotationZChannel->currentValue()) : args->aZ();
196
197 args->setAX(xRotation);
198 args->setAY(yRotation);
199 args->setAZ(zRotation);
200 }
201 }
202
203 args->setTransformedCenter(centerOffsetCurvesToArgs(*args));
204
205 return args;
206}
207
209{
210 m_d->defaultBounds = bounds;
211 m_d->baseArgs.setDefaultBounds(bounds);
212
213 Q_FOREACH(QSharedPointer<KisScalarKeyframeChannel> channel, m_d->transformChannels) {
214 channel->setDefaultBounds(bounds);
215 }
216}
217
222
224{
225 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_d->transformChannels.contains(id), m_d->transformChannels.value(id).data());
226
230 KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->defaultBounds->currentLevelOfDetail() <= 0);
231
232 const KoID channelId = KisKeyframeChannel::channelIdToKoId(id);
233 KisScalarKeyframeChannel *channel = new KisScalarKeyframeChannel(channelId, m_d->defaultBounds);
236 m_d->transformChannels.insert(id, toQShared(channel));
237
238
239 // TODO: recover or remove this link!!!
240 //
241 // channel->connect(m_d->transformChannels[name].data(), &KisKeyframeChannel::sigAnyKeyframeChange, [this] () {
242 // this->clearChangedFlag();
243 // });
244
245 return channel;
246}
247
249{
250 return m_d->transformChannels.value(id, nullptr).data();
251}
252
254{
256
258 return args->transformedCenter().x();
259 } else if (id == KisKeyframeChannel::PositionY) {
260 return args->transformedCenter().y();
261 } else if (id == KisKeyframeChannel::ScaleX) {
262 return args->scaleX();
263 } else if (id == KisKeyframeChannel::ScaleY) {
264 return args->scaleY();
265 } else if (id == KisKeyframeChannel::ShearX) {
266 return args->shearX();
267 } else if (id == KisKeyframeChannel::ShearY) {
268 return args->shearY();
269 } else if (id == KisKeyframeChannel::RotationX) {
270 return kisRadiansToDegrees(args->aX());
271 } else if (id == KisKeyframeChannel::RotationY) {
272 return kisRadiansToDegrees(args->aY());
273 } else if (id == KisKeyframeChannel::RotationZ) {
274 return kisRadiansToDegrees(args->aZ());
275 } else {
276 return 0.0f;
277 }
278}
279
281{
282 m_d->baseArgs.syncLodCache();
283}
284
289
294
296{
297 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->transformChannels.isEmpty() || m_d->transformChannels.size() == 9);
298
299 const KisTransformMaskAdapter *adapter = dynamic_cast<const KisTransformMaskAdapter*>(params);
301
302 makeChangeValueCommand<&Private::isHidden>(m_d.data(), adapter->isHidden(), parentCommand);
303 makeChangeValueCommand<&Private::isInitialized>(m_d.data(), adapter->isInitialized(), parentCommand);
304
305 setNewTransformArgs(*adapter->transformArgs(), parentCommand);
306}
307
309{
310 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->transformChannels.isEmpty() || m_d->transformChannels.size() == 9);
311
312 struct ChangeParamsCommand : KisChangeValueCommand<&Private::baseArgs, KisLodCapableTransformArgs::LodState>
313 {
314 ChangeParamsCommand(Private *base,
316 KUndo2Command *parent = nullptr)
317 : KisChangeValueCommand(base, newValue, parent)
318 {
319 KIS_SAFE_ASSERT_RECOVER_NOOP(m_oldValue.first == m_newValue.first);
320 }
321 };
322
323 const QPointF layerCenterOffset = args.originalCenter() - m_d->baseArgs->originalCenter();
324
325 new ChangeParamsCommand(m_d.data(), std::make_pair(m_d->defaultBounds->currentLevelOfDetail(), args), parentCommand);
326
327 if (m_d->transformChannels.isEmpty()) return;
328 if (m_d->defaultBounds->currentLevelOfDetail() > 0) return;
329 if (args.mode() != ToolTransformArgs::FREE_TRANSFORM) return;
330
331 if (!layerCenterOffset.isNull()) {
337 auto translateChannel = [this] (const KoID &channelId, qreal offset, KUndo2Command *parentCommand)
338 {
339 KisScalarKeyframeChannel *channel = m_d->transformChannels.value(channelId.id()).data();
341
342 Q_FOREACH(int time, channel->allKeyframeTimes()) {
343 KisScalarKeyframeSP keyframe = channel->keyframeAt(time).dynamicCast<KisScalarKeyframe>();
344 KIS_SAFE_ASSERT_RECOVER(keyframe) { break; }
345 keyframe->setValue(keyframe->value() + offset, parentCommand);
346 }
347 };
348
349 translateChannel(KisKeyframeChannel::PositionX, layerCenterOffset.x(), parentCommand);
350 translateChannel(KisKeyframeChannel::PositionY, layerCenterOffset.y(), parentCommand);
351 }
352
353 const int currentTime = m_d->defaultBounds->currentTime();
354
355 auto setKeyframe = [this] (const KoID &channelId, int time, qreal value, KUndo2Command *parentCommand)
356 {
357 KisScalarKeyframeChannel *channel = m_d->transformChannels.value(channelId.id()).data();
359
360 if (channel->keyframeAt(time)){
361 KisScalarKeyframeSP keyframe = channel->keyframeAt<KisScalarKeyframe>(time);
362 keyframe->setValue(value, parentCommand);
363 }
364 };
365
366 const QPointF curvesCenterOffset = centerOffsetArgsToCurves(args);
367
368 setKeyframe(KisKeyframeChannel::PositionX, currentTime, curvesCenterOffset.x(), parentCommand);
369 setKeyframe(KisKeyframeChannel::PositionY, currentTime, curvesCenterOffset.y(), parentCommand);
370
371 setKeyframe(KisKeyframeChannel::ScaleX, currentTime, args.scaleX(), parentCommand);
372 setKeyframe(KisKeyframeChannel::ScaleY, currentTime, args.scaleY(), parentCommand);
373
374 setKeyframe(KisKeyframeChannel::ShearX, currentTime, args.shearX(), parentCommand);
375 setKeyframe(KisKeyframeChannel::ShearY, currentTime, args.shearY(), parentCommand);
376
377 setKeyframe(KisKeyframeChannel::RotationX, currentTime, kisRadiansToDegrees(args.aX()), parentCommand);
378 setKeyframe(KisKeyframeChannel::RotationY, currentTime, kisRadiansToDegrees(args.aY()), parentCommand);
379 setKeyframe(KisKeyframeChannel::RotationZ, currentTime, kisRadiansToDegrees(args.aZ()), parentCommand);
380}
381
float value(const T *src, size_t ch)
const QSharedPointer< ToolTransformArgs > transformArgs() const
KisAnimatedTransformParamsHolderInterfaceSP clone() const override
KisKeyframeChannel * requestKeyframeChannel(const QString &id) override
KisDefaultBoundsBaseSP defaultBounds() const override
void setParamsAtCurrentPosition(const KisTransformMaskParamsInterface *params, KUndo2Command *parentCommand) override
KisTransformMaskParamsInterfaceSP bakeIntoParams() const override
KisKeyframeChannel * getKeyframeChannel(const QString &id) const override
void setDefaultBounds(KisDefaultBoundsBaseSP bounds) override
KisAnimatedTransformMaskParamsHolder(KisDefaultBoundsBaseSP defaultBounds)
void setNewTransformArgs(const ToolTransformArgs &args, KUndo2Command *parentCommand)
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
static const KoID RotationY
static const KoID ScaleY
KisKeyframeSP keyframeAt(int time) const
Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
static const KoID RotationZ
static KoID channelIdToKoId(const QString &id)
static const KoID ScaleX
static const KoID RotationX
static const KoID PositionX
static const KoID PositionY
static const KoID ShearX
static const KoID ShearY
static qreal lodToScale(int levelOfDetail)
The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisSca...
void setDefaultInterpolationMode(KisScalarKeyframe::InterpolationMode mode)
The KisScalarKeyframe class is a concrete subclass of KisKeyframe that wraps a scalar value and inter...
virtual const QSharedPointer< ToolTransformArgs > transformArgs() const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
QPointF transformedCenter() const
void scale3dSrcAndDst(qreal scale)
QPointF originalCenter() const
QPointF rotationCenterOffset() const
TransformMode mode() const
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define bounds(x, a, b)
T kisRadiansToDegrees(T radians)
Definition kis_global.h:181
T kisDegreesToRadians(T degrees)
Definition kis_global.h:176
QSharedPointer< T > toQShared(T *ptr)
ToolTransformArgs syncLodNValue< ToolTransformArgs >(const ToolTransformArgs &value, int lod)
QHash< QString, QSharedPointer< KisScalarKeyframeChannel > > TransformChannels