From c72899fb82eadf4e6d3a223b132040504d7f9197 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Fri, 20 Sep 2019 19:41:07 -0600 Subject: [PATCH 1/3] Make painting more closely match the final result In particular this changes two big things: 1. The render order. Now the buffer image is rendered directly above the active layer, rather above all layers. 2. The eraser tool no longer paints white, it erases the current layer while drawing. --- core_lib/src/canvaspainter.cpp | 44 +++++++++++++++++++------ core_lib/src/canvaspainter.h | 13 +++++--- core_lib/src/interface/scribblearea.cpp | 29 +++++----------- core_lib/src/tool/erasertool.cpp | 32 ++++++++---------- 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index d86760495..9cd514276 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -69,13 +69,14 @@ void CanvasPainter::ignoreTransformedSelection() mRenderTransform = false; } -void CanvasPainter::paint(const Object* object, int layer, int frame, QRect rect) +void CanvasPainter::paint(const Object* object, int layer, int frame, QRect rect, BitmapImage *buffer) { Q_ASSERT(object); mObject = object; mCurrentLayerIndex = layer; mFrameNumber = frame; + mBuffer = buffer; //QRectF mappedInvCanvas = mViewInverse.mapRect(QRectF(mCanvas->rect())); //QSizeF croppedPainter = QSizeF(mappedInvCanvas.size()); @@ -141,8 +142,8 @@ void CanvasPainter::paintOnionSkin(QPainter& painter) switch (layer->type()) { - case Layer::BITMAP: { paintBitmapFrame(painter, layer, onionFrameNumber, mOptions.bColorizePrevOnion, false); break; } - case Layer::VECTOR: { paintVectorFrame(painter, layer, onionFrameNumber, mOptions.bColorizePrevOnion, false); break; } + case Layer::BITMAP: { paintBitmapFrame(painter, layer, onionFrameNumber, mOptions.bColorizePrevOnion, false, false); break; } + case Layer::VECTOR: { paintVectorFrame(painter, layer, onionFrameNumber, mOptions.bColorizePrevOnion, false, false); break; } default: break; } opacity = opacity - prevOpacityIncrement; @@ -167,8 +168,8 @@ void CanvasPainter::paintOnionSkin(QPainter& painter) switch (layer->type()) { - case Layer::BITMAP: { paintBitmapFrame(painter, layer, onionFrameNumber, mOptions.bColorizeNextOnion, false); break; } - case Layer::VECTOR: { paintVectorFrame(painter, layer, onionFrameNumber, mOptions.bColorizeNextOnion, false); break; } + case Layer::BITMAP: { paintBitmapFrame(painter, layer, onionFrameNumber, mOptions.bColorizeNextOnion, false, false); break; } + case Layer::VECTOR: { paintVectorFrame(painter, layer, onionFrameNumber, mOptions.bColorizeNextOnion, false, false); break; } default: break; } opacity = opacity - nextOpacityIncrement; @@ -183,7 +184,8 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, Layer* layer, int nFrame, bool colorize, - bool useLastKeyFrame) + bool useLastKeyFrame, + bool isCurrentFrame) { #ifdef _DEBUG LayerBitmap* bitmapLayer = dynamic_cast(layer); @@ -218,6 +220,11 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, BitmapImage paintToImage; paintToImage.paste(paintedImage); + if (isCurrentFrame) + { + paintToImage.paste(mBuffer, mOptions.cmBufferBlendMode); + } + if (colorize) { QBrush colorBrush = QBrush(Qt::transparent); //no color for the current frame @@ -278,7 +285,8 @@ void CanvasPainter::paintVectorFrame(QPainter& painter, Layer* layer, int nFrame, bool colorize, - bool useLastKeyFrame) + bool useLastKeyFrame, + bool isCurrentFrame) { #ifdef _DEBUG LayerVector* vectorLayer = dynamic_cast(layer); @@ -314,6 +322,11 @@ void CanvasPainter::paintVectorFrame(QPainter& painter, BitmapImage tempBitmapImage; tempBitmapImage.setImage(pImage); + if (isCurrentFrame) + { + tempBitmapImage.paste(mBuffer, mOptions.cmBufferBlendMode); + } + if (colorize) { QBrush colorBrush = QBrush(Qt::transparent); //no color for the current frame @@ -355,6 +368,16 @@ void CanvasPainter::paintTransformedSelection(QPainter& painter) } } +void CanvasPainter::paintBuffer(BitmapImage *targetImage, BitmapImage *buffer, Layer::LAYER_TYPE layerType) +{ + /*QPainter::CompositionMode prevCompositionMode = targetImage.compositionMode(); + //qDebug() << (prevCompositionMode == QPainter::CompositionMode_SourceOver); + targetImage.setCompositionMode(mOptions.cmBufferBlendMode); + + buffer->paintImage(targetImage); + targetImage.setCompositionMode(prevCompositionMode);*/ +} + void CanvasPainter::paintCurrentFrame(QPainter& painter) { //bool isCamera = mObject->getLayer(mCurrentLayerIndex)->type() == Layer::CAMERA; @@ -367,7 +390,8 @@ void CanvasPainter::paintCurrentFrame(QPainter& painter) if (layer->visible() == false) continue; - if (i == mCurrentLayerIndex) { + if (i == mCurrentLayerIndex) + { paintOnionSkin(painter); painter.setOpacity(1.0); } @@ -376,8 +400,8 @@ void CanvasPainter::paintCurrentFrame(QPainter& painter) { switch (layer->type()) { - case Layer::BITMAP: { paintBitmapFrame(painter, layer, mFrameNumber, false, true); break; } - case Layer::VECTOR: { paintVectorFrame(painter, layer, mFrameNumber, false, true); break; } + case Layer::BITMAP: { paintBitmapFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; } + case Layer::VECTOR: { paintVectorFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; } default: break; } } diff --git a/core_lib/src/canvaspainter.h b/core_lib/src/canvaspainter.h index 07910b96c..0d88f2a22 100644 --- a/core_lib/src/canvaspainter.h +++ b/core_lib/src/canvaspainter.h @@ -23,9 +23,9 @@ GNU General Public License for more details. #include #include "log.h" +#include "layer.h" class Object; -class Layer; class BitmapImage; class ViewManager; @@ -51,6 +51,7 @@ struct CanvasPainterOptions float scaling = 1.0f; bool isPlaying = false; bool onionWhilePlayback = false; + QPainter::CompositionMode cmBufferBlendMode = QPainter::CompositionMode_SourceOver; }; @@ -59,7 +60,7 @@ class CanvasPainter : public QObject Q_OBJECT public: - explicit CanvasPainter(QObject* parent = 0); + explicit CanvasPainter(QObject* parent = nullptr); virtual ~CanvasPainter(); void setCanvas(QPixmap* canvas); @@ -69,7 +70,7 @@ class CanvasPainter : public QObject void ignoreTransformedSelection(); QRect getCameraRect(); - void paint(const Object* object, int layer, int frame, QRect rect); + void paint(const Object* object, int layer, int frame, QRect rect, BitmapImage* buffer); void renderGrid(QPainter& painter); private: @@ -78,10 +79,11 @@ class CanvasPainter : public QObject void paintCurrentFrame(QPainter& painter); - void paintBitmapFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame); - void paintVectorFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame); + void paintBitmapFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame, bool isCurrentFrame); + void paintVectorFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame, bool isCurrentFrame); void paintTransformedSelection(QPainter& painter); + void paintBuffer(BitmapImage *targetImage, BitmapImage *buffer, Layer::LAYER_TYPE layerType); void paintGrid(QPainter& painter); void paintCameraBorder(QPainter& painter); void paintAxis(QPainter& painter); @@ -99,6 +101,7 @@ class CanvasPainter : public QObject int mCurrentLayerIndex = 0; int mFrameNumber = 0; + BitmapImage* mBuffer = nullptr; QImage mScaledBitmap; diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index daa4dd758..ed294706c 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -937,6 +937,10 @@ void ScribbleArea::paintEvent(QPaintEvent* event) //qDebug() << "Repaint canvas!"; } } + else + { + drawCanvas(mEditor->currentFrame(), event->rect()); + } if (currentTool()->type() == MOVE) { @@ -1024,28 +1028,10 @@ void ScribbleArea::paintEvent(QPaintEvent* event) { break; } - } // end siwtch + } // end switch } - // paints the buffer image - if (mEditor->layers()->currentLayer() != nullptr) - { - painter.setOpacity(1.0); - if (mEditor->layers()->currentLayer()->type() == Layer::BITMAP) - { - painter.setWorldMatrixEnabled(true); - painter.setTransform(mEditor->view()->getView()); - } - else if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR) - { - painter.setWorldMatrixEnabled(false); - } - - // TODO: move to above if vector statement - mBufferImg->paintImage(painter); - - paintCanvasCursor(painter); - } + paintCanvasCursor(painter); mCanvasPainter.renderGrid(painter); @@ -1125,6 +1111,7 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) o.scaling = mEditor->view()->scaling(); o.onionWhilePlayback = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK); o.isPlaying = mEditor->playback()->isPlaying() ? true : false; + o.cmBufferBlendMode = mEditor->tools()->currentTool()->type() == ToolType::ERASER ? QPainter::CompositionMode_DestinationOut : QPainter::CompositionMode_SourceOver; mCanvasPainter.setOptions(o); mCanvasPainter.setCanvas(&mCanvas); @@ -1132,7 +1119,7 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) ViewManager* vm = mEditor->view(); mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse()); - mCanvasPainter.paint(object, mEditor->layers()->currentLayerIndex(), frame, rect); + mCanvasPainter.paint(object, mEditor->layers()->currentLayerIndex(), frame, rect, mBufferImg); } void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor colour, qreal opacity, qreal offset) diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp index 022eb82d3..d37ee4d87 100644 --- a/core_lib/src/tool/erasertool.cpp +++ b/core_lib/src/tool/erasertool.cpp @@ -196,21 +196,17 @@ void EraserTool::drawStroke() if (layer->type() == Layer::BITMAP) { - for (auto & i : p) + for (int i = 0; i < p.size(); i++) { - i = mEditor->view()->mapScreenToCanvas(i); + p[i] = mEditor->view()->mapScreenToCanvas(p[i]); } - qreal opacity = 1.0; - mCurrentWidth = properties.width; - if (properties.pressure) - { - opacity = strokeManager()->getPressure(); - mCurrentWidth = (mCurrentWidth + (strokeManager()->getPressure() * mCurrentWidth)) * 0.5; - } + qreal pressure = (properties.pressure) ? mCurrentPressure : 1.0; + qreal opacity = (properties.pressure) ? (mCurrentPressure * 0.5) : 1.0; + qreal brushWidth = properties.width * pressure; + mCurrentWidth = brushWidth; - qreal brushWidth = mCurrentWidth; - qreal brushStep = (0.5 * brushWidth) - ((properties.feather / 100.0) * brushWidth * 0.5); + qreal brushStep = (0.5 * brushWidth); brushStep = qMax(1.0, brushStep); BlitRect rect; @@ -219,31 +215,29 @@ void EraserTool::drawStroke() QPointF b = getCurrentPoint(); qreal distance = 4 * QLineF(b, a).length(); - int steps = qRound(distance) / brushStep; + int steps = qRound(distance / brushStep); for (int i = 0; i < steps; i++) { - QPointF point = mLastBrushPoint + (i + 1) * (brushStep)* (b - mLastBrushPoint) / distance; + QPointF point = mLastBrushPoint + (i + 1) * brushStep * (getCurrentPoint() - mLastBrushPoint) / distance; + rect.extend(point.toPoint()); mScribbleArea->drawBrush(point, brushWidth, properties.feather, - QColor(255, 255, 255, 255), + Qt::white, opacity, properties.useFeather, properties.useAA); - if (i == (steps - 1)) { - mLastBrushPoint = point; + mLastBrushPoint = getCurrentPoint(); } } - int rad = qRound(brushWidth) / 2 + 2; + int rad = qRound(brushWidth / 2 + 2); - // continuously update buffer to update stroke behind grid. mScribbleArea->paintBitmapBufferRect(rect); - mScribbleArea->refreshBitmap(rect, rad); } else if (layer->type() == Layer::VECTOR) From 8fbffde88a341c3de695ae2f5450f0ad6b00d884 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 21 Sep 2019 13:20:43 -0600 Subject: [PATCH 2/3] Add pre and post layer caches --- core_lib/src/canvaspainter.cpp | 119 ++++++++++++++++++------ core_lib/src/canvaspainter.h | 15 ++- core_lib/src/interface/scribblearea.cpp | 55 ++++++++++- core_lib/src/interface/scribblearea.h | 5 +- 4 files changed, 156 insertions(+), 38 deletions(-) diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 9cd514276..0275f84bb 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -69,38 +69,92 @@ void CanvasPainter::ignoreTransformedSelection() mRenderTransform = false; } -void CanvasPainter::paint(const Object* object, int layer, int frame, QRect rect, BitmapImage *buffer) +QPainter* CanvasPainter::initializePainter(QPixmap *pixmap) { - Q_ASSERT(object); - mObject = object; + QPainter *painter = new QPainter(pixmap); - mCurrentLayerIndex = layer; - mFrameNumber = frame; - mBuffer = buffer; + painter->setWorldMatrixEnabled(true); + painter->setWorldTransform(mViewTransform); //QRectF mappedInvCanvas = mViewInverse.mapRect(QRectF(mCanvas->rect())); //QSizeF croppedPainter = QSizeF(mappedInvCanvas.size()); //QRectF aligned = QRectF(QPointF(mappedInvCanvas.topLeft()), croppedPainter); - QPainter painter(mCanvas); - painter.setWorldMatrixEnabled(true); - painter.setWorldTransform(mViewTransform); + //painter.setClipRect(aligned); // this aligned rect is valid only for bitmap images. - Q_UNUSED(rect); + return painter; +} - paintBackground(); +void CanvasPainter::renderPreLayers(QPixmap *pixmap) +{ + QScopedPointer painter(initializePainter(pixmap)); + renderPreLayers(painter.get()); +} - //painter.setClipRect(aligned); // this aligned rect is valid only for bitmap images. - paintCurrentFrame(painter); - paintCameraBorder(painter); +void CanvasPainter::renderPreLayers(QPainter *painter) +{ + if (mOptions.nShowAllLayers > 0) + { + paintCurrentFrame(*painter, 0, mCurrentLayerIndex-1); + } + + paintOnionSkin(*painter); + painter->setOpacity(1.0); +} + +void CanvasPainter::renderCurLayer(QPixmap *pixmap) +{ + QScopedPointer painter(initializePainter(pixmap)); + renderCurLayer(painter.get()); +} + +void CanvasPainter::renderCurLayer(QPainter *painter) +{ + paintCurrentFrame(*painter, mCurrentLayerIndex, mCurrentLayerIndex); +} + +void CanvasPainter::renderPostLayers(QPixmap *pixmap) +{ + QScopedPointer painter(initializePainter(pixmap)); + renderPostLayers(painter.get()); +} + +void CanvasPainter::renderPostLayers(QPainter *painter) +{ + if (mOptions.nShowAllLayers > 0) + { + paintCurrentFrame(*painter, mCurrentLayerIndex+1, mObject->getLayerCount()-1); + } + + paintCameraBorder(*painter); // post effects if (mOptions.bAxis) { - paintAxis(painter); + paintAxis(*painter); } } +void CanvasPainter::setPaintSettings(const Object* object, int currentLayer, int frame, QRect rect, BitmapImage *buffer) +{ + Q_UNUSED(rect); + Q_ASSERT(object); + mObject = object; + + mCurrentLayerIndex = currentLayer; + mFrameNumber = frame; + mBuffer = buffer; +} + +void CanvasPainter::paint() +{ + QScopedPointer painter(initializePainter(mCanvas)); + + renderPreLayers(painter.get()); + renderCurLayer(painter.get()); + renderPostLayers(painter.get()); +} + void CanvasPainter::paintBackground() { mCanvas->fill(Qt::transparent); @@ -209,11 +263,17 @@ void CanvasPainter::paintBitmapFrame(QPainter& painter, paintedImage = bitmapLayer->getBitmapImageAtFrame(nFrame); } - if (paintedImage == nullptr || paintedImage->bounds().isEmpty()) + if ((paintedImage == nullptr || paintedImage->bounds().isEmpty()) + && !(isCurrentFrame && mBuffer != nullptr && !mBuffer->bounds().isEmpty())) { return; } + if (paintedImage == nullptr) + { + paintedImage = new BitmapImage(); + } + paintedImage->loadFile(); // Critical! force the BitmapImage to load the image //qCDebug(mLog) << "Paint Image Size:" << paintedImage->image()->size(); @@ -378,32 +438,29 @@ void CanvasPainter::paintBuffer(BitmapImage *targetImage, BitmapImage *buffer, L targetImage.setCompositionMode(prevCompositionMode);*/ } -void CanvasPainter::paintCurrentFrame(QPainter& painter) +/** Paints layers within the specified range for the current frame. + * + * @param painter The painter to paint to + * @param startLayer The first layer to paint (inclusive) + * @param endLayer The last layer to paint (inclusive) + */ +void CanvasPainter::paintCurrentFrame(QPainter& painter, int startLayer, int endLayer) { //bool isCamera = mObject->getLayer(mCurrentLayerIndex)->type() == Layer::CAMERA; painter.setOpacity(1.0); - for (int i = 0; i < mObject->getLayerCount(); ++i) + for (int i = startLayer; i <= endLayer; ++i) { Layer* layer = mObject->getLayer(i); if (layer->visible() == false) continue; - if (i == mCurrentLayerIndex) + switch (layer->type()) { - paintOnionSkin(painter); - painter.setOpacity(1.0); - } - - if (i == mCurrentLayerIndex || mOptions.nShowAllLayers > 0) - { - switch (layer->type()) - { - case Layer::BITMAP: { paintBitmapFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; } - case Layer::VECTOR: { paintVectorFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; } - default: break; - } + case Layer::BITMAP: { paintBitmapFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; } + case Layer::VECTOR: { paintVectorFrame(painter, layer, mFrameNumber, false, true, i == mCurrentLayerIndex); break; } + default: break; } } } diff --git a/core_lib/src/canvaspainter.h b/core_lib/src/canvaspainter.h index 0d88f2a22..4df44e5ff 100644 --- a/core_lib/src/canvaspainter.h +++ b/core_lib/src/canvaspainter.h @@ -70,14 +70,23 @@ class CanvasPainter : public QObject void ignoreTransformedSelection(); QRect getCameraRect(); - void paint(const Object* object, int layer, int frame, QRect rect, BitmapImage* buffer); - void renderGrid(QPainter& painter); + QPainter *initializePainter(QPixmap *pixmap); + + void renderPreLayers(QPixmap *pixmap); + void renderPreLayers(QPainter *painter); + void renderCurLayer(QPixmap *pixmap); + void renderCurLayer(QPainter *painter); + void renderPostLayers(QPixmap *pixmap); + void renderPostLayers(QPainter *pixmap); + void setPaintSettings(const Object* object, int currentLayer, int frame, QRect rect, BitmapImage* buffer); + void paint(); + void renderGrid(QPainter& painter); private: void paintBackground(); void paintOnionSkin(QPainter& painter); - void paintCurrentFrame(QPainter& painter); + void paintCurrentFrame(QPainter& painter, int startLayer, int endLayer); void paintBitmapFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame, bool isCurrentFrame); void paintVectorFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame, bool isCurrentFrame); diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index ed294706c..be8a9aafa 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -227,6 +227,13 @@ void ScribbleArea::setModified(int layerNumber, int frameNumber) } } +void ScribbleArea::setAllDirty() +{ + mNeedUpdateAll = true; + mPreLayersCache.reset(); + mPostLayersCache.reset(); +} + /************************************************************************/ /* key event handlers */ /************************************************************************/ @@ -939,7 +946,42 @@ void ScribbleArea::paintEvent(QPaintEvent* event) } else { - drawCanvas(mEditor->currentFrame(), event->rect()); + QPixmap tempPixmap(mCanvas.size()); + tempPixmap.fill(Qt::transparent); + mCanvas.fill(Qt::transparent); + QScopedPointer tempPainter(mCanvasPainter.initializePainter(&tempPixmap)); + QScopedPointer canvasPainter(mCanvasPainter.initializePainter(&mCanvas)); + + prepCanvas(mEditor->currentFrame(), event->rect()); + + if (!mPreLayersCache) + { + mCanvasPainter.renderPreLayers(canvasPainter.get()); + mPreLayersCache.reset(new QPixmap(mCanvas)); + } + else + { + canvasPainter->setWorldMatrixEnabled(false); + canvasPainter->drawPixmap(0, 0, *(mPreLayersCache.get())); + canvasPainter->setWorldMatrixEnabled(true); + } + + mCanvasPainter.renderCurLayer(canvasPainter.get()); + + if (!mPostLayersCache) + { + mCanvasPainter.renderPostLayers(tempPainter.get()); + mPostLayersCache.reset(new QPixmap(tempPixmap)); + canvasPainter->setWorldMatrixEnabled(false); + canvasPainter->drawPixmap(0, 0, tempPixmap); + canvasPainter->setWorldMatrixEnabled(true); + } + else + { + canvasPainter->setWorldMatrixEnabled(false); + canvasPainter->drawPixmap(0, 0, *(mPostLayersCache.get())); + canvasPainter->setWorldMatrixEnabled(true); + } } if (currentTool()->type() == MOVE) @@ -1086,7 +1128,7 @@ VectorImage* ScribbleArea::currentVectorImage(Layer* layer) const return vectorLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); } -void ScribbleArea::drawCanvas(int frame, QRect rect) +void ScribbleArea::prepCanvas(int frame, QRect rect) { Object* object = mEditor->object(); @@ -1119,7 +1161,14 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) ViewManager* vm = mEditor->view(); mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse()); - mCanvasPainter.paint(object, mEditor->layers()->currentLayerIndex(), frame, rect, mBufferImg); + mCanvasPainter.setPaintSettings(object, mEditor->layers()->currentLayerIndex(), frame, rect, mBufferImg); +} + +void ScribbleArea::drawCanvas(int frame, QRect rect) +{ + mCanvas.fill(Qt::transparent); + prepCanvas(frame, rect); + mCanvasPainter.paint(); } void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor colour, qreal opacity, qreal offset) diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index f445fafd0..58a8b06bd 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -97,7 +97,7 @@ class ScribbleArea : public QWidget void setModified(int layerNumber, int frameNumber); bool shouldUpdateAll() const { return mNeedUpdateAll; } - void setAllDirty() { mNeedUpdateAll = true; } + void setAllDirty(); void flipSelection(bool flipVertical); @@ -182,6 +182,7 @@ public slots: QPixmap mTransCursImg; private: + void prepCanvas(int frame, QRect rect); void drawCanvas(int frame, QRect rect); void settingUpdated(SETTING setting); void paintSelectionVisuals(); @@ -241,6 +242,8 @@ public slots: // Pixmap Cache keys std::vector mPixmapCacheKeys; + // Caches specificially for when drawing on the canvas + std::unique_ptr mPreLayersCache, mPostLayersCache; // debug QRectF mDebugRect; From 1665f01801364fad94c2c84c12a23c045ea2bb8b Mon Sep 17 00:00:00 2001 From: CandyFace Date: Sat, 28 Sep 2019 16:14:46 +0200 Subject: [PATCH 3/3] Re-structure code * remove unnecessary qscopedpointer allocations for qpainter objects and use normal object instance with references. * Hide logic from scribblearea --- core_lib/src/canvaspainter.cpp | 111 +++++++++++++++--------- core_lib/src/canvaspainter.h | 33 ++++--- core_lib/src/interface/scribblearea.cpp | 39 +-------- core_lib/src/interface/scribblearea.h | 2 - 4 files changed, 96 insertions(+), 89 deletions(-) diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index 0275f84bb..25e232a58 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -69,75 +69,115 @@ void CanvasPainter::ignoreTransformedSelection() mRenderTransform = false; } -QPainter* CanvasPainter::initializePainter(QPixmap *pixmap) +void CanvasPainter::paintCached() { - QPainter *painter = new QPainter(pixmap); + QPixmap tempPixmap(mCanvas->size()); + tempPixmap.fill(Qt::transparent); + mCanvas->fill(Qt::transparent); + QPainter tempPainter; + QPainter painter; + initializePainter(tempPainter, tempPixmap); + initializePainter(painter, *mCanvas); + + if (!mPreLayersCache) + { + renderPreLayers(painter); + mPreLayersCache.reset(new QPixmap(*mCanvas)); + } + else + { + painter.setWorldMatrixEnabled(false); + painter.drawPixmap(0, 0, *(mPreLayersCache.get())); + painter.setWorldMatrixEnabled(true); + } - painter->setWorldMatrixEnabled(true); - painter->setWorldTransform(mViewTransform); + renderCurLayer(painter); - //QRectF mappedInvCanvas = mViewInverse.mapRect(QRectF(mCanvas->rect())); - //QSizeF croppedPainter = QSizeF(mappedInvCanvas.size()); - //QRectF aligned = QRectF(QPointF(mappedInvCanvas.topLeft()), croppedPainter); + if (!mPostLayersCache) + { + renderPostLayers(tempPainter); + mPostLayersCache.reset(new QPixmap(tempPixmap)); + painter.setWorldMatrixEnabled(false); + painter.drawPixmap(0, 0, tempPixmap); + painter.setWorldMatrixEnabled(true); + } + else + { + painter.setWorldMatrixEnabled(false); + painter.drawPixmap(0, 0, *(mPostLayersCache.get())); + painter.setWorldMatrixEnabled(true); + } +} - //painter.setClipRect(aligned); // this aligned rect is valid only for bitmap images. +void CanvasPainter::resetLayerCache() +{ + mPreLayersCache.reset(); + mPostLayersCache.reset(); +} - return painter; +void CanvasPainter::initializePainter(QPainter& painter, QPixmap& pixmap) +{ + painter.begin(&pixmap); + painter.setWorldMatrixEnabled(true); + painter.setWorldTransform(mViewTransform); } void CanvasPainter::renderPreLayers(QPixmap *pixmap) { - QScopedPointer painter(initializePainter(pixmap)); - renderPreLayers(painter.get()); + QPainter painter; + initializePainter(painter, *pixmap); + renderPreLayers(painter); } -void CanvasPainter::renderPreLayers(QPainter *painter) +void CanvasPainter::renderPreLayers(QPainter& painter) { if (mOptions.nShowAllLayers > 0) { - paintCurrentFrame(*painter, 0, mCurrentLayerIndex-1); + paintCurrentFrame(painter, 0, mCurrentLayerIndex-1); } - paintOnionSkin(*painter); - painter->setOpacity(1.0); + paintOnionSkin(painter); + painter.setOpacity(1.0); } void CanvasPainter::renderCurLayer(QPixmap *pixmap) { - QScopedPointer painter(initializePainter(pixmap)); - renderCurLayer(painter.get()); + QPainter painter; + initializePainter(painter, *pixmap); + renderCurLayer(painter); } -void CanvasPainter::renderCurLayer(QPainter *painter) +void CanvasPainter::renderCurLayer(QPainter& painter) { - paintCurrentFrame(*painter, mCurrentLayerIndex, mCurrentLayerIndex); + paintCurrentFrame(painter, mCurrentLayerIndex, mCurrentLayerIndex); } void CanvasPainter::renderPostLayers(QPixmap *pixmap) { - QScopedPointer painter(initializePainter(pixmap)); - renderPostLayers(painter.get()); + QPainter painter; + initializePainter(painter, *pixmap); + renderPostLayers(painter); } -void CanvasPainter::renderPostLayers(QPainter *painter) +void CanvasPainter::renderPostLayers(QPainter& painter) { if (mOptions.nShowAllLayers > 0) { - paintCurrentFrame(*painter, mCurrentLayerIndex+1, mObject->getLayerCount()-1); + paintCurrentFrame(painter, mCurrentLayerIndex+1, mObject->getLayerCount()-1); } - paintCameraBorder(*painter); + paintCameraBorder(painter); // post effects if (mOptions.bAxis) { - paintAxis(*painter); + paintAxis(painter); } } void CanvasPainter::setPaintSettings(const Object* object, int currentLayer, int frame, QRect rect, BitmapImage *buffer) { - Q_UNUSED(rect); + Q_UNUSED(rect) Q_ASSERT(object); mObject = object; @@ -148,11 +188,12 @@ void CanvasPainter::setPaintSettings(const Object* object, int currentLayer, int void CanvasPainter::paint() { - QScopedPointer painter(initializePainter(mCanvas)); + QPainter painter; + initializePainter(painter, *mCanvas); - renderPreLayers(painter.get()); - renderCurLayer(painter.get()); - renderPostLayers(painter.get()); + renderPreLayers(painter); + renderCurLayer(painter); + renderPostLayers(painter); } void CanvasPainter::paintBackground() @@ -428,16 +469,6 @@ void CanvasPainter::paintTransformedSelection(QPainter& painter) } } -void CanvasPainter::paintBuffer(BitmapImage *targetImage, BitmapImage *buffer, Layer::LAYER_TYPE layerType) -{ - /*QPainter::CompositionMode prevCompositionMode = targetImage.compositionMode(); - //qDebug() << (prevCompositionMode == QPainter::CompositionMode_SourceOver); - targetImage.setCompositionMode(mOptions.cmBufferBlendMode); - - buffer->paintImage(targetImage); - targetImage.setCompositionMode(prevCompositionMode);*/ -} - /** Paints layers within the specified range for the current frame. * * @param painter The painter to paint to diff --git a/core_lib/src/canvaspainter.h b/core_lib/src/canvaspainter.h index 4df44e5ff..cdbc1a999 100644 --- a/core_lib/src/canvaspainter.h +++ b/core_lib/src/canvaspainter.h @@ -70,29 +70,39 @@ class CanvasPainter : public QObject void ignoreTransformedSelection(); QRect getCameraRect(); - QPainter *initializePainter(QPixmap *pixmap); - - void renderPreLayers(QPixmap *pixmap); - void renderPreLayers(QPainter *painter); - void renderCurLayer(QPixmap *pixmap); - void renderCurLayer(QPainter *painter); - void renderPostLayers(QPixmap *pixmap); - void renderPostLayers(QPainter *pixmap); - void setPaintSettings(const Object* object, int currentLayer, int frame, QRect rect, BitmapImage* buffer); void paint(); + void paintCached(); void renderGrid(QPainter& painter); + void resetLayerCache(); + private: + + /** + * @brief CanvasPainter::initializePainter + * Enriches the painter with a context and sets it's initial matrix. + * @param The in/out painter + * @param The paint device ie. a pixmap + */ + void initializePainter(QPainter& painter, QPixmap& pixmap); + + void renderPreLayers(QPainter& painter); + void renderCurLayer(QPainter& painter); + void renderPostLayers(QPainter& painter); + void paintBackground(); void paintOnionSkin(QPainter& painter); + void renderPostLayers(QPixmap *pixmap); + void renderCurLayer(QPixmap *pixmap); + void renderPreLayers(QPixmap *pixmap); + void paintCurrentFrame(QPainter& painter, int startLayer, int endLayer); void paintBitmapFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame, bool isCurrentFrame); void paintVectorFrame(QPainter&, Layer* layer, int nFrame, bool colorize, bool useLastKeyFrame, bool isCurrentFrame); void paintTransformedSelection(QPainter& painter); - void paintBuffer(BitmapImage *targetImage, BitmapImage *buffer, Layer::LAYER_TYPE layerType); void paintGrid(QPainter& painter); void paintCameraBorder(QPainter& painter); void paintAxis(QPainter& painter); @@ -122,6 +132,9 @@ class CanvasPainter : public QObject QTransform mSelectionTransform; QLoggingCategory mLog; + + // Caches specificially for when drawing on the canvas + std::unique_ptr mPreLayersCache, mPostLayersCache; }; #endif // CANVASRENDERER_H diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index be8a9aafa..f535c3241 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -230,8 +230,7 @@ void ScribbleArea::setModified(int layerNumber, int frameNumber) void ScribbleArea::setAllDirty() { mNeedUpdateAll = true; - mPreLayersCache.reset(); - mPostLayersCache.reset(); + mCanvasPainter.resetLayerCache(); } /************************************************************************/ @@ -946,42 +945,8 @@ void ScribbleArea::paintEvent(QPaintEvent* event) } else { - QPixmap tempPixmap(mCanvas.size()); - tempPixmap.fill(Qt::transparent); - mCanvas.fill(Qt::transparent); - QScopedPointer tempPainter(mCanvasPainter.initializePainter(&tempPixmap)); - QScopedPointer canvasPainter(mCanvasPainter.initializePainter(&mCanvas)); - prepCanvas(mEditor->currentFrame(), event->rect()); - - if (!mPreLayersCache) - { - mCanvasPainter.renderPreLayers(canvasPainter.get()); - mPreLayersCache.reset(new QPixmap(mCanvas)); - } - else - { - canvasPainter->setWorldMatrixEnabled(false); - canvasPainter->drawPixmap(0, 0, *(mPreLayersCache.get())); - canvasPainter->setWorldMatrixEnabled(true); - } - - mCanvasPainter.renderCurLayer(canvasPainter.get()); - - if (!mPostLayersCache) - { - mCanvasPainter.renderPostLayers(tempPainter.get()); - mPostLayersCache.reset(new QPixmap(tempPixmap)); - canvasPainter->setWorldMatrixEnabled(false); - canvasPainter->drawPixmap(0, 0, tempPixmap); - canvasPainter->setWorldMatrixEnabled(true); - } - else - { - canvasPainter->setWorldMatrixEnabled(false); - canvasPainter->drawPixmap(0, 0, *(mPostLayersCache.get())); - canvasPainter->setWorldMatrixEnabled(true); - } + mCanvasPainter.paintCached(); } if (currentTool()->type() == MOVE) diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 58a8b06bd..076f38c8b 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -242,8 +242,6 @@ public slots: // Pixmap Cache keys std::vector mPixmapCacheKeys; - // Caches specificially for when drawing on the canvas - std::unique_ptr mPreLayersCache, mPostLayersCache; // debug QRectF mDebugRect;