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 &currentRawArgs()
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