File indexing completed on 2024-05-19 04:25:04

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_PAINTING_TWEAKS_H
0008 #define __KIS_PAINTING_TWEAKS_H
0009 
0010 #include "kritaglobal_export.h"
0011 
0012 #include <QPen>
0013 #include <QBrush>
0014 
0015 #include <QVector3D>
0016 #include <QVector2D>
0017 
0018 class QPainter;
0019 class QRegion;
0020 class QRect;
0021 class QPen;
0022 
0023 namespace KisPaintingTweaks {
0024 
0025     /**
0026      * This is a workaround for QPainter::clipRegion() bug. When zoom
0027      * is about 2000% and rotation is in a range[-5;5] degrees, the
0028      * generated region will have about 20k+ rectangles inside. Their
0029      * processing will be really slow. These functions work around
0030      * the issue.
0031      */
0032     KRITAGLOBAL_EXPORT QRegion safeClipRegion(const QPainter &painter);
0033 
0034     /**
0035      * \see safeClipRegion()
0036      */
0037     KRITAGLOBAL_EXPORT QRect safeClipBoundingRect(const QPainter &painter);
0038 
0039     KRITAGLOBAL_EXPORT void initAntsPen(QPen *antsPen, QPen *outlinePen,
0040                                         int antLength = 4, int antSpace = 4);
0041 
0042 
0043     /**
0044      * A special class to save painter->pen() and painter->brush() using RAII
0045      * principle.
0046      */
0047     class KRITAGLOBAL_EXPORT PenBrushSaver
0048     {
0049     public:
0050         struct allow_noop_t { explicit allow_noop_t() = default; };
0051         static constexpr allow_noop_t   allow_noop { };
0052 
0053         /**
0054          * Saves pen and brush state of the provided painter object. \p painter cannot be null.
0055          */
0056         PenBrushSaver(QPainter *painter);
0057 
0058         /**
0059          * Overrides pen and brush of \p painter with the provided values. \p painter cannot be null.
0060          */
0061         PenBrushSaver(QPainter *painter, const QPen &pen, const QBrush &brush);
0062 
0063         /**
0064          * Overrides pen and brush of \p painter with the provided values. \p painter cannot be null.
0065          */
0066         PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair);
0067 
0068         /**
0069          * A special constructor of PenBrushSaver that allows \p painter to be null. Passing null
0070          * pointer will basically mean that the whole saver existence will be a noop.
0071          */
0072         PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair, allow_noop_t);
0073 
0074         /**
0075          * Restores the state of the painter that has been saved during the construction of the saver
0076          */
0077         ~PenBrushSaver();
0078 
0079     private:
0080         PenBrushSaver(const PenBrushSaver &rhs) = delete;
0081         QPainter *m_painter;
0082         QPen m_pen;
0083         QBrush m_brush;
0084     };
0085 
0086     QColor KRITAGLOBAL_EXPORT blendColors(const QColor &c1, const QColor &c2, qreal r1);
0087 
0088 
0089     /**
0090      * @brief luminosityCoarse
0091      * This calculates the luminosity of the given QColor.
0092      * It uses a very coarse (10 step) lut to linearize the sRGB trc, and then
0093      * uses rec709 values to calculate the luminosity. Because of the effect of
0094      * linearization, this is still more precise than one that just calculates
0095      * based on coefficients.
0096      * @param c the color to calculate the luminosity of.
0097      * @param sRGBtrc whether to linearize the sRGB trc.
0098      * @return a delinearized luminosity value, quantized to steps of 0.1.
0099      */
0100     qreal KRITAGLOBAL_EXPORT luminosityCoarse(const QColor &c, bool sRGBtrc = true);
0101 
0102     /**
0103      * \return an approximate difference between \p c1 and \p c2
0104      *         in a (nonlinear) range [0, 3]
0105      *
0106      * The colors are compared using the formula:
0107      *     difference = sqrt(2 * diff_R^2 + 4 * diff_G^2 + 3 * diff_B^2)
0108      */
0109     qreal KRITAGLOBAL_EXPORT colorDifference(const QColor &c1, const QColor &c2);
0110 
0111     /**
0112      * Make the color \p color differ from \p baseColor for at least \p threshold value
0113      */
0114     void KRITAGLOBAL_EXPORT dragColor(QColor *color, const QColor &baseColor, qreal threshold);
0115 
0116     inline void rectToVertices(QVector3D* vertices, const QRectF &rc)
0117     {
0118         vertices[0] = QVector3D(rc.left(),  rc.bottom(), 0.f);
0119         vertices[1] = QVector3D(rc.left(),  rc.top(),    0.f);
0120         vertices[2] = QVector3D(rc.right(), rc.bottom(), 0.f);
0121         vertices[3] = QVector3D(rc.left(),  rc.top(), 0.f);
0122         vertices[4] = QVector3D(rc.right(), rc.top(), 0.f);
0123         vertices[5] = QVector3D(rc.right(), rc.bottom(),    0.f);
0124     }
0125 
0126     inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc)
0127     {
0128         texCoords[0] = QVector2D(rc.left(), rc.bottom());
0129         texCoords[1] = QVector2D(rc.left(), rc.top());
0130         texCoords[2] = QVector2D(rc.right(), rc.bottom());
0131         texCoords[3] = QVector2D(rc.left(), rc.top());
0132         texCoords[4] = QVector2D(rc.right(), rc.top());
0133         texCoords[5] = QVector2D(rc.right(), rc.bottom());
0134     }
0135 }
0136 
0137 #endif /* __KIS_PAINTING_TWEAKS_H */