kis_paint_information.h 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 *  Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
 *  Copyright (c) 2006 Boudewijn Rempt <boud@valdyas.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
#ifndef _KIS_PAINT_INFORMATION_
#define _KIS_PAINT_INFORMATION_

22
#include <kis_debug.h>
23
#include <QTime>
24

25
#include "kis_global.h"
26
#include "kritaimage_export.h"
Boudewijn Rempt's avatar
Boudewijn Rempt committed
27
#include <kis_distance_information.h>
28
#include "kis_random_source.h"
29
#include "KisPerStrokeRandomSource.h"
30 31
#include "kis_spacing_information.h"
#include "kis_timing_information.h"
32

33

34 35
class QDomDocument;
class QDomElement;
36
class KisDistanceInformation;
37

38

39
/**
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
 * KisPaintInformation contains information about the input event that
 * causes the brush action to happen to the brush engine's paint
 * methods.
 *
 * XXX: we directly pass the KoPointerEvent x and y tilt to
 * KisPaintInformation, and their range is -60 to +60!
 *
 * @param pos: the position of the paint event in subpixel accuracy
 * @param pressure: the pressure of the stylus
 * @param xTilt: the angle between the device (a pen, for example) and
 * the perpendicular in the direction of the x axis. Positive values
 * are towards the bottom of the tablet. The angle is within the range
 * 0 to 1
 * @param yTilt: the angle between the device (a pen, for example) and
 * the perpendicular in the direction of the y axis. Positive values
 * are towards the bottom of the tablet. The angle is within the range
 * 0 to .
 * @param movement: current position minus the last position of the call to paintAt
 * @param rotation
 * @param tangentialPressure
60
 * @param perspective
61
 **/
Boudewijn Rempt's avatar
Boudewijn Rempt committed
62 63
class KRITAIMAGE_EXPORT KisPaintInformation
{
64 65 66 67 68 69
public:
    /**
     * Note, that this class is relied on the compiler optimization
     * of the return value. So if it doesn't work for some reason,
     * please implement a proper copy c-tor
     */
70 71
    class KRITAIMAGE_EXPORT DistanceInformationRegistrar
    {
72
    public:
Boudewijn Rempt's avatar
Boudewijn Rempt committed
73 74
        DistanceInformationRegistrar(KisPaintInformation *_p, KisDistanceInformation *distanceInfo);
        ~DistanceInformationRegistrar();
75 76 77
    private:
        KisPaintInformation *p;
    };
78 79

public:
80 81 82 83

    /**
     * Create a new KisPaintInformation object.
     */
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    KisPaintInformation(const QPointF & pos,
                        qreal pressure,
                        qreal xTilt,
                        qreal yTilt,
                        qreal rotation,
                        qreal tangentialPressure,
                        qreal perspective,
                        qreal time,
                        qreal speed);

    KisPaintInformation(const QPointF & pos,
                        qreal pressure,
                        qreal xTilt,
                        qreal yTilt,
                        qreal rotation);

100
    KisPaintInformation(const QPointF & pos = QPointF(),
101
                        qreal pressure = PRESSURE_DEFAULT);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
102

103
    KisPaintInformation(const KisPaintInformation& rhs);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
104

105
    void operator=(const KisPaintInformation& rhs);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
106

107
    ~KisPaintInformation();
108

109 110 111
    template <class PaintOp>
    void paintAt(PaintOp &op, KisDistanceInformation *distanceInfo) {
        KisSpacingInformation spacingInfo;
112
        KisTimingInformation timingInfo;
113 114 115
        {
            DistanceInformationRegistrar r = registerDistanceInformation(distanceInfo);
            spacingInfo = op.paintAt(*this);
116
            timingInfo = op.updateTimingImpl(*this);
117 118 119 120 121 122 123

            // Initiate the process of locking the drawing angle. The locked value will
            // always be present in the internals, but it will be requested but the users
            // with a special parameter of drawingAngle() only.
            if (!this->isHoveringMode()) {
                distanceInfo->lockCurrentDrawingAngle(*this);
            }
124 125
        }

126
        distanceInfo->registerPaintedDab(*this, spacingInfo, timingInfo);
127
    }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
128

129
    const QPointF& pos() const;
130
    void setPos(const QPointF& p);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
131

132
    /// The pressure of the value (from 0.0 to 1.0)
133
    qreal pressure() const;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
134

135
    /// Set the pressure
136
    void setPressure(qreal p);
137 138

