1 /*
2 * Copyright (c) 2016 Jouni Pentikäinen <joupent@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "kis_animated_transform_parameters.h"
20 #include "kis_scalar_keyframe_channel.h"
21 #include "kis_transform_args_keyframe_channel.h"
22 #include "tool_transform_args.h"
23 #include "kis_time_range.h"
24 #include "kis_transform_mask.h"
25
26 struct KisAnimatedTransformMaskParameters::Private
27 {
PrivateKisAnimatedTransformMaskParameters::Private28 Private() :
29 hidden(false),
30 argsCache()
31 {}
32
33 KisTransformArgsKeyframeChannel *rawArgsChannel{0};
34
35 KisScalarKeyframeChannel *positionXchannel{0};
36 KisScalarKeyframeChannel *positionYchannel{0};
37 KisScalarKeyframeChannel *scaleXchannel{0};
38 KisScalarKeyframeChannel *scaleYchannel{0};
39 KisScalarKeyframeChannel *shearXchannel{0};
40 KisScalarKeyframeChannel *shearYchannel{0};
41 KisScalarKeyframeChannel *rotationXchannel{0};
42 KisScalarKeyframeChannel *rotationYchannel{0};
43 KisScalarKeyframeChannel *rotationZchannel{0};
44
45 bool hidden;
46 KisTimeRange validRange;
47
48 ToolTransformArgs argsCache;
49
currentRawArgsKisAnimatedTransformMaskParameters::Private50 ToolTransformArgs ¤tRawArgs()
51 {
52 if (!rawArgsChannel) return argsCache;
53
54 KisKeyframeSP keyframe = rawArgsChannel->currentlyActiveKeyframe();
55 if (keyframe.isNull()) return argsCache;
56
57 return rawArgsChannel->transformArgs(keyframe);
58 }
59
getChannelKisAnimatedTransformMaskParameters::Private60 KisScalarKeyframeChannel *getChannel(KisScalarKeyframeChannel * Private::*field, const KoID &channelId, KisNodeSP parent)
61 {
62 KisScalarKeyframeChannel *channel = this->*field;
63
64 if (!channel) {
65 channel = this->*field = new KisScalarKeyframeChannel(channelId, -qInf(), qInf(), parent, KisKeyframe::Linear);
66 }
67
68 return channel;
69 }
70 };
71
KisAnimatedTransformMaskParameters()72 KisAnimatedTransformMaskParameters::KisAnimatedTransformMaskParameters()
73 : KisTransformMaskAdapter(ToolTransformArgs()),
74 m_d(new Private())
75 {
76 }
77
KisAnimatedTransformMaskParameters(const KisTransformMaskAdapter * staticTransform)78 KisAnimatedTransformMaskParameters::KisAnimatedTransformMaskParameters(const KisTransformMaskAdapter *staticTransform)
79 : KisTransformMaskAdapter(staticTransform->transformArgs()),
80 m_d(new Private())
81 {
82 m_d->argsCache = staticTransform->transformArgs();
83 }
84
~KisAnimatedTransformMaskParameters()85 KisAnimatedTransformMaskParameters::~KisAnimatedTransformMaskParameters()
86 {}
87
getInterpolatedPoint(QPointF def,KisScalarKeyframeChannel * xChannel,KisScalarKeyframeChannel * yChannel)88 QPointF getInterpolatedPoint(QPointF def, KisScalarKeyframeChannel *xChannel, KisScalarKeyframeChannel *yChannel)
89 {
90 if (xChannel) {
91 qreal x = xChannel->currentValue();
92 if (!qIsNaN(x)) def.setX(x);
93 }
94
95 if (yChannel) {
96 qreal y = yChannel->currentValue();
97 if (!qIsNaN(y)) def.setY(y);
98 }
99
100 return def;
101 }
102
getInterpolatedValue(KisScalarKeyframeChannel * channel,qreal defaultValue)103 qreal getInterpolatedValue(KisScalarKeyframeChannel *channel, qreal defaultValue)
104 {
105 if (!channel) return defaultValue;
106 qreal value = channel->currentValue();
107 if (qIsNaN(value)) return defaultValue;
108 return value;
109 }
110
transformArgs() const111 const ToolTransformArgs &KisAnimatedTransformMaskParameters::transformArgs() const
112 {
113 m_d->argsCache = m_d->currentRawArgs();
114
115 QPointF pos = getInterpolatedPoint(m_d->argsCache.transformedCenter(), m_d->positionXchannel, m_d->positionYchannel);
116 m_d->argsCache.setTransformedCenter(pos);
117
118 m_d->argsCache.setScaleX(getInterpolatedValue(m_d->scaleXchannel, m_d->argsCache.scaleX()));
119 m_d->argsCache.setScaleY(getInterpolatedValue(m_d->scaleYchannel, m_d->argsCache.scaleY()));
120
121 m_d->argsCache.setShearX(getInterpolatedValue(m_d->shearXchannel, m_d->argsCache.shearX()));
122 m_d->argsCache.setShearY(getInterpolatedValue(m_d->shearYchannel, m_d->argsCache.shearY()));
123
124 m_d->argsCache.setAX(normalizeAngle(getInterpolatedValue(m_d->rotationXchannel, m_d->argsCache.aX())));
125 m_d->argsCache.setAY(normalizeAngle(getInterpolatedValue(m_d->rotationYchannel, m_d->argsCache.aY())));
126 m_d->argsCache.setAZ(normalizeAngle(getInterpolatedValue(m_d->rotationZchannel, m_d->argsCache.aZ())));
127
128 return m_d->argsCache;
129 }
130
id() const131 QString KisAnimatedTransformMaskParameters::id() const
132 {
133 return "animatedtransformparams";
134 }
135
toXML(QDomElement * e) const136 void KisAnimatedTransformMaskParameters::toXML(QDomElement *e) const
137 {
138 Q_UNUSED(e);
139 }
140
fromXML(const QDomElement & e)141 KisTransformMaskParamsInterfaceSP KisAnimatedTransformMaskParameters::fromXML(const QDomElement &e)
142 {
143 Q_UNUSED(e);
144 return toQShared(new KisAnimatedTransformMaskParameters());
145 }
146
animate(KisTransformMaskParamsInterfaceSP params)147 KisTransformMaskParamsInterfaceSP KisAnimatedTransformMaskParameters::animate(KisTransformMaskParamsInterfaceSP params)
148 {
149 KisTransformMaskParamsInterface *animatedParams;
150
151 KisTransformMaskAdapter *tma = dynamic_cast<KisTransformMaskAdapter*>(params.data());
152 if (tma) {
153 animatedParams = new KisAnimatedTransformMaskParameters(tma);
154 } else {
155 animatedParams = new KisAnimatedTransformMaskParameters();
156 }
157
158 return toQShared(animatedParams);
159 }
160
translate(const QPointF & offset)161 void KisAnimatedTransformMaskParameters::translate(const QPointF &offset)
162 {
163 ToolTransformArgs &args = m_d->currentRawArgs();
164 args.translate(offset);
165 }
166
getKeyframeChannel(const QString & id,KisNodeSP parent)167 KisKeyframeChannel *KisAnimatedTransformMaskParameters::getKeyframeChannel(const QString &id, KisNodeSP parent)
168 {
169 if (id == KisKeyframeChannel::TransformArguments.id()) {
170 if (!m_d->rawArgsChannel) {
171 m_d->rawArgsChannel = new KisTransformArgsKeyframeChannel(KisKeyframeChannel::TransformArguments, parent, m_d->currentRawArgs());
172 }
173 return m_d->rawArgsChannel;
174 } else {
175 KisScalarKeyframeChannel * Private::*field = 0;
176 KoID channelId;
177
178 if (id == KisKeyframeChannel::TransformPositionX.id()) {
179 channelId = KisKeyframeChannel::TransformPositionX;
180 field = &Private::positionXchannel;
181 } else if (id == KisKeyframeChannel::TransformPositionY.id()) {
182 channelId = KisKeyframeChannel::TransformPositionY;
183 field = &Private::positionYchannel;
184 } else if (id == KisKeyframeChannel::TransformScaleX.id()) {
185 channelId = KisKeyframeChannel::TransformScaleX;
186 field = &Private::scaleXchannel;
187 } else if (id == KisKeyframeChannel::TransformScaleY.id()) {
188 channelId = KisKeyframeChannel::TransformScaleY;
189 field = &Private::scaleYchannel;
190 } else if (id == KisKeyframeChannel::TransformShearX.id()) {
191 channelId = KisKeyframeChannel::TransformShearX;
192 field = &Private::shearXchannel;
193 } else if (id == KisKeyframeChannel::TransformShearY.id()) {
194 channelId = KisKeyframeChannel::TransformShearY;
195 field = &Private::shearYchannel;
196 } else if (id == KisKeyframeChannel::TransformRotationX.id()) {
197 channelId = KisKeyframeChannel::TransformRotationX;
198 field = &Private::rotationXchannel;
199 } else if (id == KisKeyframeChannel::TransformRotationY.id()) {
200 channelId = KisKeyframeChannel::TransformRotationY;
201 field = &Private::rotationYchannel;
202 } else if (id == KisKeyframeChannel::TransformRotationZ.id()) {
203 channelId = KisKeyframeChannel::TransformRotationZ;
204 field = &Private::rotationZchannel;
205 }
206
207 if (field) {
208 return m_d->getChannel(field, channelId, parent);
209 }
210 }
211
212 return 0;
213 }
214
isHidden() const215 bool KisAnimatedTransformMaskParameters::isHidden() const
216 {
217 return m_d->hidden;
218 }
219
setHidden(bool hidden)220 void KisAnimatedTransformMaskParameters::setHidden(bool hidden)
221 {
222 m_d->hidden = hidden;
223 }
224
clearChangedFlag()225 void KisAnimatedTransformMaskParameters::clearChangedFlag()
226 {
227 int currentTime = (m_d->rawArgsChannel) ? m_d->rawArgsChannel->currentTime() : 0;
228
229 KisTimeRange validRange = KisTimeRange::infinite(0);
230
231 if (m_d->rawArgsChannel) validRange &= m_d->rawArgsChannel->identicalFrames(currentTime);
232 if (m_d->positionXchannel) validRange &= m_d->positionXchannel->identicalFrames(currentTime);
233 if (m_d->positionYchannel) validRange &= m_d->positionYchannel->identicalFrames(currentTime);
234
235 m_d->validRange = validRange;
236 }
237
hasChanged() const238 bool KisAnimatedTransformMaskParameters::hasChanged() const
239 {
240 int currentTime = (m_d->rawArgsChannel) ? m_d->rawArgsChannel->currentTime() : 0;
241 bool valid = m_d->validRange.contains(currentTime);
242 return !valid;
243 }
244
isAnimated() const245 bool KisAnimatedTransformMaskParameters::isAnimated() const
246 {
247 return true;
248 }
249
setScalarChannelValue(KisTransformMaskSP mask,const KoID & channelId,int time,qreal value,KUndo2Command * parentCommand)250 void setScalarChannelValue(KisTransformMaskSP mask, const KoID &channelId, int time, qreal value, KUndo2Command *parentCommand)
251 {
252 KisScalarKeyframeChannel *channel = dynamic_cast<KisScalarKeyframeChannel*>(mask->getKeyframeChannel(channelId.id(), true));
253 KIS_ASSERT_RECOVER_RETURN(channel);
254 new KisScalarKeyframeChannel::AddKeyframeCommand(channel, time, value, parentCommand);
255 }
256
addKeyframes(KisTransformMaskSP mask,int time,KisTransformMaskParamsInterfaceSP params,KUndo2Command * parentCommand)257 void KisAnimatedTransformMaskParameters::addKeyframes(KisTransformMaskSP mask, int time, KisTransformMaskParamsInterfaceSP params, KUndo2Command *parentCommand)
258 {
259 KisTransformMaskParamsInterfaceSP currentParams = mask->transformParams();
260 if (dynamic_cast<KisAnimatedTransformMaskParameters*>(currentParams.data()) == 0) {
261 mask->setTransformParams(animate(currentParams));
262 }
263
264 if (params.isNull()) {
265 params = currentParams;
266 }
267
268 ToolTransformArgs args;
269 auto *adapterParams = dynamic_cast<KisTransformMaskAdapter*>(params.data());
270
271 if (adapterParams) {
272 args = adapterParams->transformArgs();
273 } else {
274 if (params->isHidden()) return;
275 args.setOriginalCenter(mask->exactBounds().center());
276 args.setTransformedCenter(args.originalCenter()); // offset?
277 }
278
279 KisTransformArgsKeyframeChannel *rawArgsChannel = dynamic_cast<KisTransformArgsKeyframeChannel*>(mask->getKeyframeChannel(KisKeyframeChannel::TransformArguments.id(), true));
280 if (rawArgsChannel) {
281 new KisTransformArgsKeyframeChannel::AddKeyframeCommand(rawArgsChannel, time, args, parentCommand);
282 }
283
284 setScalarChannelValue(mask, KisKeyframeChannel::TransformPositionX, time, args.transformedCenter().x(), parentCommand);
285 setScalarChannelValue(mask, KisKeyframeChannel::TransformPositionY, time, args.transformedCenter().y(), parentCommand);
286 setScalarChannelValue(mask, KisKeyframeChannel::TransformScaleX, time, args.scaleX(), parentCommand);
287 setScalarChannelValue(mask, KisKeyframeChannel::TransformScaleY, time, args.scaleY(), parentCommand);
288 setScalarChannelValue(mask, KisKeyframeChannel::TransformShearX, time, args.shearX(), parentCommand);
289 setScalarChannelValue(mask, KisKeyframeChannel::TransformShearY, time, args.shearY(), parentCommand);
290 setScalarChannelValue(mask, KisKeyframeChannel::TransformRotationX, time, args.aX(), parentCommand);
291 setScalarChannelValue(mask, KisKeyframeChannel::TransformRotationY, time, args.aY(), parentCommand);
292 setScalarChannelValue(mask, KisKeyframeChannel::TransformRotationZ, time, args.aZ(), parentCommand);
293 }
294
295 #include "kis_transform_mask_params_factory_registry.h"
296
297 struct AnimatedTransformParamsRegistrar {
AnimatedTransformParamsRegistrarAnimatedTransformParamsRegistrar298 AnimatedTransformParamsRegistrar() {
299 KisTransformMaskParamsFactory f(KisAnimatedTransformMaskParameters::fromXML);
300 KisTransformMaskParamsFactoryRegistry::instance()->addFactory("animatedtransformparams", f);
301
302 KisAnimatedTransformMaskParamsFactory a(KisAnimatedTransformMaskParameters::animate);
303 KisTransformMaskParamsFactoryRegistry::instance()->setAnimatedParamsFactory(a);
304
305 KisTransformMaskKeyframeFactory k(KisAnimatedTransformMaskParameters::addKeyframes);
306 KisTransformMaskParamsFactoryRegistry::instance()->setKeyframeFactory(k);
307 }
308 };
309 static AnimatedTransformParamsRegistrar __animatedTransformParamsRegistrar;
310