diff --git a/core_lib/src/canvaspainter.cpp b/core_lib/src/canvaspainter.cpp index ef1324065..f03ae616f 100644 --- a/core_lib/src/canvaspainter.cpp +++ b/core_lib/src/canvaspainter.cpp @@ -159,9 +159,8 @@ void CanvasPainter::renderPostLayers(QPainter& painter, const QRect& blitRect) } } -void CanvasPainter::setPaintSettings(const Object* object, int currentLayer, int frame, QRect rect, TiledBuffer* tiledBuffer) +void CanvasPainter::setPaintSettings(const Object* object, int currentLayer, int frame, TiledBuffer* tiledBuffer) { - Q_UNUSED(rect) Q_ASSERT(object); mObject = object; diff --git a/core_lib/src/canvaspainter.h b/core_lib/src/canvaspainter.h index 66c6e1d98..99b90c6be 100644 --- a/core_lib/src/canvaspainter.h +++ b/core_lib/src/canvaspainter.h @@ -67,7 +67,7 @@ class CanvasPainter void setTransformedSelection(QRect selection, QTransform transform); void ignoreTransformedSelection(); - void setPaintSettings(const Object* object, int currentLayer, int frame, QRect rect, TiledBuffer* tilledBuffer); + void setPaintSettings(const Object* object, int currentLayer, int frame, TiledBuffer* tilledBuffer); void paint(const QRect& blitRect); void paintCached(const QRect& blitRect); void resetLayerCache(); diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index 7e6d58ede..4e8d5e319 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -1006,7 +1006,7 @@ void ScribbleArea::paintEvent(QPaintEvent* event) } else { - prepCanvas(currentFrame, event->rect()); + prepCanvas(currentFrame); prepCameraPainter(currentFrame); prepOverlays(currentFrame); @@ -1118,7 +1118,7 @@ void ScribbleArea::paintEvent(QPaintEvent* event) paintCanvasCursor(painter); - mOverlayPainter.paint(painter); + mOverlayPainter.paint(painter, rect()); // paints the selection outline if (mEditor->select()->somethingSelected()) @@ -1196,7 +1196,7 @@ void ScribbleArea::prepCameraPainter(int frame) mCameraPainter.setOnionSkinPainterOptions(onionSkinOptions); } -void ScribbleArea::prepCanvas(int frame, QRect rect) +void ScribbleArea::prepCanvas(int frame) { Object* object = mEditor->object(); @@ -1231,12 +1231,12 @@ void ScribbleArea::prepCanvas(int frame, QRect rect) mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse()); mCanvasPainter.setTransformedSelection(sm->mySelectionRect().toRect(), sm->selectionTransform()); - mCanvasPainter.setPaintSettings(object, mEditor->layers()->currentLayerIndex(), frame, rect, &mTiledBuffer); + mCanvasPainter.setPaintSettings(object, mEditor->layers()->currentLayerIndex(), frame, &mTiledBuffer); } void ScribbleArea::drawCanvas(int frame, QRect rect) { - prepCanvas(frame, rect); + prepCanvas(frame); prepCameraPainter(frame); prepOverlays(frame); mCanvasPainter.paint(rect); diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index 41c62ca6a..c31ffca13 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -215,7 +215,7 @@ public slots: void prepOverlays(int frame); void prepCameraPainter(int frame); - void prepCanvas(int frame, QRect rect); + void prepCanvas(int frame); void drawCanvas(int frame, QRect rect); void settingUpdated(SETTING setting); void paintSelectionVisuals(QPainter &painter); diff --git a/core_lib/src/overlaypainter.cpp b/core_lib/src/overlaypainter.cpp index a969cb96b..b1cd48010 100644 --- a/core_lib/src/overlaypainter.cpp +++ b/core_lib/src/overlaypainter.cpp @@ -3,10 +3,10 @@ #include "layercamera.h" #include "camera.h" #include "layer.h" +#include "util.h" -Q_CONSTEXPR static qreal LINELENGTHFACTOR = 2.0; -Q_CONSTEXPR static int LEFTANGLEOFFSET = 90; -Q_CONSTEXPR static int RIGHTANGLEOFFSET = -90; +Q_CONSTEXPR static int LEFT_ANGLE_OFFSET = 90; +Q_CONSTEXPR static int RIGHT_ANGLE_OFFSET = -90; Q_CONSTEXPR static int HANDLE_WIDTH = 12; OverlayPainter::OverlayPainter() @@ -33,7 +33,7 @@ void OverlayPainter::setViewTransform(const QTransform view) mViewTransform = view; } -void OverlayPainter::paint(QPainter &painter) +void OverlayPainter::paint(QPainter &painter, const QRect& viewport) { if (mCameraLayer == nullptr) { return; } @@ -65,17 +65,18 @@ void OverlayPainter::paint(QPainter &painter) paintOverlaySafeAreas(painter, *camera, camTransform, cameraRect); } + const QRect mappedViewport = mViewTransform.inverted().mapRect(viewport); if (mOptions.bPerspective1) { - paintOverlayPerspectiveOnePoint(painter, camTransform, cameraRect); + paintOverlayPerspectiveOnePoint(painter, mappedViewport, camTransform); } - if (mOptions.bPerspective2) + if (mOptions.bPerspective2 || mOptions.bPerspective3) { - paintOverlayPerspectiveTwoPoints(painter, *camera, camTransform, cameraRect); + paintOverlayPerspectiveTwoPoints(painter, mappedViewport, *camera, camTransform); } if (mOptions.bPerspective3) { - paintOverlayPerspectiveThreePoints(painter, *camera, camTransform, cameraRect); + paintOverlayPerspectiveThreePoints(painter, mappedViewport, *camera, camTransform); } if (mOptions.bGrid) @@ -211,7 +212,7 @@ void OverlayPainter::paintOverlaySafeAreas(QPainter &painter, const Camera& came QTransform t = scale.inverted() * rot * trans; painter.setTransform(t, true); - painter.drawText(QPoint(), QObject::tr("Safe Action area %1 %").arg(action)); + painter.drawText(QPoint(), tr("Safe Action area %1 %").arg(action)); painter.restore(); } } @@ -238,45 +239,35 @@ void OverlayPainter::paintOverlaySafeAreas(QPainter &painter, const Camera& came QTransform t = scale.inverted() * rot * trans; painter.setTransform(t, true); - painter.drawText(QPoint(), QObject::tr("Safe Title area %1 %").arg(title)); + painter.drawText(QPoint(), tr("Safe Title area %1 %").arg(title)); painter.restore(); } } painter.restore(); } -void OverlayPainter::paintOverlayPerspectiveOnePoint(QPainter& painter, const QTransform& camTransform, const QRect& camRect) const +void OverlayPainter::paintOverlayPerspectiveOnePoint(QPainter& painter, const QRect& viewport, const QTransform& camTransform) const { - painter.save(); - painter.setRenderHint(QPainter::Antialiasing, true); - qreal degrees = static_cast(mOptions.nOverlayAngle); if (degrees == 7.0) { degrees = 7.5; } - int repeats = static_cast(360 / degrees); - QLineF angleLine; QPointF singlePoint = camTransform.inverted().map(mOptions.mSinglePerspPoint); - if (singlePoint == QPointF(0, 0)) - { - // TODO: bug in Qt prevents points from being (0,0)... - singlePoint = QPointF(0.1, 0.1); - } + QLineF angleLine(singlePoint.x(), singlePoint.y(), singlePoint.x() + 1, singlePoint.y()); - angleLine.setP1(singlePoint); QVector lines; - for (int i = 0; i < repeats; i++) + for (qreal angle = 0; angle < 180; angle += degrees) { - angleLine.setAngle(i * degrees); - angleLine.setLength(camRect.width() * 2.0); - lines.append(angleLine); + angleLine.setAngle(angle); + lines.append(clipLine(angleLine, viewport, -qInf(), qInf())); } - painter.drawLines(lines); - - painter.setWorldMatrixEnabled(false); - singlePoint = mViewTransform.map(singlePoint); + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.drawLines(lines); if (mOptions.bShowHandle) { + singlePoint = mViewTransform.map(singlePoint); + painter.setWorldMatrixEnabled(false); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); painter.setPen(mPalette.color(QPalette::HighlightedText)); painter.setBrush(mPalette.color(QPalette::Highlight)); @@ -284,57 +275,35 @@ void OverlayPainter::paintOverlayPerspectiveOnePoint(QPainter& painter, const QT } painter.restore(); - } -void OverlayPainter::paintOverlayPerspectiveTwoPoints(QPainter& painter, const Camera& camera, const QTransform& camTransform, const QRect& camRect) const +void OverlayPainter::paintOverlayPerspectiveTwoPoints(QPainter& painter, const QRect& viewport, const Camera& camera, const QTransform& camTransform) const { - painter.save(); - painter.setRenderHint(QPainter::Antialiasing, true); - qreal degrees = static_cast(mOptions.nOverlayAngle); if (degrees == 7.0) { degrees = 7.5; } - int repeats = static_cast(180 / degrees); QPointF leftPoint = camTransform.inverted().map(mOptions.mLeftPerspPoint); QPointF rightPoint = camTransform.inverted().map(mOptions.mRightPerspPoint); - if (leftPoint == QPointF(0.0, 0.0)) - { - // TODO: bug in Qt prevents points from being (0,0)... - leftPoint = QPointF(0.1, 0.1); - } + QLineF angleLineLeft(leftPoint.x(), leftPoint.y(), leftPoint.x() + 1, leftPoint.y()); + QLineF angleLineRight(rightPoint.x(), rightPoint.y(), rightPoint.x() + 1, rightPoint.y()); - if (rightPoint == QPointF(0.0, 0.0)) - { - // TODO: bug in Qt prevents points from being (0,0)... - rightPoint = QPointF(0.1, 0.1); - } - - QLineF angleLineLeft; - QLineF angleLineRight; - angleLineLeft.setAngle(LEFTANGLEOFFSET); - angleLineLeft.setP1(leftPoint); - angleLineLeft.setLength(camRect.width() * LINELENGTHFACTOR); - angleLineRight.setAngle(RIGHTANGLEOFFSET); - angleLineRight.setP1(rightPoint); - angleLineRight.setLength(camRect.width() * LINELENGTHFACTOR); QVector lines; - for (int i = 0; i <= repeats; i++) + for (qreal angle = 0; angle <= 180; angle += degrees) { - angleLineLeft.setAngle((LEFTANGLEOFFSET - i * degrees) + camera.rotation()); - angleLineRight.setAngle((RIGHTANGLEOFFSET - i * degrees) + camera.rotation()); - lines.append(angleLineRight); - lines.append(angleLineLeft); + angleLineLeft.setAngle(LEFT_ANGLE_OFFSET - angle + camera.rotation()); + angleLineRight.setAngle(RIGHT_ANGLE_OFFSET - angle + camera.rotation()); + lines.append(clipLine(angleLineLeft, viewport, 0, qInf())); + lines.append(clipLine(angleLineRight, viewport, 0, qInf())); } + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, true); painter.drawLines(lines); - painter.setWorldMatrixEnabled(false); - - leftPoint = mViewTransform.map(leftPoint); - rightPoint = mViewTransform.map(rightPoint); - if (mOptions.bShowHandle) { + leftPoint = mViewTransform.map(leftPoint); + rightPoint = mViewTransform.map(rightPoint); + painter.setWorldMatrixEnabled(false); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); painter.setPen(mPalette.color(QPalette::HighlightedText)); painter.setBrush(mPalette.color(QPalette::Highlight)); @@ -345,44 +314,29 @@ void OverlayPainter::paintOverlayPerspectiveTwoPoints(QPainter& painter, const C painter.restore(); } -void OverlayPainter::paintOverlayPerspectiveThreePoints(QPainter& painter, const Camera& camera, const QTransform& camTransform, const QRect& camRect) const +void OverlayPainter::paintOverlayPerspectiveThreePoints(QPainter& painter, const QRect& viewport, const Camera& camera, const QTransform& camTransform) const { - if (!mOptions.bPerspective2) - paintOverlayPerspectiveTwoPoints(painter, camera, camTransform, camRect); - - painter.save(); - painter.setRenderHint(QPainter::Antialiasing, true); - qreal degrees = static_cast(mOptions.nOverlayAngle); if (degrees == 7.0) { degrees = 7.5; } - int repeats = static_cast(180 / degrees); QPointF middlePoint = camTransform.inverted().map(mOptions.mMiddlePerspPoint); - if (middlePoint == QPointF(0.0, 0.0)) - { - // TODO: bug in Qt prevents points from being (0,0)... - middlePoint = QPointF(0.1, 0.1); - } + QLineF angleLine(middlePoint.x(), middlePoint.y(), middlePoint.x() + 1, middlePoint.y()); const int middleAngleOffset = mOptions.mLeftPerspPoint.y() < mOptions.mMiddlePerspPoint.y() ? 180 : 0; - - QLineF angleLine; - angleLine.setAngle(middleAngleOffset); - angleLine.setP1(middlePoint); - angleLine.setLength(camRect.width() * LINELENGTHFACTOR); QVector lines; - for (int i = 0; i <= repeats; i++) + for (qreal angle = 0; angle <= 180; angle += degrees) { - angleLine.setAngle((middleAngleOffset - i * degrees) + camera.rotation()); - lines.append(angleLine); + angleLine.setAngle(middleAngleOffset - angle + camera.rotation()); + lines.append(clipLine(angleLine, viewport, 0, qInf())); } - painter.drawLines(lines); - painter.setWorldMatrixEnabled(false); - - middlePoint = mViewTransform.map(middlePoint); + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.drawLines(lines); if (mOptions.bShowHandle) { + middlePoint = mViewTransform.map(middlePoint); + painter.setWorldMatrixEnabled(false); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); painter.setPen(mPalette.color(QPalette::HighlightedText)); painter.setBrush(mPalette.color(QPalette::Highlight)); diff --git a/core_lib/src/overlaypainter.h b/core_lib/src/overlaypainter.h index b66762513..ce96f8f48 100644 --- a/core_lib/src/overlaypainter.h +++ b/core_lib/src/overlaypainter.h @@ -32,8 +32,6 @@ struct OverlayPainterOptions QPointF mLeftPerspPoint; QPointF mRightPerspPoint; QPointF mMiddlePerspPoint; - - QPainter::CompositionMode cmBufferBlendMode = QPainter::CompositionMode_SourceOver; }; class OverlayPainter @@ -47,7 +45,7 @@ class OverlayPainter void preparePainter(const LayerCamera* cameraLayer, const QPalette& palette); - void paint(QPainter& painter); + void paint(QPainter& painter, const QRect& viewport); private: void initializePainter(QPainter& painter); @@ -56,9 +54,9 @@ class OverlayPainter void paintOverlayThirds(QPainter& painter, const QTransform& camTransform, const QRect& camRect) const; void paintOverlayGolden(QPainter& painter, const QTransform& camTransform, const QRect& camRect) const; void paintOverlaySafeAreas(QPainter& painter, const Camera& camera, const QTransform& camTransform, const QRect& camRect) const; - void paintOverlayPerspectiveOnePoint(QPainter& painter, const QTransform& camTransform, const QRect& camRect) const; - void paintOverlayPerspectiveTwoPoints(QPainter& painter, const Camera& camera, const QTransform& camTransform, const QRect& camRect) const; - void paintOverlayPerspectiveThreePoints(QPainter& painter, const Camera& camera, const QTransform& camTransform, const QRect& camRect) const; + void paintOverlayPerspectiveOnePoint(QPainter& painter, const QRect& viewport, const QTransform& camTransform) const; + void paintOverlayPerspectiveTwoPoints(QPainter& painter, const QRect& viewport, const Camera& camera, const QTransform& camTransform) const; + void paintOverlayPerspectiveThreePoints(QPainter& painter, const QRect& viewport, const Camera& camera, const QTransform& camTransform) const; int round100(double f, int gridSize) const; diff --git a/core_lib/src/util/util.cpp b/core_lib/src/util/util.cpp index bf6721142..39468c04e 100644 --- a/core_lib/src/util/util.cpp +++ b/core_lib/src/util/util.cpp @@ -19,32 +19,40 @@ GNU General Public License for more details. #include #include -QTransform RectMapTransform( QRectF source, QRectF target ) +static inline bool clipInfiniteLineToEdge(qreal& t0, qreal& t1, qreal p, qreal q) { - qreal x1 = source.left(); - qreal y1 = source.top(); - qreal x2 = source.right(); - qreal y2 = source.bottom(); - qreal x1P = target.left(); - qreal y1P = target.top(); - qreal x2P = target.right(); - qreal y2P = target.bottom(); - - QTransform matrix; - if ( ( x1 != x2 ) && ( y1 != y2 ) ) - { - matrix = QTransform( ( x2P - x1P ) / ( x2 - x1 ), // scale x - 0, - 0, - ( y2P - y1P ) / ( y2 - y1 ), // scale y - ( x1P * x2 - x2P * x1 ) / ( x2 - x1 ), // dx - ( y1P * y2 - y2P * y1 ) / ( y2 - y1 ) ); // dy + if (p < 0) { // Line entering the clipping window + t0 = qMax(t0, q / p); + return t0 < t1; } - else - { - matrix.reset(); + if (p > 0) { // Line leaving the clipping window + t1 = qMin(t1, q / p); + return t0 < t1; } - return matrix; + return q >= 0; +} + +QLineF clipLine(const QLineF& line, const QRect& clip, qreal t0, qreal t1) +{ + int left = clip.left(), right = left + clip.width(), top = clip.top(), bottom = top + clip.height(); + qreal x1 = line.x1(), x2 = line.x2(), dx = line.dx(), y1 = line.y1(), y2 = line.y2(), dy = line.dy(); + + if (t0 == 0 && t1 == 1 && (x1 < left && x2 < left || + x1 > right && x2 > right || + y1 < top && y2 < top || + y1 > bottom && y2 > bottom) || + !clipInfiniteLineToEdge(t0, t1, -dx, x1 - left) || + !clipInfiniteLineToEdge(t0, t1, dx, right - x1) || + !clipInfiniteLineToEdge(t0, t1, -dy, y1 - top) || + !clipInfiniteLineToEdge(t0, t1, dy, bottom - y1)) { + return {}; + } + + Q_ASSERT(t0 < t1); + return {line.x1() + line.dx() * t0, + line.y1() + line.dy() * t0, + line.x1() + line.dx() * t1, + line.y1() + line.dy() * t1}; } void clearFocusOnFinished(QAbstractSpinBox *spinBox) @@ -106,14 +114,14 @@ quint64 imageSize(const QImage& img) QString uniqueString(int len) { static const char alphanum[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - const int alphanum_len = sizeof(alphanum); + const int alphanumLen = sizeof(alphanum); if (len > 128) len = 128; char s[128 + 1]; for (int i = 0; i < len; ++i) { - s[i] = alphanum[rand() % (alphanum_len - 1)]; + s[i] = alphanum[rand() % (alphanumLen - 1)]; } s[len] = 0; return QString::fromUtf8(s); diff --git a/core_lib/src/util/util.h b/core_lib/src/util/util.h index 4f19feecd..6a172502d 100644 --- a/core_lib/src/util/util.h +++ b/core_lib/src/util/util.h @@ -22,7 +22,17 @@ GNU General Public License for more details. class QAbstractSpinBox; -QTransform RectMapTransform( QRectF source, QRectF target ); +/** + * Clips a given line to a clipping window using the Liang-Barsky algorithm. + * @see https://www2.eecs.berkeley.edu/Pubs/TechRpts/1992/6271.html + * + * @param line The line to be clipped + * @param clip The clipping window to use + * @param t0 The starting point of the line to check, as a percentage + * @param t0 The ending point of the line to check, as a percentage + * @return The clipped line, or a null line if the line is completely outside the clipping window + */ +QLineF clipLine(const QLineF& line, const QRect& clip, qreal t0, qreal t1); void clearFocusOnFinished(QAbstractSpinBox *spinBox); diff --git a/tests/tests.pro b/tests/tests.pro index e229371c8..b18992808 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -9,7 +9,7 @@ TEMPLATE = app CONFIG += console CONFIG -= app_bundle -QT += core widgets gui xml multimedia svg testlib +QT += core widgets gui xml multimedia svg TARGET = tests