Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • core_lib
  • src
  • structure
layercamera.cpp
1/*
2
3Pencil2D - Traditional Animation Software
4Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5Copyright (C) 2012-2020 Matthew Chiawen Chang
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation; version 2 of the License.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16*/
17#include "layercamera.h"
18
19#include <QSettings>
20#include <QEasingCurve>
21
22#include "camera.h"
23#include "pencildef.h"
24
25LayerCamera::LayerCamera(int id) : Layer(id, Layer::CAMERA)
26{
27 setName(tr("Camera Layer"));
28
29 QSettings settings(PENCIL2D, PENCIL2D);
30 mFieldW = settings.value("FieldW").toInt();
31 mFieldH = settings.value("FieldH").toInt();
32 if (mFieldW < 2 || mFieldH < 2)
33 {
34 mFieldW = 800;
35 mFieldH = 600;
36 }
37 viewRect = QRect(QPoint(-mFieldW / 2, -mFieldH / 2), QSize(mFieldW, mFieldH));
38}
39
40LayerCamera::~LayerCamera()
41{
42}
43
44bool LayerCamera::addKeyFrame(int position, KeyFrame *pKeyFrame)
45{
46 bool keyAdded = Layer::addKeyFrame(position, pKeyFrame);
47 if (keyAdded) {
48 splitControlPointIfNeeded(position);
49 }
50 return keyAdded;
51}
52
53bool LayerCamera::removeKeyFrame(int position)
54{
55 mergeControlPointIfNeeded(position);
56 return Layer::removeKeyFrame(position);
57}
58
59void LayerCamera::replaceKeyFrame(const KeyFrame* camera)
60{
61 *getCameraAtFrame(camera->pos()) = *static_cast<const Camera*>(camera);
62}
63
64Camera* LayerCamera::getCameraAtFrame(int frameNumber) const
65{
66 return static_cast<Camera*>(getKeyFrameAt(frameNumber));
67}
68
69Camera* LayerCamera::getLastCameraAtFrame(int frameNumber, int increment) const
70{
71 return static_cast<Camera*>(getLastKeyFrameAtPosition(frameNumber + increment));
72}
73
74QTransform LayerCamera::getViewAtFrame(int frameNumber) const
75{
76 if (keyFrameCount() == 0)
77 {
78 return QTransform();
79 }
80
81 // IMO: There should always be a keyframe on frame 1 on the Camera layer! (David)
82 if (frameNumber < firstKeyFramePosition())
83 {
84 frameNumber = firstKeyFramePosition();
85 }
86
87 Camera* camera1 = static_cast<Camera*>(getLastKeyFrameAtPosition(frameNumber));
88
89 int nextFrame = getNextKeyFramePosition(frameNumber);
90 Camera* camera2 = static_cast<Camera*>(getLastKeyFrameAtPosition(nextFrame));
91
92 if (camera1 == nullptr && camera2 == nullptr)
93 {
94 return QTransform();
95 }
96 else if (camera1 == nullptr && camera2 != nullptr)
97 {
98 return camera2->getView();
99 }
100 else if (camera2 == nullptr && camera1 != nullptr)
101 {
102 return camera1->getView();
103 }
104
105 if (camera1->compare(*camera2))
106 {
107 return camera1->getView();
108 }
109
110 double frame1 = camera1->pos();
111 double frame2 = camera2->pos();
112
113 // interpolation
114 qreal percent = getInterpolationPercent(camera1->getEasingType(), (frameNumber - frame1) / (frame2 - frame1));
115 auto lerp = [](double f1, double f2, double percent) -> double
116 {
117 return f1 * (1.0 - percent) + f2 * percent;
118 };
119
120 QPointF controlPoint = camera1->getPathControlPoint();
121 if (!camera1->pathControlPointMoved()) {
122 controlPoint = getCenteredPathPoint(frame1);
123 }
124
125 const QPointF& point = getBezierPoint(camera1->translation(), camera2->translation(),
126 -controlPoint, percent);
127
128 double dx = point.x();
129 double dy = point.y();
130 double r = lerp(camera1->rotation(), camera2->rotation(), percent);
131 double s = lerp(camera1->scaling(), camera2->scaling(), percent);
132
133 QTransform camTransform;
134 camTransform.scale(s, s);
135 camTransform.rotate(r);
136 camTransform.translate(dx, dy);
137
138 return camTransform;
139}
140
141void LayerCamera::linearInterpolateTransform(Camera* cam)
142{
143 if (keyFrameCount() == 0)
144 return;
145
146 int frameNumber = cam->pos();
147 Camera* camera1 = static_cast<Camera*>(getLastKeyFrameAtPosition(frameNumber - 1));
148
149 int nextFrame = getNextKeyFramePosition(frameNumber);
150 Camera* camera2 = static_cast<Camera*>(getLastKeyFrameAtPosition(nextFrame));
151
152 if (camera1 == nullptr && camera2 == nullptr)
153 {
154 return; // do nothing
155 }
156
157 else if (camera1 == nullptr && camera2 != nullptr)
158 {
159 return cam->assign(*camera2);
160 }
161
162 else if (camera2 == nullptr && camera1 != nullptr)
163 {
164 return cam->assign(*camera1);
165 }
166
167 if (camera1->compare(*camera2))
168 {
169 return cam->assign(*camera1);
170 }
171
172 double frame1 = camera1->pos();
173 double frame2 = camera2->pos();
174
175 // interpolation
176 qreal percent = getInterpolationPercent(camera1->getEasingType(), (frameNumber - frame1)/ (frame2 - frame1));
177
178 auto lerp = [](double f1, double f2, double percent) -> double
179 {
180 return f1 * (1.0 - percent) + f2 * percent;
181 };
182
183 QPointF controlPoint = camera1->getPathControlPoint();
184 if (!camera1->pathControlPointMoved()) {
185 controlPoint = getCenteredPathPoint(frame1);
186 }
187
188 QPointF point = getBezierPoint(camera1->translation(), camera2->translation(),
189 -controlPoint, percent);
190 double dx = point.x();
191 double dy = point.y();
192 double r = lerp(camera1->rotation(), camera2->rotation(), percent);
193 double s = lerp(camera1->scaling(), camera2->scaling(), percent);
194
195 cam->translate(dx, dy);
196 cam->rotate(r);
197 cam->scale(s);
198}
199
200qreal LayerCamera::getInterpolationPercent(CameraEasingType type, qreal percent) const
201{
202 QEasingCurve easing;
203
204 switch (type)
205 {
206 case CameraEasingType::LINEAR : easing.setType(QEasingCurve::Linear); break;
207 case CameraEasingType::INQUAD : easing.setType(QEasingCurve::InQuad); break;
208 case CameraEasingType::OUTQUAD : easing.setType(QEasingCurve::OutQuad); break;
209 case CameraEasingType::INOUTQUAD : easing.setType(QEasingCurve::InOutQuad); break;
210 case CameraEasingType::OUTINQUAD : easing.setType(QEasingCurve::OutInQuad); break;
211 case CameraEasingType::INCUBIC : easing.setType(QEasingCurve::InCubic); break;
212 case CameraEasingType::OUTCUBIC : easing.setType(QEasingCurve::OutCubic); break;
213 case CameraEasingType::INOUTCUBIC : easing.setType(QEasingCurve::InOutCubic); break;
214 case CameraEasingType::OUTINCUBIC : easing.setType(QEasingCurve::OutInCubic); break;
215 case CameraEasingType::INQUART : easing.setType(QEasingCurve::InQuart); break;
216 case CameraEasingType::OUTQUART : easing.setType(QEasingCurve::OutQuart); break;
217 case CameraEasingType::INOUTQUART : easing.setType(QEasingCurve::InOutQuart); break;
218 case CameraEasingType::OUTINQUART : easing.setType(QEasingCurve::OutInQuart); break;
219 case CameraEasingType::INQUINT : easing.setType(QEasingCurve::InQuint); break;
220 case CameraEasingType::OUTQUINT : easing.setType(QEasingCurve::OutQuint); break;
221 case CameraEasingType::INOUTQUINT : easing.setType(QEasingCurve::InOutQuint); break;
222 case CameraEasingType::OUTINQUINT : easing.setType(QEasingCurve::OutInQuint); break;
223 case CameraEasingType::INSINE : easing.setType(QEasingCurve::InSine); break;
224 case CameraEasingType::OUTSINE : easing.setType(QEasingCurve::OutSine); break;
225 case CameraEasingType::INOUTSINE : easing.setType(QEasingCurve::InOutSine); break;
226 case CameraEasingType::OUTINSINE: easing.setType(QEasingCurve::OutInSine); break;
227 case CameraEasingType::INEXPO : easing.setType(QEasingCurve::InExpo); break;
228 case CameraEasingType::OUTEXPO : easing.setType(QEasingCurve::OutExpo); break;
229 case CameraEasingType::INOUTEXPO : easing.setType(QEasingCurve::InOutExpo); break;
230 case CameraEasingType::OUTINEXPO: easing.setType(QEasingCurve::OutInExpo); break;
231 case CameraEasingType::INCIRC : easing.setType(QEasingCurve::InCirc); break;
232 case CameraEasingType::OUTCIRC : easing.setType(QEasingCurve::OutCirc); break;
233 case CameraEasingType::INOUTCIRC : easing.setType(QEasingCurve::InOutCirc); break;
234 case CameraEasingType::OUTINCIRC: easing.setType(QEasingCurve::OutInCirc); break;
235 case CameraEasingType::INELASTIC: easing.setType(QEasingCurve::InElastic); break;
236 case CameraEasingType::OUTELASTIC: easing.setType(QEasingCurve::OutElastic); break;
237 case CameraEasingType::INOUTELASTIC: easing.setType(QEasingCurve::InOutElastic); break;
238 case CameraEasingType::OUTINELASTIC: easing.setType(QEasingCurve::OutInElastic); break;
239 case CameraEasingType::INBACK: easing.setType(QEasingCurve::InBack); break;
240 case CameraEasingType::OUTBACK: easing.setType(QEasingCurve::OutBack); break;
241 case CameraEasingType::INOUTBACK: easing.setType(QEasingCurve::InOutBack); break;
242 case CameraEasingType::OUTINBACK: easing.setType(QEasingCurve::OutInBack); break;
243 case CameraEasingType::INBOUNCE: easing.setType(QEasingCurve::InBounce); break;
244 case CameraEasingType::OUTBOUNCE: easing.setType(QEasingCurve::OutBounce); break;
245 case CameraEasingType::INOUTBOUNCE: easing.setType(QEasingCurve::InOutBounce); break;
246 case CameraEasingType::OUTINBOUNCE: easing.setType(QEasingCurve::OutInBounce); break;
247 default: Q_UNREACHABLE(); break;
248 }
249 return easing.valueForProgress(percent);
250}
251
252QPointF LayerCamera::getBezierPoint(const QPointF& first, const QPointF& last, const QPointF& pathPoint, qreal percent) const
253{
254 QLineF line1(first, pathPoint);
255 QLineF line2(pathPoint, last);
256 return QLineF(line1.pointAt(percent), line2.pointAt(percent)).pointAt(percent);
257}
258
259void LayerCamera::splitControlPointIfNeeded(int frame) const
260{
261 int next = getNextKeyFramePosition(frame);
262 int prev = getPreviousKeyFramePosition(frame);
263
264 // if inbetween frames
265 if (frame > prev && (frame > 1) && frame < next)
266 {
267 Camera* camFrame = getLastCameraAtFrame(frame, 0);
268 Camera* camPrev = getCameraAtFrame(prev);
269 Camera* camNext = getCameraAtFrame(next);
270 Q_ASSERT(camPrev && camFrame && camNext);
271
272 if (camPrev->pathControlPointMoved()) {
273 qreal t = static_cast<qreal>(frame - prev) / (next - prev);
274 QPointF previousControlPoint = camPrev->getPathControlPoint();
275
276 // Line from the current control point to the next frame
277 QLineF interpolatedLineCN = QLineF(previousControlPoint, -camNext->translation());
278
279 // Line from the previous frame to the current control point
280 QLineF interpolatedLinePC = QLineF(-camPrev->translation(), previousControlPoint);
281 // Place the new control points, so the curve is kept
282 camPrev->setPathControlPoint(interpolatedLinePC.pointAt(t));
283 camFrame->setPathControlPoint(interpolatedLineCN.pointAt(t));
284 camFrame->setPathControlPointMoved(true);
285 }
286 } else {
287 Camera* camPrev = getCameraAtFrame(prev);
288 camPrev->setPathControlPointMoved(false);
289 }
290}
291
292void LayerCamera::mergeControlPointIfNeeded(int frame) const
293{
294 int next = getNextKeyFramePosition(frame);
295 int prev = getPreviousKeyFramePosition(frame);
296
297 // if inbetween frames
298 if (frame > prev && (frame > 1) && frame < next)
299 {
300 Camera* camPrev = getCameraAtFrame(prev);
301 Camera* camFrame = getLastCameraAtFrame(frame, 0);
302 Camera* camNext = getCameraAtFrame(next);
303 Q_ASSERT(camPrev && camFrame && camNext);
304
305 if (camPrev->pathControlPointMoved()) {
306
307 // Line from the current control point to the next frame
308 const QLineF& interpolatedLineCN = QLineF(camFrame->getPathControlPoint(), -camNext->translation());
309
310 // Line from the previous frame translation to previous control point
311 const QLineF& interpolatedLinePC = QLineF(-camPrev->translation(), camPrev->getPathControlPoint());
312
313 QPointF mergedCPoint;
314#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
315 auto intersection = interpolatedLinePC.intersects(interpolatedLineCN, &mergedCPoint);
316#else
317 auto intersection = interpolatedLinePC.intersect(interpolatedLineCN, &mergedCPoint);
318#endif
319 // Try to recover the control point if the distance is within the threshold, otherwise do nothing
320 if (intersection == QLineF::UnboundedIntersection &&
321 QLineF(camFrame->getPathControlPoint(), mergedCPoint).length() < mControlPointMergeThreshold)
322 {
323 camPrev->setPathControlPoint(mergedCPoint);
324 camPrev->setPathControlPointMoved(true);
325 } else if (intersection == QLineF::NoIntersection) {
326 camPrev->setPathControlPointMoved(false);
327 }
328 }
329 }
330}
331
332QRect LayerCamera::getViewRect() const
333{
334 return viewRect;
335}
336
337QSize LayerCamera::getViewSize() const
338{
339 return viewRect.size();
340}
341
342void LayerCamera::setViewRect(QRect newViewRect)
343{
344 viewRect = newViewRect;
345}
346
347void LayerCamera::setCameraEasingAtFrame(CameraEasingType type, int frame) const
348{
349 Camera* camera = getLastCameraAtFrame(frame, 0);
350 camera->setEasingType(type);
351 camera->updateViewTransform();
352}
353
354void LayerCamera::resetCameraAtFrame(CameraFieldOption type, int frame) const
355{
356 int frameToModify = frame;
357 if (!keyExists(frame)) {
358 frameToModify = getPreviousKeyFramePosition(frame);
359 }
360 Camera* camera = getLastCameraAtFrame(frameToModify, 0);
361
362 switch (type)
363 {
364 case CameraFieldOption::RESET_FIELD:
365 camera->resetTransform();
366 break;
367 case CameraFieldOption::RESET_TRANSLATION:
368 camera->translate(QPoint(0,0));
369 break;
370 case CameraFieldOption::RESET_SCALING:
371 camera->scale(1.0);
372 break;
373 case CameraFieldOption::RESET_ROTATION:
374 camera->rotate(0.0);
375 break;
376 case CameraFieldOption::ALIGN_HORIZONTAL: {
377 qreal otherYCoord = camera->translation().y();
378 Camera* nextCam = getCameraAtFrame(getNextKeyFramePosition(frameToModify));
379 nextCam->translate(nextCam->translation().x(), otherYCoord);
380 camera->setPathControlPointMoved(false);
381 break;
382 }
383 case CameraFieldOption::ALIGN_VERTICAL: {
384 qreal otherXCoord = camera->translation().x();
385 Camera* nextCam = getCameraAtFrame(getNextKeyFramePosition(frameToModify));
386 nextCam->translate(otherXCoord, nextCam->translation().y());
387 camera->setPathControlPointMoved(false);
388 break;
389 }
390 case CameraFieldOption::HOLD_FRAME: {
391
392 if (getMaxKeyFramePosition() == camera->pos()) { return; }
393
394 QPointF translation = camera->translation();
395 qreal rotation = camera->rotation();
396 qreal scaling = camera->scaling();
397 camera->setPathControlPointMoved(false);
398 Camera* nextCamera = getLastCameraAtFrame(getNextKeyFramePosition(frame), 0);
399 nextCamera->translate(translation);
400 nextCamera->scale(scaling);
401 nextCamera->rotate(rotation);
402 nextCamera->setPathControlPointMoved(false);
403 break;
404 }
405 default:
406 Q_UNREACHABLE();
407 break;
408 }
409
410 if (type != CameraFieldOption::RESET_SCALING && type != CameraFieldOption::RESET_ROTATION) {
411 setPathMovedAtFrame(frame - 1, false);
412 }
413
414 camera->updateViewTransform();
415}
416
417void LayerCamera::updateDotColor(DotColorType color)
418{
419 switch (color)
420 {
421 case DotColorType::RED:
422 mDotColor = Qt::red;
423 break;
424 case DotColorType::GREEN:
425 mDotColor = Qt::green;
426 break;
427 case DotColorType::BLUE:
428 mDotColor = Qt::blue;
429 break;
430 case DotColorType::BLACK:
431 mDotColor = Qt::black;
432 break;
433 case DotColorType::WHITE:
434 mDotColor = Qt::white;
435 break;
436 }
437 mDotColorType = color;
438}
439
440QString LayerCamera::getInterpolationTextAtFrame(int frame) const
441{
442 Camera* camera = getLastCameraAtFrame(frame, 0);
443 return getInterpolationText(camera->getEasingType());
444}
445
446QPointF LayerCamera::getPathControlPointAtFrame(int frame) const
447{
448 Camera* camera = getCameraAtFrame(getPreviousKeyFramePosition(frame));
449 Q_ASSERT(camera);
450
451 return camera->getPathControlPoint();
452}
453
454bool LayerCamera::hasSameTranslation(int frame1, int frame2) const
455{
456 Camera* camera1 = getCameraAtFrame(frame1);
457 Camera* camera2 = getCameraAtFrame(frame2);
458
459 if (camera1 == nullptr)
460 {
461 return false;
462 }
463 else if (camera2 == nullptr)
464 {
465 return false;
466 }
467
468 return camera1->translation() == camera2->translation();
469}
470
471QList<QPointF> LayerCamera::getBezierPointsAtFrame(int frame) const
472{
473 QList<QPointF> points;
474 int prevFrame = getPreviousKeyFramePosition(frame);
475 int nextFrame = getNextKeyFramePosition(frame);
476 if (prevFrame < nextFrame)
477 {
478 Camera* prevCam = getCameraAtFrame(prevFrame);
479 Camera* nextCam = getCameraAtFrame(nextFrame);
480 points.append(QPointF(-prevCam->translation()));
481 if (prevCam->pathControlPointMoved()) {
482 points.append(QPointF(prevCam->getPathControlPoint()));
483 } else {
484 points.append(QPointF(getCenteredPathPoint(prevFrame)));
485 }
486 points.append(QPointF(-nextCam->translation()));
487 }
488 return points;
489}
490
491QPointF LayerCamera::getCenteredPathPoint(int frame) const
492{
493 if (!keyExists(frame) || frame == getMaxKeyFramePosition())
494 frame = getPreviousKeyFramePosition(frame);
495 int nextFrame = getNextKeyFramePosition(frame);
496 Camera* cam1 = getCameraAtFrame(frame);
497 Camera* cam2 = getCameraAtFrame(nextFrame);
498
499 if (cam1 && cam2 == nullptr) {
500 return -cam1->translation();
501 } else if (cam2 && cam1 == nullptr) {
502 return -cam2->translation();
503 } else if (cam1 == nullptr && cam2 == nullptr) {
504 return QPointF();
505 }
506 return QLineF(-cam1->translation(), -cam2->translation()).pointAt(0.5);
507}
508
509void LayerCamera::setPathMovedAtFrame(int frame, bool moved) const
510{
511 Camera* cam = getLastCameraAtFrame(frame, 0);
512 Q_ASSERT(cam);
513
514 cam->setPathControlPointMoved(moved);
515}
516
517void LayerCamera::updatePathControlPointAtFrame(const QPointF& point, int frame) const
518{
519 Camera* camera = getLastCameraAtFrame(frame, 0);
520 Q_ASSERT(camera);
521
522 camera->setPathControlPoint(point);
523 camera->setPathControlPointMoved(true);
524}
525
526void LayerCamera::loadImageAtFrame(int frameNumber, qreal dx, qreal dy, qreal rotate, qreal scale, CameraEasingType easing, const QPointF& pathPoint, bool pathMoved)
527{
528 if (keyExists(frameNumber))
529 {
530 removeKeyFrame(frameNumber);
531 }
532 Camera* camera = new Camera(QPointF(dx, dy), rotate, scale);
533 camera->setPos(frameNumber);
534 camera->setEasingType(easing);
535 if (pathMoved) {
536 camera->setPathControlPoint(pathPoint);
537 camera->setPathControlPointMoved(pathMoved);
538 }
539 loadKey(camera);
540}
541
542Status LayerCamera::saveKeyFrameFile(KeyFrame*, QString)
543{
544 return Status::OK;
545}
546
547KeyFrame* LayerCamera::createKeyFrame(int position)
548{
549 Camera* c = new Camera;
550 c->setPos(position);
551 c->setEasingType(CameraEasingType::LINEAR);
552 linearInterpolateTransform(c);
553 c->setPathControlPoint(c->translation());
554 return c;
555}
556
557QDomElement LayerCamera::createDomElement(QDomDocument& doc) const
558{
559 QDomElement layerElem = createBaseDomElement(doc);
560 layerElem.setAttribute("width", viewRect.width());
561 layerElem.setAttribute("height", viewRect.height());
562
563 if (mShowPath) {
564 layerElem.setAttribute("showPath", mShowPath);
565 }
566
567 if (mDotColorType != DotColorType::RED) {
568 layerElem.setAttribute("pathColorType", static_cast<int>(mDotColorType));
569 }
570
571 foreachKeyFrame([&](KeyFrame* pKeyFrame)
572 {
573 Camera* camera = static_cast<Camera*>(pKeyFrame);
574 QDomElement keyTag = doc.createElement("camera");
575 keyTag.setAttribute("frame", camera->pos());
576
577 keyTag.setAttribute("r", camera->rotation());
578 keyTag.setAttribute("s", camera->scaling());
579 keyTag.setAttribute("dx", camera->translation().x());
580 keyTag.setAttribute("dy", camera->translation().y());
581
582 if (camera->getEasingType() != CameraEasingType::LINEAR) {
583 keyTag.setAttribute("easing", static_cast<int>(camera->getEasingType()));
584 }
585 if (camera->pathControlPointMoved()) {
586 keyTag.setAttribute("pathCPX", camera->getPathControlPoint().x());
587 keyTag.setAttribute("pathCPY", camera->getPathControlPoint().y());
588 }
589 layerElem.appendChild(keyTag);
590 });
591
592 return layerElem;
593}
594
595void LayerCamera::loadDomElement(const QDomElement& element, QString dataDirPath, ProgressCallback progressStep)
596{
597 Q_UNUSED(dataDirPath)
598 Q_UNUSED(progressStep)
599
600 this->loadBaseDomElement(element);
601
602 int width = element.attribute("width").toInt();
603 int height = element.attribute("height").toInt();
604 mShowPath = element.attribute("showPath").toInt();
605 updateDotColor(static_cast<DotColorType>(element.attribute("pathColorType").toInt()));
606 viewRect = QRect(-width / 2, -height / 2, width, height);
607
608 QDomNode imageTag = element.firstChild();
609 while (!imageTag.isNull())
610 {
611 QDomElement imageElement = imageTag.toElement();
612 if (!imageElement.isNull())
613 {
614 if (imageElement.tagName() == "camera")
615 {
616 int frame = imageElement.attribute("frame").toInt();
617
618 qreal rotate = imageElement.attribute("r", "0").toDouble();
619 qreal scale = imageElement.attribute("s", "1").toDouble();
620 qreal dx = imageElement.attribute("dx", "0").toDouble();
621 qreal dy = imageElement.attribute("dy", "0").toDouble();
622 CameraEasingType easing = static_cast<CameraEasingType>(imageElement.attribute("easing", "0").toInt());
623 qreal pathX = imageElement.attribute("pathCPX", "0").toDouble();
624 qreal pathY = imageElement.attribute("pathCPY", "0").toDouble();
625
626 bool pathMoved = pathX != 0 || pathY != 0;
627
628 loadImageAtFrame(frame, dx, dy, rotate, scale, easing, QPointF(pathX, pathY), pathMoved);
629 }
630 }
631 imageTag = imageTag.nextSibling();
632 }
633}
Camera
Definition: camera.h:25
KeyFrame
Definition: keyframe.h:30
LayerCamera::addKeyFrame
bool addKeyFrame(int position, KeyFrame *pKeyFrame) override
Adds a keyframe at the given position, unless one already exists.
Definition: layercamera.cpp:44
Layer
Definition: layer.h:33
Layer::addKeyFrame
virtual bool addKeyFrame(int position, KeyFrame *pKeyFrame)
Adds a keyframe at the given position, unless one already exists.
Definition: layer.cpp:191
Status
Definition: pencilerror.h:40
QDomDocument
QDomDocument::createElement
QDomElement createElement(const QString &tagName)
QDomElement
QDomElement::attribute
QString attribute(const QString &name, const QString &defValue) const const
QDomElement::setAttribute
void setAttribute(const QString &name, const QString &value)
QDomElement::tagName
QString tagName() const const
QDomNode
QDomNode::appendChild
QDomNode appendChild(const QDomNode &newChild)
QDomNode::firstChild
QDomNode firstChild() const const
QDomNode::isNull
bool isNull() const const
QDomNode::nextSibling
QDomNode nextSibling() const const
QDomNode::toElement
QDomElement toElement() const const
QEasingCurve
QEasingCurve::Linear
Linear
QEasingCurve::setType
void setType(QEasingCurve::Type type)
QEasingCurve::valueForProgress
qreal valueForProgress(qreal progress) const const
QLineF::UnboundedIntersection
UnboundedIntersection
QLineF::intersect
QLineF::IntersectType intersect(const QLineF &line, QPointF *intersectionPoint) const const
QLineF
QLineF::intersects
QLineF::IntersectionType intersects(const QLineF &line, QPointF *intersectionPoint) const const
QLineF::length
qreal length() const const
QLineF::pointAt
QPointF pointAt(qreal t) const const
QList
QList::append
void append(const T &value)
QPoint
QPointF
QPointF::x
qreal x() const const
QPointF::y
qreal y() const const
QRect
QRect::height
int height() const const
QRect::size
QSize size() const const
QRect::width
int width() const const
QSettings
QSize
QString
QString::toDouble
double toDouble(bool *ok) const const
QString::toInt
int toInt(bool *ok, int base) const const
Qt::red
red
QTransform
QTransform::rotate
QTransform & rotate(qreal angle, Qt::Axis axis)
QTransform::scale
QTransform & scale(qreal sx, qreal sy)
QTransform::translate
QTransform & translate(qreal dx, qreal dy)
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39