1 #pragma once
2 
3 #ifndef SCENEVIEWER_H
4 #define SCENEVIEWER_H
5 
6 // TnzCore includes
7 #include "tgeometry.h"
8 #include "tgl.h"
9 
10 // TnzLib includes
11 #include "toonz/imagepainter.h"
12 
13 // TnzQt includes
14 #include "toonzqt/menubarcommand.h"
15 #include "toonzqt/flipconsole.h"
16 #include "toonzqt/glwidget_for_highdpi.h"
17 
18 // TnzTools includes
19 #include "tools/tool.h"
20 
21 // Toonz includes
22 #include "pane.h"
23 #include "previewer.h"
24 
25 #include <array>
26 #include <QMatrix4x4>
27 #include <QTouchDevice>
28 
29 //=====================================================================
30 
31 //  Forward declarations
32 
33 class Ruler;
34 class QMenu;
35 class SceneViewer;
36 class LocatorPopup;
37 class QGestureEvent;
38 class QTouchEvent;
39 class QOpenGLFramebufferObject;
40 class LutCalibrator;
41 class StopMotion;
42 
43 namespace ImageUtils {
44 class FullScreenWidget;
45 }
46 
47 //=====================================================================
48 
49 class ToggleCommandHandler final : public MenuItemHandler {
50   int m_status;
51 
52 public:
53   ToggleCommandHandler(CommandId id, bool startStatus);
54 
getStatus()55   bool getStatus() const { return m_status; }
56   // For reproducing the UI toggle when launch
setStatus(bool status)57   void setStatus(bool status) { m_status = status; }
58   void execute() override;
59 };
60 
61 //=============================================================================
62 // SceneViewer
63 //-----------------------------------------------------------------------------
64 
65 class SceneViewer final : public GLWidgetForHighDpi,
66                           public TTool::Viewer,
67                           public Previewer::Listener {
68   Q_OBJECT
69 
70   double m_pressure;
71   QPointF m_lastMousePos;
72   QPointF m_pos;
73   Qt::MouseButton m_mouseButton;
74   bool m_foregroundDrawing;
75   bool m_tabletEvent, m_tabletMove;
76   enum TabletState {
77     None = 0,
78     Touched,      // Pressed for mouse
79     StartStroke,  // this state is to detect the first call
80                   // of TabletMove just after TabletPress
81     OnStroke,
82     Released
83   } m_tabletState = None,
84     m_mouseState  = None;
85   // used to handle wrong mouse drag events!
86   bool m_buttonClicked, m_toolSwitched;
87   bool m_shownOnce                       = false;
88   bool m_gestureActive                   = false;
89   bool m_touchActive                     = false;
90   QTouchDevice::DeviceType m_touchDevice = QTouchDevice::TouchScreen;
91   bool m_rotating                        = false;
92   bool m_zooming                         = false;
93   bool m_panning                         = false;
94   QPointF m_firstPanPoint;
95   QPointF m_undoPoint;
96   double m_scaleFactor;    // used for zoom gesture
97   double m_rotationDelta;  // used for rotate gesture
98   int m_referenceMode;
99   int m_previewMode;
100   bool m_isMouseEntered, m_forceGlFlush;
101   bool m_isFlippedX = false, m_isFlippedY = false;
102   /*!  FreezedStatus:
103    *  \li NO_FREEZED freezed is not active;
104    *  \li NORMAL_FREEZED freezed is active: show grab image;
105    *  \li UPDATE_FREEZED freezed is active: draw last unfreezed image and grab
106    * view;
107    */
108   enum FreezedStatus {
109     NO_FREEZED     = 0,
110     NORMAL_FREEZED = 1,
111     UPDATE_FREEZED = 2,
112   } m_freezedStatus;
113   TRaster32P m_viewGrabImage;
114 
115   int m_FPS;
116 
117   ImagePainter::CompareSettings m_compareSettings;
118   Ruler *m_hRuler;
119   Ruler *m_vRuler;
120 
121   TPointD m_pan3D;
122   double m_zoomScale3D;
123   double m_phi3D;
124   double m_theta3D;
125   double m_minZ;
126 
127   // current pan/zoom matrix (two different matrices are used for editing scenes
128   // and leves)
129   std::array<TAffine, 2> m_viewAff;
130   int m_viewMode;
131 
132   TPointD m_dpiScale;
133 
134   int m_tableDLId;  // To compute table DisplayList only if necessary.
135 
136   int m_groupIndexToBeEntered;
137 
138   double m_pixelSize;
139   bool m_eraserPointerOn;
140   QString m_backupTool;
141   TRectD m_clipRect;
142 
143   bool m_isPicking;
144 
145   TRaster32P m_3DSideL;
146   TRaster32P m_3DSideR;
147   TRaster32P m_3DTop;
148 #if defined(x64)
149   TRasterImageP m_stopMotionImage, m_stopMotionLineUpImage;
150   StopMotion *m_stopMotion        = NULL;
151   bool m_hasStopMotionImage       = false;
152   bool m_hasStopMotionLineUpImage = false;
153 #endif
154   TPointD m_sideRasterPos;
155   TPointD m_topRasterPos;
156   QString m_toolDisableReason;
157 
158   bool m_editPreviewSubCamera;
159 
160   // used for color calibration with 3DLUT
161   QOpenGLFramebufferObject *m_fbo = NULL;
162   LutCalibrator *m_lutCalibrator  = NULL;
163 
164   enum Device3D {
165     NONE,
166     SIDE_LEFT_3D,
167     SIDE_RIGHT_3D,
168     TOP_3D,
169   } m_current3DDevice;
170 
171   LocatorPopup *m_locator;
172   bool m_isLocator;
173   bool m_isStyleShortcutSwitchable;
174 
175   bool m_isBusyOnTabletMove;
176 
177   QMatrix4x4 m_projectionMatrix;
178 
179   // Used for texture management.
180   // Changing dock / float state of the panel will alter the context.
181   // So discarding the resources in old context in initializeGL.
182   TGlContext m_currentContext;
183 
184   // used for updating viewer where the animated guide appears
185   // updated in drawScene() and used in GLInvalidateRect()
186   TRectD m_guidedDrawingBBox;
187 
188   double m_rotationAngle[2];
189 
190   bool m_firstInitialized = true;
191 
192 public:
193   enum ReferenceMode {
194     NORMAL_REFERENCE   = 1,
195     CAMERA3D_REFERENCE = 2,
196     CAMERA_REFERENCE   = 3,
197     LEVEL_MODE         = 128,
198   };
199 
200   // Zoom/Pan matrices are selected by ViewMode
201   enum ViewMode { SCENE_VIEWMODE = 0, LEVEL_VIEWMODE = 1 };
202 
203   enum PreviewMode { NO_PREVIEW = 0, FULL_PREVIEW = 1, SUBCAMERA_PREVIEW = 2 };
204 
205   SceneViewer(ImageUtils::FullScreenWidget *parent);
206   ~SceneViewer();
207 
getPixelSize()208   double getPixelSize() const override { return m_pixelSize; }
209 
210   // Previewer::Listener
211   TRectD getPreviewRect() const override;
212   void onRenderStarted(int frame) override;
213   void onRenderCompleted(int frame) override;
214   void onPreviewUpdate() override;
215 
isPreviewEnabled()216   bool isPreviewEnabled() const { return m_previewMode != NO_PREVIEW; }
getPreviewMode()217   int getPreviewMode() const { return m_previewMode; }
218 
219   void setVisual(const ImagePainter::VisualSettings &settings);
220 
221   TRect getActualClipRect(const TAffine &aff);
222 
223   //! Return the view matrix.
224   //! The view matrix is a matrix contained in \b m_viewAff; if the SceneViewer
225   //! in showing images
226   //! in Camera view Mode (m_referenceMode = CAMERA_REFERENCE) the returned
227   //! affine is composed with camera
228   //! transformation.
229   TAffine getViewMatrix() const override;
230   //! Return the view matrix.
231   //! The view matrix is a matrix contained in \b m_viewAff
232   TAffine getSceneMatrix() const;
233 
234   void setViewMatrix(const TAffine &aff, int viewMode);
235 
getFPS()236   int getFPS() { return m_FPS; }
237 
setRulers(Ruler * v,Ruler * h)238   void setRulers(Ruler *v, Ruler *h) {
239     m_vRuler = v;
240     m_hRuler = h;
241   }
242 
243   bool is3DView() const override;
getViewportSize()244   TDimension getViewportSize() const { return TDimension(width(), height()); }
245 
246   void invalidateAll() override;
247   void GLInvalidateAll() override;
248   void GLInvalidateRect(const TRectD &rect) override;
249   void invalidateToolStatus() override;
250 
getPan3D()251   TPointD getPan3D() const { return m_pan3D; }
getZoomScale3D()252   double getZoomScale3D() const { return m_zoomScale3D; }
253 
254   double projectToZ(const TPointD &delta) override;
255 
getDpiScale()256   TPointD getDpiScale() const override { return m_dpiScale; }
257   void zoomQt(bool forward, bool reset);
258   TAffine getNormalZoomScale();
259 
260   bool canSwapCompared() const;
261 
isEditPreviewSubcamera()262   bool isEditPreviewSubcamera() const { return m_editPreviewSubCamera; }
getIsFlippedX()263   bool getIsFlippedX() const override { return m_isFlippedX; }
getIsFlippedY()264   bool getIsFlippedY() const override { return m_isFlippedY; }
setEditPreviewSubcamera(bool enabled)265   void setEditPreviewSubcamera(bool enabled) {
266     m_editPreviewSubCamera = enabled;
267   }
268 
269   // panning by dragging the navigator in the levelstrip
270   void navigatorPan(const QPoint &delta);
271   // a factor for getting pixel-based zoom ratio
272   double getDpiFactor();
273   // when showing the viewer with full-screen mode,
274   // add a zoom factor which can show image fitting with the screen size
275   double getZoomScaleFittingWithScreen();
276   // return the viewer geometry in order to avoid picking the style outside of
277   // the viewer
278   // when using the stylepicker and the finger tools
279   TRectD getGeometry() const override;
280 
setFocus(Qt::FocusReason reason)281   void setFocus(Qt::FocusReason reason) { QWidget::setFocus(reason); };
282 
setIsLocator()283   void setIsLocator() { m_isLocator = true; }
setIsStyleShortcutSwitchable()284   void setIsStyleShortcutSwitchable() { m_isStyleShortcutSwitchable = true; }
285   int getVGuideCount() override;
286   int getHGuideCount() override;
287   double getVGuide(int index) override;
288   double getHGuide(int index) override;
289 
290   void bindFBO() override;
291   void releaseFBO() override;
292 
293 public:
294   // SceneViewer's gadget public functions
295   TPointD winToWorld(const QPointF &pos) const;
296   TPointD winToWorld(const TPointD &winPos) const override;
297 
298   TPointD worldToPos(const TPointD &worldPos) const override;
299 
300 protected:
301   // Paint vars
302   TAffine m_drawCameraAff;
303   TAffine m_drawTableAff;
304   bool m_draw3DMode;
305   bool m_drawCameraTest;
306   bool m_drawIsTableVisible;
307   bool m_drawEditingLevel;
308   TRect m_actualClipRect;
309 
310   // Paint methods
311   void drawBuildVars();
312   void drawEnableScissor();
313   void drawDisableScissor();
314   void drawBackground();
315   void drawCameraStand();
316   void drawPreview();
317   void drawOverlay();
318 
319   void drawScene();
320   void drawToolGadgets();
321 
322 protected:
323   void mult3DMatrix();
324 
325   void initializeGL() override;
326   void resizeGL(int width, int height) override;
327 
328   void paintGL() override;
329 
330   void showEvent(QShowEvent *) override;
331   void hideEvent(QHideEvent *) override;
332 
333   void gestureEvent(QGestureEvent *e);
334   void touchEvent(QTouchEvent *e, int type);
335   void tabletEvent(QTabletEvent *) override;
336   void leaveEvent(QEvent *) override;
337   void enterEvent(QEvent *) override;
338   void mouseMoveEvent(QMouseEvent *event) override;
339   void mousePressEvent(QMouseEvent *event) override;
340   void mouseReleaseEvent(QMouseEvent *event) override;
341   void mouseDoubleClickEvent(QMouseEvent *event) override;
342 
343   void onPress(const TMouseEvent &event);
344   void onMove(const TMouseEvent &event);
345   void onRelease(const TMouseEvent &event);
346   void onContextMenu(const QPoint &pos, const QPoint &globalPos);
347   void onEnter();
348   void onLeave();
349 
350   void wheelEvent(QWheelEvent *) override;
351   void keyPressEvent(QKeyEvent *event) override;
352   void keyReleaseEvent(QKeyEvent *event) override;
353   void contextMenuEvent(QContextMenuEvent *event) override;
354   void inputMethodEvent(QInputMethodEvent *) override;
355   void drawCompared();
356   bool event(QEvent *event) override;
357 
358   // delta.x: right panning, pixel; delta.y: down panning, pixel
359   void panQt(const QPointF &delta);
360 
361   // center: window coordinate, pixels, topleft origin
362   void zoomQt(const QPoint &center, double scaleFactor);
363 
364   // overriden from TTool::Viewer
pan(const TPointD & delta)365   void pan(const TPointD &delta) override { panQt(QPointF(delta.x, delta.y)); }
366 
367   // overriden from TTool::Viewer
368   void zoom(const TPointD &center, double factor) override;
369   void rotate(const TPointD &center, double angle) override;
370   void rotate3D(double dPhi, double dTheta) override;
371 
372   TAffine getToolMatrix() const;
373 
374   //! return the column index of the drawing intersecting point \b p
375   //! (window coordinate, pixels, bottom-left origin)
376   int pick(const TPointD &point) override;
377 
378   //! return the column indexes of the drawings intersecting point \b p
379   //! (window coordinate, pixels, bottom-left origin)
380   int posToColumnIndex(const TPointD &p, double distance,
381                        bool includeInvisible = true) const override;
382   void posToColumnIndexes(const TPointD &p, std::vector<int> &indexes,
383                           double distance,
384                           bool includeInvisible = true) const override;
385 
386   //! return the row of the drawings intersecting point \b p (used with onion
387   //! skins)
388   //! (window coordinate, pixels, bottom-left origin)
389   int posToRow(const TPointD &p, double distance, bool includeInvisible = true,
390                bool currentColumnOnly = false) const override;
391 
392   void dragEnterEvent(QDragEnterEvent *event) override;
393   void dropEvent(QDropEvent *event) override;
394 
395   void resetInputMethod() override;
396 
397   void set3DLeftSideView();
398   void set3DRightSideView();
399   void set3DTopView();
400 
setFocus()401   void setFocus() override { QWidget::setFocus(); };
402 
403   void registerContext();
404 
405 public slots:
406 
407   void resetSceneViewer();
408   void resetZoom();
409   void resetRotation();
410   void resetPosition();
411   void setActualPixelSize();
412   void flipX();
413   void flipY();
414   void zoomIn();
415   void zoomOut();
416   void onXsheetChanged();
417   void onObjectSwitched();
418   // when tool options are changed, update tooltip immediately
419   void onToolChanged();
420   void onToolSwitched();
421   void onSceneChanged();
422   void onLevelChanged();
423   // when level is switched, update m_dpiScale in order to show white background
424   // for Ink&Paint work properly
425   void onLevelSwitched();
426   void onFrameSwitched();
onOnionSkinMaskChanged()427   void onOnionSkinMaskChanged() { GLInvalidateAll(); }
428 
429   void setReferenceMode(int referenceMode);
430   void enablePreview(int previewMode);
431   void freeze(bool on);
432 
433   void onButtonPressed(FlipConsole::EGadget button);
434   void fitToCamera();
435   void fitToCameraOutline();
436   void swapCompared();
437   void regeneratePreviewFrame();
438   void regeneratePreview();
439 
440   // delete preview-subcamera executed from context menu
441   void doDeleteSubCamera();
442 
443   void resetTabletStatus();
444 
releaseBusyOnTabletMove()445   void releaseBusyOnTabletMove() { m_isBusyOnTabletMove = false; }
446 
447   void onContextAboutToBeDestroyed();
448 #if defined(x64)
449   void onNewStopMotionImageReady();
450   void onStopMotionLiveViewStopped();
451 #endif
452   void onPreferenceChanged(const QString &prefName);
453 
454 signals:
455 
456   void onZoomChanged();
457   void onFlipHChanged(bool);
458   void onFlipVChanged(bool);
459   void freezeStateChanged(bool);
460   void previewStatusChanged();
461   // when pan/zoom on the viewer, notify to level strip in order to update the
462   // navigator
463   void refreshNavi();
464   // for updating the titlebar
465   void previewToggled();
466   // to notify FilmStripFrames and safely disconnect with this
467   void aboutToBeDestroyed();
468 };
469 
470 // Functions
471 
472 void invalidateIcons();
473 
474 #endif  // SCENEVIEWER_H
475