All Classes Namespaces Functions Variables Enumerations Properties Pages
canvaspainter.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2012-2020 Matthew Chiawen Chang
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 */
16 
17 #include "canvaspainter.h"
18 
19 #include <QtMath>
20 #include "object.h"
21 #include "layerbitmap.h"
22 #include "layervector.h"
23 #include "bitmapimage.h"
24 #include "layercamera.h"
25 #include "vectorimage.h"
26 #include "util.h"
27 
28 
29 CanvasPainter::CanvasPainter()
30 {
31 }
32 
33 CanvasPainter::~CanvasPainter()
34 {
35 }
36 
37 void CanvasPainter::setCanvas(QPixmap* canvas)
38 {
39  Q_ASSERT(canvas);
40  mCanvas = canvas;
41 }
42 
43 void CanvasPainter::setViewTransform(const QTransform view, const QTransform viewInverse)
44 {
45  if (mViewTransform != view || mViewInverse != viewInverse) {
46  mViewTransform = view;
47  mViewInverse = viewInverse;
48  }
49 }
50 
51 void CanvasPainter::setTransformedSelection(QRect selection, QTransform transform)
52 {
53  // Make sure that the selection is not empty
54  if (selection.width() > 0 && selection.height() > 0)
55  {
56  mSelection = selection;
57  mSelectionTransform = transform;
58  mRenderTransform = true;
59  }
60  else
61  {
62  // Otherwise we shouldn't be in transformation mode
63  ignoreTransformedSelection();
64  }
65 }
66 
67 void CanvasPainter::ignoreTransformedSelection()
68 {
69  mRenderTransform = false;
70 }
71 
72 void CanvasPainter::paintCached()
73 {
74  QPixmap tempPixmap(mCanvas->size());
75  tempPixmap.fill(Qt::transparent);
76  mCanvas->fill(Qt::transparent);
77  QPainter tempPainter;
78  QPainter painter;
79  initializePainter(tempPainter, tempPixmap);
80  initializePainter(painter, *mCanvas);
81 
82  if (!mPreLayersCache)
83  {
84  renderPreLayers(painter);
85  mPreLayersCache.reset(new QPixmap(*mCanvas));
86  }
87  else
88  {
89  painter.setWorldMatrixEnabled(false);
90  painter.drawPixmap(0, 0, *(mPreLayersCache.get()));
91  painter.setWorldMatrixEnabled(true);
92  }
93 
94  renderCurLayer(painter);
95 
96  if (!mPostLayersCache)
97  {
98  renderPostLayers(tempPainter);
99  mPostLayersCache.reset(new QPixmap(tempPixmap));
100  painter.setWorldMatrixEnabled(false);
101  painter.drawPixmap(0, 0, tempPixmap);
102  painter.setWorldMatrixEnabled(true);
103  }
104  else
105  {
106  painter.setWorldMatrixEnabled(false);
107  painter.drawPixmap(0, 0, *(mPostLayersCache.get()));
108  painter.setWorldMatrixEnabled(true);
109  }
110 }
111 
112 void CanvasPainter::resetLayerCache()
113 {
114  mPreLayersCache.reset();
115  mPostLayersCache.reset();
116 }
117 
119 {
120  painter.begin(&pixmap);
121  painter.setWorldMatrixEnabled(true);
122  painter.setWorldTransform(mViewTransform);
123 }
124 
125 void CanvasPainter::renderPreLayers(QPixmap* pixmap)
126 {
127  QPainter painter;
128  initializePainter(painter, *pixmap);
129  renderPreLayers(painter);
130 }
131 
132 void CanvasPainter::renderPreLayers(QPainter& painter)
133 {
134  if (mOptions.eLayerVisibility != LayerVisibility::CURRENTONLY || mObject->getLayer(mCurrentLayerIndex)->type() == Layer::CAMERA)
135  {
136  paintCurrentFrame(painter, 0, mCurrentLayerIndex - 1);
137  }
138 
139  paintOnionSkin(painter);
140  painter.setOpacity(1.0);
141 }
142 
143 void CanvasPainter::renderCurLayer(QPixmap* pixmap)
144 {
145  QPainter painter;
146  initializePainter(painter, *pixmap);
147  renderCurLayer(painter);
148 }
149 
150 void CanvasPainter::renderCurLayer(QPainter& painter)
151 {
152  paintCurrentFrame(painter, mCurrentLayerIndex, mCurrentLayerIndex);
153 }
154 
155 void CanvasPainter::renderPostLayers(QPixmap* pixmap)
156 {
157  QPainter painter;
158  initializePainter(painter, *pixmap);
159  renderPostLayers(painter);
160 }
161 
162 void CanvasPainter::renderPostLayers(QPainter& painter)
163 {
164  if (mOptions.eLayerVisibility != LayerVisibility::CURRENTONLY || mObject->getLayer(mCurrentLayerIndex)->type() == Layer::CAMERA)
165  {
166  paintCurrentFrame(painter, mCurrentLayerIndex + 1, mObject->getLayerCount() - 1);
167  }
168 
169  paintCameraBorder(painter);
170 
171  // post effects
172  if (mOptions.bAxis)
173  {
174  paintAxis(painter);
175  }
176 }
177 
178 void CanvasPainter::setPaintSettings(const Object* object, int currentLayer, int frame, QRect rect, BitmapImage* buffer)
179 {
180  Q_UNUSED(rect);
181  Q_ASSERT(object);
182  mObject = object;
183 
184  CANVASPAINTER_LOG("Set CurrentLayerIndex = %d", currentLayer);
185  mCurrentLayerIndex = currentLayer;
186  mFrameNumber = frame;
187  mBuffer = buffer;
188 }
189 
190 void CanvasPainter::paint()
191 {
192  QPainter painter;
193  initializePainter(painter, *mCanvas);
194 
195  renderPreLayers(painter);
196  renderCurLayer(painter);
197  renderPostLayers(painter);
198 }
199 
200 void CanvasPainter::paintBackground()
201 {
202  mCanvas->fill(Qt::transparent);
203 }
204 
205 void CanvasPainter::paintOnionSkin(QPainter& painter)
206 {
207  if (!mOptions.onionWhilePlayback && mOptions.isPlaying) { return; }
208 
209  Layer* layer = mObject->getLayer(mCurrentLayerIndex);
210 
211  if (layer->visible() == false)
212  return;
213 
214  if (layer->keyFrameCount() == 0)
215  return;
216 
217  qreal minOpacity = static_cast<qreal>(mOptions.fOnionSkinMinOpacity / 100);
218  qreal maxOpacity = static_cast<qreal>(mOptions.fOnionSkinMaxOpacity / 100);
219 
220  if (mOptions.bPrevOnionSkin && mFrameNumber > 1)
221  {
222  // Paint onion skin before current frame.
223  qreal prevOpacityIncrement = (maxOpacity - minOpacity) / mOptions.nPrevOnionSkinCount;
224  qreal opacity = maxOpacity;
225 
226  int onionFrameNumber = mFrameNumber;
227  if (mOptions.bIsOnionAbsolute)
228  {
229  onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber + 1, true);
230  }
231  onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber, mOptions.bIsOnionAbsolute);
232 
233  int onionPosition = 0;
234 
235  while (onionPosition < mOptions.nPrevOnionSkinCount && onionFrameNumber > 0)
236  {
237  painter.setOpacity(opacity);
238 
239  switch (layer->type())
240  {
241  case Layer::BITMAP: { paintBitmapFrame(painter, layer, onionFrameNumber, mOptions.bColorizePrevOnion, false, false); break; }
242  case Layer::VECTOR: { paintVectorFrame(painter, layer, onionFrameNumber, mOptions.bColorizePrevOnion, false, false); break; }
243  default: break;
244  }
245  opacity = opacity - prevOpacityIncrement;
246 
247  onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber, mOptions.bIsOnionAbsolute);
248  onionPosition++;
249  }
250  }
251 
252  if (mOptions.bNextOnionSkin)
253  {
254  // Paint onion skin after current frame.
255  qreal nextOpacityIncrement = (maxOpacity - minOpacity) / mOptions.nNextOnionSkinCount;
256  qreal opacity = maxOpacity;
257 
258  int onionFrameNumber = layer->getNextFrameNumber(mFrameNumber, mOptions.bIsOnionAbsolute);
259  int onionPosition = 0;
260 
261  while (onionPosition < mOptions.nNextOnionSkinCount && onionFrameNumber > 0)
262  {
263  painter.setOpacity(opacity);
264 
265  switch (layer->type())
266  {
267  case Layer::BITMAP: { paintBitmapFrame(painter, layer, onionFrameNumber, mOptions.bColorizeNextOnion, false, false); break; }
268  case Layer::VECTOR: { paintVectorFrame(painter, layer, onionFrameNumber, mOptions.bColorizeNextOnion, false, false); break; }
269  default: break;
270  }
271  opacity = opacity - nextOpacityIncrement;
272 
273  onionFrameNumber = layer->getNextFrameNumber(onionFrameNumber, mOptions.bIsOnionAbsolute);
274  onionPosition++;
275  }
276  }
277 }
278 
279 void CanvasPainter::paintBitmapFrame(QPainter& painter,
280  Layer* layer,
281  int nFrame,
282  bool colorize,
283  bool useLastKeyFrame,
284  bool isCurrentFrame)
285 {
286 #ifdef _DEBUG
287  LayerBitmap* bitmapLayer = dynamic_cast<LayerBitmap*>(layer);
288  Q_ASSERT(bitmapLayer);
289 #else
290  LayerBitmap* bitmapLayer = static_cast<LayerBitmap*>(layer);
291 #endif
292 
293  CANVASPAINTER_LOG(" Paint Bitmap Frame = %d, UseLastKeyFrame = %d", nFrame, useLastKeyFrame);
294  BitmapImage* paintedImage = nullptr;
295  if (useLastKeyFrame)
296  {
297  paintedImage = bitmapLayer->getLastBitmapImageAtFrame(nFrame, 0);
298  CANVASPAINTER_LOG(" Actual frame = %d", paintedImage->pos());
299  }
300  else
301  {
302  paintedImage = bitmapLayer->getBitmapImageAtFrame(nFrame);
303  }
304 
305  if (paintedImage == nullptr) { return; }
306  paintedImage->loadFile(); // Critical! force the BitmapImage to load the image
307  CANVASPAINTER_LOG(" Paint Image Size: %dx%d", paintedImage->image()->width(), paintedImage->image()->height());
308 
309  const bool frameIsEmpty = (paintedImage == nullptr || paintedImage->bounds().isEmpty());
310  const bool isDrawing = isCurrentFrame && mBuffer && !mBuffer->bounds().isEmpty();
311  if (frameIsEmpty && !isDrawing)
312  {
313  CANVASPAINTER_LOG(" Early return frame %d, %d", frameIsEmpty, isDrawing);
314  return;
315  }
316 
317  BitmapImage paintToImage;
318  paintToImage.paste(paintedImage);
319 
320  if (isCurrentFrame)
321  {
322  paintToImage.paste(mBuffer, mOptions.cmBufferBlendMode);
323  }
324 
325  if (colorize)
326  {
327  QBrush colorBrush = QBrush(Qt::transparent); //no color for the current frame
328 
329  if (nFrame < mFrameNumber)
330  {
331  colorBrush = QBrush(Qt::red);
332  }
333  else if (nFrame > mFrameNumber)
334  {
335  colorBrush = QBrush(Qt::blue);
336  }
337 
338  paintToImage.drawRect(paintedImage->bounds(),
339  Qt::NoPen,
340  colorBrush,
342  false);
343  }
344 
345  // If the current frame on the current layer has a transformation, we apply it.
346  bool shouldPaintTransform = mRenderTransform && nFrame == mFrameNumber && layer == mObject->getLayer(mCurrentLayerIndex);
347  if (shouldPaintTransform)
348  {
349  paintToImage.clear(mSelection);
350  }
351 
352  painter.setWorldMatrixEnabled(true);
353 
354  prescale(&paintToImage);
355  paintToImage.paintImage(painter, mScaledBitmap, mScaledBitmap.rect(), paintToImage.bounds());
356 
357  if (shouldPaintTransform)
358  {
359  paintTransformedSelection(painter);
360  }
361 // static int cc = 0;
362 // QString path = QString("C:/Temp/pencil2d/canvas-%1-%2-%3.png")
363 // .arg(cc++, 3, 10, QChar('0'))
364 // .arg(layer->name())
365 // .arg(mFrameNumber);
366 // Q_ASSERT(mCanvas->save(path));
367 
368 }
369 
370 void CanvasPainter::prescale(BitmapImage* bitmapImage)
371 {
372  QImage origImage = bitmapImage->image()->copy();
373 
374  // copy content of our unmodified qimage
375  // to our (not yet) scaled bitmap
376  mScaledBitmap = origImage.copy();
377 
378  if (mOptions.scaling >= 1.0f)
379  {
380  // TODO: Qt doesn't handle huge upscaled qimages well...
381  // possible solution, myPaintLib canvas renderer splits its canvas up in chunks.
382  }
383  else
384  {
385  // map to correct matrix
386  QRect mappedOrigImage = mViewTransform.mapRect(bitmapImage->bounds());
387  mScaledBitmap = mScaledBitmap.scaled(mappedOrigImage.size(),
389  }
390 }
391 
392 void CanvasPainter::paintVectorFrame(QPainter& painter,
393  Layer* layer,
394  int nFrame,
395  bool colorize,
396  bool useLastKeyFrame,
397  bool isCurrentFrame)
398 {
399 #ifdef _DEBUG
400  LayerVector* vectorLayer = dynamic_cast<LayerVector*>(layer);
401  Q_ASSERT(vectorLayer);
402 #else
403  LayerVector* vectorLayer = static_cast<LayerVector*>(layer);
404 #endif
405 
406  CANVASPAINTER_LOG("Paint Onion skin vector, Frame = %d", nFrame);
407  VectorImage* vectorImage = nullptr;
408  if (useLastKeyFrame)
409  {
410  vectorImage = vectorLayer->getLastVectorImageAtFrame(nFrame, 0);
411  }
412  else
413  {
414  vectorImage = vectorLayer->getVectorImageAtFrame(nFrame);
415  }
416  if (vectorImage == nullptr)
417  {
418  return;
419  }
420 
421  QImage* strokeImage = new QImage(mCanvas->size(), QImage::Format_ARGB32_Premultiplied);
422  vectorImage->outputImage(strokeImage, mViewTransform, mOptions.bOutlines, mOptions.bThinLines, mOptions.bAntiAlias);
423 
424  // Go through a Bitmap image to paint the onion skin colour
425  BitmapImage rasterizedVectorImage;
426  rasterizedVectorImage.setImage(strokeImage);
427 
428  if (colorize)
429  {
430  QBrush colorBrush = QBrush(Qt::transparent); //no color for the current frame
431 
432  if (nFrame < mFrameNumber)
433  {
434  colorBrush = QBrush(Qt::red);
435  }
436  else if (nFrame > mFrameNumber)
437  {
438  colorBrush = QBrush(Qt::blue);
439  }
440  rasterizedVectorImage.drawRect(strokeImage->rect(),
441  Qt::NoPen, colorBrush,
443  }
444 
445  // Don't transform the image here as we used the viewTransform in the image output
446  painter.setWorldMatrixEnabled(false);
447 
448  // Paint image as is
449  rasterizedVectorImage.paintImage(painter);
450  if (isCurrentFrame)
451  {
452  // Paste buffer onto image to see stroke in realtime
453  rasterizedVectorImage.paste(mBuffer, mOptions.cmBufferBlendMode);
454  }
455 
456  // Paint buffer pasted on top of vector image:
457  // fixes polyline not being rendered properly
458  rasterizedVectorImage.paintImage(painter);
459 }
460 
461 void CanvasPainter::paintTransformedSelection(QPainter& painter)
462 {
463  // Make sure there is something selected
464  if (mSelection.width() == 0 || mSelection.height() == 0)
465  return;
466 
467  Layer* layer = mObject->getLayer(mCurrentLayerIndex);
468 
469  if (layer->type() == Layer::BITMAP)
470  {
471  // Get the transformed image
472  BitmapImage* bitmapImage = static_cast<LayerBitmap*>(layer)->getLastBitmapImageAtFrame(mFrameNumber, 0);
473  if (bitmapImage == nullptr) { return; };
474  BitmapImage transformedImage = bitmapImage->transformed(mSelection, mSelectionTransform, mOptions.bAntiAlias);
475 
476  // Paint the transformation output
477  painter.setWorldMatrixEnabled(true);
478  transformedImage.paintImage(painter);
479  }
480 }
481 
488 void CanvasPainter::paintCurrentFrame(QPainter& painter, int startLayer, int endLayer)
489 {
490  painter.setOpacity(1.0);
491 
492 
493  bool isCameraLayer = mObject->getLayer(mCurrentLayerIndex)->type() == Layer::CAMERA;
494 
495  for (int i = startLayer; i <= endLayer; ++i)
496  {
497  Layer* layer = mObject->getLayer(i);
498 
499  if (layer->visible() == false)
500  continue;
501 
502  if (mOptions.eLayerVisibility == LayerVisibility::RELATED && !isCameraLayer)
503  {
505  }
506 
507  CANVASPAINTER_LOG(" Render Layer[%d] %s", i, layer->name());
508  switch (layer->type())
509  {
510  case Layer::BITMAP: { paintBitmapFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; }
511  case Layer::VECTOR: { paintVectorFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; }
512  default: break;
513  }
514  }
515 }
516 
518 {
519  int layerOffset = mCurrentLayerIndex - layerIndex;
520  int absoluteOffset = qAbs(layerOffset);
521  qreal newOpacity = 1.0;
522  if (absoluteOffset != 0)
523  {
524  newOpacity = qPow(static_cast<qreal>(mOptions.fLayerVisibilityThreshold), absoluteOffset);
525  }
526  return newOpacity;
527 }
528 
529 void CanvasPainter::paintAxis(QPainter& painter)
530 {
531  painter.setPen(Qt::green);
532  painter.drawLine(QLineF(0, -500, 0, 500));
533 
534  painter.setPen(Qt::red);
535  painter.drawLine(QLineF(-500, 0, 500, 0));
536 }
537 
538 int round100(double f, int gridSize)
539 {
540  return static_cast<int>(f) / gridSize * gridSize;
541 }
542 
543 void CanvasPainter::paintGrid(QPainter& painter)
544 {
545  int gridSizeW = mOptions.nGridSizeW;
546  int gridSizeH = mOptions.nGridSizeH;
547 
548  QRectF rect = painter.viewport();
549  QRectF boundingRect = mViewTransform.inverted().mapRect(rect);
550 
551  int left = round100(boundingRect.left(), gridSizeW) - gridSizeW;
552  int right = round100(boundingRect.right(), gridSizeW) + gridSizeW;
553  int top = round100(boundingRect.top(), gridSizeH) - gridSizeH;
554  int bottom = round100(boundingRect.bottom(), gridSizeH) + gridSizeH;
555 
556  QPen pen(Qt::lightGray);
557  pen.setCosmetic(true);
558  painter.setPen(pen);
559  painter.setWorldMatrixEnabled(true);
560  painter.setBrush(Qt::NoBrush);
561  QPainter::RenderHints previous_renderhints = painter.renderHints();
562  painter.setRenderHint(QPainter::Antialiasing, false);
563  // draw vertical grid lines
564  for (int x = left; x < right; x += gridSizeW)
565  {
566  painter.drawLine(x, top, x, bottom);
567  }
568 
569  // draw horizontal grid lines
570  for (int y = top; y < bottom; y += gridSizeH)
571  {
572  painter.drawLine(left, y, right, y);
573  }
574  painter.setRenderHints(previous_renderhints);
575 }
576 
577 void CanvasPainter::paintOverlayCenter(QPainter& painter)
578 {
579  QRect rect = getCameraRect();
580 
581  Layer* layer = mObject->getLayer(mCurrentLayerIndex);
582  bool isCameraMode = (layer->type() == Layer::CAMERA);
583 
584  painter.save();
586 
587  QPen pen(Qt::DashLine);
588  qreal space = 10;
589  QVector<qreal> dashes;
590  dashes << 10 << space << 10 << space << 10 << space;
591  pen.setDashPattern(dashes);
592  pen.setCosmetic(true);
593  painter.setPen(pen);
594  painter.setWorldMatrixEnabled(!isCameraMode);
595  painter.setBrush(Qt::NoBrush);
596  painter.setRenderHint(QPainter::Antialiasing, false);
597 
598  QPoint offsetX(OVERLAY_SAFE_CENTER_CROSS_SIZE, 0), offsetY(0, OVERLAY_SAFE_CENTER_CROSS_SIZE);
599  painter.drawLine(rect.center(), rect.center() - offsetX);
600  painter.drawLine(rect.center(), rect.center() + offsetX);
601  painter.drawLine(rect.center(), rect.center() - offsetY);
602  painter.drawLine(rect.center(), rect.center() + offsetY);
603 
604  painter.restore();
605 }
606 
607 void CanvasPainter::paintOverlayThirds(QPainter& painter)
608 {
609  QRect rect = getCameraRect();
610  painter.save();
612 
613  Layer* layer = mObject->getLayer(mCurrentLayerIndex);
614  bool isCameraMode = (layer->type() == Layer::CAMERA);
615 
616  QPen pen(Qt::DashLine);
617  qreal space = 10;
618  QVector<qreal> dashes;
619  dashes << 10 << space << 10 << space << 10 << space;
620  pen.setDashPattern(dashes);
621  pen.setCosmetic(true);
622  painter.setPen(pen);
623  painter.setWorldMatrixEnabled(!isCameraMode);
624  painter.setBrush(Qt::NoBrush);
625  QPainter::RenderHints previous_renderhints = painter.renderHints();
626  painter.setRenderHint(QPainter::Antialiasing, false);
627 
628  painter.drawLine(rect.x(), rect.y() + (rect.height() / 3), rect.right(), rect.y() + (rect.height() / 3));
629  painter.drawLine(rect.x(), rect.y() + (rect.height() * 2 / 3), rect.x() + rect.width(), rect.y() + (rect.height() * 2 / 3));
630  painter.drawLine(rect.x() + rect.width() / 3, rect.y(), rect.x() + rect.width() / 3, rect.y() + rect.height());
631  painter.drawLine(rect.x() + rect.width() * 2 / 3, rect.y(), rect.x() + rect.width() * 2 / 3, rect.y() + rect.height());
632 
633  painter.setRenderHints(previous_renderhints);
634  painter.restore();
635 }
636 
637 void CanvasPainter::paintOverlayGolden(QPainter& painter)
638 {
639  QRect rect = getCameraRect();
640  painter.save();
642 
643  Layer* layer = mObject->getLayer(mCurrentLayerIndex);
644  bool isCameraMode = (layer->type() == Layer::CAMERA);
645 
646  QPen pen(Qt::DashLine);
647  qreal space = 10;
648  QVector<qreal> dashes;
649  dashes << 10 << space << 10 << space << 10 << space;
650  pen.setDashPattern(dashes);
651  pen.setCosmetic(true);
652  painter.setPen(pen);
653  painter.setWorldMatrixEnabled(!isCameraMode);
654  painter.setBrush(Qt::NoBrush);
655  QPainter::RenderHints previous_renderhints = painter.renderHints();
656  painter.setRenderHint(QPainter::Antialiasing, false);
657 
658  painter.drawLine(rect.x(), static_cast<int>(rect.y() + (rect.height() * 0.38)), rect.right(), static_cast<int>(rect.y() + (rect.height() * 0.38)));
659  painter.drawLine(rect.x(), static_cast<int>(rect.y() + (rect.height() * 0.62)), rect.x() + rect.width(), static_cast<int>(rect.y() + (rect.height() * 0.62)));
660  painter.drawLine(static_cast<int>(rect.x() + rect.width() * 0.38), rect.y(), static_cast<int>(rect.x() + rect.width() * 0.38), rect.bottom());
661  painter.drawLine(static_cast<int>(rect.x() + rect.width() * 0.62), rect.y(), static_cast<int>(rect.x() + rect.width() * 0.62), rect.bottom());
662 
663  painter.setRenderHints(previous_renderhints);
664  painter.restore();
665 }
666 
667 void CanvasPainter::paintOverlaySafeAreas(QPainter& painter)
668 {
669  QRect rect = getCameraRect();
670 
671  Layer* layer = mObject->getLayer(mCurrentLayerIndex);
672  bool isCameraMode = (layer->type() == Layer::CAMERA);
673 
674  painter.save();
676  QPen pen(Qt::DashLine);
677  qreal space = 10;
678  QVector<qreal> dashes;
679  dashes << 10 << space << 10 << space << 10 << space;
680  pen.setDashPattern(dashes);
681  pen.setCosmetic(true);
682  painter.setPen(pen);
683  painter.setWorldMatrixEnabled(!isCameraMode);
684  painter.setBrush(Qt::NoBrush);
685  QPainter::RenderHints previous_renderhints = painter.renderHints();
687 
688  if (mOptions.bActionSafe)
689  {
690  int action = mOptions.nActionSafe;
691  QRect safeAction = QRect(rect.x() + rect.width() * action / 200,
692  rect.y() + rect.height() * action / 200,
693  rect.width() * (100 - action) / 100,
694  rect.height() * (100 - action) / 100);
695  painter.drawRect(safeAction);
696 
697  if (mOptions.bShowSafeAreaHelperText)
698  {
699  painter.drawText(safeAction.x(), safeAction.y() - 1, QObject::tr("Safe Action area %1 %").arg(action));
700  }
701  }
702  if (mOptions.bTitleSafe)
703  {
704  int title = mOptions.nTitleSafe;
705  QRect safeTitle = QRect(rect.x() + rect.width() * title / 200,
706  rect.y() + rect.height() * title / 200,
707  rect.width() * (100 - title) / 100,
708  rect.height() * (100 - title) / 100);
709  painter.drawRect(safeTitle);
710 
711  if (mOptions.bShowSafeAreaHelperText)
712  {
713  painter.drawText(safeTitle.x(), safeTitle.y() - 1, QObject::tr("Safe Title area %1 %").arg(title));
714  }
715  }
716 
717  painter.setRenderHints(previous_renderhints);
718  painter.restore();
719 }
720 
721 void CanvasPainter::renderGrid(QPainter& painter)
722 {
723  if (mOptions.bGrid)
724  {
725  painter.save();
726  painter.setWorldTransform(mViewTransform);
727  paintGrid(painter);
728  painter.restore();
729  }
730 }
731 
732 void CanvasPainter::renderOverlays(QPainter& painter)
733 {
734  if (mOptions.bCenter)
735  {
736  painter.save();
737  painter.setWorldTransform(mViewTransform);
738  paintOverlayCenter(painter);
739  painter.restore();
740  }
741  if (mOptions.bThirds)
742  {
743  painter.save();
744  painter.setWorldTransform(mViewTransform);
745  paintOverlayThirds(painter);
746  painter.restore();
747  }
748  if (mOptions.bGoldenRatio)
749  {
750  painter.save();
751  painter.setWorldTransform(mViewTransform);
752  paintOverlayGolden(painter);
753  painter.restore();
754  }
755  if (mOptions.bSafeArea)
756  {
757  painter.save();
758  painter.setWorldTransform(mViewTransform);
759  paintOverlaySafeAreas(painter);
760  painter.restore();
761  }
762 
763 }
764 
765 void CanvasPainter::paintCameraBorder(QPainter& painter)
766 {
767  LayerCamera* cameraLayer = nullptr;
768  bool isCameraMode = false;
769 
770  // Find the first visible camera layers
771  for (int i = 0; i < mObject->getLayerCount(); ++i)
772  {
773  Layer* layer = mObject->getLayer(i);
774  if (layer->type() == Layer::CAMERA && layer->visible())
775  {
776  cameraLayer = static_cast<LayerCamera*>(layer);
777  isCameraMode = (i == mCurrentLayerIndex);
778  break;
779  }
780  }
781 
782  if (cameraLayer == nullptr) { return; }
783 
784  QRectF viewRect = painter.viewport();
785  QRect boundingRect;
786  mCameraRect = cameraLayer->getViewRect();
787 
788  QRegion rg2(mCameraRect);
789  if (isCameraMode)
790  {
791  painter.setWorldMatrixEnabled(false);
792  QTransform center = QTransform::fromTranslate(viewRect.width() / 2.0, viewRect.height() / 2.0);
793  boundingRect = viewRect.toAlignedRect();
794  mCameraRect = center.mapRect(mCameraRect);
795  rg2 = center.map(rg2);
796  }
797  else
798  {
799  painter.setWorldMatrixEnabled(true);
800  QTransform viewInverse = mViewTransform.inverted();
801  boundingRect = viewInverse.mapRect(viewRect).toAlignedRect();
802 
803  QTransform camTransform = cameraLayer->getViewAtFrame(mFrameNumber);
804  mCameraRect = camTransform.inverted().mapRect(mCameraRect);
805  rg2 = camTransform.inverted().map(rg2);
806  }
807 
808  painter.setOpacity(1.0);
809  painter.setPen(Qt::NoPen);
810  painter.setBrush(QColor(0, 0, 0, 80));
811 
812  QRegion rg1(boundingRect);
813  QRegion rg3 = rg1.subtracted(rg2);
814 
815  painter.setClipRegion(rg3);
816  painter.drawRect(boundingRect);
817 
818  /*
819  painter.setClipping(false);
820 
821  QPen pen( Qt::black,
822  2,
823  Qt::SolidLine,
824  Qt::FlatCap,
825  Qt::MiterJoin );
826  painter.setPen( pen );
827  painter.setBrush( Qt::NoBrush );
828  painter.drawRect( mCameraRect.adjusted( -1, -1, 1, 1) );
829  */
830 }
831 
832 QRect CanvasPainter::getCameraRect()
833 {
834  return mCameraRect;
835 }
QTransform fromTranslate(qreal dx, qreal dy)
void setOpacity(qreal opacity)
QSize size() const const
QSize size() const const
void setCompositionMode(QPainter::CompositionMode mode)
void paintCurrentFrame(QPainter &painter, int startLayer, int endLayer)
Paints layers within the specified range for the current frame.
void setRenderHint(QPainter::RenderHint hint, bool on)
Format_ARGB32_Premultiplied
void fill(const QColor &color)
int right() const const
QPainter::RenderHints renderHints() const const
QPoint map(const QPoint &point) const const
QTextStream & right(QTextStream &stream)
void save()
qreal top() const const
int height() const const
int x() const const
int y() const const
void setClipRegion(const QRegion &region, Qt::ClipOperation operation)
void drawLine(const QLineF &line)
QImage copy(const QRect &rectangle) const const
QString tr(const char *sourceText, const char *disambiguation, int n)
qreal left() const const
QTransform inverted(bool *invertible) const const
QTextStream & left(QTextStream &stream)
qreal bottom() const const
void drawRect(const QRectF &rectangle)
QRegion subtracted(const QRegion &r) const const
void setPen(const QColor &color)
void setWorldTransform(const QTransform &matrix, bool combine)
int width() const const
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
QRect rect() const const
Definition: layer.h:39
QTextStream & center(QTextStream &stream)
void setBrush(const QBrush &brush)
void drawText(const QPointF &position, const QString &text)
QPoint center() const const
qreal right() const const
CompositionMode_SourceIn
bool isEmpty() const const
void initializePainter(QPainter &painter, QPixmap &pixmap)
CanvasPainter::initializePainter Enriches the painter with a context and sets it's initial matrix...
qreal calculateRelativeOpacityForLayer(int layerIndex) const
Calculate layer opacity based on current layer offset.
QRect viewport() const const
void setRenderHints(QPainter::RenderHints hints, bool on)
void restore()
int width() const const
qreal width() const const
IgnoreAspectRatio
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void setWorldMatrixEnabled(bool enable)
int bottom() const const
QRect toAlignedRect() const const
qreal height() const const
int height() const const
Definition: object.h:54
transparent
typedef RenderHints
bool begin(QPaintDevice *device)
SmoothTransformation
QRect mapRect(const QRect &rectangle) const const
void outputImage(QImage *image, QTransform myView, bool simplified, bool showThinCurves, bool antialiasing)
VectorImage::outputImage.
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const