    /// The tilt of the pen on the horizontal axis (from 0.0 to 1.0)
139
    qreal xTilt() const;
140 141

    /// The tilt of the pen on the vertical axis (from 0.0 to 1.0)
142
    qreal yTilt() const;
143

144
    /// XXX !!! :-| Please add dox!
145 146
    void overrideDrawingAngle(qreal angle);

147
    /// XXX !!! :-| Please add dox!
148 149
    qreal drawingAngleSafe(const KisDistanceInformation &distance) const;

150 151 152 153 154 155 156
    /**
     * Causes the specified distance information to be temporarily registered with this
     * KisPaintInformation object, so that the KisPaintInformation can compute certain values that
     * may be needed at painting time, such as the drawing direction. When the returned object is
     * destroyed, the KisDistanceInformation will be unregistered. At most one
     * KisDistanceInformation can be registered with a given KisPaintInformation at a time.
     */
Boudewijn Rempt's avatar
Boudewijn Rempt committed
157
    DistanceInformationRegistrar registerDistanceInformation(KisDistanceInformation *distance);
158

159 160 161 162 163 164
    /**
     * Current brush direction computed from the cursor movement
     *
     * WARNING: this method is available *only* inside paintAt() call,
     * that is when the distance information is registered.
     */
165
    qreal drawingAngle(bool considerLockedAngle = false) const;
166

167 168 169 170 171 172 173 174
    /**
     * Current brush direction vector computed from the cursor movement
     *
     * WARNING: this method is available *only* inside paintAt() call,
     * that is when the distance information is registered.
     */
    QPointF drawingDirectionVector() const;

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    /**
     * Current brush speed computed from the cursor movement
     *
     * WARNING: this method is available *only* inside paintAt() call,
     * that is when the distance information is registered.
     */
    qreal drawingSpeed() const;

    /**
     * Current distance from the previous dab
     *
     * WARNING: this method is available *only* inside paintAt() call,
     * that is when the distance information is registered.
     */
    qreal drawingDistance() const;
190 191

    /// rotation as given by the tablet event
192
    qreal rotation() const;
193 194

    /// tangential pressure (i.e., rate for an airbrush device)
195
    qreal tangentialPressure() const;
196 197 198

    /// reciprocal of distance on the perspective grid
    qreal perspective() const;
199

200
    /// Number of ms since the beginning of the stroke
201
    qreal currentTime() const;
202

203 204 205
    /// Number of dabs painted since the beginning of the stroke
    int currentDabSeqNo() const;

Boudewijn Rempt's avatar
Boudewijn Rempt committed
206
    /// The length of the stroke **before** painting the current dab
207 208
    qreal totalStrokeLength() const;

209 210 211
    // random source for generating in-stroke effects
    KisRandomSourceSP randomSource() const;

212 213 214
    // the stroke should initialize random source of all the used
    // paint info objects, otherwise it shows a warning
    void setRandomSource(KisRandomSourceSP value);
215

216 217 218 219 220 221 222
    // random source for generating in-stroke effects, generates one(!) value per stroke
    KisPerStrokeRandomSourceSP perStrokeRandomSource() const;

