1
2 #if defined(LINUX) || defined(FREEBSD)
3 #define GL_GLEXT_PROTOTYPES
4 #endif
5
6 // Toonz includes
7 #include "tapp.h"
8 #include "viewerpane.h"
9 #include "onionskinmaskgui.h"
10 #include "viewerdraw.h"
11 #include "menubarcommandids.h"
12 #include "ruler.h"
13 #include "locatorpopup.h"
14 #if defined(x64)
15 #include "../stopmotion/stopmotion.h"
16 #endif
17
18 // TnzTools includes
19 #include "tools/cursors.h"
20 #include "tools/cursormanager.h"
21 #include "tools/toolhandle.h"
22 #include "tools/toolcommandids.h"
23 #include "tools/toolutils.h"
24
25 // TnzQt includes
26 #include "toonzqt/icongenerator.h"
27 #include "toonzqt/gutil.h"
28 #include "toonzqt/imageutils.h"
29 #include "toonzqt/lutcalibrator.h"
30 #include "toonzqt/viewcommandids.h"
31
32 // TnzLib includes
33 #include "toonz/tscenehandle.h"
34 #include "toonz/txsheethandle.h"
35 #include "toonz/tframehandle.h"
36 #include "toonz/tcolumnhandle.h"
37 #include "toonz/txshlevelhandle.h"
38 #include "toonz/sceneproperties.h"
39 #include "toonz/toonzscene.h"
40 #include "toonz/levelset.h"
41 #include "toonz/txshsimplelevel.h"
42 #include "toonz/tcamera.h"
43 #include "toonz/stage2.h"
44 #include "toonz/stage.h"
45 #include "toonz/stageplayer.h"
46 #include "toonz/stagevisitor.h"
47 #include "toonz/txsheet.h"
48 #include "toonz/tstageobjecttree.h"
49 #include "toonz/tstageobjectspline.h"
50 #include "toonz/tobjecthandle.h"
51 #include "toonz/tonionskinmaskhandle.h"
52 #include "toonz/palettecontroller.h"
53 #include "toonz/tpalettehandle.h"
54 #include "toonz/childstack.h"
55 #include "toonz/dpiscale.h"
56 #include "toonz/txshlevel.h"
57 #include "toonz/txshlevelcolumn.h"
58 #include "toonz/preferences.h"
59 #include "toonz/glrasterpainter.h"
60 #include "toonz/cleanupparameters.h"
61 #include "toonz/toonzimageutils.h"
62 #include "toonz/txshleveltypes.h"
63 #include "subcameramanager.h"
64
65 // TnzCore includes
66 #include "tpalette.h"
67 #include "tropcm.h"
68 #include "tgl.h"
69 #include "tofflinegl.h"
70 #include "tstopwatch.h"
71 #include "trop.h"
72 #include "tproperty.h"
73 #include "timagecache.h"
74 #include "trasterimage.h"
75 #include "tstroke.h"
76 #include "ttoonzimage.h"
77
78 // Qt includes
79 #include <QMenu>
80 #include <QApplication>
81 #include <QDesktopWidget>
82 #if QT_VERSION >= 0x050000
83 #include <QInputMethod>
84 #else
85 #include <QInputContext>
86 #endif
87 #include <QGLContext>
88 #include <QOpenGLFramebufferObject>
89 #include <QMainWindow>
90
91 #include "sceneviewer.h"
92
93 void drawSpline(const TAffine &viewMatrix, const TRect &clipRect, bool camera3d,
94 double pixelSize);
95
96 //-------------------------------------------------------------------------------
97 namespace {
98
99 int l_mainDisplayListsSpaceId =
100 -1; //!< Display lists space id associated with SceneViewers
101 std::set<TGlContext>
102 l_contexts; //!< Stores every SceneViewer context (see ~SceneViewer)
103
104 //-------------------------------------------------------------------------------
105
106 struct DummyProxy : public TGLDisplayListsProxy {
~DummyProxy__anon6ddebecf0111::DummyProxy107 ~DummyProxy() {}
makeCurrent__anon6ddebecf0111::DummyProxy108 void makeCurrent() {}
doneCurrent__anon6ddebecf0111::DummyProxy109 void doneCurrent() {}
110 };
111
112 //-------------------------------------------------------------------------------
113
getActualFrameRate()114 double getActualFrameRate() {
115 // compute frame per second
116 static double fps = 0;
117 static TStopWatch stopwatch;
118 static int frame = 0;
119 ++frame;
120
121 stopwatch.start();
122
123 unsigned long tt = stopwatch.getTotalTime();
124
125 // wait a time greater than one second
126 if (tt > 1000) {
127 stopwatch.stop();
128 fps = troundp(((1000 * frame) / (double)tt));
129 stopwatch.start(true);
130 frame = 0;
131 }
132 return fps;
133 }
134
135 //-----------------------------------------------------------------------------
136
copyFrontBufferToBackBuffer()137 void copyFrontBufferToBackBuffer() {
138 static GLint viewport[4];
139 static GLfloat raster_pos[4];
140
141 glGetIntegerv(GL_VIEWPORT, viewport);
142
143 /* set source buffer */
144 glReadBuffer(GL_FRONT);
145
146 /* set projection matrix */
147 glMatrixMode(GL_PROJECTION);
148 glPushMatrix();
149 glLoadIdentity();
150 gluOrtho2D(0, viewport[2], 0, viewport[3]);
151
152 /* set modelview matrix */
153 glMatrixMode(GL_MODELVIEW);
154 glPushMatrix();
155 glLoadIdentity();
156
157 /* save old raster position */
158 glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
159
160 /* set raster position */
161 glRasterPos4f(0.0, 0.0, 0.0, 1.0);
162
163 /* copy buffer */
164 glCopyPixels(0, 0, viewport[2], viewport[3], GL_COLOR);
165
166 /* restore old raster position */
167 glRasterPos4fv(raster_pos);
168
169 /* restore old matrices */
170 glPopMatrix();
171 glMatrixMode(GL_PROJECTION);
172 glPopMatrix();
173 glMatrixMode(GL_MODELVIEW);
174
175 /* restore source buffer */
176 glReadBuffer(GL_BACK);
177 }
178 //-----------------------------------------------------------------------------
179 /*! Compute new 3Dposition and new 2D position. */
computeNew3DPosition(T3DPointD start3DPos,TPointD delta2D,TPointD & new2dPos,GLdouble modelView3D[16],GLdouble projection3D[16],GLint viewport3D[4],int devPixRatio)180 T3DPointD computeNew3DPosition(T3DPointD start3DPos, TPointD delta2D,
181 TPointD &new2dPos, GLdouble modelView3D[16],
182 GLdouble projection3D[16], GLint viewport3D[4],
183 int devPixRatio) {
184 GLdouble pos2D_x, pos2D_y, pos2D_z;
185 gluProject(-start3DPos.x, -start3DPos.y, start3DPos.z, modelView3D,
186 projection3D, viewport3D, &pos2D_x, &pos2D_y, &pos2D_z);
187 new2dPos = TPointD(pos2D_x + delta2D.x, pos2D_y + delta2D.y);
188 GLdouble pos3D_x, pos3D_y, pos3D_z;
189 gluUnProject(new2dPos.x, new2dPos.y, 1, modelView3D, projection3D, viewport3D,
190 &pos3D_x, &pos3D_y, &pos3D_z);
191 new2dPos.y = viewport3D[3] - new2dPos.y - 20 * devPixRatio;
192 return T3DPointD(pos3D_x, pos3D_y, pos3D_z);
193 }
194
195 //-----------------------------------------------------------------------------
196 #ifdef DA_RIVEDERE
197
198 // Il metodo copia una porzione del BACK_BUFFER definita da rect nel
199 // FRONTE_BUFFER
200 // Attualmente si notano delle brutture intorno al rettangolo.
201 // Per il momento si lavora nel BACK_BUFFER e sicopia tutto il FRONT_BUFFER.
202 // Riattivando questo metodo bisogna ricordarsi di disattivare lo swapbuffer in
203 // GLInvalidateRect prima di
204 // fare updateGL() e riattivarlo immediatamernte dopo!
copyBackBufferToFrontBuffer(const TRect & rect)205 void copyBackBufferToFrontBuffer(const TRect &rect) {
206 static GLint viewport[4];
207 static GLfloat raster_pos[4];
208
209 glGetIntegerv(GL_VIEWPORT, viewport);
210
211 /* set source buffer */
212 glReadBuffer(GL_BACK);
213 glDrawBuffer(GL_FRONT);
214
215 /* set projection matrix */
216 glMatrixMode(GL_PROJECTION);
217 glPushMatrix();
218 glLoadIdentity();
219 gluOrtho2D(0, viewport[2], 0, viewport[3]);
220
221 /* set modelview matrix */
222 glMatrixMode(GL_MODELVIEW);
223 glPushMatrix();
224 glLoadIdentity();
225
226 /* save old raster position */
227 glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
228
229 /* set raster position */
230 glRasterPos4f(0.0, 0.0, 0.0, 1.0);
231
232 /* copy buffer */
233 glCopyPixels(0, 0, viewport[2], viewport[3], GL_COLOR);
234
235 /* restore old raster position */
236 glRasterPos4fv(raster_pos);
237
238 /* restore old matrices */
239 glPopMatrix();
240 glMatrixMode(GL_PROJECTION);
241 glPopMatrix();
242 glMatrixMode(GL_MODELVIEW);
243
244 /* restore source buffer */
245 glDrawBuffer(GL_BACK);
246 }
247
248 #endif
249
250 const TRectD InvalidateAllRect(0, 0, -1, -1);
251
252 //-----------------------------------------------------------------------------
253 } // namespace
254 //-----------------------------------------------------------------------------
255
256 //=============================================================================
257 // ToggleCommand
258 //-----------------------------------------------------------------------------
259
ToggleCommandHandler(CommandId id,bool startStatus)260 ToggleCommandHandler::ToggleCommandHandler(CommandId id, bool startStatus)
261 : MenuItemHandler(id), m_status(startStatus) {}
262
execute()263 void ToggleCommandHandler::execute() {
264 m_status = !m_status;
265 // emit sceneChanged WITHOUT dirty flag
266 TApp::instance()->getCurrentScene()->notifySceneChanged(false);
267 }
268
269 //-----------------------------------------------------------------------------
270
271 ToggleCommandHandler viewTableToggle(MI_ViewTable, false);
272 ToggleCommandHandler editInPlaceToggle(MI_ToggleEditInPlace, false);
273 ToggleCommandHandler fieldGuideToggle(MI_FieldGuide, false);
274 ToggleCommandHandler safeAreaToggle(MI_SafeArea, false);
275 ToggleCommandHandler rasterizePliToggle(MI_RasterizePli, false);
276
277 ToggleCommandHandler viewClcToggle("MI_ViewColorcard", false);
278 ToggleCommandHandler viewCameraToggle("MI_ViewCamera", false);
279 ToggleCommandHandler viewBBoxToggle("MI_ViewBBox", false);
280 ToggleCommandHandler viewGuideToggle("MI_ViewGuide", false);
281 ToggleCommandHandler viewRulerToggle("MI_ViewRuler", false);
282
283 //-----------------------------------------------------------------------------
284
invalidateIcons()285 void invalidateIcons() {
286 ToonzCheck *tc = ToonzCheck::instance();
287 int mask = tc->getChecks();
288 IconGenerator::Settings s;
289 s.m_blackBgCheck = mask & ToonzCheck::eBlackBg;
290 s.m_transparencyCheck = mask & ToonzCheck::eTransparency;
291 s.m_inksOnly = mask & ToonzCheck::eInksOnly;
292 // emphasize lines with style#1 regardless of the current style
293 if (mask & ToonzCheck::eInk1) s.m_inkIndex = 1;
294 // emphasize lines with the current style
295 else if (mask & ToonzCheck::eInk)
296 s.m_inkIndex = tc->getColorIndex();
297 else
298 s.m_inkIndex = -1;
299 s.m_paintIndex = mask & ToonzCheck::ePaint ? tc->getColorIndex() : -1;
300 IconGenerator::instance()->setSettings(s);
301
302 // Force icons to refresh for Toonz Vector levels
303 TXshLevel *sl = TApp::instance()->getCurrentLevel()->getLevel();
304 if (sl && sl->getType() == PLI_XSHLEVEL) {
305 std::vector<TFrameId> fids;
306 sl->getFids(fids);
307
308 for (int i = 0; i < (int)fids.size(); i++)
309 IconGenerator::instance()->invalidate(sl, fids[i]);
310 }
311
312 // Do not remove icons here as they will be re-used for updating icons in the
313 // level strip
314
315 // emit sceneChanged WITHOUT dirty flag
316 TApp::instance()->getCurrentScene()->notifySceneChanged(false);
317 TApp::instance()->getCurrentLevel()->notifyLevelViewChange();
318 }
319
320 //--------------------------------------------------------------
321
executeCheck(int checkType)322 static void executeCheck(int checkType) {
323 ToonzCheck::instance()->toggleCheck(checkType);
324 invalidateIcons();
325 }
326
327 //-----------------------------------------------------------------------------
328
329 class TCheckToggleCommand final : public MenuItemHandler {
330 public:
TCheckToggleCommand()331 TCheckToggleCommand() : MenuItemHandler("MI_TCheck") {}
execute()332 void execute() override { executeCheck(ToonzCheck::eTransparency); }
333 } tcheckToggle;
334
335 //-----------------------------------------------------------------------------
336
337 class ICheckToggleCommand final : public MenuItemHandler {
338 public:
ICheckToggleCommand()339 ICheckToggleCommand() : MenuItemHandler("MI_ICheck") {}
execute()340 void execute() override { executeCheck(ToonzCheck::eInk); }
341 } icheckToggle;
342
343 //-----------------------------------------------------------------------------
344
345 class PCheckToggleCommand final : public MenuItemHandler {
346 public:
PCheckToggleCommand()347 PCheckToggleCommand() : MenuItemHandler("MI_PCheck") {}
execute()348 void execute() override { executeCheck(ToonzCheck::ePaint); }
349 } pcheckToggle;
350
351 //-----------------------------------------------------------------------------
352
353 class BCheckToggleCommand final : public MenuItemHandler {
354 public:
BCheckToggleCommand()355 BCheckToggleCommand() : MenuItemHandler("MI_BCheck") {}
execute()356 void execute() override { executeCheck(ToonzCheck::eBlackBg); }
357 } bcheckToggle;
358
359 //-----------------------------------------------------------------------------
360
361 class TAutocloseToggleCommand final : public MenuItemHandler {
362 public:
TAutocloseToggleCommand()363 TAutocloseToggleCommand() : MenuItemHandler("MI_ACheck") {}
execute()364 void execute() override { executeCheck(ToonzCheck::eAutoclose); }
365 } tautocloseToggle;
366
367 //-----------------------------------------------------------------------------
368
369 class TGapToggleCommand final : public MenuItemHandler {
370 public:
TGapToggleCommand()371 TGapToggleCommand() : MenuItemHandler("MI_GCheck") {}
execute()372 void execute() override { executeCheck(ToonzCheck::eGap); }
373 } tgapToggle;
374
375 //-----------------------------------------------------------------------------
376
377 class TInksOnlyToggleCommand final : public MenuItemHandler {
378 public:
TInksOnlyToggleCommand()379 TInksOnlyToggleCommand() : MenuItemHandler("MI_IOnly") {}
execute()380 void execute() override { executeCheck(ToonzCheck::eInksOnly); }
381 } tinksOnlyToggle;
382
383 //-----------------------------------------------------------------------------
384 /*! emphasize lines with style#1 regardless of the current style
385 */
386 class Ink1CheckToggleCommand final : public MenuItemHandler {
387 public:
Ink1CheckToggleCommand()388 Ink1CheckToggleCommand() : MenuItemHandler("MI_Ink1Check") {}
execute()389 void execute() override { executeCheck(ToonzCheck::eInk1); }
390 } ink1checkToggle;
391
392 //=============================================================================
393
394 class TShiftTraceToggleCommand final : public MenuItemHandler {
395 CommandId m_cmdId;
396
397 public:
TShiftTraceToggleCommand(CommandId cmdId)398 TShiftTraceToggleCommand(CommandId cmdId)
399 : MenuItemHandler(cmdId), m_cmdId(cmdId) {}
execute()400 void execute() override {
401 CommandManager *cm = CommandManager::instance();
402 QAction *action = cm->getAction(m_cmdId);
403 bool checked = action->isChecked();
404 if (std::string(m_cmdId) == MI_ShiftTrace) {
405 cm->enable(MI_EditShift, checked);
406 cm->enable(MI_NoShift, checked);
407 if (checked) OnioniSkinMaskGUI::resetShiftTraceFrameOffset();
408 // cm->getAction(MI_NoShift)->setChecked(false);
409 TApp::instance()->getCurrentOnionSkin()->notifyOnionSkinMaskChanged();
410 } else if (std::string(m_cmdId) == MI_EditShift) {
411 if (checked) {
412 QAction *noShiftAction =
413 CommandManager::instance()->getAction(MI_NoShift);
414 if (noShiftAction) noShiftAction->setChecked(false);
415 TApp::instance()->getCurrentTool()->setPseudoTool("T_ShiftTrace");
416 } else {
417 TApp::instance()->getCurrentTool()->unsetPseudoTool();
418 }
419 CommandManager::instance()->enable(MI_NoShift, !checked);
420 } else if (std::string(m_cmdId) == MI_NoShift) {
421 }
422 updateShiftTraceStatus();
423 }
424
isChecked(CommandId id) const425 bool isChecked(CommandId id) const {
426 QAction *action = CommandManager::instance()->getAction(id);
427 return action != 0 && action->isChecked();
428 }
updateShiftTraceStatus()429 void updateShiftTraceStatus() {
430 OnionSkinMask::ShiftTraceStatus status = OnionSkinMask::DISABLED;
431 if (isChecked(MI_ShiftTrace)) {
432 if (isChecked(MI_EditShift))
433 status = OnionSkinMask::EDITING_GHOST;
434 else if (isChecked(MI_NoShift))
435 status = OnionSkinMask::ENABLED_WITHOUT_GHOST_MOVEMENTS;
436 else
437 status = OnionSkinMask::ENABLED;
438 }
439 OnionSkinMask osm =
440 TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask();
441 osm.setShiftTraceStatus(status);
442 osm.clearGhostFlipKey();
443 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
444 TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(osm);
445 }
446 };
447
448 TShiftTraceToggleCommand shiftTraceToggleCommand(MI_ShiftTrace),
449 editShiftToggleCommand(MI_EditShift), noShiftToggleCommand(MI_NoShift);
450
451 class TResetShiftTraceCommand final : public MenuItemHandler {
452 public:
TResetShiftTraceCommand()453 TResetShiftTraceCommand() : MenuItemHandler(MI_ResetShift) {}
execute()454 void execute() override {
455 OnionSkinMask osm =
456 TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask();
457 osm.setShiftTraceGhostCenter(0, TPointD());
458 osm.setShiftTraceGhostCenter(1, TPointD());
459 osm.setShiftTraceGhostAff(0, TAffine());
460 osm.setShiftTraceGhostAff(1, TAffine());
461 TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(osm);
462 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
463 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
464 if (tool) tool->reset();
465 }
466 } resetShiftTraceCommand;
467
468 //-----------------------------------------------------------------------------
469 // Following commands (VB_***) are registered for command bar buttons.
470 // They are separatd from the original visalization commands
471 // so that they will not break a logic of ShortcutZoomer.
472
473 class TViewResetCommand final : public MenuItemHandler {
474 public:
TViewResetCommand()475 TViewResetCommand() : MenuItemHandler(VB_ViewReset) {}
execute()476 void execute() override {
477 if (TApp::instance()->getActiveViewer())
478 TApp::instance()->getActiveViewer()->resetSceneViewer();
479 }
480 } viewResetCommand;
481
482 class TZoomResetCommand final : public MenuItemHandler {
483 public:
TZoomResetCommand()484 TZoomResetCommand() : MenuItemHandler(VB_ZoomReset) {}
execute()485 void execute() override {
486 if (TApp::instance()->getActiveViewer())
487 TApp::instance()->getActiveViewer()->resetZoom();
488 }
489 } zoomResetCommand;
490
491 class TZoomFitCommand final : public MenuItemHandler {
492 public:
TZoomFitCommand()493 TZoomFitCommand() : MenuItemHandler(VB_ZoomFit) {}
execute()494 void execute() override {
495 if (TApp::instance()->getActiveViewer())
496 TApp::instance()->getActiveViewer()->fitToCamera();
497 }
498 } zoomFitCommand;
499
500 class TActualPixelSizeCommand final : public MenuItemHandler {
501 public:
TActualPixelSizeCommand()502 TActualPixelSizeCommand() : MenuItemHandler(VB_ActualPixelSize) {}
execute()503 void execute() override {
504 if (TApp::instance()->getActiveViewer())
505 TApp::instance()->getActiveViewer()->setActualPixelSize();
506 }
507 } actualPixelSizeCommand;
508
509 class TFlipViewerXCommand final : public MenuItemHandler {
510 public:
TFlipViewerXCommand()511 TFlipViewerXCommand() : MenuItemHandler(VB_FlipX) {}
execute()512 void execute() override {
513 if (TApp::instance()->getActiveViewer())
514 TApp::instance()->getActiveViewer()->flipX();
515 }
516 } flipViewerXCommand;
517
518 class TFlipViewerYCommand final : public MenuItemHandler {
519 public:
TFlipViewerYCommand()520 TFlipViewerYCommand() : MenuItemHandler(VB_FlipY) {}
execute()521 void execute() override {
522 if (TApp::instance()->getActiveViewer())
523 TApp::instance()->getActiveViewer()->flipY();
524 }
525 } flipViewerYCommand;
526
527 class TRotateResetCommand final : public MenuItemHandler {
528 public:
TRotateResetCommand()529 TRotateResetCommand() : MenuItemHandler(VB_RotateReset) {}
execute()530 void execute() override {
531 if (TApp::instance()->getActiveViewer())
532 TApp::instance()->getActiveViewer()->resetRotation();
533 }
534 } rotateResetCommand;
535
536 class TPositionResetCommand final : public MenuItemHandler {
537 public:
TPositionResetCommand()538 TPositionResetCommand() : MenuItemHandler(VB_PositionReset) {}
execute()539 void execute() override {
540 if (TApp::instance()->getActiveViewer())
541 TApp::instance()->getActiveViewer()->resetPosition();
542 }
543 } positionResetCommand;
544
545 class TVectorGuidedDrawingToggleCommand final : public MenuItemHandler {
546 public:
TVectorGuidedDrawingToggleCommand()547 TVectorGuidedDrawingToggleCommand()
548 : MenuItemHandler(MI_VectorGuidedDrawing) {}
execute()549 void execute() override {
550 CommandManager *cm = CommandManager::instance();
551 QAction *action = cm->getAction(MI_VectorGuidedDrawing);
552 Preferences::instance()->setValue(guidedDrawingType,
553 action->isChecked() ? 1 : 0);
554 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
555 TApp::instance()->getCurrentScene()->notifyPreferenceChanged(
556 "GuidedDrawingFrame");
557 }
558
isChecked(CommandId id) const559 bool isChecked(CommandId id) const {
560 QAction *action = CommandManager::instance()->getAction(id);
561 return action != 0 && action->isChecked();
562 }
563 } vectorGuidedDrawingToggleCommand;
564
565 class TSelectGuideStrokeResetCommand final : public MenuItemHandler {
566 public:
TSelectGuideStrokeResetCommand()567 TSelectGuideStrokeResetCommand()
568 : MenuItemHandler(MI_SelectGuideStrokeReset) {}
execute()569 void execute() override {
570 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
571 if (!vi) return;
572
573 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
574 if (!tool) return;
575
576 tool->getViewer()->setGuidedStrokePickerMode(0);
577 tool->getViewer()->setGuidedBackStroke(-1);
578 tool->getViewer()->setGuidedFrontStroke(-1);
579 tool->getViewer()->invalidateAll();
580 }
581 } SelectGuideStrokeResetCommand;
582
583 class TSelectGuideStrokeNextCommand final : public MenuItemHandler {
584 public:
TSelectGuideStrokeNextCommand()585 TSelectGuideStrokeNextCommand() : MenuItemHandler(MI_SelectNextGuideStroke) {}
execute()586 void execute() override {
587 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
588 if (!vi) return;
589
590 Preferences *pref = Preferences::instance();
591 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
592 pref->getGuidedDrawingType() != 2))
593 return;
594
595 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
596 if (!tool) return;
597
598 tool->getViewer()->setGuidedStrokePickerMode(1);
599 }
600 } selectGuideStrokeNextCommand;
601
602 class TSelectGuideStrokePrevCommand final : public MenuItemHandler {
603 public:
TSelectGuideStrokePrevCommand()604 TSelectGuideStrokePrevCommand() : MenuItemHandler(MI_SelectPrevGuideStroke) {}
execute()605 void execute() override {
606 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
607 if (!vi) return;
608
609 Preferences *pref = Preferences::instance();
610 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
611 pref->getGuidedDrawingType() != 2))
612 return;
613
614 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
615 if (!tool) return;
616
617 tool->getViewer()->setGuidedStrokePickerMode(-1);
618 }
619 } selectGuideStrokePrevCommand;
620
621 class TSelectBothGuideStrokesCommand final : public MenuItemHandler {
622 public:
TSelectBothGuideStrokesCommand()623 TSelectBothGuideStrokesCommand()
624 : MenuItemHandler(MI_SelectBothGuideStrokes) {}
execute()625 void execute() override {
626 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
627 if (!vi) return;
628
629 Preferences *pref = Preferences::instance();
630 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
631 pref->getGuidedDrawingType() != 2))
632 return;
633
634 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
635 if (!tool) return;
636
637 tool->getViewer()->setGuidedStrokePickerMode(-2);
638 }
639 } selectBothGuideStrokesCommand;
640
641 class TTweenGuideStrokesCommand final : public MenuItemHandler {
642 public:
TTweenGuideStrokesCommand()643 TTweenGuideStrokesCommand() : MenuItemHandler(MI_TweenGuideStrokes) {}
execute()644 void execute() override {
645 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
646 if (!vi) return;
647
648 Preferences *pref = Preferences::instance();
649 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
650 pref->getGuidedDrawingType() != 2))
651 return;
652
653 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
654 if (!tool) return;
655
656 tool->tweenSelectedGuideStrokes();
657 }
658 } tweenGuideStrokesCommand;
659
660 class TTweenGuideStrokeToSelectedCommand final : public MenuItemHandler {
661 public:
TTweenGuideStrokeToSelectedCommand()662 TTweenGuideStrokeToSelectedCommand()
663 : MenuItemHandler(MI_TweenGuideStrokeToSelected) {}
execute()664 void execute() override {
665 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
666 if (!vi) return;
667
668 Preferences *pref = Preferences::instance();
669 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
670 pref->getGuidedDrawingType() != 2))
671 return;
672
673 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
674 if (!tool) return;
675
676 tool->tweenGuideStrokeToSelected();
677 }
678 } tweenGuideStrokeToSelectedCommand;
679
680 class TSelectGuidesAndTweenCommand final : public MenuItemHandler {
681 public:
TSelectGuidesAndTweenCommand()682 TSelectGuidesAndTweenCommand()
683 : MenuItemHandler(MI_SelectGuidesAndTweenMode) {}
execute()684 void execute() override {
685 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
686 if (!vi) return;
687
688 Preferences *pref = Preferences::instance();
689 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
690 pref->getGuidedDrawingType() != 2))
691 return;
692
693 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
694 if (!tool) return;
695
696 tool->getViewer()->setGuidedStrokePickerMode(-3);
697 }
698 } selectGuidesAndTweenCommand;
699
700 class TFlipNextStrokeDirectionCommand final : public MenuItemHandler {
701 public:
TFlipNextStrokeDirectionCommand()702 TFlipNextStrokeDirectionCommand() : MenuItemHandler(MI_FlipNextGuideStroke) {}
execute()703 void execute() override {
704 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
705 if (!vi) return;
706
707 Preferences *pref = Preferences::instance();
708 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
709 pref->getGuidedDrawingType() != 2))
710 return;
711
712 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
713 if (!tool) return;
714
715 tool->flipGuideStrokeDirection(1);
716 }
717 } flipNextStrokeDirectionCommand;
718
719 class TFlipPrevStrokeDirectionCommand final : public MenuItemHandler {
720 public:
TFlipPrevStrokeDirectionCommand()721 TFlipPrevStrokeDirectionCommand() : MenuItemHandler(MI_FlipPrevGuideStroke) {}
execute()722 void execute() override {
723 TVectorImageP vi = (TVectorImageP)TTool::getImage(false);
724 if (!vi) return;
725
726 Preferences *pref = Preferences::instance();
727 if (!pref->isOnionSkinEnabled() || (pref->getGuidedDrawingType() != 1 &&
728 pref->getGuidedDrawingType() != 2))
729 return;
730
731 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
732 if (!tool) return;
733
734 tool->flipGuideStrokeDirection(-1);
735 }
736 } flipPrevStrokeDirectionCommand;
737
738 //=============================================================================
739 // SceneViewer
740 //-----------------------------------------------------------------------------
741
SceneViewer(ImageUtils::FullScreenWidget * parent)742 SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent)
743 : GLWidgetForHighDpi(parent)
744 , m_pressure(0)
745 , m_lastMousePos(0, 0)
746 , m_mouseButton(Qt::NoButton)
747 , m_foregroundDrawing(false)
748 , m_tabletEvent(false)
749 , m_tabletMove(false)
750 , m_buttonClicked(false)
751 , m_referenceMode(NORMAL_REFERENCE)
752 , m_previewMode(NO_PREVIEW)
753 , m_isMouseEntered(false)
754 , m_forceGlFlush(true)
755 , m_freezedStatus(NO_FREEZED)
756 , m_viewGrabImage(0)
757 , m_FPS(0)
758 , m_hRuler(0)
759 , m_vRuler(0)
760 , m_viewMode(SCENE_VIEWMODE)
761 , m_pos(0, 0)
762 , m_pan3D(TPointD(0, 0))
763 , m_zoomScale3D(0.1)
764 , m_theta3D(20)
765 , m_phi3D(30)
766 , m_dpiScale(TPointD(1, 1))
767 , m_compareSettings()
768 , m_minZ(0)
769 , m_tableDLId(-1)
770 , m_groupIndexToBeEntered(-1)
771 , m_pixelSize(1)
772 , m_eraserPointerOn(false)
773 , m_backupTool("")
774 , m_clipRect()
775 , m_isPicking(false)
776 , m_current3DDevice(NONE)
777 , m_sideRasterPos()
778 , m_topRasterPos()
779 , m_toolDisableReason("")
780 , m_editPreviewSubCamera(false)
781 , m_locator(NULL)
782 , m_isLocator(false)
783 , m_isBusyOnTabletMove(false) {
784 m_visualSettings.m_sceneProperties =
785 TApp::instance()->getCurrentScene()->getScene()->getProperties();
786 #if defined(x64)
787 m_stopMotion = StopMotion::instance();
788 #endif
789 // Enables multiple key input.
790 setAttribute(Qt::WA_KeyCompression);
791 // Enables input methods for Asian languages.
792 setAttribute(Qt::WA_InputMethodEnabled);
793 setFocusPolicy(Qt::StrongFocus);
794 setAcceptDrops(true);
795 this->setMouseTracking(true);
796 // introduced from Qt 5.9
797 #if QT_VERSION >= 0x050900
798 this->setTabletTracking(true);
799 #endif
800
801 for (int i = 0; i < m_viewAff.size(); ++i) {
802 setViewMatrix(getNormalZoomScale(), i);
803 m_rotationAngle[i] = 0.0;
804 }
805
806 m_3DSideR = rasterFromQPixmap(svgToPixmap(":Resources/3Dside_r.svg"));
807 m_3DSideL = rasterFromQPixmap(svgToPixmap(":Resources/3Dside_l.svg"));
808 m_3DTop = rasterFromQPixmap(svgToPixmap(":Resources/3Dtop.svg"));
809
810 setAttribute(Qt::WA_AcceptTouchEvents);
811 grabGesture(Qt::SwipeGesture);
812 grabGesture(Qt::PanGesture);
813 grabGesture(Qt::PinchGesture);
814
815 setUpdateBehavior(QOpenGLWidget::PartialUpdate);
816
817 if (Preferences::instance()->isColorCalibrationEnabled())
818 m_lutCalibrator = new LutCalibrator();
819 }
820
821 //-----------------------------------------------------------------------------
822
setVisual(const ImagePainter::VisualSettings & settings)823 void SceneViewer::setVisual(const ImagePainter::VisualSettings &settings) {
824 // m_visualSettings.m_blankColor = settings.m_blankColor;//for the blank
825 // frames, I don't have to repaint the viewer are using updateGl!
826 bool repaint = m_visualSettings.needRepaint(settings);
827 m_visualSettings = settings;
828 m_visualSettings.m_sceneProperties =
829 TApp::instance()->getCurrentScene()->getScene()->getProperties();
830 if (repaint) GLInvalidateAll();
831 }
832
833 //-----------------------------------------------------------------------------
834
~SceneViewer()835 SceneViewer::~SceneViewer() {
836 // notify FilmStripFrames and safely disconnect with this
837 emit aboutToBeDestroyed();
838
839 if (m_fbo) delete m_fbo;
840
841 // release all the registered context (once when exit the software)
842 std::set<TGlContext>::iterator ct, cEnd(l_contexts.end());
843 for (ct = l_contexts.begin(); ct != cEnd; ++ct)
844 TGLDisplayListsManager::instance()->releaseContext(*ct);
845 l_contexts.clear();
846 }
847
848 //-------------------------------------------------------------------------------
849
850 // Builds the view area, in camera reference
getPreviewRect() const851 TRectD SceneViewer::getPreviewRect() const {
852 TApp *app = TApp::instance();
853 int row = app->getCurrentFrame()->getFrame();
854 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
855 TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
856 double cameraZ = xsh->getZ(cameraId, row);
857 TAffine cameraAff =
858 xsh->getPlacement(cameraId, row) * TScale((1000 + cameraZ) / 1000);
859
860 TDimensionD cameraSize =
861 app->getCurrentScene()->getScene()->getCurrentCamera()->getSize();
862 TDimension cameraRes =
863 app->getCurrentScene()->getScene()->getCurrentCamera()->getRes();
864 TScale cameraScale(Stage::inch * cameraSize.lx / cameraRes.lx,
865 Stage::inch * cameraSize.ly / cameraRes.ly);
866
867 TRectD viewRect(-width() * 0.5, -height() * 0.5, width() * 0.5,
868 height() * 0.5);
869
870 return (getViewMatrix() * cameraAff * cameraScale).inv() * viewRect;
871 }
872
873 //-------------------------------------------------------------------------------
874
onRenderStarted(int frame)875 void SceneViewer::onRenderStarted(int frame) { emit previewStatusChanged(); }
876
877 //-------------------------------------------------------------------------------
878
onRenderCompleted(int frame)879 void SceneViewer::onRenderCompleted(int frame) {
880 invalidateAll();
881 emit previewStatusChanged();
882 }
883
884 //-------------------------------------------------------------------------------
885
onPreviewUpdate()886 void SceneViewer::onPreviewUpdate() {
887 update();
888 emit previewStatusChanged();
889 }
890
891 //-----------------------------------------------------------------------------
892
setReferenceMode(int referenceMode)893 void SceneViewer::setReferenceMode(int referenceMode) {
894 if (m_referenceMode == referenceMode) return;
895
896 TApp *app = TApp::instance();
897 if (app->getCurrentFrame()->isEditingLevel())
898 app->getCurrentFrame()->setFrame(app->getCurrentFrame()->getFrame());
899 if (m_freezedStatus != NO_FREEZED) {
900 freeze(false);
901 emit freezeStateChanged(false);
902 }
903
904 m_referenceMode = referenceMode;
905 invalidateAll();
906 emit onZoomChanged();
907 }
908
909 //-------------------------------------------------------------------------------
910
freeze(bool on)911 void SceneViewer::freeze(bool on) {
912 if (!on) {
913 m_viewGrabImage = TRaster32P();
914 m_freezedStatus = NO_FREEZED;
915 } else {
916 setCursor(Qt::ForbiddenCursor);
917 m_freezedStatus = UPDATE_FREEZED;
918 }
919 GLInvalidateAll();
920 }
921
922 //-------------------------------------------------------------------------------
923
enablePreview(int previewMode)924 void SceneViewer::enablePreview(int previewMode) {
925 if (m_previewMode == previewMode) return;
926
927 TApp *app = TApp::instance();
928 if (app->getCurrentFrame()->isEditingLevel() && previewMode != NO_PREVIEW)
929 app->getCurrentFrame()->setFrame(app->getCurrentFrame()->getFrame());
930
931 if (m_freezedStatus != NO_FREEZED) {
932 freeze(false);
933 emit freezeStateChanged(false);
934 }
935
936 if (m_previewMode != NO_PREVIEW)
937 Previewer::instance(m_previewMode == SUBCAMERA_PREVIEW)
938 ->removeListener(this);
939
940 // Schedule as a listener to Previewer.
941 if (previewMode != NO_PREVIEW) {
942 Previewer *previewer =
943 Previewer::instance(previewMode == SUBCAMERA_PREVIEW);
944 previewer->addListener(this);
945 previewer->update();
946 }
947
948 m_previewMode = previewMode;
949
950 GLInvalidateAll();
951
952 // for updating the title bar
953 emit previewToggled();
954 }
955
956 //-----------------------------------------------------------------------------
957
winToWorld(const QPointF & pos) const958 TPointD SceneViewer::winToWorld(const QPointF &pos) const {
959 // coordinate window (origine in alto a sinistra) -> coordinate colonna
960 // (origine al centro dell'immagine)
961 TPointD pp(pos.x() - (double)width() / 2.0,
962 -pos.y() + (double)height() / 2.0);
963 if (is3DView()) {
964 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
965 TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
966 double z = xsh->getStageObject(cameraId)->getZ(
967 TApp::instance()->getCurrentFrame()->getFrame());
968
969 TPointD p(pp.x - m_pan3D.x, pp.y - m_pan3D.y);
970 p = p * (1 / m_zoomScale3D);
971 double theta = m_theta3D * M_PI_180;
972 double phi = m_phi3D * M_PI_180;
973 double cs_phi = cos(phi);
974 double sn_phi = sin(phi);
975 double cs_theta = cos(theta);
976 double sn_theta = sin(theta);
977 TPointD a(cs_phi, sn_theta * sn_phi); // proiezione di (1,0,0)
978 TPointD b(0, cs_theta); // proiezione di (0,1,0)
979 TPointD c(sn_phi, -sn_theta * cs_phi); // proiezione di (0,0,1)
980 TPointD aa = rotate90(a);
981 TPointD bb = rotate90(b);
982
983 double abb = a * bb;
984 double baa = b * aa;
985 if (fabs(abb) > 0.001 && fabs(baa) > 0.001) {
986 p -= c * z;
987 TPointD g((p * bb) / (a * bb), (p * aa) / (b * aa));
988 return TAffine() * g;
989 } else
990 return TAffine() * TPointD(0, 0);
991 }
992
993 return getViewMatrix().inv() * pp;
994 }
995
996 //-----------------------------------------------------------------------------
997
winToWorld(const TPointD & winPos) const998 TPointD SceneViewer::winToWorld(const TPointD &winPos) const {
999 return winToWorld(QPointF(winPos.x, height() - winPos.y));
1000 }
1001
1002 //-----------------------------------------------------------------------------
1003
worldToPos(const TPointD & worldPos) const1004 TPointD SceneViewer::worldToPos(const TPointD &worldPos) const {
1005 TPointD p = getViewMatrix() * worldPos;
1006 return TPointD(width() / 2 + p.x, height() / 2 + p.y);
1007 }
1008
1009 //-----------------------------------------------------------------------------
1010
showEvent(QShowEvent *)1011 void SceneViewer::showEvent(QShowEvent *) {
1012 m_visualSettings.m_sceneProperties =
1013 TApp::instance()->getCurrentScene()->getScene()->getProperties();
1014
1015 // Se il viewer e' show e il preview e' attivo aggiungo il listner al preview
1016 if (m_previewMode != NO_PREVIEW)
1017 Previewer::instance(m_previewMode == SUBCAMERA_PREVIEW)->addListener(this);
1018
1019 TApp *app = TApp::instance();
1020
1021 TSceneHandle *sceneHandle = app->getCurrentScene();
1022 bool ret = connect(sceneHandle, SIGNAL(sceneSwitched()), this,
1023 SLOT(resetSceneViewer()));
1024 ret = ret && connect(sceneHandle, SIGNAL(sceneChanged()), this,
1025 SLOT(onSceneChanged()));
1026 ret = ret && connect(sceneHandle, SIGNAL(preferenceChanged(const QString &)),
1027 this, SLOT(onPreferenceChanged(const QString &)));
1028
1029 TFrameHandle *frameHandle = app->getCurrentFrame();
1030 ret = ret && connect(frameHandle, SIGNAL(frameSwitched()), this,
1031 SLOT(onFrameSwitched()));
1032
1033 TPaletteHandle *paletteHandle =
1034 app->getPaletteController()->getCurrentLevelPalette();
1035 ret = ret && connect(paletteHandle, SIGNAL(colorStyleChanged(bool)), this,
1036 SLOT(update()));
1037
1038 ret = ret && connect(app->getCurrentObject(), SIGNAL(objectSwitched()), this,
1039 SLOT(onObjectSwitched()));
1040 ret = ret && connect(app->getCurrentObject(), SIGNAL(objectChanged(bool)),
1041 this, SLOT(update()));
1042
1043 ret =
1044 ret && connect(app->getCurrentOnionSkin(), SIGNAL(onionSkinMaskChanged()),
1045 this, SLOT(onOnionSkinMaskChanged()));
1046
1047 ret = ret && connect(app->getCurrentLevel(), SIGNAL(xshLevelChanged()), this,
1048 SLOT(update()));
1049 ret = ret && connect(app->getCurrentLevel(), SIGNAL(xshCanvasSizeChanged()),
1050 this, SLOT(update()));
1051 // when level is switched, update m_dpiScale in order to show white background
1052 // for Ink&Paint work properly
1053 ret = ret &&
1054 connect(app->getCurrentLevel(), SIGNAL(xshLevelSwitched(TXshLevel *)),
1055 this, SLOT(onLevelSwitched()));
1056
1057 ret = ret && connect(app->getCurrentXsheet(), SIGNAL(xsheetChanged()), this,
1058 SLOT(onXsheetChanged()));
1059 ret = ret && connect(app->getCurrentXsheet(), SIGNAL(xsheetSwitched()), this,
1060 SLOT(update()));
1061
1062 // update tooltip when tool options are changed
1063 ret = ret && connect(app->getCurrentTool(), SIGNAL(toolChanged()), this,
1064 SLOT(onToolChanged()));
1065 ret = ret && connect(app->getCurrentTool(), SIGNAL(toolCursorTypeChanged()),
1066 this, SLOT(onToolChanged()));
1067
1068 ret = ret &&
1069 connect(app, SIGNAL(tabletLeft()), this, SLOT(resetTabletStatus()));
1070 #if defined(x64)
1071 if (m_stopMotion) {
1072 ret = ret && connect(m_stopMotion, SIGNAL(newLiveViewImageReady()), this,
1073 SLOT(onNewStopMotionImageReady()));
1074 ret = ret && connect(m_stopMotion, SIGNAL(liveViewStopped()), this,
1075 SLOT(onStopMotionLiveViewStopped()));
1076 }
1077 #endif
1078 assert(ret);
1079
1080 if (m_hRuler && m_vRuler) {
1081 if (!viewRulerToggle.getStatus()) {
1082 m_hRuler->hide();
1083 m_vRuler->hide();
1084 } else {
1085 m_hRuler->show();
1086 m_vRuler->show();
1087 }
1088 }
1089 if (m_shownOnce == false) {
1090 fitToCamera();
1091 m_shownOnce = true;
1092 }
1093 TApp::instance()->setActiveViewer(this);
1094
1095 onPreferenceChanged("ColorCalibration");
1096 update();
1097 }
1098
1099 //-----------------------------------------------------------------------------
1100
hideEvent(QHideEvent *)1101 void SceneViewer::hideEvent(QHideEvent *) {
1102 // Se il viewer e' hide e il preview e' attivo rimuovo il listner dal preview
1103 if (m_previewMode != NO_PREVIEW)
1104 Previewer::instance(m_previewMode == SUBCAMERA_PREVIEW)
1105 ->removeListener(this);
1106
1107 TApp *app = TApp::instance();
1108
1109 TSceneHandle *sceneHandle = app->getCurrentScene();
1110 if (sceneHandle) sceneHandle->disconnect(this);
1111
1112 TFrameHandle *frameHandle = app->getCurrentFrame();
1113 if (frameHandle) frameHandle->disconnect(this);
1114
1115 TPaletteHandle *paletteHandle =
1116 app->getPaletteController()->getCurrentLevelPalette();
1117 if (paletteHandle) paletteHandle->disconnect(this);
1118
1119 TObjectHandle *objectHandle = app->getCurrentObject();
1120 if (objectHandle) objectHandle->disconnect(this);
1121
1122 TOnionSkinMaskHandle *onionHandle = app->getCurrentOnionSkin();
1123 if (onionHandle) onionHandle->disconnect(this);
1124
1125 TXshLevelHandle *levelHandle = app->getCurrentLevel();
1126 if (levelHandle) levelHandle->disconnect(this);
1127
1128 TXsheetHandle *xsheetHandle = app->getCurrentXsheet();
1129 if (xsheetHandle) xsheetHandle->disconnect(this);
1130
1131 ToolHandle *toolHandle = app->getCurrentTool();
1132 if (toolHandle) toolHandle->disconnect(this);
1133
1134 disconnect(app, SIGNAL(tabletLeft()), this, SLOT(resetTabletStatus()));
1135
1136 #if defined(x64)
1137 if (m_stopMotion) {
1138 disconnect(m_stopMotion, SIGNAL(newImageReady()), this,
1139 SLOT(onNewStopMotionImageReady()));
1140 disconnect(m_stopMotion, SIGNAL(liveViewStopped()), this,
1141 SLOT(onStopMotionLiveViewStopped()));
1142 }
1143 #endif
1144
1145 // hide locator
1146 if (m_locator && m_locator->isVisible()) m_locator->hide();
1147 }
1148
getVGuideCount()1149 int SceneViewer::getVGuideCount() {
1150 if (viewGuideToggle.getStatus())
1151 return m_vRuler->getGuideCount();
1152 else
1153 return 0;
1154 }
getHGuideCount()1155 int SceneViewer::getHGuideCount() {
1156 if (viewGuideToggle.getStatus())
1157 return m_hRuler->getGuideCount();
1158 else
1159 return 0;
1160 }
1161
getVGuide(int index)1162 double SceneViewer::getVGuide(int index) { return m_vRuler->getGuide(index); }
getHGuide(int index)1163 double SceneViewer::getHGuide(int index) { return m_hRuler->getGuide(index); }
1164
1165 #if defined(x64)
1166 //-----------------------------------------------------------------------------
1167
onNewStopMotionImageReady()1168 void SceneViewer::onNewStopMotionImageReady() {
1169 if (m_stopMotion->m_hasLineUpImage) {
1170 // if (m_hasStopMotionLineUpImage) delete m_stopMotionLineUpImage;
1171 m_stopMotionLineUpImage =
1172 (TRasterImageP)m_stopMotion->m_lineUpImage->clone();
1173 m_stopMotionLineUpImage->setDpi(m_stopMotion->m_liveViewDpi.x,
1174 m_stopMotion->m_liveViewDpi.y);
1175 m_hasStopMotionLineUpImage = true;
1176 }
1177 if (m_stopMotion->m_hasLiveViewImage) {
1178 // if (m_hasStopMotionImage) delete m_stopMotionImage;
1179 m_stopMotionImage = m_stopMotion->m_liveViewImage->clone();
1180 m_stopMotionImage->setDpi(m_stopMotion->m_liveViewDpi.x,
1181 m_stopMotion->m_liveViewDpi.y);
1182 m_hasStopMotionImage = true;
1183 if (m_stopMotion->m_canon->m_pickLiveViewZoom) {
1184 setToolCursor(this, ToolCursor::ZoomCursor);
1185 }
1186 onSceneChanged();
1187 }
1188 }
1189
1190 //-----------------------------------------------------------------------------
1191
onStopMotionLiveViewStopped()1192 void SceneViewer::onStopMotionLiveViewStopped() {
1193 m_hasStopMotionImage = false;
1194 m_hasStopMotionLineUpImage = false;
1195 onSceneChanged();
1196 }
1197
1198 #endif // x64
1199 //-----------------------------------------------------------------------------
1200
onPreferenceChanged(const QString & prefName)1201 void SceneViewer::onPreferenceChanged(const QString &prefName) {
1202 if (prefName == "ColorCalibration") {
1203 if (Preferences::instance()->isColorCalibrationEnabled()) {
1204 // if the window is so shriked that the gl widget is empty,
1205 // showEvent can be called before creating the context.
1206 if (!context()) return;
1207 makeCurrent();
1208 if (!m_lutCalibrator)
1209 m_lutCalibrator = new LutCalibrator();
1210 else
1211 m_lutCalibrator->cleanup();
1212 m_lutCalibrator->initialize();
1213 connect(context(), SIGNAL(aboutToBeDestroyed()), this,
1214 SLOT(onContextAboutToBeDestroyed()));
1215 if (m_lutCalibrator->isValid() && !m_fbo)
1216 m_fbo = new QOpenGLFramebufferObject(width(), height());
1217 doneCurrent();
1218 }
1219 update();
1220 }
1221 }
1222
1223 //-----------------------------------------------------------------------------
initializeGL()1224 void SceneViewer::initializeGL() {
1225 initializeOpenGLFunctions();
1226
1227 registerContext();
1228
1229 // to be computed once through the software
1230 if (m_lutCalibrator && !m_lutCalibrator->isInitialized()) {
1231 m_lutCalibrator->initialize();
1232 connect(context(), SIGNAL(aboutToBeDestroyed()), this,
1233 SLOT(onContextAboutToBeDestroyed()));
1234 }
1235
1236 // glClearColor(1.0,1.0,1.0,1);
1237 glClear(GL_COLOR_BUFFER_BIT);
1238
1239 if (m_firstInitialized)
1240 m_firstInitialized = false;
1241 else {
1242 resizeGL(width(), height());
1243 update();
1244 }
1245 // re-computing the display list for the table
1246 m_tableDLId = -1;
1247 }
1248
1249 //-----------------------------------------------------------------------------
1250
resizeGL(int w,int h)1251 void SceneViewer::resizeGL(int w, int h) {
1252 w *= getDevPixRatio();
1253 h *= getDevPixRatio();
1254 glViewport(0, 0, w, h);
1255 glMatrixMode(GL_PROJECTION);
1256 glLoadIdentity();
1257 glOrtho(0, w, 0, h, -4000, 4000);
1258 m_projectionMatrix.setToIdentity();
1259 m_projectionMatrix.ortho(0, w, 0, h, -4000, 4000);
1260
1261 glMatrixMode(GL_MODELVIEW);
1262 glLoadIdentity();
1263 glTranslatef(0.375, 0.375, 0.0);
1264 // make the center of the viewer = origin
1265 glTranslated(w * 0.5, h * 0.5, 0);
1266
1267 if (m_freezedStatus == NORMAL_FREEZED) m_freezedStatus = UPDATE_FREEZED;
1268
1269 if (m_previewMode != NO_PREVIEW) requestTimedRefresh();
1270
1271 // remake fbo with new size
1272 if (m_lutCalibrator && m_lutCalibrator->isValid()) {
1273 if (m_fbo) delete m_fbo;
1274 m_fbo = new QOpenGLFramebufferObject(w, h);
1275 }
1276
1277 // for updating the navigator in levelstrip
1278 emit refreshNavi();
1279 }
1280
1281 //-----------------------------------------------------------------------------
1282
drawBuildVars()1283 void SceneViewer::drawBuildVars() {
1284 TApp *app = TApp::instance();
1285
1286 int frame = app->getCurrentFrame()->getFrame();
1287 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
1288
1289 // Camera affine
1290 TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
1291 TStageObject *camera = xsh->getStageObject(cameraId);
1292 TAffine cameraPlacement = camera->getPlacement(frame);
1293 double cameraZ = camera->getZ(frame);
1294
1295 m_drawCameraAff =
1296 getViewMatrix() * cameraPlacement * TScale((1000 + cameraZ) / 1000);
1297
1298 // Table affine
1299 TStageObject *table = xsh->getStageObject(TStageObjectId::TableId);
1300 TAffine tablePlacement = table->getPlacement(frame);
1301 double tableZ = table->getZ(frame);
1302 TAffine placement;
1303
1304 m_drawIsTableVisible = TStageObject::perspective(
1305 placement, cameraPlacement, cameraZ, tablePlacement, tableZ, 0);
1306 m_drawTableAff = getViewMatrix() * tablePlacement;
1307
1308 // Camera test check
1309 m_drawCameraTest = CameraTestCheck::instance()->isEnabled();
1310
1311 if (m_previewMode == NO_PREVIEW) {
1312 m_drawEditingLevel = app->getCurrentFrame()->isEditingLevel();
1313 m_viewMode = m_drawEditingLevel ? LEVEL_VIEWMODE : SCENE_VIEWMODE;
1314 m_draw3DMode = is3DView() && (m_previewMode != SUBCAMERA_PREVIEW);
1315 } else {
1316 m_drawEditingLevel = false;
1317 m_viewMode = app->getCurrentFrame()->isEditingLevel();
1318 m_draw3DMode = false;
1319 }
1320
1321 // Clip rect
1322 if (!m_clipRect.isEmpty() && !m_draw3DMode) {
1323 m_actualClipRect = getActualClipRect(getViewMatrix());
1324 m_actualClipRect += TPoint(width() * 0.5, height() * 0.5);
1325 }
1326
1327 TTool *tool = app->getCurrentTool()->getTool();
1328 if (tool && !m_isLocator) tool->setViewer(this);
1329 }
1330
1331 //-----------------------------------------------------------------------------
1332
drawEnableScissor()1333 void SceneViewer::drawEnableScissor() {
1334 if (!m_clipRect.isEmpty() && !m_draw3DMode) {
1335 glEnable(GL_SCISSOR_TEST);
1336 glScissor(m_actualClipRect.x0, m_actualClipRect.y0,
1337 m_actualClipRect.getLx(), m_actualClipRect.getLy());
1338 }
1339 }
1340
1341 //-----------------------------------------------------------------------------
1342
drawDisableScissor()1343 void SceneViewer::drawDisableScissor() {
1344 if (!m_clipRect.isEmpty() && !m_draw3DMode) {
1345 glDisable(GL_SCISSOR_TEST);
1346 }
1347 // clear the clipping rect
1348 m_clipRect.empty();
1349 }
1350
1351 //-----------------------------------------------------------------------------
1352
drawBackground()1353 void SceneViewer::drawBackground() {
1354 TApp *app = TApp::instance();
1355 ToonzScene *scene = app->getCurrentScene()->getScene();
1356
1357 if (m_visualSettings.m_colorMask == 0) {
1358 TPixel32 bgColor;
1359
1360 if (isPreviewEnabled())
1361 bgColor = Preferences::instance()->getPreviewBgColor();
1362 else
1363 bgColor = Preferences::instance()->getViewerBgColor();
1364 glClearColor(bgColor.r / 255.0f, bgColor.g / 255.0f, bgColor.b / 255.0f,
1365 1.0);
1366 } else
1367 glClearColor(0, 0, 0, 1.0);
1368
1369 glClear(GL_COLOR_BUFFER_BIT);
1370 if (glGetError() == GL_INVALID_FRAMEBUFFER_OPERATION) {
1371 /* 起動時一回目になぜか GL_FRAMEBUFFER_COMPLETE なのに invalid operation
1372 * が出る */
1373 GLenum status = 0;
1374 #ifdef _WIN32
1375 PROC proc = wglGetProcAddress("glCheckFramebufferStatusEXT");
1376 if (proc != nullptr)
1377 status = reinterpret_cast<PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC>(proc)(
1378 GL_FRAMEBUFFER);
1379 #else
1380 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1381 #endif
1382 printf("GL_INVALID_FRAMEBUFFER_OPERATION: framebuffer:%d\n", status);
1383 }
1384 }
1385
check_framebuffer_status()1386 static bool check_framebuffer_status() {
1387 #ifdef _WIN32
1388 PROC proc = wglGetProcAddress("glCheckFramebufferStatusEXT");
1389 if (proc == nullptr) return true;
1390 GLenum s = reinterpret_cast<PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC>(proc)(
1391 GL_FRAMEBUFFER);
1392 #else
1393 GLenum s = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1394 #endif
1395 if (s == GL_FRAMEBUFFER_UNDEFINED)
1396 printf("Warning: FB undefined: %d\n", s);
1397 else if (s == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
1398 printf("Warning: FB incomplete(attachment): %d\n", s);
1399 else if (s == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
1400 printf("Warning: FB incomplete(missing attachment): %d\n", s);
1401 else if (s == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER)
1402 printf("Warning: FB incomplete(draw buffer): %d\n", s);
1403 else if (s == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER)
1404 printf("Warning: FB incomplete(read buffer): %d\n", s);
1405 else if (s == GL_FRAMEBUFFER_UNSUPPORTED)
1406 printf("Warning: FB unsupported: %d\n", s);
1407 else if (s == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE)
1408 printf("Warning: FB incomplete(multi-sample): %d\n", s);
1409 else if (s == GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
1410 printf("Warning: FB incomplete(multi-sample): %d\n", s);
1411 else if (s == GL_FRAMEBUFFER_COMPLETE)
1412 ;
1413 else
1414 printf("Warning: FB not complete(unknown cause): %d\n", s);
1415 return s == GL_FRAMEBUFFER_COMPLETE;
1416 }
1417
1418 //-----------------------------------------------------------------------------
1419
drawCameraStand()1420 void SceneViewer::drawCameraStand() {
1421 GLint e = glGetError();
1422 check_framebuffer_status();
1423 assert(e == GL_NO_ERROR);
1424
1425 TXshSimpleLevel::m_rasterizePli = rasterizePliToggle.getStatus();
1426
1427 // clear
1428 if (m_draw3DMode) {
1429 glEnable(GL_DEPTH_TEST);
1430 glDepthFunc(GL_ALWAYS);
1431 glClear(GL_DEPTH_BUFFER_BIT);
1432 glPushMatrix();
1433 mult3DMatrix();
1434 } else
1435 glDisable(GL_DEPTH_TEST);
1436
1437 assert(glGetError() == GL_NO_ERROR);
1438
1439 // draw table
1440 if (!m_draw3DMode && viewTableToggle.getStatus() && m_drawIsTableVisible &&
1441 m_visualSettings.m_colorMask == 0 && m_drawEditingLevel == false &&
1442 !m_drawCameraTest) {
1443 glPushMatrix();
1444 tglMultMatrix(m_drawTableAff);
1445 ViewerDraw::drawDisk(m_tableDLId);
1446 glPopMatrix();
1447 }
1448
1449 // draw colorcard (with camera BG color)
1450 // Hide camera BG when level editing mode.
1451 if (m_drawEditingLevel == false && viewClcToggle.getStatus() &&
1452 !m_drawCameraTest) {
1453 glPushMatrix();
1454 tglMultMatrix(m_drawCameraAff);
1455 glEnable(GL_BLEND);
1456 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1457 ViewerDraw::drawColorcard(m_visualSettings.m_colorMask);
1458 glDisable(GL_BLEND);
1459 glPopMatrix();
1460 }
1461
1462 // Show white background when level editing mode.
1463 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
1464 if (m_drawEditingLevel && tool && tool->isEnabled()) {
1465 if (!m_isLocator) tool->setViewer(this);
1466 glPushMatrix();
1467 if (m_referenceMode == CAMERA3D_REFERENCE) {
1468 mult3DMatrix();
1469 tglMultMatrix(tool->getMatrix());
1470 } else {
1471 tglMultMatrix(getViewMatrix() * tool->getMatrix());
1472 }
1473 glScaled(m_dpiScale.x, m_dpiScale.y, 1);
1474
1475 TImageP image = tool->getImage(false);
1476
1477 TToonzImageP ti = image;
1478 TRasterImageP ri = image;
1479 if (ti) {
1480 TRect imgRect(0, 0, ti->getSize().lx - 1, ti->getSize().ly - 1);
1481 TRectD bbox = ToonzImageUtils::convertRasterToWorld(imgRect, ti);
1482
1483 TPixel32 imgRectColor;
1484 // draw black rectangle instead, if the BlackBG check is ON
1485 if (ToonzCheck::instance()->getChecks() & ToonzCheck::eBlackBg)
1486 imgRectColor = TPixel::Black;
1487 else
1488 imgRectColor = Preferences::instance()->getLevelEditorBoxColor();
1489 ToolUtils::fillRect(bbox * ti->getSubsampling(), imgRectColor);
1490 } else if (ri) {
1491 TRectD bbox = ri->getBBox();
1492 bbox.x0 -= ri->getBBox().getLx() * 0.5;
1493 bbox.x1 -= ri->getBBox().getLx() * 0.5;
1494 bbox.y0 -= ri->getBBox().getLy() * 0.5;
1495 bbox.y1 -= ri->getBBox().getLy() * 0.5;
1496
1497 TPixel32 imgRectColor;
1498 // draw black rectangle instead, if the BlackBG check is ON
1499 if (ToonzCheck::instance()->getChecks() & ToonzCheck::eBlackBg)
1500 imgRectColor = TPixel::Black;
1501 else
1502 imgRectColor = Preferences::instance()->getLevelEditorBoxColor();
1503 ToolUtils::fillRect(bbox * ri->getSubsampling(), imgRectColor);
1504 }
1505 glPopMatrix();
1506 }
1507
1508 // draw 3dframe
1509 if (m_draw3DMode) {
1510 glDepthFunc(GL_LEQUAL);
1511 ViewerDraw::draw3DFrame(m_minZ, m_phi3D);
1512 glDepthFunc(GL_ALWAYS);
1513 }
1514
1515 // draw scene
1516 assert(glGetError() == GL_NO_ERROR);
1517 drawScene();
1518 assert((glGetError()) == GL_NO_ERROR);
1519 }
1520
1521 //-----------------------------------------------------------------------------
1522
drawPreview()1523 void SceneViewer::drawPreview() {
1524 const double inch = Stage::inch;
1525 TApp *app = TApp::instance();
1526 int row = app->getCurrentFrame()->getFrame();
1527 TCamera *currCamera = app->getCurrentScene()->getScene()->getCurrentCamera();
1528 TDimensionD cameraSize = currCamera->getSize();
1529
1530 Previewer *previewer =
1531 Previewer::instance(m_previewMode == SUBCAMERA_PREVIEW);
1532
1533 TRasterP ras =
1534 previewer->getRaster(row, m_visualSettings.m_recomputeIfNeeded);
1535 if (ras) {
1536 TRectD previewStageRectD, cameraStageRectD = currCamera->getStageRect();
1537
1538 TRect subCameraRect(currCamera->getInterestRect());
1539 if (m_previewMode == SUBCAMERA_PREVIEW && subCameraRect.getLx() > 0 &&
1540 subCameraRect.getLy() > 0)
1541 previewStageRectD = currCamera->getInterestStageRect();
1542 else
1543 previewStageRectD = cameraStageRectD;
1544
1545 TAffine rasterToStageRef(
1546 previewStageRectD.getLx() / ras->getLx(), 0.0,
1547 previewStageRectD.x0 + 0.5 * previewStageRectD.getLx(), 0.0,
1548 previewStageRectD.getLy() / ras->getLy(),
1549 previewStageRectD.y0 + 0.5 * previewStageRectD.getLy());
1550
1551 TDimension dim(width(), height());
1552 TAffine finalAff = m_drawCameraAff * rasterToStageRef;
1553 m_visualSettings.m_useTexture = !Preferences::instance()->useDrawPixel();
1554 ImagePainter::paintImage(TRasterImageP(ras), ras->getSize(), dim, finalAff,
1555 m_visualSettings, m_compareSettings, TRect());
1556 }
1557
1558 glPushMatrix();
1559 tglMultMatrix(m_drawCameraAff);
1560
1561 TRectD frameRect(cameraSize);
1562 frameRect.x1 *= inch;
1563 frameRect.y1 *= inch;
1564 frameRect -= 0.5 * (frameRect.getP00() + frameRect.getP11());
1565
1566 if (m_visualSettings.m_blankColor != TPixel::Transparent) {
1567 tglColor(m_visualSettings.m_blankColor);
1568 tglFillRect(frameRect);
1569 }
1570
1571 if (!previewer->isFrameReady(row) ||
1572 (app->getCurrentFrame()->isPlaying() && previewer->isBusy())) {
1573 glColor3d(1, 0, 0);
1574
1575 tglDrawRect(frameRect);
1576 tglDrawRect(frameRect.enlarge(5));
1577 }
1578
1579 glPopMatrix();
1580 }
1581
1582 //-----------------------------------------------------------------------------
1583
drawOverlay()1584 void SceneViewer::drawOverlay() {
1585 TApp *app = TApp::instance();
1586
1587 // draw camera mask
1588 if (m_referenceMode == CAMERA_REFERENCE && !m_drawCameraTest) {
1589 glPushMatrix();
1590 tglMultMatrix(m_drawCameraAff);
1591 ViewerDraw::drawCameraMask(this);
1592 glPopMatrix();
1593 }
1594
1595 // draw FieldGuide
1596 if (fieldGuideToggle.getStatus()) {
1597 glPushMatrix();
1598 tglMultMatrix(m_drawTableAff);
1599 ViewerDraw::drawFieldGuide();
1600 glPopMatrix();
1601 }
1602
1603 if (!m_drawCameraTest) {
1604 // draw grid & guides
1605 if (viewGuideToggle.getStatus() &&
1606 ((m_vRuler && m_vRuler->getGuideCount()) ||
1607 (m_hRuler && m_hRuler->getGuideCount()))) {
1608 glPushMatrix();
1609 tglMultMatrix(getViewMatrix());
1610 ViewerDraw::drawGridAndGuides(
1611 this, (m_draw3DMode) ? m_zoomScale3D : m_viewAff[m_viewMode].det(),
1612 m_vRuler, m_hRuler, false);
1613 glPopMatrix();
1614 }
1615
1616 // draw camera
1617 if (viewCameraToggle.getStatus() && m_drawEditingLevel == false) {
1618 unsigned long f = 0;
1619 if (m_referenceMode == CAMERA_REFERENCE)
1620 f |= ViewerDraw::CAMERA_REFERENCE;
1621 if (m_draw3DMode) f |= ViewerDraw::CAMERA_3D;
1622 if (m_previewMode == SUBCAMERA_PREVIEW || m_editPreviewSubCamera)
1623 f |= ViewerDraw::SUBCAMERA;
1624 if (m_draw3DMode)
1625 ViewerDraw::draw3DCamera(f, m_minZ, m_phi3D);
1626 else {
1627 glPushMatrix();
1628 tglMultMatrix(m_drawCameraAff);
1629 m_pixelSize = sqrt(tglGetPixelSize2()) * getDevPixRatio();
1630 ViewerDraw::drawCamera(f, m_pixelSize);
1631 glPopMatrix();
1632 }
1633 }
1634
1635 #ifdef WITH_CANON
1636 if (m_stopMotion->m_liveViewStatus == StopMotion::LiveViewOpen &&
1637 app->getCurrentFrame()->getFrame() ==
1638 m_stopMotion->getXSheetFrameNumber() - 1) {
1639 int x0, x1, y0, y1;
1640 rect().getCoords(&x0, &y0, &x1, &y1);
1641 x0 = (-(x1 / 2)) + 15;
1642 y0 = ((y1 / 2)) - 15;
1643 tglDrawDisk(TPointD(x0, y0), 10);
1644 }
1645
1646 // draw Stop Motion Zoom Box
1647 if (m_stopMotion->m_liveViewStatus == 2 &&
1648 m_stopMotion->m_canon->m_pickLiveViewZoom) {
1649 glPushMatrix();
1650 tglMultMatrix(m_drawCameraAff);
1651 m_pixelSize = sqrt(tglGetPixelSize2()) * getDevPixRatio();
1652 TRect rect = m_stopMotion->m_canon->m_zoomRect;
1653
1654 glColor3d(1.0, 0.0, 0.0);
1655
1656 // border
1657 glBegin(GL_LINE_STRIP);
1658 glVertex2d(rect.x0, rect.y0);
1659 glVertex2d(rect.x0, rect.y1 - m_pixelSize);
1660 glVertex2d(rect.x1 - m_pixelSize, rect.y1 - m_pixelSize);
1661 glVertex2d(rect.x1 - m_pixelSize, rect.y0);
1662 glVertex2d(rect.x0, rect.y0);
1663 glEnd();
1664
1665 glPopMatrix();
1666 }
1667
1668 #endif
1669
1670 // safe area
1671 if (safeAreaToggle.getStatus() && m_drawEditingLevel == false &&
1672 !is3DView()) {
1673 glPushMatrix();
1674 tglMultMatrix(m_drawCameraAff);
1675 ViewerDraw::drawSafeArea();
1676 glPopMatrix();
1677 }
1678
1679 // record fps (frame per second)
1680 if (app->getCurrentFrame()->isPlaying())
1681 m_FPS = getActualFrameRate();
1682 else
1683 m_FPS = 0;
1684
1685 if (m_freezedStatus != NO_FREEZED) {
1686 tglColor(TPixel32::Red);
1687 tglDrawText(TPointD(0, 0), "FROZEN");
1688 }
1689 assert(glGetError() == GL_NO_ERROR);
1690
1691 } //! cameraTest
1692
1693 // draw 3d Top/Side Buttons
1694 if (m_draw3DMode && !m_isPicking) {
1695 tglColor(TPixel32::Black);
1696
1697 GLdouble modelView3D[16];
1698 GLdouble projection3D[16];
1699 GLint viewport3D[4];
1700
1701 glGetDoublev(GL_MODELVIEW_MATRIX, modelView3D);
1702 glGetDoublev(GL_PROJECTION_MATRIX, projection3D);
1703 glGetIntegerv(GL_VIEWPORT, viewport3D);
1704
1705 if (m_phi3D > 0) {
1706 T3DPointD topRasterPos3D = computeNew3DPosition(
1707 T3DPointD(500, 500, 1000), TPointD(-10, -10), m_topRasterPos,
1708 modelView3D, projection3D, viewport3D, getDevPixRatio());
1709 glRasterPos3f(topRasterPos3D.x, topRasterPos3D.y, topRasterPos3D.z);
1710 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1711 glDrawPixels(m_3DTop->getWrap(), m_3DTop->getLy(), TGL_FMT, TGL_TYPE,
1712 m_3DTop->getRawData());
1713
1714 T3DPointD sideRasterPos3D = computeNew3DPosition(
1715 T3DPointD(-500, -500, 1000), TPointD(-10, -10), m_sideRasterPos,
1716 modelView3D, projection3D, viewport3D, getDevPixRatio());
1717 glRasterPos3f(sideRasterPos3D.x, sideRasterPos3D.y, sideRasterPos3D.z);
1718 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1719 glDrawPixels(m_3DSideR->getWrap(), m_3DSideR->getLy(), TGL_FMT, TGL_TYPE,
1720 m_3DSideR->getRawData());
1721 } else {
1722 T3DPointD topRasterPos3D = computeNew3DPosition(
1723 T3DPointD(-500, 500, 1000), TPointD(-10, -10), m_topRasterPos,
1724 modelView3D, projection3D, viewport3D, getDevPixRatio());
1725 glRasterPos3f(topRasterPos3D.x, topRasterPos3D.y, topRasterPos3D.z);
1726 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1727 glDrawPixels(m_3DTop->getWrap(), m_3DTop->getLy(), TGL_FMT, TGL_TYPE,
1728 m_3DTop->getRawData());
1729
1730 T3DPointD sideRasterPos3D = computeNew3DPosition(
1731 T3DPointD(500, -500, 1000), TPointD(-10, -10), m_sideRasterPos,
1732 modelView3D, projection3D, viewport3D, getDevPixRatio());
1733 glRasterPos3f(sideRasterPos3D.x, sideRasterPos3D.y, sideRasterPos3D.z);
1734 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1735 glDrawPixels(m_3DSideL->getWrap(), m_3DSideL->getLy(), TGL_FMT, TGL_TYPE,
1736 m_3DSideL->getRawData());
1737 }
1738 }
1739
1740 if (m_draw3DMode) {
1741 glDisable(GL_DEPTH_TEST);
1742 glPopMatrix();
1743 assert(glGetError() == GL_NO_ERROR);
1744 }
1745
1746 // draw tool gadgets
1747 TTool *tool = app->getCurrentTool()->getTool();
1748 TXshSimpleLevel *sl = app->getCurrentLevel()->getSimpleLevel();
1749 // Call tool->draw() even if the level is read only (i.e. to show hooks)
1750 if (tool && (tool->isEnabled() || (sl && sl->isReadOnly()))) {
1751 // tool->setViewer(this); // Moved at
1752 // drawBuildVars(), before drawing anything
1753 glPushMatrix();
1754 if (m_draw3DMode) {
1755 mult3DMatrix();
1756 tglMultMatrix(tool->getMatrix());
1757 } else
1758 tglMultMatrix(getViewMatrix() * tool->getMatrix());
1759 if (tool->getToolType() & TTool::LevelTool &&
1760 !app->getCurrentObject()->isSpline())
1761 glScaled(m_dpiScale.x, m_dpiScale.y, 1);
1762 m_pixelSize = sqrt(tglGetPixelSize2()) * getDevPixRatio();
1763 tool->draw();
1764 glPopMatrix();
1765 // Used (only in the T_RGBPicker tool) to notify and set the currentColor
1766 // outside the draw() methods:
1767 // using special style there was a conflict between the draw() methods of
1768 // the tool
1769 // and the genaration of the icon inside the style editor (makeIcon()) which
1770 // use
1771 // another glContext
1772 if (tool->getName() == "T_RGBPicker") tool->onImageChanged();
1773
1774 // draw cross at the center of the locator window
1775 if (m_isLocator) {
1776 glColor3d(1.0, 0.0, 0.0);
1777 tglDrawSegment(TPointD(-4, 0), TPointD(5, 0));
1778 tglDrawSegment(TPointD(0, -4), TPointD(0, 5));
1779 }
1780 }
1781 }
1782
1783 //-----------------------------------------------------------------------------
1784
drawFpsGraph(int t0,int t1)1785 static void drawFpsGraph(int t0, int t1) {
1786 glDisable(GL_BLEND);
1787 static std::deque<std::pair<int, int>> times;
1788 times.push_back(std::make_pair(t0, t1));
1789 while (times.size() > 200) times.pop_front();
1790 double x0 = 10, y0 = 10;
1791 double x1 = x0 + 200;
1792 double y1 = y0 + 150;
1793 glPushMatrix();
1794 glLoadIdentity();
1795 glColor3d(0, 0, 0);
1796 glRectd(x0, y0, x1, y1);
1797 glColor3d(0, 0.5, 1);
1798 glBegin(GL_LINE_STRIP);
1799 glVertex2d(x0, y0);
1800 glVertex2d(x1, y0);
1801 glVertex2d(x1, y1);
1802 glVertex2d(x0, y1);
1803 glVertex2d(x0, y0);
1804 glEnd();
1805 glColor3d(0.5, 0.5, 0.5);
1806 glBegin(GL_LINES);
1807 for (int y = y0 + 5; y < y1; y += 20) {
1808 glVertex2d(x0, y);
1809 glVertex2d(x1, y);
1810 }
1811 for (int i = 0; i < (int)times.size(); i++) {
1812 double x = x1 - i;
1813 glColor3d(1, 0, 0);
1814 glVertex2d(x, y0);
1815 glVertex2d(x, y0 + 5 + times[i].first / 5);
1816 glColor3d(0, 1, 0);
1817 glVertex2d(x, y0 + 5 + times[i].first / 5);
1818 glVertex2d(x, y0 + 5 + times[i].second / 5);
1819 }
1820 glEnd();
1821 glPopMatrix();
1822 }
1823
1824 //-----------------------------------------------------------------------------
1825
1826 //#define FPS_HISTOGRAM
1827
paintGL()1828 void SceneViewer::paintGL() {
1829 #ifdef _DEBUG
1830 if (!check_framebuffer_status()) {
1831 /* QGLWidget の widget 生成/削除のタイミングで(platform によって?)
1832 * GL_FRAMEBUFFER_UNDEFINED の状態で paintGL() が呼ばれてしまうようだ */
1833 return;
1834 }
1835 #endif
1836 #ifdef MACOSX
1837 // followin lines are necessary to solve a problem on iMac20
1838 // It seems that for some errors in the openGl implementation, buffers are not
1839 // set corretly.
1840 if (m_isMouseEntered && m_forceGlFlush) {
1841 m_isMouseEntered = false;
1842 m_forceGlFlush = false;
1843 glDrawBuffer(GL_FRONT);
1844 glFlush();
1845 glDrawBuffer(GL_BACK);
1846 }
1847 #endif
1848
1849 #ifdef FPS_HISTOGRAM
1850 QTime time;
1851 time.start();
1852 #endif
1853
1854 if (!m_isPicking && m_lutCalibrator && m_lutCalibrator->isValid())
1855 m_fbo->bind();
1856
1857 if (m_hRuler && m_vRuler) {
1858 if (!viewRulerToggle.getStatus() &&
1859 (m_hRuler->isVisible() || m_vRuler->isVisible())) {
1860 m_hRuler->hide();
1861 m_vRuler->hide();
1862 } else if (viewRulerToggle.getStatus() &&
1863 (!m_hRuler->isVisible() || !m_vRuler->isVisible())) {
1864 m_hRuler->show();
1865 m_vRuler->show();
1866 }
1867 }
1868
1869 // Il freezed e' attivo ed e' in stato "normale": mostro l'immagine grabbata.
1870 if (m_freezedStatus == NORMAL_FREEZED) {
1871 assert(!!m_viewGrabImage);
1872 m_viewGrabImage->lock();
1873 glPushMatrix();
1874 glLoadIdentity();
1875
1876 glRasterPos2d(0, 0);
1877 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1878
1879 glDrawPixels(m_viewGrabImage->getLx(), m_viewGrabImage->getLy(), TGL_FMT,
1880 TGL_TYPE, m_viewGrabImage->getRawData());
1881
1882 glPopMatrix();
1883 m_viewGrabImage->unlock();
1884
1885 if (!m_isPicking && m_lutCalibrator && m_lutCalibrator->isValid())
1886 m_lutCalibrator->onEndDraw(m_fbo);
1887
1888 return;
1889 }
1890
1891 drawBuildVars();
1892
1893 // This seems not to be necessary for now.
1894 // copyFrontBufferToBackBuffer();
1895
1896 drawEnableScissor();
1897 drawBackground();
1898
1899 if (m_previewMode != FULL_PREVIEW) {
1900 drawCameraStand();
1901 }
1902
1903 if (isPreviewEnabled()) drawPreview();
1904
1905 drawOverlay();
1906
1907 drawDisableScissor();
1908
1909 // Il freezed e' attivo ed e' in stato "update": faccio il grab del viewer.
1910 if (m_freezedStatus == UPDATE_FREEZED) {
1911 m_viewGrabImage = rasterFromQImage(grabFramebuffer());
1912 m_freezedStatus = NORMAL_FREEZED;
1913 }
1914
1915 #ifdef FPS_HISTOGRAM
1916 int t0 = time.elapsed();
1917 glFlush();
1918 glFinish();
1919 int t1 = time.elapsed();
1920 drawFpsGraph(t0, t1);
1921 #endif
1922 // TOfflineGL::setContextManager(0);
1923
1924 if (!m_isPicking && m_lutCalibrator && m_lutCalibrator->isValid())
1925 m_lutCalibrator->onEndDraw(m_fbo);
1926 }
1927
1928 //-----------------------------------------------------------------------------
1929
drawScene()1930 void SceneViewer::drawScene() {
1931 TApp *app = TApp::instance();
1932 ToonzScene *scene = app->getCurrentScene()->getScene();
1933 int frame = app->getCurrentFrame()->getFrame();
1934 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
1935 TRect clipRect = getActualClipRect(getViewMatrix());
1936 clipRect += TPoint(width() * 0.5, height() * 0.5);
1937
1938 ChildStack *childStack = scene->getChildStack();
1939 bool editInPlace = editInPlaceToggle.getStatus() &&
1940 !app->getCurrentFrame()->isEditingLevel();
1941
1942 bool fillFullColorRaster = TXshSimpleLevel::m_fillFullColorRaster;
1943 TXshSimpleLevel::m_fillFullColorRaster = false;
1944
1945 // Guided Drawing Check
1946 int useGuidedDrawing = Preferences::instance()->getGuidedDrawingType();
1947 TTool *tool = app->getCurrentTool()->getTool();
1948 int guidedFrontStroke = tool ? tool->getViewer()->getGuidedFrontStroke() : -1;
1949 int guidedBackStroke = tool ? tool->getViewer()->getGuidedBackStroke() : -1;
1950
1951 m_minZ = 0;
1952 if (is3DView()) {
1953 Stage::OpenGlPainter painter(getViewMatrix(), clipRect, m_visualSettings,
1954 true, false);
1955 painter.enableCamera3D(true);
1956 painter.setPhi(m_phi3D);
1957 int xsheetLevel = 0;
1958 std::pair<TXsheet *, int> xr;
1959 if (editInPlace) {
1960 xr = childStack->getAncestor(frame);
1961 xsheetLevel = childStack->getAncestorCount();
1962 } else
1963 xr = std::make_pair(xsh, frame);
1964
1965 Stage::VisitArgs args;
1966 args.m_scene = scene;
1967 args.m_xsh = xr.first;
1968 args.m_row = xr.second;
1969 args.m_col = app->getCurrentColumn()->getColumnIndex();
1970 OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
1971 args.m_osm = &osm;
1972 args.m_camera3d = true;
1973 args.m_xsheetLevel = xsheetLevel;
1974 args.m_currentFrameId =
1975 app->getCurrentXsheet()
1976 ->getXsheet()
1977 ->getCell(app->getCurrentFrame()->getFrame(), args.m_col)
1978 .getFrameId();
1979 args.m_isGuidedDrawingEnabled = useGuidedDrawing;
1980 args.m_guidedFrontStroke = guidedFrontStroke;
1981 args.m_guidedBackStroke = guidedBackStroke;
1982
1983 // args.m_currentFrameId = app->getCurrentFrame()->getFid();
1984 Stage::visit(painter, args);
1985
1986 m_minZ = painter.getMinZ();
1987 } else {
1988 // camera 2D (normale)
1989 TDimension viewerSize(width(), height());
1990
1991 TAffine viewAff = getViewMatrix();
1992
1993 if (editInPlace) {
1994 TAffine aff;
1995 if (scene->getChildStack()->getAncestorAffine(aff, frame))
1996 viewAff = viewAff * aff.inv();
1997 }
1998
1999 m_visualSettings.m_showBBox = viewBBoxToggle.getStatus();
2000
2001 Stage::RasterPainter painter(viewerSize, viewAff, clipRect,
2002 m_visualSettings, true);
2003
2004 // darken blended view mode for viewing the non-cleanuped and stacked
2005 // drawings
2006 painter.setRasterDarkenBlendedView(
2007 Preferences::instance()
2008 ->isShowRasterImagesDarkenBlendedInViewerEnabled());
2009
2010 TFrameHandle *frameHandle = TApp::instance()->getCurrentFrame();
2011 if (app->getCurrentFrame()->isEditingLevel()) {
2012 Stage::visit(painter, app->getCurrentLevel()->getLevel(),
2013 app->getCurrentFrame()->getFid(),
2014 app->getCurrentOnionSkin()->getOnionSkinMask(),
2015 frameHandle->isPlaying(), useGuidedDrawing, guidedBackStroke,
2016 guidedFrontStroke);
2017 } else {
2018 std::pair<TXsheet *, int> xr;
2019 int xsheetLevel = 0;
2020 if (editInPlace) {
2021 xr = scene->getChildStack()->getAncestor(frame);
2022 xsheetLevel = scene->getChildStack()->getAncestorCount();
2023 } else
2024 xr = std::make_pair(xsh, frame);
2025
2026 Stage::VisitArgs args;
2027 args.m_scene = scene;
2028 args.m_xsh = xr.first;
2029 args.m_row = xr.second;
2030 args.m_col = app->getCurrentColumn()->getColumnIndex();
2031 OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
2032 args.m_osm = &osm;
2033 args.m_xsheetLevel = xsheetLevel;
2034 args.m_isPlaying = frameHandle->isPlaying();
2035 if (app->getCurrentLevel() && app->getCurrentLevel()->getLevel() &&
2036 !app->getCurrentLevel()->getLevel()->getSoundLevel())
2037 args.m_currentFrameId =
2038 app->getCurrentXsheet()
2039 ->getXsheet()
2040 ->getCell(app->getCurrentFrame()->getFrame(), args.m_col)
2041 .getFrameId();
2042 args.m_isGuidedDrawingEnabled = useGuidedDrawing;
2043 args.m_guidedFrontStroke = guidedFrontStroke;
2044 args.m_guidedBackStroke = guidedBackStroke;
2045
2046 #if defined(x64)
2047 if (m_stopMotion->m_alwaysUseLiveViewImages &&
2048 m_stopMotion->m_liveViewStatus > 0 &&
2049 frame != m_stopMotion->getXSheetFrameNumber() - 1 &&
2050 m_hasStopMotionImage && !m_stopMotion->m_reviewTimer->isActive()) {
2051 TRaster32P image;
2052 bool hasImage = m_stopMotion->loadLiveViewImage(frame, image);
2053 if (hasImage) {
2054 Stage::Player smPlayer;
2055 double dpiX, dpiY;
2056 m_stopMotionImage->getDpi(dpiX, dpiY);
2057 smPlayer.m_dpiAff = TScale(Stage::inch / dpiX, Stage::inch / dpiY);
2058 smPlayer.m_opacity = 255;
2059 smPlayer.m_sl = m_stopMotion->m_sl;
2060 args.m_liveViewImage = static_cast<TRasterImageP>(image);
2061 args.m_liveViewPlayer = smPlayer;
2062 // painter.onRasterImage(static_cast<TRasterImageP>(image).getPointer(),
2063 // smPlayer);
2064 }
2065 }
2066 if ( //! m_stopMotion->m_drawBeneathLevels &&
2067 m_stopMotion->m_liveViewStatus == 2 &&
2068 ( //! frameHandle->isPlaying() ||
2069 frame == m_stopMotion->getXSheetFrameNumber() - 1)) {
2070 if (m_hasStopMotionLineUpImage && m_stopMotion->m_showLineUpImage) {
2071 Stage::Player smPlayer;
2072 double dpiX, dpiY;
2073 m_stopMotionLineUpImage->getDpi(dpiX, dpiY);
2074 smPlayer.m_dpiAff = TScale(Stage::inch / dpiX, Stage::inch / dpiY);
2075 smPlayer.m_opacity = 255;
2076 smPlayer.m_sl = m_stopMotion->m_sl;
2077 args.m_lineupImage = m_stopMotionLineUpImage;
2078 args.m_lineupPlayer = smPlayer;
2079 // painter.onRasterImage(m_stopMotionLineUpImage.getPointer(),
2080 // smPlayer);
2081 }
2082 if (m_hasStopMotionImage) {
2083 Stage::Player smPlayer;
2084 double dpiX, dpiY;
2085 m_stopMotionImage->getDpi(dpiX, dpiY);
2086 smPlayer.m_dpiAff = TScale(Stage::inch / dpiX, Stage::inch / dpiY);
2087 bool hide_opacity = false;
2088 #ifdef WITH_CANON
2089 hide_opacity = m_stopMotion->m_canon->m_zooming ||
2090 m_stopMotion->m_canon->m_pickLiveViewZoom ||
2091 !m_hasStopMotionLineUpImage;
2092 #endif
2093 smPlayer.m_opacity =
2094 hide_opacity ? 255.0 : m_stopMotion->getOpacity();
2095 smPlayer.m_sl = m_stopMotion->m_sl;
2096 args.m_liveViewImage = m_stopMotionImage;
2097 args.m_liveViewPlayer = smPlayer;
2098 // painter.onRasterImage(m_stopMotionImage.getPointer(), smPlayer);
2099 }
2100 }
2101 #endif // x64
2102 Stage::visit(painter, args);
2103 }
2104
2105 assert(glGetError() == 0);
2106 painter.flushRasterImages();
2107
2108 TXshSimpleLevel::m_fillFullColorRaster = fillFullColorRaster;
2109
2110 assert(glGetError() == 0);
2111 if (m_viewMode != LEVEL_VIEWMODE)
2112 drawSpline(getViewMatrix(), clipRect,
2113 m_referenceMode == CAMERA3D_REFERENCE, m_pixelSize);
2114 assert(glGetError() == 0);
2115
2116 // gather animated guide strokes' bounding boxes
2117 // it is used for updating viewer next time
2118 std::vector<TStroke *> guidedStrokes = painter.getGuidedStrokes();
2119 for (auto itr = guidedStrokes.begin(); itr != guidedStrokes.end(); ++itr) {
2120 m_guidedDrawingBBox += (*itr)->getBBox();
2121 }
2122 }
2123 }
2124
2125 //------------------------------------------------------------------------------
2126
mult3DMatrix()2127 void SceneViewer::mult3DMatrix() {
2128 glTranslated(m_pan3D.x, m_pan3D.y, 0);
2129 glScaled(m_zoomScale3D, m_zoomScale3D, 1);
2130 glRotated(m_theta3D, 1, 0, 0);
2131 glRotated(m_phi3D, 0, 1, 0);
2132 }
2133
2134 //-----------------------------------------------------------------------------
2135
projectToZ(const TPointD & delta)2136 double SceneViewer::projectToZ(const TPointD &delta) {
2137 glPushMatrix();
2138 mult3DMatrix();
2139 GLint viewport[4];
2140 double modelview[16], projection[16];
2141 glGetIntegerv(GL_VIEWPORT, viewport);
2142 for (int i = 0; i < 16; i++)
2143 projection[i] = (double)m_projectionMatrix.constData()[i];
2144 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
2145
2146 double ax, ay, az, bx, by, bz;
2147 gluProject(0, 0, 0, modelview, projection, viewport, &ax, &ay, &az);
2148 gluProject(0, 0, 1, modelview, projection, viewport, &bx, &by, &bz);
2149
2150 glPopMatrix();
2151 TPointD zdir(bx - ax, by - ay);
2152 double zdirLength2 = norm2(zdir);
2153 if (zdirLength2 > 0.0) {
2154 double dz = (delta * zdir) / zdirLength2;
2155 return dz;
2156 } else
2157 return 0.0;
2158 }
2159
2160 //-----------------------------------------------------------------------------
2161
getActualClipRect(const TAffine & aff)2162 TRect SceneViewer::getActualClipRect(const TAffine &aff) {
2163 TDimensionD viewerSize(width(), height());
2164 TRectD clipRect(viewerSize);
2165
2166 if (is3DView()) {
2167 TPointD p00 = winToWorld(clipRect.getP00());
2168 TPointD p01 = winToWorld(clipRect.getP01());
2169 TPointD p10 = winToWorld(clipRect.getP10());
2170 TPointD p11 = winToWorld(clipRect.getP11());
2171 clipRect = TRectD(TPointD(std::min(p00.x, p01.x), std::min(p00.y, p10.y)),
2172 TPointD(std::max(p11.x, p10.x), std::max(p11.y, p01.y)));
2173 }
2174 // this condition will catch both cases of m_clipRect == empty and
2175 // m_clipRect == InvalidateAllRect
2176 else if (m_clipRect.isEmpty())
2177 clipRect -= TPointD(viewerSize.lx / 2, viewerSize.ly / 2);
2178 else {
2179 TRectD app = aff * (m_clipRect.enlarge(3));
2180 clipRect =
2181 TRectD(tceil(app.x0), tceil(app.y0), tfloor(app.x1), tfloor(app.y1));
2182 }
2183
2184 return convert(clipRect);
2185 }
2186
2187 //-----------------------------------------------------------------------------
2188
getViewMatrix() const2189 TAffine SceneViewer::getViewMatrix() const {
2190 int viewMode = TApp::instance()->getCurrentFrame()->isEditingLevel()
2191 ? LEVEL_VIEWMODE
2192 : SCENE_VIEWMODE;
2193 if (is3DView()) return TAffine();
2194 if (m_referenceMode == CAMERA_REFERENCE) {
2195 int frame = TApp::instance()->getCurrentFrame()->getFrame();
2196 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
2197 TAffine aff = xsh->getCameraAff(frame);
2198 return m_viewAff[viewMode] * aff.inv();
2199 } else
2200 return m_viewAff[viewMode];
2201 }
2202
2203 //-----------------------------------------------------------------------------
2204
getSceneMatrix() const2205 TAffine SceneViewer::getSceneMatrix() const {
2206 int viewMode = TApp::instance()->getCurrentFrame()->isEditingLevel()
2207 ? LEVEL_VIEWMODE
2208 : SCENE_VIEWMODE;
2209 if (is3DView()) return TAffine();
2210 return m_viewAff[viewMode];
2211 }
2212
2213 //-----------------------------------------------------------------------------
2214
setViewMatrix(const TAffine & aff,int viewMode)2215 void SceneViewer::setViewMatrix(const TAffine &aff, int viewMode) {
2216 m_viewAff[viewMode] = aff;
2217 // In case the previewer is on, request a delayed update
2218 if (m_previewMode != NO_PREVIEW) requestTimedRefresh();
2219 }
2220
2221 //-----------------------------------------------------------------------------
2222
is3DView() const2223 bool SceneViewer::is3DView() const {
2224 bool isCameraTest = CameraTestCheck::instance()->isEnabled();
2225 return (m_referenceMode == CAMERA3D_REFERENCE && !isCameraTest);
2226 }
2227
2228 //-----------------------------------------------------------------------------
2229
invalidateAll()2230 void SceneViewer::invalidateAll() {
2231 m_clipRect = InvalidateAllRect;
2232 update();
2233 if (m_vRuler) m_vRuler->update();
2234 if (m_hRuler) m_hRuler->update();
2235 }
2236
2237 //-----------------------------------------------------------------------------
2238 /*! Pan the viewer by using "navigator" (red rectangle) in level strip
2239 */
navigatorPan(const QPoint & delta)2240 void SceneViewer::navigatorPan(const QPoint &delta) {
2241 panQt(delta);
2242 m_pos += delta;
2243 }
2244
2245 //-----------------------------------------------------------------------------
2246
GLInvalidateAll()2247 void SceneViewer::GLInvalidateAll() {
2248 m_clipRect = InvalidateAllRect;
2249 update();
2250 if (m_vRuler) m_vRuler->update();
2251 if (m_hRuler) m_hRuler->update();
2252 }
2253
2254 //-----------------------------------------------------------------------------
2255
GLInvalidateRect(const TRectD & rect)2256 void SceneViewer::GLInvalidateRect(const TRectD &rect) {
2257 // in case that GLInvalidateAll is called just before coming here,
2258 // ignore the clip rect and refresh entire viewer
2259 if (m_clipRect == InvalidateAllRect)
2260 return;
2261 else if (rect.isEmpty())
2262 m_clipRect = InvalidateAllRect;
2263 else {
2264 m_clipRect += rect;
2265 if (!m_guidedDrawingBBox.isEmpty()) {
2266 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
2267 TPointD topLeft = tool->getMatrix() * m_guidedDrawingBBox.getP00();
2268 TPointD bottomRight = tool->getMatrix() * m_guidedDrawingBBox.getP11();
2269 m_clipRect += TRectD(topLeft, bottomRight);
2270 }
2271 }
2272 update();
2273 if (m_vRuler) m_vRuler->update();
2274 if (m_hRuler) m_hRuler->update();
2275 m_guidedDrawingBBox.empty();
2276 }
2277 //-----------------------------------------------------------------------------
2278
2279 // delta.x: right panning, pixel; delta.y: down panning, pixel
panQt(const QPointF & delta)2280 void SceneViewer::panQt(const QPointF &delta) {
2281 if (delta == QPointF()) return;
2282 if (is3DView())
2283 m_pan3D += TPointD(delta.x(), -delta.y());
2284 else {
2285 // TAffine &viewAff = m_viewAff[m_viewMode];
2286 // viewAff = TTranslation(delta.x(), -delta.y()) * viewAff;
2287 setViewMatrix(TTranslation(delta.x(), -delta.y()) * m_viewAff[m_viewMode],
2288 m_viewMode);
2289 }
2290 invalidateAll();
2291 emit refreshNavi();
2292 }
2293
2294 //-----------------------------------------------------------------------------
2295
zoomQt(bool forward,bool reset)2296 void SceneViewer::zoomQt(bool forward, bool reset) {
2297 TPointD delta(m_lastMousePos.x() - width() / 2,
2298 -m_lastMousePos.y() + height() / 2);
2299
2300 if (is3DView()) {
2301 if (reset || ((m_zoomScale3D < 500 || !forward) &&
2302 (m_zoomScale3D > 0.01 || forward))) {
2303 double oldZoomScale = m_zoomScale3D;
2304 m_zoomScale3D =
2305 reset ? 1
2306 : ImageUtils::getQuantizedZoomFactor(m_zoomScale3D, forward);
2307
2308 m_pan3D = -(m_zoomScale3D / oldZoomScale) * -m_pan3D;
2309 }
2310 } else {
2311 // a factor for getting pixel-based zoom ratio
2312 double dpiFactor = getDpiFactor();
2313 // when showing the viewer with full-screen mode,
2314 // add a zoom factor which can show image fitting with the screen size
2315 double zoomScaleFittingWithScreen = 0.0f;
2316 if (dpiFactor != 1.0) {
2317 // check if the viewer is in full screen mode
2318 ImageUtils::FullScreenWidget *fsWidget =
2319 dynamic_cast<ImageUtils::FullScreenWidget *>(parentWidget());
2320 if (fsWidget && (fsWidget->windowState() & Qt::WindowFullScreen) != 0)
2321 zoomScaleFittingWithScreen = getZoomScaleFittingWithScreen();
2322 }
2323
2324 int i;
2325
2326 for (i = 0; i < 2; i++) {
2327 TAffine &viewAff = m_viewAff[i];
2328 if (m_isFlippedX) viewAff = viewAff * TScale(-1, 1);
2329 if (m_isFlippedX) viewAff = viewAff * TScale(1, -1);
2330 double scale2 = std::abs(viewAff.det());
2331 if (m_isFlippedX) viewAff = viewAff * TScale(-1, 1);
2332 if (m_isFlippedX) viewAff = viewAff * TScale(1, -1);
2333 if (reset || ((scale2 < 100000 || !forward) &&
2334 (scale2 > 0.001 * 0.05 || forward))) {
2335 double oldZoomScale = sqrt(scale2) * dpiFactor;
2336 double zoomScale =
2337 reset ? 1
2338 : ImageUtils::getQuantizedZoomFactor(oldZoomScale, forward);
2339
2340 // threshold value -0.001 is intended to absorb the error of calculation
2341 if ((oldZoomScale - zoomScaleFittingWithScreen) *
2342 (zoomScale - zoomScaleFittingWithScreen) <
2343 -0.001)
2344 zoomScale = zoomScaleFittingWithScreen;
2345 // zoom center = viewer center
2346 if (Preferences::instance()->getViewerZoomCenter())
2347 setViewMatrix(TScale(zoomScale / oldZoomScale) * viewAff, i);
2348 // zoom center = mouse pos
2349 else
2350 setViewMatrix(TTranslation(delta) * TScale(zoomScale / oldZoomScale) *
2351 TTranslation(-delta) * viewAff,
2352 i);
2353 }
2354 }
2355 }
2356
2357 GLInvalidateAll();
2358 emit onZoomChanged();
2359 }
2360
2361 //-----------------------------------------------------------------------------
2362 /*! a factor for getting pixel-based zoom ratio
2363 */
getDpiFactor()2364 double SceneViewer::getDpiFactor() {
2365 // When the current unit is "pixels", always use a standard dpi
2366 double cameraDpi = TApp::instance()
2367 ->getCurrentScene()
2368 ->getScene()
2369 ->getCurrentCamera()
2370 ->getDpi()
2371 .x;
2372 if (Preferences::instance()->getPixelsOnly()) {
2373 return Stage::inch / Stage::standardDpi;
2374 }
2375
2376 // When preview mode, use a camera DPI
2377 else if (isPreviewEnabled()) {
2378 return Stage::inch / cameraDpi;
2379 }
2380 // When level editing mode, use an image DPI
2381 else if (TApp::instance()->getCurrentFrame()->isEditingLevel()) {
2382 TXshSimpleLevel *sl;
2383 sl = TApp::instance()->getCurrentLevel()->getSimpleLevel();
2384 if (!sl) return Stage::inch / cameraDpi;
2385 if (sl->getType() == PLI_XSHLEVEL) return Stage::inch / cameraDpi;
2386 if (sl->getImageDpi() != TPointD())
2387 return Stage::inch / sl->getImageDpi().x;
2388 if (sl->getDpi() != TPointD()) return Stage::inch / sl->getDpi().x;
2389 // no valid dpi, use camera dpi
2390 return Stage::inch / cameraDpi;
2391 }
2392 // When the special case in the scene editing mode:
2393 // If the option "ActualPixelViewOnSceneEditingMode" is ON,
2394 // use current level's DPI set in the level settings.
2395 else if (Preferences::instance()
2396 ->isActualPixelViewOnSceneEditingModeEnabled()) {
2397 if (CleanupPreviewCheck::instance()->isEnabled() ||
2398 CameraTestCheck::instance()->isEnabled()) {
2399 double cleanupCameraDpi = TApp::instance()
2400 ->getCurrentScene()
2401 ->getScene()
2402 ->getProperties()
2403 ->getCleanupParameters()
2404 ->m_camera.getDpi()
2405 .x;
2406 return Stage::inch / cleanupCameraDpi;
2407 } else {
2408 TXshSimpleLevel *sl;
2409 sl = TApp::instance()->getCurrentLevel()->getSimpleLevel();
2410 if (!sl) return Stage::inch / cameraDpi;
2411 if (sl->getType() == PLI_XSHLEVEL) return Stage::inch / cameraDpi;
2412 if (sl->getDpi() == TPointD()) return Stage::inch / cameraDpi;
2413 // use default value for the argument of getDpi() (=TFrameId::NO_FRAME)
2414 // so that the dpi of the first frame in the level will be returned.
2415 return Stage::inch / sl->getDpi().x;
2416 }
2417 }
2418 // When the scene editing mode without any option, use the camera dpi
2419 else {
2420 return Stage::inch / cameraDpi;
2421 }
2422 }
2423
2424 //-----------------------------------------------------------------------------
2425 /*! when showing the viewer with full-screen mode,
2426 add a zoom factor which can show image fitting with the screen size
2427 */
2428
getZoomScaleFittingWithScreen()2429 double SceneViewer::getZoomScaleFittingWithScreen() {
2430 TDimension imgSize;
2431
2432 // get the image size to be rendered
2433
2434 if (isPreviewEnabled())
2435 imgSize = TApp::instance()
2436 ->getCurrentScene()
2437 ->getScene()
2438 ->getCurrentCamera()
2439 ->getRes();
2440 else if (TApp::instance()->getCurrentFrame()->isEditingLevel()) {
2441 TXshSimpleLevel *sl = TApp::instance()->getCurrentLevel()->getSimpleLevel();
2442 if (!sl || sl->getType() == PLI_XSHLEVEL || sl->getImageDpi() == TPointD())
2443 return 0.0;
2444
2445 imgSize = sl->getResolution();
2446 } else if (Preferences::instance()
2447 ->isActualPixelViewOnSceneEditingModeEnabled() &&
2448 !CleanupPreviewCheck::instance()->isEnabled() &&
2449 !CameraTestCheck::instance()->isEnabled()) {
2450 TXshSimpleLevel *sl = TApp::instance()->getCurrentLevel()->getSimpleLevel();
2451 if (!sl || sl->getType() == PLI_XSHLEVEL || sl->getDpi() == TPointD())
2452 return 0.0;
2453 imgSize = sl->getResolution();
2454
2455 } else // SCENE_VIEWMODE
2456 return 0.0;
2457
2458 // add small margin on the edge of the image
2459 int margin = 20;
2460 // get the desktop resolution
2461 QRect rec = QApplication::desktop()->screenGeometry();
2462
2463 // fit to either direction
2464 int moni_x = rec.width() - (margin * 2);
2465 int moni_y = rec.height() - (margin * 2);
2466 return std::min((double)moni_x / (double)imgSize.lx,
2467 (double)moni_y / (double)imgSize.ly);
2468 }
2469
2470 //-----------------------------------------------------------------------------
2471
2472 // center: window coordinate, pixels, topleft origin
zoomQt(const QPoint & center,double factor)2473 void SceneViewer::zoomQt(const QPoint ¢er, double factor) {
2474 if (factor == 1.0) return;
2475 TPointD delta(center.x() - width() / 2, -center.y() + height() / 2);
2476 double oldZoomScale = m_zoomScale3D;
2477
2478 if (is3DView()) {
2479 if ((m_zoomScale3D < 500 || factor < 1) &&
2480 (m_zoomScale3D > 0.01 || factor > 1)) {
2481 m_zoomScale3D *= factor;
2482 m_pan3D = -(m_zoomScale3D / oldZoomScale) * (delta - m_pan3D) + delta;
2483 }
2484 } else {
2485 int i;
2486 for (i = 0; i < 2; i++) {
2487 TAffine &viewAff = m_viewAff[i];
2488 double scale2 = fabs(viewAff.det());
2489 if ((scale2 < 100000 || factor < 1) &&
2490 (scale2 > 0.001 * 0.05 || factor > 1)) {
2491 if (i == m_viewMode) {
2492 // viewAff = TTranslation(delta) * TScale(factor) *
2493 // TTranslation(-delta) * viewAff;
2494 setViewMatrix(TTranslation(delta) * TScale(factor) *
2495 TTranslation(-delta) * viewAff,
2496 i);
2497 } else {
2498 // viewAff = TScale(factor) * viewAff;
2499 setViewMatrix(TScale(factor) * viewAff, i);
2500 }
2501 }
2502 }
2503 }
2504
2505 GLInvalidateAll();
2506 emit onZoomChanged();
2507 }
2508
zoom(const TPointD & center,double factor)2509 void SceneViewer::zoom(const TPointD ¢er, double factor) {
2510 zoomQt(QPoint(center.x, height() - center.y), factor);
2511 }
2512
2513 //-----------------------------------------------------------------------------
2514
flipX()2515 void SceneViewer::flipX() {
2516 double flipAngle0 = (m_rotationAngle[0] * -1) * 2;
2517 double flipAngle1 = (m_rotationAngle[1] * -1) * 2;
2518 m_rotationAngle[0] += flipAngle0;
2519 m_rotationAngle[1] += flipAngle1;
2520 if (m_isFlippedX != m_isFlippedY) {
2521 flipAngle0 = -flipAngle0;
2522 flipAngle1 = -flipAngle1;
2523 }
2524 m_viewAff[0] = m_viewAff[0] * TRotation(flipAngle0) * TScale(-1, 1);
2525 m_viewAff[1] = m_viewAff[1] * TRotation(flipAngle1) * TScale(-1, 1);
2526 m_viewAff[0].a13 *= -1;
2527 m_viewAff[1].a13 *= -1;
2528 m_isFlippedX = !m_isFlippedX;
2529 invalidateAll();
2530 emit onZoomChanged();
2531 emit onFlipHChanged(m_isFlippedX);
2532 }
2533
2534 //-----------------------------------------------------------------------------
2535
flipY()2536 void SceneViewer::flipY() {
2537 double flipAngle0 = (m_rotationAngle[0] * -1) * 2;
2538 double flipAngle1 = (m_rotationAngle[1] * -1) * 2;
2539 m_rotationAngle[0] += flipAngle0;
2540 m_rotationAngle[1] += flipAngle1;
2541 if (m_isFlippedX != m_isFlippedY) {
2542 flipAngle0 = -flipAngle0;
2543 flipAngle1 = -flipAngle1;
2544 }
2545 m_viewAff[0] = m_viewAff[0] * TRotation(flipAngle0) * TScale(1, -1);
2546 m_viewAff[1] = m_viewAff[1] * TRotation(flipAngle1) * TScale(1, -1);
2547 m_viewAff[0].a23 *= -1;
2548 m_viewAff[1].a23 *= -1;
2549 m_isFlippedY = !m_isFlippedY;
2550 invalidateAll();
2551 emit onZoomChanged();
2552 emit onFlipVChanged(m_isFlippedY);
2553 }
2554
2555 //-----------------------------------------------------------------------------
2556
zoomIn()2557 void SceneViewer::zoomIn() {
2558 m_lastMousePos = rect().center();
2559 zoomQt(true, false);
2560 }
2561
2562 //-----------------------------------------------------------------------------
2563
zoomOut()2564 void SceneViewer::zoomOut() {
2565 m_lastMousePos = rect().center();
2566 zoomQt(false, false);
2567 }
2568
2569 //-----------------------------------------------------------------------------
2570
rotate(const TPointD & center,double angle)2571 void SceneViewer::rotate(const TPointD ¢er, double angle) {
2572 if (angle == 0) return;
2573 if (m_isFlippedX != m_isFlippedY) angle = -angle;
2574 m_rotationAngle[m_viewMode] += angle;
2575 TPointD realCenter = m_viewAff[m_viewMode] * center;
2576 setViewMatrix(TRotation(realCenter, angle) * m_viewAff[m_viewMode],
2577 m_viewMode);
2578 invalidateAll();
2579 }
2580
2581 //-----------------------------------------------------------------------------
2582
rotate3D(double dPhi,double dTheta)2583 void SceneViewer::rotate3D(double dPhi, double dTheta) {
2584 if (dPhi == 0 && dTheta == 0) return;
2585 m_phi3D = (float)tcrop(m_phi3D + dPhi, -90.0, 90.0);
2586 m_theta3D = (float)tcrop(m_theta3D + dTheta, 0.0, 90.0);
2587 invalidateAll();
2588 }
2589
2590 //-----------------------------------------------------------------------------
2591
regeneratePreview()2592 void SceneViewer::regeneratePreview() {
2593 Previewer::instance(m_previewMode == SUBCAMERA_PREVIEW)->clear();
2594 update();
2595 }
2596
2597 //-----------------------------------------------------------------------------
2598
regeneratePreviewFrame()2599 void SceneViewer::regeneratePreviewFrame() {
2600 Previewer::instance(m_previewMode == SUBCAMERA_PREVIEW)
2601 ->clear(TApp::instance()->getCurrentFrame()->getFrame());
2602
2603 update();
2604 }
2605
2606 //-----------------------------------------------------------------------------
2607
swapCompared()2608 void SceneViewer::swapCompared() {
2609 m_compareSettings.m_swapCompared = !m_compareSettings.m_swapCompared;
2610 update();
2611 }
2612
2613 //-----------------------------------------------------------------------------
2614
fitToCamera()2615 void SceneViewer::fitToCamera() {
2616 // Reset the view scale to 1:1.
2617 bool tempIsFlippedX = m_isFlippedX;
2618 bool tempIsFlippedY = m_isFlippedY;
2619 resetSceneViewer();
2620
2621 m_isFlippedX = tempIsFlippedX;
2622 m_isFlippedY = tempIsFlippedY;
2623
2624 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
2625 int frame = TApp::instance()->getCurrentFrame()->getFrame();
2626 TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
2627 TStageObject *camera = xsh->getStageObject(cameraId);
2628 TAffine cameraPlacement = camera->getPlacement(frame);
2629 double cameraZ = camera->getZ(frame);
2630 TAffine cameraAff =
2631 getViewMatrix() * cameraPlacement * TScale((1000 + cameraZ) / 1000);
2632
2633 QRect viewRect = rect();
2634 TRectD cameraRect = ViewerDraw::getCameraRect();
2635 TPointD P00 = cameraAff * cameraRect.getP00();
2636 TPointD P10 = cameraAff * cameraRect.getP10();
2637 TPointD P01 = cameraAff * cameraRect.getP01();
2638 TPointD P11 = cameraAff * cameraRect.getP11();
2639 TPointD p0 = TPointD(std::min({P00.x, P01.x, P10.x, P11.x}),
2640 std::min({P00.y, P01.y, P10.y, P11.y}));
2641 TPointD p1 = TPointD(std::max({P00.x, P01.x, P10.x, P11.x}),
2642 std::max({P00.y, P01.y, P10.y, P11.y}));
2643 cameraRect = TRectD(p0.x, p0.y, p1.x, p1.y);
2644
2645 // Pan
2646 if (!is3DView()) {
2647 TPointD cameraCenter = (cameraRect.getP00() + cameraRect.getP11()) * 0.5;
2648 panQt(QPoint(-cameraCenter.x, cameraCenter.y));
2649 }
2650
2651 double xratio = (double)viewRect.width() / cameraRect.getLx();
2652 double yratio = (double)viewRect.height() / cameraRect.getLy();
2653 double ratio = std::min(xratio, yratio);
2654 if (ratio == 0.0) return;
2655 if (tempIsFlippedX)
2656 setViewMatrix(TScale(-1, 1) * m_viewAff[m_viewMode], m_viewMode);
2657 if (tempIsFlippedY)
2658 setViewMatrix(TScale(1, -1) * m_viewAff[m_viewMode], m_viewMode);
2659 // Scale and center on the center of \a rect.
2660 QPoint c = viewRect.center();
2661 zoom(TPointD(c.x(), c.y()), ratio);
2662 emit onFlipHChanged(m_isFlippedX);
2663 emit onFlipVChanged(m_isFlippedY);
2664 }
2665
2666 //-----------------------------------------------------------------------------
2667
fitToCameraOutline()2668 void SceneViewer::fitToCameraOutline() {
2669 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
2670 int frame = TApp::instance()->getCurrentFrame()->getFrame();
2671 TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
2672 TStageObject *camera = xsh->getStageObject(cameraId);
2673 TAffine cameraPlacement = camera->getPlacement(frame);
2674 double cameraZ = camera->getZ(frame);
2675 TAffine cameraAff =
2676 getViewMatrix() * cameraPlacement * TScale((1000 + cameraZ) / 1000);
2677
2678 QRect viewRect = rect();
2679 TRectD cameraRect = ViewerDraw::getCameraRect();
2680 TPointD P00 = cameraAff * cameraRect.getP00();
2681 TPointD P10 = cameraAff * cameraRect.getP10();
2682 TPointD P01 = cameraAff * cameraRect.getP01();
2683 TPointD P11 = cameraAff * cameraRect.getP11();
2684 TPointD p0 = TPointD(std::min({P00.x, P01.x, P10.x, P11.x}),
2685 std::min({P00.y, P01.y, P10.y, P11.y}));
2686 TPointD p1 = TPointD(std::max({P00.x, P01.x, P10.x, P11.x}),
2687 std::max({P00.y, P01.y, P10.y, P11.y}));
2688 cameraRect = TRectD(p0.x, p0.y, p1.x, p1.y);
2689
2690 // Pan
2691 if (!is3DView()) {
2692 TPointD cameraCenter = (cameraRect.getP00() + cameraRect.getP11()) * 0.5;
2693 panQt(QPoint(-cameraCenter.x, cameraCenter.y));
2694 }
2695
2696 double xratio = (double)viewRect.width() / cameraRect.getLx();
2697 double yratio = (double)viewRect.height() / cameraRect.getLy();
2698 double ratio = std::min(xratio, yratio);
2699 if (ratio == 0.0) return;
2700
2701 // Scale and center on the center of \a rect.
2702 QPoint c = viewRect.center();
2703 zoom(TPointD(c.x(), c.y()), ratio);
2704 zoom(TPointD(c.x(), c.y()), 0.95);
2705 }
2706
2707 //-----------------------------------------------------------------------------
2708
resetSceneViewer()2709 void SceneViewer::resetSceneViewer() {
2710 m_visualSettings.m_sceneProperties =
2711 TApp::instance()->getCurrentScene()->getScene()->getProperties();
2712
2713 for (int i = 0; i < m_viewAff.size(); ++i) {
2714 setViewMatrix(getNormalZoomScale(), i);
2715 m_rotationAngle[i] = 0.0;
2716 }
2717
2718 m_pos = QPoint(0, 0);
2719 m_pan3D = TPointD(0, 0);
2720 m_zoomScale3D = 0.1;
2721 m_theta3D = 20;
2722 m_phi3D = 30;
2723 m_isFlippedX = false;
2724 m_isFlippedY = false;
2725 fitToCameraOutline();
2726 emit onZoomChanged();
2727 emit onFlipHChanged(m_isFlippedX);
2728 emit onFlipVChanged(m_isFlippedY);
2729 invalidateAll();
2730 }
2731
2732 //-----------------------------------------------------------------------------
2733
resetZoom()2734 void SceneViewer::resetZoom() {
2735 TPointD realCenter(m_viewAff[m_viewMode].a13, m_viewAff[m_viewMode].a23);
2736 TAffine aff =
2737 getNormalZoomScale() * TRotation(realCenter, m_rotationAngle[m_viewMode]);
2738 aff.a13 = realCenter.x;
2739 aff.a23 = realCenter.y;
2740 if (m_isFlippedX) aff = aff * TScale(-1, 1);
2741 if (m_isFlippedY) aff = aff * TScale(1, -1);
2742 setViewMatrix(aff, m_viewMode);
2743 invalidateAll();
2744 emit onZoomChanged();
2745 }
2746
2747 //-----------------------------------------------------------------------------
2748
resetRotation()2749 void SceneViewer::resetRotation() {
2750 double reverseRotatation = m_rotationAngle[m_viewMode] * -1;
2751 if (m_isFlippedX) reverseRotatation *= -1;
2752 if (m_isFlippedY) reverseRotatation *= -1;
2753 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
2754 TPointD center = m_viewAff[m_viewMode].inv() * TPointD(0, 0);
2755 if (tool->getName() == "T_Rotate" &&
2756 tool->getProperties(0)
2757 ->getProperty("Rotate On Camera Center")
2758 ->getValueAsString() == "1")
2759 center = TPointD(0, 0);
2760 rotate(center, reverseRotatation);
2761 }
2762
2763 //-----------------------------------------------------------------------------
2764
resetPosition()2765 void SceneViewer::resetPosition() {
2766 m_viewAff[m_viewMode].a13 = 0.0;
2767 m_viewAff[m_viewMode].a23 = 0.0;
2768 invalidateAll();
2769 }
2770
2771 //-----------------------------------------------------------------------------
2772
setActualPixelSize()2773 void SceneViewer::setActualPixelSize() {
2774 TApp *app = TApp::instance();
2775 TXshLevel *l = app->getCurrentLevel()->getLevel();
2776 TXshSimpleLevel *sl = l ? l->getSimpleLevel() : 0;
2777 if (!sl) return;
2778
2779 TFrameId fid(app->getCurrentFrame()->getFid());
2780
2781 TPointD dpi;
2782 if (CleanupPreviewCheck::instance()->isEnabled()) {
2783 // The previewed cleanup image has no image infos yet - retrieve the dpi
2784 // through
2785 // the cleanup camera data
2786 CleanupParameters *cleanupParams = app->getCurrentScene()
2787 ->getScene()
2788 ->getProperties()
2789 ->getCleanupParameters();
2790
2791 TDimension dim(0, 0);
2792 cleanupParams->getOutputImageInfo(dim, dpi.x, dpi.y);
2793 } else
2794 dpi = sl->getDpi(fid);
2795
2796 const double inch = Stage::inch;
2797 TAffine tempAff = getNormalZoomScale();
2798 if (m_isFlippedX) tempAff = tempAff * TScale(-1, 1);
2799 if (m_isFlippedY) tempAff = tempAff * TScale(1, -1);
2800 TPointD tempScale = dpi;
2801 if (m_isFlippedX) tempScale.x = -tempScale.x;
2802 if (m_isFlippedY) tempScale.y = -tempScale.y;
2803 for (int i = 0; i < m_viewAff.size(); ++i)
2804 setViewMatrix(dpi == TPointD(0, 0)
2805 ? tempAff
2806 : TScale(tempScale.x / inch, tempScale.y / inch),
2807 i);
2808
2809 m_pos = QPoint(0, 0);
2810 m_pan3D = TPointD(0, 0);
2811 m_zoomScale3D = 0.1;
2812 m_theta3D = 20;
2813 m_phi3D = 30;
2814 emit onZoomChanged();
2815
2816 invalidateAll();
2817 }
2818
2819 //-----------------------------------------------------------------------------
2820
onLevelChanged()2821 void SceneViewer::onLevelChanged() {
2822 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
2823 if (tool) {
2824 TXshLevel *level = TApp::instance()->getCurrentLevel()->getLevel();
2825 if (level && level->getSimpleLevel())
2826 m_dpiScale =
2827 getCurrentDpiScale(level->getSimpleLevel(), tool->getCurrentFid());
2828 else
2829 m_dpiScale = TPointD(1, 1);
2830 }
2831 }
2832 //-----------------------------------------------------------------------------
2833 /*! when level is switched, update m_dpiScale in order to show white background
2834 * for Ink&Paint work properly
2835 */
onLevelSwitched()2836 void SceneViewer::onLevelSwitched() {
2837 invalidateToolStatus();
2838 TApp *app = TApp::instance();
2839 TTool *tool = app->getCurrentTool()->getTool();
2840 TXshLevel *level = app->getCurrentLevel()->getLevel();
2841 if (level && level->getSimpleLevel())
2842 m_dpiScale =
2843 getCurrentDpiScale(level->getSimpleLevel(), tool->getCurrentFid());
2844 else
2845 m_dpiScale = TPointD(1, 1);
2846 }
2847
2848 //-----------------------------------------------------------------------------
2849
onXsheetChanged()2850 void SceneViewer::onXsheetChanged() {
2851 m_forceGlFlush = true;
2852 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
2853 if (tool && tool->isEnabled()) tool->updateMatrix();
2854 onLevelChanged();
2855 GLInvalidateAll();
2856 }
2857
2858 //-----------------------------------------------------------------------------
2859
onObjectSwitched()2860 void SceneViewer::onObjectSwitched() {
2861 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
2862 if (tool && tool->isEnabled()) tool->updateMatrix();
2863 onLevelChanged();
2864 GLInvalidateAll();
2865 }
2866
2867 //-----------------------------------------------------------------------------
2868
onSceneChanged()2869 void SceneViewer::onSceneChanged() {
2870 onLevelChanged();
2871 GLInvalidateAll();
2872 }
2873
2874 //-----------------------------------------------------------------------------
2875
onFrameSwitched()2876 void SceneViewer::onFrameSwitched() {
2877 invalidateToolStatus();
2878
2879 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
2880 if (tool && tool->isEnabled()) {
2881 tool->setViewer(this);
2882 tool->updateMatrix();
2883 tool->onEnter();
2884 }
2885
2886 GLInvalidateAll();
2887 }
2888
2889 //-----------------------------------------------------------------------------
2890 /*! when tool options are changed, update tooltip immediately
2891 */
onToolChanged()2892 void SceneViewer::onToolChanged() {
2893 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
2894 if (tool) setToolCursor(this, tool->getCursorId());
2895 GLInvalidateAll();
2896 }
2897
2898 //-----------------------------------------------------------------------------
2899
pick(const TPointD & point)2900 int SceneViewer::pick(const TPointD &point) {
2901 // pick is typically called in a mouse event handler.
2902 // QGLWidget::makeCurrent() is not automatically called in these events.
2903 // (to exploit the bug: open the FxEditor preview and then select the edit
2904 // tool)
2905 m_isPicking = true;
2906 makeCurrent();
2907 assert(glGetError() == GL_NO_ERROR);
2908 GLint viewport[4];
2909 glGetIntegerv(GL_VIEWPORT, viewport);
2910 std::array<GLuint, 512> selectBuffer;
2911 glSelectBuffer(selectBuffer.size(), selectBuffer.data());
2912 glRenderMode(GL_SELECT);
2913
2914 // definisco la matrice di proiezione
2915 glMatrixMode(GL_PROJECTION);
2916 GLdouble mat[16];
2917 glGetDoublev(GL_PROJECTION_MATRIX, mat);
2918 glPushMatrix();
2919 glLoadIdentity();
2920 gluPickMatrix(point.x, point.y, 5, 5, viewport);
2921 glMultMatrixd(mat);
2922 assert(glGetError() == GL_NO_ERROR);
2923
2924 // disegno la scena
2925 glMatrixMode(GL_MODELVIEW);
2926 glPushMatrix();
2927 glInitNames();
2928 assert(glGetError() == GL_NO_ERROR);
2929
2930 // WARNING: We have to draw the scene in CAMERASTAND mode. Observe that the
2931 // preview mode may
2932 // invoke event processing - therefore triggering other pick events while in
2933 // GL_SELECT
2934 // render mode...
2935 int previewMode = m_previewMode;
2936 m_previewMode = NO_PREVIEW;
2937
2938 // OPTIMIZATION / QUICK FIX
2939 // A 1x1 clipping rect around the picked pos can very well be used instead of
2940 // redrawing
2941 // the *entire viewer*.
2942 // This is needed especially since some graphic cards (all NVidias we have
2943 // tested) are
2944 // very slow otherwise. This could be due to this particular rendering mode -
2945 // or because
2946 // we could be painting OUTSIDE a paintEvent()...
2947
2948 TRectD oldClipRect(m_clipRect);
2949 m_clipRect = TRectD(point.x, point.y, point.x + 1, point.y + 1);
2950
2951 paintGL(); // draw identifiable objects
2952
2953 m_clipRect = oldClipRect;
2954
2955 m_previewMode = previewMode;
2956
2957 assert(glGetError() == GL_NO_ERROR);
2958 glPopMatrix();
2959
2960 // rimetto a posto la matrice di proiezione
2961 glMatrixMode(GL_PROJECTION);
2962 glPopMatrix();
2963 glMatrixMode(GL_MODELVIEW);
2964
2965 assert(glGetError() == GL_NO_ERROR);
2966
2967 // conto gli hits
2968 int ret = -1;
2969 int hitCount = glRenderMode(GL_RENDER);
2970 GLuint *p = selectBuffer.data();
2971 for (int i = 0; i < hitCount; ++i) {
2972 GLuint nameCount = *p++;
2973 GLuint zmin = *p++;
2974 GLuint zmax = *p++;
2975 if (nameCount > 0) {
2976 GLuint name = *p;
2977 ret = name; // items.push_back(PickItem(name, zmin, zmax));
2978 }
2979 p += nameCount;
2980 }
2981 assert(glGetError() == GL_NO_ERROR);
2982 m_isPicking = false;
2983 return ret;
2984 }
2985
2986 //-----------------------------------------------------------------------------
2987
posToColumnIndex(const TPointD & p,double distance,bool includeInvisible) const2988 int SceneViewer::posToColumnIndex(const TPointD &p, double distance,
2989 bool includeInvisible) const {
2990 std::vector<int> ret;
2991 posToColumnIndexes(p, ret, distance, includeInvisible);
2992 return ret.empty() ? -1 : ret.back();
2993 }
2994
2995 //-----------------------------------------------------------------------------
2996
posToColumnIndexes(const TPointD & p,std::vector<int> & indexes,double distance,bool includeInvisible) const2997 void SceneViewer::posToColumnIndexes(const TPointD &p,
2998 std::vector<int> &indexes, double distance,
2999 bool includeInvisible) const {
3000 int oldRasterizePli = TXshSimpleLevel::m_rasterizePli;
3001 TApp *app = TApp::instance();
3002 ToonzScene *scene = app->getCurrentScene()->getScene();
3003 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
3004 int frame = app->getCurrentFrame()->getFrame();
3005 int currentColumnIndex = app->getCurrentColumn()->getColumnIndex();
3006 OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
3007
3008 TPointD pos = TPointD(p.x - width() / 2, p.y - height() / 2);
3009 Stage::Picker picker(getViewMatrix(), pos, m_visualSettings,
3010 getDevPixRatio());
3011 picker.setMinimumDistance(distance);
3012
3013 TXshSimpleLevel::m_rasterizePli = 0;
3014
3015 Stage::VisitArgs args;
3016 args.m_scene = scene;
3017 args.m_xsh = xsh;
3018 args.m_row = frame;
3019 args.m_col = currentColumnIndex;
3020 args.m_osm = &osm;
3021 args.m_onlyVisible = includeInvisible;
3022
3023 Stage::visit(picker, args); /*
3024 picker,
3025 scene,
3026 xsh,
3027 frame,
3028 currentColumnIndex,
3029 osm,
3030 false,
3031 0,
3032 false,
3033 includeInvisible);
3034 */
3035
3036 TXshSimpleLevel::m_rasterizePli = oldRasterizePli;
3037 picker.getColumnIndexes(indexes);
3038 }
3039
3040 //-----------------------------------------------------------------------------
3041
posToRow(const TPointD & p,double distance,bool includeInvisible,bool currentColumnOnly) const3042 int SceneViewer::posToRow(const TPointD &p, double distance,
3043 bool includeInvisible, bool currentColumnOnly) const {
3044 int oldRasterizePli = TXshSimpleLevel::m_rasterizePli;
3045 TApp *app = TApp::instance();
3046 OnionSkinMask osm = app->getCurrentOnionSkin()->getOnionSkinMask();
3047
3048 TPointD pos = TPointD(p.x - width() / 2, p.y - height() / 2);
3049 Stage::Picker picker(getViewMatrix(), pos, m_visualSettings,
3050 getDevPixRatio());
3051 picker.setMinimumDistance(distance);
3052
3053 if (app->getCurrentFrame()->isEditingLevel()) {
3054 Stage::visit(picker, app->getCurrentLevel()->getLevel(),
3055 app->getCurrentFrame()->getFid(), osm,
3056 app->getCurrentFrame()->isPlaying(), false);
3057 } else {
3058 ToonzScene *scene = app->getCurrentScene()->getScene();
3059 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
3060 int frame = app->getCurrentFrame()->getFrame();
3061 int currentColumnIndex = app->getCurrentColumn()->getColumnIndex();
3062
3063 TXshSimpleLevel::m_rasterizePli = 0;
3064
3065 Stage::VisitArgs args;
3066 args.m_scene = scene;
3067 args.m_xsh = xsh;
3068 args.m_row = frame;
3069 args.m_col = currentColumnIndex;
3070 args.m_osm = &osm;
3071 args.m_onlyVisible = includeInvisible;
3072
3073 if (currentColumnOnly) picker.setCurrentColumnIndex(currentColumnIndex);
3074
3075 Stage::visit(picker, args);
3076 }
3077 TXshSimpleLevel::m_rasterizePli = oldRasterizePli;
3078 return picker.getRow();
3079 }
3080
3081 //-----------------------------------------------------------------------------
3082
drawSpline(const TAffine & viewMatrix,const TRect & clipRect,bool camera3d,double pixelsize)3083 void drawSpline(const TAffine &viewMatrix, const TRect &clipRect, bool camera3d,
3084 double pixelsize) {
3085 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
3086
3087 TStageObjectId objId = TApp::instance()->getCurrentObject()->getObjectId();
3088
3089 TStageObject *pegbar =
3090 objId != TStageObjectId::NoneId ? xsh->getStageObject(objId) : 0;
3091 const TStroke *stroke = 0;
3092 if (pegbar && pegbar->getSpline()) stroke = pegbar->getSpline()->getStroke();
3093 if (!stroke) return;
3094
3095 int frame = TApp::instance()->getCurrentFrame()->getFrame();
3096
3097 TAffine aff;
3098 double objZ = 0, objNoScaleZ = 0;
3099 if (objId != TStageObjectId::NoneId) {
3100 aff = xsh->getParentPlacement(objId, frame);
3101 objZ = xsh->getZ(objId, frame);
3102 objNoScaleZ = xsh->getStageObject(objId)->getGlobalNoScaleZ();
3103 }
3104
3105 glPushMatrix();
3106 if (camera3d) {
3107 tglMultMatrix(aff);
3108 aff = TAffine();
3109 glTranslated(0, 0, objZ);
3110 } else {
3111 TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId();
3112 double camZ = xsh->getZ(cameraId, frame);
3113 TAffine camAff = xsh->getPlacement(cameraId, frame);
3114 TAffine tmp;
3115 TStageObject::perspective(tmp, camAff, camZ, aff, objZ, objNoScaleZ);
3116 aff = viewMatrix * tmp;
3117 }
3118
3119 if (TApp::instance()->getCurrentObject()->isSpline()) {
3120 glColor3d(1.0, 0.5, 0);
3121 glLineStipple(1, 0x18FF);
3122 } else {
3123 glLineStipple(1, 0xCCCC);
3124 glColor3d(1, 0, 1);
3125 }
3126
3127 glEnable(GL_LINE_STIPPLE);
3128 tglMultMatrix(aff);
3129
3130 double pixelSize = std::max(0.1, pixelsize);
3131 double strokeLength = stroke->getLength();
3132 int n = (int)(5 + (strokeLength / pixelSize) * 0.1);
3133
3134 glBegin(GL_LINE_STRIP);
3135 for (int i = 0; i < n; i++)
3136 tglVertex(stroke->getPoint((double)i / (double)(n - 1)));
3137 glEnd();
3138 glDisable(GL_LINE_STIPPLE);
3139 int cpCount = stroke->getControlPointCount();
3140 for (int i = 0; i * 4 < cpCount; i++) {
3141 double t = stroke->getParameterAtControlPoint(i * 4);
3142 TPointD pos = stroke->getPoint(t);
3143 tglDrawText(pos, QString::number(i).toStdString().c_str());
3144 }
3145
3146 if (pegbar) {
3147 TAffine parentAff = xsh->getParentPlacement(objId, frame);
3148 TAffine aff = xsh->getPlacement(objId, frame);
3149 TPointD center = Stage::inch * xsh->getCenter(objId, frame);
3150 glPushMatrix();
3151 tglMultMatrix(parentAff.inv() * TTranslation(aff * center));
3152 center = TPointD();
3153
3154 // draw center
3155 // tglDrawDisk(center,pixelSize*5);
3156 tglDrawDisk(center, sqrt(tglGetPixelSize2()) * 5);
3157
3158 glPopMatrix();
3159 }
3160
3161 glPopMatrix();
3162 }
3163
3164 //-----------------------------------------------------------------------------
3165
resetInputMethod()3166 void SceneViewer::resetInputMethod() {
3167 #if QT_VERSION >= 0x050000
3168 QGuiApplication::inputMethod()->reset();
3169 #else
3170 qApp->inputContext()->reset();
3171 #endif
3172 }
3173
3174 //-----------------------------------------------------------------------------
3175
set3DLeftSideView()3176 void SceneViewer::set3DLeftSideView() {
3177 m_phi3D = -90;
3178 m_theta3D = 0;
3179 invalidateAll();
3180 }
3181
3182 //-----------------------------------------------------------------------------
3183
set3DRightSideView()3184 void SceneViewer::set3DRightSideView() {
3185 m_phi3D = 90;
3186 m_theta3D = 0;
3187 invalidateAll();
3188 }
3189
3190 //-----------------------------------------------------------------------------
3191
set3DTopView()3192 void SceneViewer::set3DTopView() {
3193 m_phi3D = 0;
3194 m_theta3D = 90;
3195 invalidateAll();
3196 }
3197
3198 //-----------------------------------------------------------------------------
3199
canSwapCompared() const3200 bool SceneViewer::canSwapCompared() const {
3201 return m_visualSettings.m_doCompare && m_previewMode != NO_PREVIEW;
3202 }
3203
3204 //-----------------------------------------------------------------------------
3205
getNormalZoomScale()3206 TAffine SceneViewer::getNormalZoomScale() {
3207 return TScale(getDpiFactor()).inv();
3208 }
3209
3210 //-----------------------------------------------------------------------------
3211
invalidateToolStatus()3212 void SceneViewer::invalidateToolStatus() {
3213 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
3214 if (tool) {
3215 m_toolDisableReason = tool->updateEnabled();
3216 if (tool->isEnabled()) {
3217 setToolCursor(this, tool->getCursorId());
3218 tool->setViewer(this);
3219 tool->updateMatrix();
3220 } else
3221 setCursor(Qt::ForbiddenCursor);
3222 } else
3223 setCursor(Qt::ForbiddenCursor);
3224 }
3225
3226 //-----------------------------------------------------------------------------
3227 /*! return the viewer geometry in order to avoid picking the style outside of
3228 the viewer
3229 when using the stylepicker and the finger tools
3230 */
3231
getGeometry() const3232 TRectD SceneViewer::getGeometry() const {
3233 int devPixRatio = getDevPixRatio();
3234 TTool *tool = TApp::instance()->getCurrentTool()->getTool();
3235 TPointD topLeft =
3236 tool->getMatrix().inv() * winToWorld(geometry().topLeft() * devPixRatio);
3237 TPointD bottomRight = tool->getMatrix().inv() *
3238 winToWorld(geometry().bottomRight() * devPixRatio);
3239
3240 TObjectHandle *objHandle = TApp::instance()->getCurrentObject();
3241 if (tool->getToolType() & TTool::LevelTool && !objHandle->isSpline()) {
3242 topLeft.x /= m_dpiScale.x;
3243 topLeft.y /= m_dpiScale.y;
3244 bottomRight.x /= m_dpiScale.x;
3245 bottomRight.y /= m_dpiScale.y;
3246 }
3247
3248 return TRectD(topLeft, bottomRight);
3249 }
3250
3251 //-----------------------------------------------------------------------------
3252 /*! delete preview - subcamera executed from context menu
3253 */
doDeleteSubCamera()3254 void SceneViewer::doDeleteSubCamera() {
3255 PreviewSubCameraManager::instance()->deleteSubCamera(this);
3256 }
3257
3258 //-----------------------------------------------------------------------------
3259
bindFBO()3260 void SceneViewer::bindFBO() {
3261 if (m_fbo) m_fbo->bind();
3262 }
3263
3264 //-----------------------------------------------------------------------------
3265
releaseFBO()3266 void SceneViewer::releaseFBO() {
3267 if (m_fbo) m_fbo->release();
3268 }
3269
3270 //-----------------------------------------------------------------------------
3271
onContextAboutToBeDestroyed()3272 void SceneViewer::onContextAboutToBeDestroyed() {
3273 if (!m_lutCalibrator) return;
3274 makeCurrent();
3275 m_lutCalibrator->cleanup();
3276 doneCurrent();
3277 disconnect(context(), SIGNAL(aboutToBeDestroyed()), this,
3278 SLOT(onContextAboutToBeDestroyed()));
3279 }
3280
3281 //-----------------------------------------------------------------------------
3282 // called from SceneViewer::initializeGL()
3283
registerContext()3284 void SceneViewer::registerContext() {
3285 // release the old context, if any
3286 // this will be happen when dock / float the viewer panel.
3287 bool hasOldContext;
3288 #ifdef _WIN32
3289 hasOldContext =
3290 (m_currentContext.first != nullptr && m_currentContext.second != nullptr);
3291 #else
3292 hasOldContext = m_currentContext != nullptr;
3293 #endif
3294 if (hasOldContext) {
3295 int ret = l_contexts.erase(m_currentContext);
3296 if (ret)
3297 TGLDisplayListsManager::instance()->releaseContext(m_currentContext);
3298 }
3299
3300 // then, register context and the space Id correspondent to it.
3301 int displayListId;
3302 if (TApp::instance()->getMainWindow() &&
3303 TApp::instance()->getMainWindow()->isAncestorOf(this) &&
3304 QThread::currentThread() == qGuiApp->thread()) {
3305 // obtain displaySpaceId for main thread
3306 if (l_mainDisplayListsSpaceId == -1)
3307 l_mainDisplayListsSpaceId =
3308 TGLDisplayListsManager::instance()->storeProxy(new DummyProxy);
3309
3310 displayListId = l_mainDisplayListsSpaceId;
3311 }
3312 // for the other cases (such as for floating viewer), it can't share the
3313 // context so
3314 // obtain different id
3315 else
3316 displayListId =
3317 TGLDisplayListsManager::instance()->storeProxy(new DummyProxy);
3318 TGlContext tglContext(tglGetCurrentContext());
3319 TGLDisplayListsManager::instance()->attachContext(displayListId, tglContext);
3320 l_contexts.insert(tglContext);
3321 }
3322