Pencil2D  ff90c0872e88be3bf81c548cd60f01983012ec49
Pencil2D is an animation software for both bitmap and vector graphics. It is free, multi-platform, and open source.
 All Classes Functions
canvasrenderer.cpp
1 /*
2 
3 Pencil - Traditional Animation Software
4 Copyright (C) 2012-2017 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 "canvasrenderer.h"
18 #include "object.h"
19 #include "layerbitmap.h"
20 #include "layervector.h"
21 #include "bitmapimage.h"
22 #include "layercamera.h"
23 #include "vectorimage.h"
24 #include "util.h"
25 
26 
27 
28 CanvasRenderer::CanvasRenderer( QObject* parent ) : QObject( parent )
29  , mLog( "CanvasRenderer" )
30 {
31  ENABLE_DEBUG_LOG( mLog, false );
32 }
33 
34 CanvasRenderer::~CanvasRenderer()
35 {
36 }
37 
38 void CanvasRenderer::setCanvas( QPixmap* canvas )
39 {
40  Q_ASSERT( canvas );
41  mCanvas = canvas;
42 }
43 
44 void CanvasRenderer::setViewTransform( QTransform viewTransform )
45 {
46  mViewTransform = viewTransform;
47 }
48 
49 void CanvasRenderer::setTransformedSelection(QRect selection, QTransform transform)
50 {
51  // Make sure that the selection is not empty
52  //
53  if (selection.width() > 0 && selection.height() > 0) {
54 
55  mSelection = selection;
56  mSelectionTransform = transform;
57  mRenderTransform = true;
58  }
59  else {
60 
61  // Otherwise we shouldn't be in transformation mode
62  //
63  ignoreTransformedSelection();
64  }
65 }
66 
67 void CanvasRenderer::ignoreTransformedSelection()
68 {
69  mRenderTransform = false;
70 }
71 
72 void CanvasRenderer::paint( Object* object, int layer, int frame, QRect rect )
73 {
74  Q_ASSERT( object );
75  mObject = object;
76 
77  mLayerIndex = layer;
78  mFrameNumber = frame;
79 
80  QPainter painter( mCanvas );
81 
82  painter.setWorldTransform( mViewTransform );
83  painter.setRenderHint( QPainter::SmoothPixmapTransform, mOptions.bAntiAlias );
84  painter.setRenderHint( QPainter::Antialiasing, true );
85 
86  // Don't set clip rect, paint whole canvas. `rect` therefore unused.
87  Q_UNUSED(rect);
88  //painter.setClipRect( rect );
89  //painter.setClipping( true );
90 
91  painter.setWorldMatrixEnabled( true );
92 
93  paintBackground();
94  paintOnionSkin( painter );
95 
96  paintCurrentFrame( painter );
97  paintCameraBorder( painter );
98 
99  // post effects
100  if ( mOptions.bAxis )
101  {
102  paintAxis( painter );
103  }
104 }
105 
106 void CanvasRenderer::paintBackground()
107 {
108  mCanvas->fill( Qt::transparent );
109 }
110 
111 void CanvasRenderer::paintOnionSkin( QPainter& painter )
112 {
113  Layer* layer = mObject->getLayer( mLayerIndex );
114 
115  if ( layer->keyFrameCount() == 0 )
116  {
117  return;
118  }
119 
120  qreal minOpacity = mOptions.fOnionSkinMinOpacity / 100;
121  qreal maxOpacity = mOptions.fOnionSkinMaxOpacity / 100;
122 
123  if ( mOptions.bPrevOnionSkin && mFrameNumber > 1 )
124  {
125  // Paint onion skin before current frame.
126  //
127  qreal prevOpacityIncrement = (maxOpacity - minOpacity) / mOptions.nPrevOnionSkinCount;
128  qreal opacity = maxOpacity;
129 
130  int onionFrameNumber = layer->getPreviousFrameNumber(mFrameNumber, mOptions.bIsOnionAbsolute);
131  int onionPosition = 0;
132 
133  while (onionPosition < mOptions.nPrevOnionSkinCount && onionFrameNumber > 0)
134  {
135  painter.setOpacity( opacity );
136 
137  switch ( layer->type() )
138  {
139  case Layer::BITMAP: { paintBitmapFrame( painter, mLayerIndex, onionFrameNumber, mOptions.bColorizePrevOnion, false ); break; }
140  case Layer::VECTOR: { paintVectorFrame( painter, mLayerIndex, onionFrameNumber, mOptions.bColorizePrevOnion, false ); break; }
141  case Layer::CAMERA: break;
142  case Layer::SOUND: break;
143  default: Q_ASSERT( false ); break;
144  }
145  opacity = opacity - prevOpacityIncrement;
146 
147 
148  onionFrameNumber = layer->getPreviousFrameNumber(onionFrameNumber, mOptions.bIsOnionAbsolute);
149  onionPosition++;
150  }
151  }
152 
153  if ( mOptions.bNextOnionSkin )
154  {
155  // Paint onion skin after current frame.
156  //
157  qreal nextOpacityIncrement = (maxOpacity - minOpacity) / mOptions.nNextOnionSkinCount;
158  qreal opacity = maxOpacity;
159 
160  int onionFrameNumber = layer->getNextFrameNumber(mFrameNumber, mOptions.bIsOnionAbsolute);
161  int onionPosition = 0;
162 
163  while (onionPosition < mOptions.nNextOnionSkinCount && onionFrameNumber > 0)
164  {
165  painter.setOpacity( opacity );
166 
167  switch ( layer->type() )
168  {
169  case Layer::BITMAP: { paintBitmapFrame( painter, mLayerIndex, onionFrameNumber, mOptions.bColorizeNextOnion, false ); break; }
170  case Layer::VECTOR: { paintVectorFrame( painter, mLayerIndex, onionFrameNumber, mOptions.bColorizeNextOnion, false ); break; }
171  case Layer::CAMERA: break;
172  case Layer::SOUND: break;
173  default: Q_ASSERT( false ); break;
174  }
175 
176  opacity = opacity - nextOpacityIncrement;
177 
178  onionFrameNumber = layer->getNextFrameNumber(onionFrameNumber, mOptions.bIsOnionAbsolute);
179  onionPosition++;
180  }
181  }
182 }
183 
184 void CanvasRenderer::paintBitmapFrame( QPainter& painter,
185  int layerId,
186  int nFrame,
187  bool colorize,
188  bool useLastKeyFrame )
189 {
190  Layer* layer = mObject->getLayer( layerId );
191 
192  if ( !layer->visible() )
193  {
194  return;
195  }
196 
197  LayerBitmap* bitmapLayer = dynamic_cast< LayerBitmap* >( layer );
198  if ( bitmapLayer == nullptr )
199  {
200  Q_ASSERT( bitmapLayer );
201  return;
202  }
203 
204  qCDebug( mLog ) << "Paint Onion skin bitmap, Frame = " << nFrame;
205  BitmapImage* bitmapImage;
206  if (useLastKeyFrame) {
207  bitmapImage = bitmapLayer->getLastBitmapImageAtFrame( nFrame, 0 );
208  }
209  else {
210  bitmapImage = bitmapLayer->getBitmapImageAtFrame( nFrame );
211  }
212 
213  if ( bitmapImage == nullptr )
214  {
215  return;
216  }
217 
218  BitmapImage* tempBitmapImage = new BitmapImage;
219  tempBitmapImage->paste(bitmapImage);
220 
221  if ( colorize )
222  {
223  QBrush colorBrush = QBrush(Qt::transparent); //no color for the current frame
224 
225  if (nFrame < mFrameNumber)
226  {
227  colorBrush = QBrush(Qt::red);
228  }
229  else if (nFrame > mFrameNumber)
230  {
231  colorBrush = QBrush(Qt::blue);
232  }
233 
234  tempBitmapImage->drawRect( bitmapImage->bounds(),
235  Qt::NoPen,
236  colorBrush,
237  QPainter::CompositionMode_SourceIn,
238  false);
239  }
240 
241  // If the current frame on the current layer has a transformation, we apply it.
242  //
243  if (mRenderTransform && nFrame == mFrameNumber && layerId == mLayerIndex ) {
244  tempBitmapImage->clear(mSelection);
245  paintTransformedSelection(painter);
246  }
247 
248  painter.setWorldMatrixEnabled( true );
249 
250  if (mRenderTransform && nFrame) {
251  painter.setOpacity( bitmapLayer->getOpacity() );
252  }
253 
254  tempBitmapImage->paintImage( painter );
255 
256  delete tempBitmapImage;
257 }
258 
259 void CanvasRenderer::paintVectorFrame( QPainter& painter,
260  int layerId,
261  int nFrame,
262  bool colorize,
263  bool useLastKeyFrame )
264 {
265  Layer* layer = mObject->getLayer( layerId );
266 
267  if ( !layer->visible() )
268  {
269  return;
270  }
271 
272  LayerVector* vectorLayer = dynamic_cast< LayerVector* >( layer );
273  if ( vectorLayer == nullptr )
274  {
275  Q_ASSERT( vectorLayer );
276  return;
277  }
278 
279  qCDebug( mLog ) << "Paint Onion skin vector, Frame = " << nFrame;
280  VectorImage* vectorImage;
281  if (useLastKeyFrame)
282  {
283  vectorImage = vectorLayer->getLastVectorImageAtFrame( nFrame, 0 );
284  }
285  else
286  {
287  vectorImage = vectorLayer->getVectorImageAtFrame( nFrame );
288  }
289  if ( vectorImage == nullptr )
290  {
291  return;
292  }
293 
294  QImage* pImage = new QImage( mCanvas->size(), QImage::Format_ARGB32_Premultiplied );
295  vectorImage->outputImage( pImage, mViewTransform, mOptions.bOutlines, mOptions.bThinLines, mOptions.bAntiAlias );
296 
297 
298  //painter.drawImage( QPoint( 0, 0 ), *pImage );
299 
300  // Go through a Bitmap image to paint the onion skin colour
301  //
302  BitmapImage* tempBitmapImage = new BitmapImage();
303  tempBitmapImage->setImage(pImage);
304 
305  if ( colorize )
306  {
307  QBrush colorBrush = QBrush(Qt::transparent); //no color for the current frame
308 
309  if (nFrame < mFrameNumber)
310  {
311  colorBrush = QBrush(Qt::red);
312  }
313  else if (nFrame > mFrameNumber)
314  {
315  colorBrush = QBrush(Qt::blue);
316  }
317 
318  tempBitmapImage->drawRect( pImage->rect(),
319  Qt::NoPen,
320  colorBrush,
321  QPainter::CompositionMode_SourceIn,
322  false);
323  }
324 
325  painter.setWorldMatrixEnabled( false ); //Don't tranform the image here as we used the viewTransform in the image output
326  tempBitmapImage->paintImage( painter );
327 
328  delete tempBitmapImage;
329 }
330 
331 void CanvasRenderer::paintTransformedSelection( QPainter& painter )
332 {
333  // Make sure there is something selected
334  //
335  if (mSelection.width() == 0 || mSelection.height() == 0) {
336  return;
337  }
338 
339  Layer* layer = mObject->getLayer( mLayerIndex );
340 
341  if (layer->type() == Layer::BITMAP) {
342 
343  // Get the transformed image
344  //
345  BitmapImage* bitmapImage = dynamic_cast< LayerBitmap* >( layer )->getLastBitmapImageAtFrame( mFrameNumber, 0 );
346 
347  BitmapImage transformedImage = bitmapImage->transformed(mSelection, mSelectionTransform, mOptions.bAntiAlias);
348 
349 
350  // Paint the transformation output
351  //
352  painter.setWorldMatrixEnabled( true );
353  transformedImage.paintImage(painter);
354  }
355 }
356 
357 void CanvasRenderer::paintCurrentFrame( QPainter& painter )
358 {
359  bool isCamera = mObject->getLayer(mLayerIndex)->type() == Layer::CAMERA;
360  for ( int i = 0; i < mObject->getLayerCount(); ++i )
361  {
362  Layer* layer = mObject->getLayer( i );
363  if ( i == mLayerIndex || mOptions.nShowAllLayers != 1 )
364  {
365  painter.setOpacity( 1.0 );
366  } else if ( isCamera != true ) {
367 
368  painter.setOpacity( 0.8 );
369  }
370 
371  if ( i == mLayerIndex || mOptions.nShowAllLayers > 0 ) {
372  switch ( layer->type() )
373  {
374  case Layer::BITMAP: { paintBitmapFrame( painter, i, mFrameNumber ); break; }
375  case Layer::VECTOR: { paintVectorFrame( painter, i, mFrameNumber ); break; }
376  case Layer::CAMERA: break;
377  case Layer::SOUND: break;
378  default: Q_ASSERT( false ); break;
379  }
380  }
381  }
382 }
383 
384 void CanvasRenderer::paintAxis( QPainter& painter )
385 {
386  painter.setPen( Qt::green );
387  painter.drawLine( QLineF( 0, -500, 0, 500 ) );
388 
389  painter.setPen( Qt::red );
390  painter.drawLine( QLineF( -500, 0, 500, 0 ) );
391 }
392 
393 int round100( double f, int gridSize )
394 {
395  return static_cast< int >( f ) / gridSize * gridSize;
396 }
397 
398 void CanvasRenderer::paintGrid( QPainter& painter )
399 {
400  int gridSize = mOptions.nGridSize;
401 
402  QRectF rect = painter.viewport();
403  QRectF boundingRect = mViewTransform.inverted().mapRect( rect );
404 
405  //qDebug() << mViewTransform;
406  //qDebug() << mViewTransform.inverted();
407 
408  int left = round100( boundingRect.left(), gridSize ) - gridSize;
409  int right = round100( boundingRect.right(), gridSize ) + gridSize;
410  int top = round100( boundingRect.top(), gridSize ) - gridSize;
411  int bottom = round100( boundingRect.bottom(), gridSize ) + gridSize;
412 
413  QPen pen( Qt::lightGray );
414  pen.setCosmetic( true );
415  painter.setPen( pen );
416  painter.setWorldMatrixEnabled( true );
417  painter.setBrush( Qt::NoBrush );
418  QPainter::RenderHints previous_renderhints = painter.renderHints();
419  painter.setRenderHint( QPainter::Antialiasing, false );
420  for ( int x = left; x < right; x += gridSize )
421  {
422  painter.drawLine( x, top, x, bottom );
423  }
424 
425  for ( int y = top; y < bottom; y += gridSize )
426  {
427  painter.drawLine( left, y, right, y );
428  }
429  painter.setRenderHints(previous_renderhints);
430 }
431 
432 void CanvasRenderer::renderGrid(QPainter& painter)
433 {
434  if ( mOptions.bGrid )
435  {
436  painter.setWorldTransform( mViewTransform );
437  paintGrid( painter );
438  }
439 }
440 
441 void CanvasRenderer::paintCameraBorder(QPainter &painter)
442 {
443 
444  for ( int i = 0; i < mObject->getLayerCount(); ++i )
445  {
446  Layer* layer = mObject->getLayer( i );
447 
448  if ( layer->type() == Layer::CAMERA && (i == mLayerIndex || mOptions.nShowAllLayers > 0) && layer->visible() ) {
449 
450  if ( i == mLayerIndex || mOptions.nShowAllLayers != 1 )
451  {
452  painter.setOpacity( 1.0 );
453  }
454  else {
455  painter.setOpacity( 0.8 );
456  }
457 
458  QRectF viewRect = painter.viewport();
459  QRect boundingRect = mViewTransform.inverted().mapRect( viewRect ).toRect();
460 
461 
462  LayerCamera* cameraLayer = dynamic_cast< LayerCamera* >( layer );
463 
464  mCameraRect = cameraLayer->getViewRect();
465 
466  painter.setWorldMatrixEnabled( true );
467  painter.setPen( Qt::NoPen );
468  painter.setBrush( QColor( 0, 0, 0, 160 ) );
469 
470  QRegion rg1(boundingRect);
471  QRegion rg2(mCameraRect);
472  QRegion rg3=rg1.subtracted(rg2);
473 
474  painter.setClipRegion(rg3);
475 
476  painter.drawRect( boundingRect );
477 
478  painter.setClipping(false);
479 
480  QPen pen( Qt::black,
481  2,
482  Qt::SolidLine,
483  Qt::FlatCap,
484  Qt::MiterJoin );
485  painter.setPen( pen );
486  painter.setBrush( Qt::NoBrush );
487  painter.drawRect( mCameraRect.adjusted( -1, -1, 1, 1) );
488  }
489  }
490 }
491 
492 QRect CanvasRenderer::getCameraRect()
493 {
494  return mCameraRect;
495 }
Definition: layer.h:32
Definition: object.h:71