    // the stroke should initialize per stroke random source of all the used
    // paint info objects, otherwise it shows a warning
    void setPerStrokeRandomSource(KisPerStrokeRandomSourceSP value);

223
    // set level of detail which info object has been generated for
224
    void setLevelOfDetail(int levelOfDetail);
225

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
    /**
     * The paint information may be generated not only during real
     * stroke when the actual painting is happening, but also when the
     * cursor is hovering the canvas. In this mode some of the sensors
     * work a bit differently. The most outstanding example is Fuzzy
     * sensor, which returns unit value in this mode, otherwise it is
     * too irritating for a user.
     *
     * This value is true only for paint information objects created with
     * createHoveringModeInfo() constructor.
     *
     * \see createHoveringModeInfo()
     */
    bool isHoveringMode() const;

    /**
     * Create a fake info object with isHoveringMode() property set to
     * true.
     *
     * \see isHoveringMode()
     */
247
    static KisPaintInformation createHoveringModeInfo(const QPointF &pos,
248 249 250 251
            qreal pressure = PRESSURE_DEFAULT,
            qreal xTilt = 0.0, qreal yTilt = 0.0,
            qreal rotation = 0.0,
            qreal tangentialPressure = 0.0,
252
            qreal perspective = 1.0,
253 254 255 256 257 258 259 260 261 262 263
	        qreal speed = 0.0,
            int canvasrotation = 0,
            bool canvasMirroredH = false);
    /**
     *Returns the canvas rotation if that has been given to the kispaintinformation.
     */
    int canvasRotation() const;
    /**
     *set the canvas rotation.
     */
    void setCanvasRotation(int rotation);
264

265 266 267 268
    /*
     *Whether the canvas is mirrored for the paint-operation.
     */
    bool canvasMirroredH() const;
269

270 271 272 273
    /*
     *Set whether the canvas is mirrored for the paint-operation.
     */
    void setCanvasHorizontalMirrorState(bool mir);
274

275
    void toXML(QDomDocument&, QDomElement&) const;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
276

277
    static KisPaintInformation fromXML(const QDomElement&);
278

279 280 281 282 283 284 285
    // TODO: Refactor the static mix functions to non-static in-place mutation
    //       versions like mixOtherOnlyPosition and mixOtherWithoutTime.
    // Heap allocation on Windows is awfully slow and will fragment the memory
    // badly. Since KisPaintInformation allocates on the heap, we should re-use
    // existing instance whenever possible, especially in loops.
    // Ref: https://phabricator.kde.org/D6578

286
    /// (1-t) * p1 + t * p2
287
    static KisPaintInformation mixOnlyPosition(qreal t, const KisPaintInformation& mixedPi, const KisPaintInformation& basePi);
288
    static KisPaintInformation mix(const QPointF& p, qreal t, const KisPaintInformation& p1, const KisPaintInformation& p2);
289
    static KisPaintInformation mix(qreal t, const KisPaintInformation& pi1, const KisPaintInformation& pi2);
290 291
    static KisPaintInformation mixWithoutTime(const QPointF &p, qreal t, const KisPaintInformation &p1, const KisPaintInformation &p2);
    static KisPaintInformation mixWithoutTime(qreal t, const KisPaintInformation &pi1, const KisPaintInformation &pi2);
292 293
    void mixOtherOnlyPosition(qreal t, const KisPaintInformation& other);
    void mixOtherWithoutTime(qreal t, const KisPaintInformation& other);
294 295
    static qreal tiltDirection(const KisPaintInformation& info, bool normalize = true);
    static qreal tiltElevation(const KisPaintInformation& info, qreal maxTiltX = 60.0, qreal maxTiltY = 60.0, bool normalize = true);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
296

297 298
private:
    static KisPaintInformation mixImpl(const QPointF &p, qreal t, const KisPaintInformation &p1, const KisPaintInformation &p2, bool posOnly, bool mixTime);
299
    void mixOtherImpl(const QPointF &p, qreal t, const KisPaintInformation &other, bool posOnly, bool mixTime);
300

301 302 303
private:
    struct Private;
    Private* const d;
304
};
305 306 307 308

KRITAIMAGE_EXPORT QDebug operator<<(QDebug debug, const KisPaintInformation& info);


309
#endif