1 /*
2  *  Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef KISASYNCANIMATIONRENDERDIALOGBASE_H
20 #define KISASYNCANIMATIONRENDERDIALOGBASE_H
21 
22 #include <QObject>
23 #include "kis_types.h"
24 #include "kritaui_export.h"
25 
26 class KisTimeRange;
27 class KisAsyncAnimationRendererBase;
28 class KisViewManager;
29 class KisRegion;
30 
31 /**
32  * @brief KisAsyncAnimationRenderDialogBase is a special class for rendering multiple
33  *        frames of the image and putting them somewhere (saving into a file or just
34  *        pushing into an openGL cache)
35  *
36  * The class handles a lot of boilerplate code for you and optimizes regeneration of
37  * the frames using multithreading, according to the user's settings. The responsibilities
38  * of the class are the following:
39  *
40  * Rendering itself:
41  *   - fetch the list of dirtly frames using calcDirtyFrames()
42  *   - create some clones of the image according to the user's settings
43  *     to facilitate multithreaded rendering and processing of the frames
44  *   - if the user doesn't have enough RAM, the clones will not be created
45  *     (the memory overhead is calculated using "projections" metric of the
46  *      statistics server).
47  *   - feed the images/threads with dirty frames until the all the frames
48  *     are done
49  *
50  * Progress reporting:
51  *   - if batchMode() is false, the user will see a progress dialog showing
52  *     the current progress with estimate about total processing timer
53  *   - the user can also cancel the regeneration by pressing Cancel button
54  *
55  * Usage Details:
56  *   - one should implement two methods to make the rendering work:
57  *     - calcDirtyFrames()
58  *     - createRenderer(KisImageSP image)
59  *   - these methods will be called on the start of the rendering
60  */
61 class KRITAUI_EXPORT KisAsyncAnimationRenderDialogBase : public QObject
62 {
63     Q_OBJECT
64 public:
65     enum Result {
66         RenderComplete,
67         RenderCancelled,
68         RenderFailed
69     };
70 
71 public:
72     /**
73      * @brief construct and initialize the dialog
74      * @param actionTitle the first line of the status reports that the user sees in the dialog
75      * @param image the image that will be as a source of frames. Make sure the image is *not*
76      *              locked by the time regenerateRange() is called
77      * @param busyWait the dialog will not show for the specified time (in milliseconds)
78      */
79     KisAsyncAnimationRenderDialogBase(const QString &actionTitle, KisImageSP image, int busyWait = 200);
80     virtual ~KisAsyncAnimationRenderDialogBase();
81 
82     /**
83      * @brief start generation of frames and (if not in batch mode) show the dialog
84      *
85      * The link to view manager is used to barrier lock with visual feedback in the
86      * end of the operation
87      */
88     virtual Result regenerateRange(KisViewManager *viewManager);
89 
90     /**
91      * Set area of image that will be regenerated. If \p roi is empty,
92      * full area of the image is regenerated.
93      */
94     void setRegionOfInterest(const KisRegion &roi);
95 
96     /**
97      * @see setRegionOfInterest()
98      */
99     KisRegion regionOfInterest() const;
100 
101     /**
102      * @brief setting batch mode to true will prevent any dialogs or message boxes from
103      *        showing on screen. Please take it into account that using batch mode prevents
104      *        some potentially dangerous recovery execution paths (e.g. delete the existing
105      *        frames in the destination folder). In such case the rendering will be stopped with
106      *        RenderFailed result.
107      */
108     void setBatchMode(bool value);
109 
110     /**
111      * @see setBatchMode
112      */
113     bool batchMode() const;
114 
115 private Q_SLOTS:
116     void slotFrameCompleted(int frame);
117     void slotFrameCancelled(int frame);
118 
119     void slotCancelRegeneration();
120     void slotUpdateCompressedProgressData();
121 
122 private:
123     void tryInitiateFrameRegeneration();
124     void updateProgressLabel();
125     void cancelProcessingImpl(bool isUserCancelled);
126 
127 protected:
128     /**
129      * @brief returns a list of frames that should be regenerated by the dialog
130      *
131      * Called by the dialog in the very beginning of regenerateRange()
132      */
133     virtual QList<int> calcDirtyFrames() const = 0;
134 
135     /**
136      * @brief create a renderer object linked to \p image
137      *
138      * Renderer are special objects that connect to the individual image signals,
139      * react on them and fetch the final frames data
140      *
141      * @see KisAsyncAnimationRendererBase
142      */
143     virtual KisAsyncAnimationRendererBase* createRenderer(KisImageSP image) = 0;
144 
145     virtual void initializeRendererForFrame(KisAsyncAnimationRendererBase *renderer,
146                                             KisImageSP image, int frame) = 0;
147 
148 private:
149     struct Private;
150     const QScopedPointer<Private> m_d;
151 };
152 
153 #endif // KISASYNCANIMATIONRENDERDIALOGBASE_H
154