All Classes Namespaces Functions Variables Enumerations Properties Pages
layercamera.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2020 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU 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 #include "cameraeasingtype.h"
25 
26 
27 LayerCamera::LayerCamera(Object* object) : Layer(object, Layer::CAMERA)
28 {
29  setName(tr("Camera Layer"));
30 
31  QSettings settings(PENCIL2D, PENCIL2D);
32  mFieldW = settings.value("FieldW").toInt();
33  mFieldH = settings.value("FieldH").toInt();
34  if (mFieldW < 2 || mFieldH < 2)
35  {
36  mFieldW = 800;
37  mFieldH = 600;
38  }
39  viewRect = QRect(QPoint(-mFieldW / 2, -mFieldH / 2), QSize(mFieldW, mFieldH));
40 }
41 
42 LayerCamera::~LayerCamera()
43 {
44 }
45 
46 Camera* LayerCamera::getCameraAtFrame(int frameNumber)
47 {
48  return static_cast<Camera*>(getKeyFrameAt(frameNumber));
49 }
50 
51 Camera* LayerCamera::getLastCameraAtFrame(int frameNumber, int increment)
52 {
53  return static_cast<Camera*>(getLastKeyFrameAtPosition(frameNumber + increment));
54 }
55 
56 QTransform LayerCamera::getViewAtFrame(int frameNumber) const
57 {
58  if (keyFrameCount() == 0)
59  {
60  return QTransform();
61  }
62 
63  Camera* camera1 = static_cast<Camera*>(getLastKeyFrameAtPosition(frameNumber));
64  camera1->setEasingType(camera1->getEasingType());
65 
66  int nextFrame = getNextKeyFramePosition(frameNumber);
67  Camera* camera2 = static_cast<Camera*>(getLastKeyFrameAtPosition(nextFrame));
68  camera2->setEasingType(camera2->getEasingType());
69 
70  if (camera1 == nullptr && camera2 == nullptr)
71  {
72  return QTransform();
73  }
74  else if (camera1 == nullptr && camera2 != nullptr)
75  {
76  return camera2->view;
77  }
78  else if (camera2 == nullptr && camera1 != nullptr)
79  {
80  return camera1->view;
81  }
82 
83  if (camera1 == camera2)
84  {
85  return camera1->view;
86  }
87 
88  double frame1 = camera1->pos();
89  double frame2 = camera2->pos();
90 
91  // interpolation
92  qreal percent = getInterpolationPercent(camera1->getEasingType(), (frameNumber - frame1)/ (frame2 - frame1));
93 
94  auto interpolation = [=](double f1, double f2) -> double
95  {
96  return f1 * (1.0 - percent) + f2 * percent;
97  };
98 
99  return QTransform(interpolation(camera1->view.m11(), camera2->view.m11()),
100  interpolation(camera1->view.m12(), camera2->view.m12()),
101  interpolation(camera1->view.m21(), camera2->view.m21()),
102  interpolation(camera1->view.m22(), camera2->view.m22()),
103  interpolation(camera1->view.m31(), camera2->view.m31()),
104  interpolation(camera1->view.m32(), camera2->view.m32()));
105 }
106 
107 void LayerCamera::linearInterpolateTransform(Camera* cam)
108 {
109  if (keyFrameCount() == 0)
110  return;
111 
112  int frameNumber = cam->pos();
113  Camera* camera1 = static_cast<Camera*>(getLastKeyFrameAtPosition(frameNumber - 1));
114 
115  int nextFrame = getNextKeyFramePosition(frameNumber);
116  Camera* camera2 = static_cast<Camera*>(getLastKeyFrameAtPosition(nextFrame));
117 
118  if (camera1 == nullptr && camera2 == nullptr)
119  {
120  return; // do nothing
121  }
122  else if (camera1 == nullptr && camera2 != nullptr)
123  {
124  return cam->assign(*camera2);
125  }
126  else if (camera2 == nullptr && camera1 != nullptr)
127  {
128  return cam->assign(*camera1);
129  }
130 
131  if (camera1 == camera2)
132  {
133  return cam->assign(*camera1);
134  }
135 
136  double frame1 = camera1->pos();
137  double frame2 = camera2->pos();
138 
139  // interpolation
140  qreal percent = getInterpolationPercent(camera1->getEasingType(), (frameNumber - frame1)/ (frame2 - frame1));
141 
142  auto lerp = [](double f1, double f2, double percent) -> double
143  {
144  return f1 * (1.0 - percent) + f2 * percent;
145  };
146 
147  double dx = lerp(camera1->translation().x(), camera2->translation().x(), percent);
148  double dy = lerp(camera1->translation().y(), camera2->translation().y(), percent);
149  double r = lerp(camera1->rotation(), camera2->rotation(), percent);
150  double s = lerp(camera1->scaling(), camera2->scaling(), percent);
151 
152  cam->translate(dx, dy);
153  cam->rotate(r);
154  cam->scale(s);
155 }
156 
157 qreal LayerCamera::getInterpolationPercent(CameraEasingType type, qreal percent) const
158 {
159  QEasingCurve easing;
160 
161  switch (type)
162  {
163  case CameraEasingType::LINEAR : easing.setType(QEasingCurve::Linear); break;
164  case CameraEasingType::INQUAD : easing.setType(QEasingCurve::InQuad); break;
165  case CameraEasingType::OUTQUAD : easing.setType(QEasingCurve::OutQuad); break;
166  case CameraEasingType::INOUTQUAD : easing.setType(QEasingCurve::InOutQuad); break;
167  case CameraEasingType::OUTINQUAD : easing.setType(QEasingCurve::OutInQuad); break;
168  case CameraEasingType::INCUBIC : easing.setType(QEasingCurve::InCubic); break;
169  case CameraEasingType::OUTCUBIC : easing.setType(QEasingCurve::OutCubic); break;
170  case CameraEasingType::INOUTCUBIC : easing.setType(QEasingCurve::InOutCubic); break;
171  case CameraEasingType::OUTINCUBIC : easing.setType(QEasingCurve::OutInCubic); break;
172  case CameraEasingType::INQUART : easing.setType(QEasingCurve::InQuart); break;
173  case CameraEasingType::OUTQUART : easing.setType(QEasingCurve::OutQuart); break;
174  case CameraEasingType::INOUTQUART : easing.setType(QEasingCurve::InOutQuart); break;
175  case CameraEasingType::OUTINQUART : easing.setType(QEasingCurve::OutInQuart); break;
176  case CameraEasingType::INQUINT : easing.setType(QEasingCurve::InQuint); break;
177  case CameraEasingType::OUTQUINT : easing.setType(QEasingCurve::OutQuint); break;
178  case CameraEasingType::INOUTQUINT : easing.setType(QEasingCurve::InOutQuint); break;
179  case CameraEasingType::OUTINQUINT : easing.setType(QEasingCurve::OutInQuint); break;
180  case CameraEasingType::INSINE : easing.setType(QEasingCurve::InSine); break;
181  case CameraEasingType::OUTSINE : easing.setType(QEasingCurve::OutSine); break;
182  case CameraEasingType::INOUTSINE : easing.setType(QEasingCurve::InOutSine); break;
183  case CameraEasingType::OUTINSINE: easing.setType(QEasingCurve::OutInSine); break;
184  case CameraEasingType::INEXPO : easing.setType(QEasingCurve::InExpo); break;
185  case CameraEasingType::OUTEXPO : easing.setType(QEasingCurve::OutExpo); break;
186  case CameraEasingType::INOUTEXPO : easing.setType(QEasingCurve::InOutExpo); break;
187  case CameraEasingType::OUTINEXPO: easing.setType(QEasingCurve::OutInExpo); break;
188  case CameraEasingType::INCIRC : easing.setType(QEasingCurve::InCirc); break;
189  case CameraEasingType::OUTCIRC : easing.setType(QEasingCurve::OutCirc); break;
190  case CameraEasingType::INOUTCIRC : easing.setType(QEasingCurve::InOutCirc); break;
191  case CameraEasingType::OUTINCIRC: easing.setType(QEasingCurve::OutInCirc); break;
192  default: easing.setType(QEasingCurve::Linear); break;
193  }
194  return easing.valueForProgress(percent);
195 }
196 
197 QRect LayerCamera::getViewRect()
198 {
199  return viewRect;
200 }
201 
202 QSize LayerCamera::getViewSize() const
203 {
204  return viewRect.size();
205 }
206 
207 void LayerCamera::setViewRect(QRect newViewRect)
208 {
209  viewRect = newViewRect;
210 }
211 
212 void LayerCamera::loadImageAtFrame(int frameNumber, qreal dx, qreal dy, qreal rotate, qreal scale, CameraEasingType type)
213 {
214  if (keyExists(frameNumber))
215  {
216  removeKeyFrame(frameNumber);
217  }
218  Camera* camera = new Camera(QPointF(dx, dy), rotate, scale, type);
219  camera->setPos(frameNumber);
220  loadKey(camera);
221 }
222 
223 Status LayerCamera::saveKeyFrameFile(KeyFrame*, QString)
224 {
225  return Status::OK;
226 }
227 
228 KeyFrame* LayerCamera::createKeyFrame(int position, Object*)
229 {
230  Camera* c = new Camera;
231  c->setPos(position);
232  linearInterpolateTransform(c);
233  return c;
234 }
235 
236 QDomElement LayerCamera::createDomElement(QDomDocument& doc) const
237 {
238  QDomElement layerElem = createBaseDomElement(doc);
239  layerElem.setAttribute("width", viewRect.width());
240  layerElem.setAttribute("height", viewRect.height());
241 
242  foreachKeyFrame([&](KeyFrame* pKeyFrame)
243  {
244  Camera* camera = static_cast<Camera*>(pKeyFrame);
245  QDomElement keyTag = doc.createElement("camera");
246  keyTag.setAttribute("frame", camera->pos());
247 
248  keyTag.setAttribute("r", camera->rotation());
249  keyTag.setAttribute("s", camera->scaling());
250  keyTag.setAttribute("dx", camera->translation().x());
251  keyTag.setAttribute("dy", camera->translation().y());
252  keyTag.setAttribute("easing", static_cast<int>(camera->getEasingType()));
253  layerElem.appendChild(keyTag);
254  });
255 
256  return layerElem;
257 }
258 
259 void LayerCamera::loadDomElement(const QDomElement& element, QString dataDirPath, ProgressCallback progressStep)
260 {
261  Q_UNUSED(dataDirPath);
262  Q_UNUSED(progressStep);
263 
264  this->loadBaseDomElement(element);
265 
266  int width = element.attribute("width").toInt();
267  int height = element.attribute("height").toInt();
268  viewRect = QRect(-width / 2, -height / 2, width, height);
269 
270  QDomNode imageTag = element.firstChild();
271  while (!imageTag.isNull())
272  {
273  QDomElement imageElement = imageTag.toElement();
274  if (!imageElement.isNull())
275  {
276  if (imageElement.tagName() == "camera")
277  {
278  int frame = imageElement.attribute("frame").toInt();
279 
280  qreal rotate = imageElement.attribute("r", "0").toDouble();
281  qreal scale = imageElement.attribute("s", "1").toDouble();
282  qreal dx = imageElement.attribute("dx", "0").toDouble();
283  qreal dy = imageElement.attribute("dy", "0").toDouble();
284  CameraEasingType type = static_cast<CameraEasingType>(imageElement.attribute("easing", "0").toInt());
285 
286  loadImageAtFrame(frame, dx, dy, rotate, scale, type);
287  }
288  }
289  imageTag = imageTag.nextSibling();
290  }
291 }
void setType(QEasingCurve::Type type)
QSize size() const const
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const const
int height() const const
double toDouble(bool *ok) const const
Definition: camera.h:24
QString tr(const char *sourceText, const char *disambiguation, int n)
QDomNode nextSibling() const const
QDomElement toElement() const const
qreal x() const const
qreal y() const const
void setAttribute(const QString &name, const QString &value)
qreal m31() const const
qreal m32() const const
qreal m11() const const
qreal m12() const const
qreal m21() const const
qreal m22() const const
int toInt(bool *ok, int base) const const
Definition: layer.h:38
bool isNull() const const
QDomNode firstChild() const const
int width() const const
qreal valueForProgress(qreal progress) const const
Definition: object.h:41
QString tagName() const const
QDomElement createElement(const QString &tagName)