diff --git a/toonz/sources/common/tvrender/tglregions.cpp b/toonz/sources/common/tvrender/tglregions.cpp index e489878..f698d84 100644 --- a/toonz/sources/common/tvrender/tglregions.cpp +++ b/toonz/sources/common/tvrender/tglregions.cpp @@ -16,6 +16,7 @@ #include "tconvert.h" #include "tcurves.h" #include "tstrokeoutline.h" +#include <QTime> #ifndef _WIN32 #define CALLBACK @@ -132,6 +133,108 @@ void drawControlPoints(const TVectorRenderData &rd, TStroke *stroke, #endif +//----------------------------------------------------------------------------- + +void drawArrows(TStroke *stroke, bool onlyFirstPoint) { + double length = stroke->getLength(0.0, 1.0); + int points = length / 20; + if (points < 2) points += 1; + double currentPosition = 0.0; + + TPointD prePoint, point, postPoint; + glColor3d(1.0, 0.0, 0.0); + for (int i = 0; i <= points; i++) { + currentPosition = i / (double)points; + point = stroke->getPointAtLength(length * currentPosition); + prePoint = (i == 0) ? point : stroke->getPointAtLength( + length * (currentPosition - 0.02)); + postPoint = (i == points) ? point : stroke->getPointAtLength( + length * (currentPosition + 0.02)); + + if (prePoint == postPoint) continue; + + double radian = + std::atan2(postPoint.y - prePoint.y, postPoint.x - prePoint.x); + double degree = radian * 180.0 / 3.14159265; + + glPushMatrix(); + glTranslated(point.x, point.y, 0); + glRotated(degree, 0, 0, 1); + glBegin(GL_LINES); + glVertex2d(0, 0); + glVertex2d(-3, -3); + glVertex2d(0, 0); + glVertex2d(-3, 3); + glEnd(); + glPopMatrix(); + + if (onlyFirstPoint) break; + // make the arrow blue from the second one + glColor3d(0.0, 0.0, 1.0); + } +} + +//----------------------------------------------------------------------------- +// Used for Guided Drawing +void drawFirstControlPoint(const TVectorRenderData &rd, TStroke *stroke) { + TPointD p = stroke->getPoint(0.0); + double length = stroke->getLength(0.0, 1.0); + int msecs = QTime::currentTime().msec(); + double modifier = (msecs / 100) * 0.1; + TPointD startPoint = stroke->getPointAtLength(length * modifier); + TPointD endPoint = stroke->getPointAtLength(length * 0.10); + double j = 0.025; + + glPushMatrix(); + tglMultMatrix(rd.m_aff); + if (!rd.m_animatedGuidedDrawing) glLineWidth(2.0f); + glColor3d(0.0, 1.0, 0.0); + if (!rd.m_animatedGuidedDrawing) { + drawArrows(stroke, false); + } + + if (rd.m_animatedGuidedDrawing) { + drawArrows(stroke, true); + glColor3d(0.0, 1.0, 0.0); + j = 0.025 + modifier; + glBegin(GL_LINES); + // draw the first animated section + for (int i = 0; i < 8; i++) { + endPoint = stroke->getPointAtLength(length * j); + glVertex2d(startPoint.x, startPoint.y); + glVertex2d(endPoint.x, endPoint.y); + startPoint = endPoint; + j += 0.025; + if (j > 1) { + j -= 1; + startPoint = stroke->getPointAtLength(length * j); + } + } + + modifier = modifier + 0.5; + if (modifier >= 1) modifier -= 1; + startPoint = stroke->getPointAtLength(length * modifier); + j = 0.025 + modifier; + + // draw another animated section + for (int i = 0; i < 8; i++) { + endPoint = stroke->getPointAtLength(length * j); + glVertex2d(startPoint.x, startPoint.y); + glVertex2d(endPoint.x, endPoint.y); + startPoint = endPoint; + j += 0.025; + if (j > 1) { + j -= 1; + startPoint = stroke->getPointAtLength(length * j); + } + } + glEnd(); + } + + glLineWidth(1.0f); + glPopMatrix(); +} + //============================================================================= /*TPixel TransparencyCheckBlackBgInk = TPixel(255,255,255); @@ -483,11 +586,20 @@ static void tglDoDraw(const TVectorRenderData &rd, const TStroke *s) { if (color.m != 0) visible = true; } } -#if DISEGNO_OUTLINE == 0 - if (visible) -#endif - tglDraw(rd, s, false); + if (visible) { + // Change stroke color to blue if guided drawing + if (rd.m_showGuidedDrawing && rd.m_highLightNow) { + TVectorRenderData *newRd = new TVectorRenderData( + rd, rd.m_aff, rd.m_clippingRect, rd.m_palette, rd.m_guidedCf); + tglDraw(*newRd, s, false); + delete newRd; + TStroke *new_s = (TStroke *)s; + drawFirstControlPoint(rd, new_s); + } else { + tglDraw(rd, s, false); + } + } #ifdef _DEBUG // drawControlPoints(rd, vim->getStroke(i), sqrt(tglGetPixelSize2()), true); // assert(checkQuadraticDistance(vim->getStroke(i),true)); @@ -542,6 +654,11 @@ rdRegions.m_alphaChannel = rdRegions.m_antiAliasing = false;*/ tglDoDraw(rdRegions, vim->getRegion(regionIndex)); while (strokeIndex < vim->getStrokeCount() && vim->sameGroup(strokeIndex, currStrokeIndex)) { + if (rd.m_indexToHighlight != strokeIndex) { + rd.m_highLightNow = false; + } else { + rd.m_highLightNow = true; + } #if DISEGNO_OUTLINE == 1 CurrStrokeIndex = strokeIndex; CurrVimg = vim; diff --git a/toonz/sources/include/toonz/preferences.h b/toonz/sources/include/toonz/preferences.h index 10c6094..17abd0c 100644 --- a/toonz/sources/include/toonz/preferences.h +++ b/toonz/sources/include/toonz/preferences.h @@ -329,6 +329,11 @@ public: return m_useNumpadForSwitchingStyles; } + void setGuidedDrawing(int status); + int getGuidedDrawing() { return m_guidedDrawingType; } + void setAnimatedGuidedDrawing(bool status); + bool getAnimatedGuidedDrawing() const { return m_animatedGuidedDrawing; } + void enableNewLevelSizeToCameraSize(bool on); bool isNewLevelSizeToCameraSizeEnabled() const { return m_newLevelSizeToCameraSizeEnabled; @@ -519,7 +524,7 @@ private: m_chunkSize, m_blanksCount, m_onionPaperThickness, m_step, m_shrink, m_textureSize, m_autocreationType, m_keyframeType, m_animationStep, m_ffmpegTimeout; // seconds - int m_projectRoot, m_importPolicy, m_interfaceFontWeight; + int m_projectRoot, m_importPolicy, m_interfaceFontWeight, m_guidedDrawingType; QString m_currentLanguage, m_currentStyleSheet; int m_undoMemorySize, // in megabytes m_dragCellsBehaviour, m_lineTestFpsCapture, m_defLevelType, m_xsheetStep, @@ -531,7 +536,7 @@ private: m_rewindAfterPlaybackEnabled, m_fitToFlipbookEnabled, m_autosaveEnabled, m_autosaveSceneEnabled, m_autosaveOtherFilesEnabled, m_defaultViewerEnabled, m_pixelsOnly, m_showXSheetToolbar, - m_expandFunctionHeader, m_showColumnNumbers; + m_expandFunctionHeader, m_showColumnNumbers, m_animatedGuidedDrawing; bool m_rasterOptimizedMemory, m_saveUnpaintedInCleanup, m_askForOverrideRender, m_automaticSVNFolderRefreshEnabled, m_SVNEnabled, m_levelsBackupEnabled, m_minimizeSaveboxAfterEditing, diff --git a/toonz/sources/include/toonz/stage.h b/toonz/sources/include/toonz/stage.h index c490aa8..39abc4e 100644 --- a/toonz/sources/include/toonz/stage.h +++ b/toonz/sources/include/toonz/stage.h @@ -65,12 +65,14 @@ DVAPI void visit(Visitor &visitor, ToonzScene *scene, TXsheet *xsh, int row); //----------------------------------------------------------------------------- DVAPI void visit(Visitor &visitor, TXshSimpleLevel *level, const TFrameId &fid, - const OnionSkinMask &osm, bool isPlaying); + const OnionSkinMask &osm, bool isPlaying, + int isGuidedDrawingEnabled = 0); //----------------------------------------------------------------------------- DVAPI void visit(Visitor &visitor, TXshLevel *level, const TFrameId &fid, - const OnionSkinMask &osm, bool isPlaying); + const OnionSkinMask &osm, bool isPlaying, + double isGuidedDrawingEnabled = 0.0); //----------------------------------------------------------------------------- } // namespace Stage diff --git a/toonz/sources/include/toonz/stageplayer.h b/toonz/sources/include/toonz/stageplayer.h index b5379b0..cdb6a8b 100644 --- a/toonz/sources/include/toonz/stageplayer.h +++ b/toonz/sources/include/toonz/stageplayer.h @@ -83,12 +83,15 @@ public: //! of) the current column bool m_isCurrentXsheetLevel; //!< Whether the player's xsheet is the \a //! current one - + bool m_isEditingLevel; + bool m_isVisibleinOSM; // Whether the current frame is in the onion skin + int m_isGuidedDrawingEnabled = 0; TXshSimpleLevel *m_sl; //!< (not owned) The player's simple level TFrameId m_fid; //!< The player's frame in m_sl - - TXsheet *m_xsh; //!< (not owned) The player's xsheet - int m_column; //!< The player's xsheet column + TFrameId + m_currentFrameId; // The current frame selected in the level or xsheet + TXsheet *m_xsh; //!< (not owned) The player's xsheet + int m_column; //!< The player's xsheet column int m_frame; //!< The player's xhseet row (could be not the current, due to //! onion skin?) @@ -101,6 +104,8 @@ public: static double m_onionSkinFrontSize; static double m_onionSkinBackSize; + static double m_firstBackOnionSkin; + static double m_lastBackVisibleSkin; TPixel32 m_filterColor; diff --git a/toonz/sources/include/toonz/stagevisitor.h b/toonz/sources/include/toonz/stagevisitor.h index ec03556..4461362 100644 --- a/toonz/sources/include/toonz/stagevisitor.h +++ b/toonz/sources/include/toonz/stagevisitor.h @@ -126,12 +126,13 @@ struct DVAPI VisitArgs { const OnionSkinMask *m_osm; int m_xsheetLevel; - + TFrameId m_currentFrameId; bool m_camera3d; bool m_isPlaying; bool m_onlyVisible; bool m_checkPreviewVisibility; bool m_rasterizePli; + int m_isGuidedDrawingEnabled; public: VisitArgs() @@ -145,6 +146,7 @@ public: , m_isPlaying(false) , m_onlyVisible(false) , m_checkPreviewVisibility(false) + , m_isGuidedDrawingEnabled(0) , m_rasterizePli(false) {} }; diff --git a/toonz/sources/include/tvectorrenderdata.h b/toonz/sources/include/tvectorrenderdata.h index 885879c..f59622a 100644 --- a/toonz/sources/include/tvectorrenderdata.h +++ b/toonz/sources/include/tvectorrenderdata.h @@ -49,6 +49,7 @@ public: public: const TColorFunction *m_cf; //!< [\p not-owned] Transform to be used for drawing RGBM colors. + const TColorFunction *m_guidedCf; const TPalette *m_palette; //!< [\p not-owned] Palette to be used for //! translating color indexes to //! RGBM colors. @@ -61,8 +62,9 @@ public: TPixel m_tCheckInk; //!< Color to be used for <I>ink check</I> mode. TPixel m_tCheckPaint; //!< Color to be used for <I>paint check</I> mode. - int m_colorCheckIndex; //!< Color index to be highlighted in <I>color - //! check</I> mode. + int m_colorCheckIndex; //!< Color index to be highlighted in <I>color + //! check</I> mode. + int m_indexToHighlight; // for guided vector drawing bool m_alphaChannel, //!< Whether alpha channel is enabled. m_antiAliasing, //!< Whether antialiasing must be applied. @@ -79,8 +81,12 @@ public: //! rendered anyway. m_regionAntialias, //!< Whether regions should be rendered with //! antialiasing at boundaries. - m_isOfflineRender; //!< Whether image rendering is in render or + m_isOfflineRender, //!< Whether image rendering is in render or //! camera-stand (preview) mode. + m_showGuidedDrawing, // Whether this image is being used for guided + // drawing + m_highLightNow; // Show highlight on active stroke + bool m_animatedGuidedDrawing = false; //! \deprecated Use the above individual options instead. //! \todo Remove it ASAP. public: @@ -111,7 +117,11 @@ public: , m_regionAntialias(false) // No need for pretty region boundaries, // typically shadowed by strokes // This is also related to interference with the directly above param - , m_isOfflineRender(false) {} // By definition + , m_isOfflineRender(false) // By definition + , m_indexToHighlight(-1) + , m_highLightNow(false) + , m_guidedCf(0) + , m_showGuidedDrawing(false) {} TVectorRenderData(ProductionSettings, const TAffine &aff, const TRect &clippingRect, const TPalette *palette, @@ -137,7 +147,11 @@ public: , m_show0ThickStrokes(false) // Invisible strokes must be invisible , m_regionAntialias(true) // Pretty region boundaries under invisible or // semitransparent strokes - , m_isOfflineRender(true) {} // By definition + , m_isOfflineRender(true) // By definition + , m_indexToHighlight(-1) + , m_highLightNow(false) + , m_guidedCf(0) + , m_showGuidedDrawing(false) {} TVectorRenderData(const TVectorRenderData &other, const TAffine &aff, const TRect &clippingRect, const TPalette *palette, @@ -161,7 +175,11 @@ public: , m_is3dView(other.m_is3dView) , m_show0ThickStrokes(other.m_show0ThickStrokes) , m_regionAntialias(other.m_regionAntialias) - , m_isOfflineRender(other.m_isOfflineRender) { + , m_isOfflineRender(other.m_isOfflineRender) + , m_indexToHighlight(other.m_indexToHighlight) + , m_highLightNow(other.m_highLightNow) + , m_guidedCf(other.m_guidedCf) + , m_showGuidedDrawing(other.m_showGuidedDrawing) { } //!< Constructs from explicit primary context settings while //! copying the rest from another instance. @@ -188,7 +206,11 @@ public: , m_is3dView(is3dView) , m_show0ThickStrokes(true) , m_regionAntialias(false) - , m_isOfflineRender(false) { + , m_isOfflineRender(false) + , m_indexToHighlight(-1) + , m_highLightNow(false) + , m_guidedCf(0) + , m_showGuidedDrawing(false) { } //!< Constructs settings with default ViewerSettings. //! \deprecated Use constructors with explicit settings type tag. }; diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index eb50118..2958b98 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -725,6 +725,12 @@ void PreferencesPopup::onOnionSkinDuringPlaybackChanged(int index) { //----------------------------------------------------------------------------- +void PreferencesPopup::onGuidedDrawingStyleChanged(int index) { + m_pref->setAnimatedGuidedDrawing(index); +} + +//----------------------------------------------------------------------------- + void PreferencesPopup::onActualPixelOnSceneModeChanged(int index) { m_pref->enableActualPixelViewOnSceneEditingMode(index == Qt::Checked); } @@ -1320,6 +1326,7 @@ PreferencesPopup::PreferencesPopup() int thickness = m_pref->getOnionPaperThickness(); m_onionPaperThickness = new DVGui::IntLineEdit(this, thickness, 0, 100); + m_guidedDrawingStyle = new QComboBox(this); //--- Transparency Check ------------------------------ categoryList->addItem(tr("Transparency Check")); @@ -1619,6 +1626,10 @@ PreferencesPopup::PreferencesPopup() m_frontOnionColor->setEnabled(m_pref->isOnionSkinEnabled()); m_backOnionColor->setEnabled(m_pref->isOnionSkinEnabled()); m_inksOnly->setEnabled(m_pref->isOnionSkinEnabled()); + QStringList guidedDrawingStyles; + guidedDrawingStyles << tr("Arrow Markers") << tr("Animated Guide"); + m_guidedDrawingStyle->addItems(guidedDrawingStyles); + m_guidedDrawingStyle->setCurrentIndex(m_pref->getAnimatedGuidedDrawing()); //--- Version Control ------------------------------ m_enableVersionControl->setChecked(m_pref->isSVNEnabled()); @@ -2167,7 +2178,17 @@ PreferencesPopup::PreferencesPopup() onionLay->addWidget(m_inksOnly, 0, Qt::AlignLeft | Qt::AlignVCenter); onionLay->addWidget(m_onionSkinDuringPlayback, 0, Qt::AlignLeft | Qt::AlignVCenter); - + QGridLayout *guidedDrawingLay = new QGridLayout(); + { + guidedDrawingLay->addWidget(new QLabel(tr("Vector Guided Style:")), 0, + 0, Qt::AlignLeft | Qt::AlignVCenter); + guidedDrawingLay->addWidget(m_guidedDrawingStyle, 0, 1, + Qt::AlignLeft | Qt::AlignVCenter); + guidedDrawingLay->setColumnStretch(0, 0); + guidedDrawingLay->setColumnStretch(1, 0); + guidedDrawingLay->setColumnStretch(2, 1); + } + onionLay->addLayout(guidedDrawingLay, 0); onionLay->addStretch(1); } onionBox->setLayout(onionLay); @@ -2474,7 +2495,8 @@ PreferencesPopup::PreferencesPopup() SLOT(onOnionSkinDuringPlaybackChanged(int))); ret = ret && connect(m_onionPaperThickness, SIGNAL(editingFinished()), SLOT(onOnionPaperThicknessChanged())); - + ret = ret && connect(m_guidedDrawingStyle, SIGNAL(currentIndexChanged(int)), + SLOT(onGuidedDrawingStyleChanged(int))); //--- Transparency Check ---------------------- ret = ret && connect(m_transpCheckBgColor, SIGNAL(colorChanged(const TPixel32 &, bool)), diff --git a/toonz/sources/toonz/preferencespopup.h b/toonz/sources/toonz/preferencespopup.h index 7da18cc..4dfb267 100644 --- a/toonz/sources/toonz/preferencespopup.h +++ b/toonz/sources/toonz/preferencespopup.h @@ -54,7 +54,8 @@ private: QComboBox *m_keyframeType, *m_cellsDragBehaviour, *m_defScanLevelType, *m_defLevelType, *m_autocreationType, *m_levelFormatNames, *m_columnIconOm, *m_unitOm, *m_cameraUnitOm, *m_importPolicy, - *m_interfaceFont, *m_interfaceFontWeight, *m_vectorSnappingTargetCB; + *m_interfaceFont, *m_interfaceFontWeight, *m_vectorSnappingTargetCB, + *m_guidedDrawingStyle; DVGui::MeasuredDoubleLineEdit *m_defLevelWidth, *m_defLevelHeight; @@ -163,6 +164,7 @@ private slots: void onReplaceAfterSaveLevelAsChanged(int index); void onOnionSkinVisibilityChanged(int); void onOnionSkinDuringPlaybackChanged(int); + void onGuidedDrawingStyleChanged(int); void onActualPixelOnSceneModeChanged(int); void onMultiLayerStylePickerChanged(int); void onLevelNameOnEachMarkerChanged(int); diff --git a/toonz/sources/toonz/sceneviewer.cpp b/toonz/sources/toonz/sceneviewer.cpp index 36acebe..e63e27a 100644 --- a/toonz/sources/toonz/sceneviewer.cpp +++ b/toonz/sources/toonz/sceneviewer.cpp @@ -65,6 +65,7 @@ #include "tofflinegl.h" #include "tstopwatch.h" #include "trop.h" +#include "tproperty.h" #include "timagecache.h" #include "trasterimage.h" #include "tstroke.h" @@ -1592,6 +1593,9 @@ void SceneViewer::drawScene() { bool fillFullColorRaster = TXshSimpleLevel::m_fillFullColorRaster; TXshSimpleLevel::m_fillFullColorRaster = false; + // Guided Drawing Check + int useGuidedDrawing = Preferences::instance()->getGuidedDrawing(); + m_minZ = 0; if (is3DView()) { Stage::OpenGlPainter painter(getViewMatrix(), clipRect, m_visualSettings, @@ -1615,6 +1619,14 @@ void SceneViewer::drawScene() { args.m_osm = &osm; args.m_camera3d = true; args.m_xsheetLevel = xsheetLevel; + args.m_currentFrameId = + app->getCurrentXsheet() + ->getXsheet() + ->getCell(app->getCurrentFrame()->getFrame(), args.m_col) + .getFrameId(); + args.m_isGuidedDrawingEnabled = useGuidedDrawing; + + // args.m_currentFrameId = app->getCurrentFrame()->getFid(); Stage::visit(painter, args); m_minZ = painter.getMinZ(); @@ -1646,7 +1658,7 @@ void SceneViewer::drawScene() { Stage::visit(painter, app->getCurrentLevel()->getLevel(), app->getCurrentFrame()->getFid(), app->getCurrentOnionSkin()->getOnionSkinMask(), - frameHandle->isPlaying()); + frameHandle->isPlaying(), useGuidedDrawing); } else { std::pair<TXsheet *, int> xr; int xsheetLevel = 0; @@ -1665,6 +1677,12 @@ void SceneViewer::drawScene() { args.m_osm = &osm; args.m_xsheetLevel = xsheetLevel; args.m_isPlaying = frameHandle->isPlaying(); + args.m_currentFrameId = + app->getCurrentXsheet() + ->getXsheet() + ->getCell(app->getCurrentFrame()->getFrame(), args.m_col) + .getFrameId(); + args.m_isGuidedDrawingEnabled = useGuidedDrawing; Stage::visit(painter, args); } diff --git a/toonz/sources/toonz/sceneviewercontextmenu.cpp b/toonz/sources/toonz/sceneviewercontextmenu.cpp index 8211476..94ef1c3 100644 --- a/toonz/sources/toonz/sceneviewercontextmenu.cpp +++ b/toonz/sources/toonz/sceneviewercontextmenu.cpp @@ -176,7 +176,32 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) if (Preferences::instance()->isOnionSkinEnabled() && !parent->isPreviewEnabled()) OnioniSkinMaskGUI::addOnionSkinCommand(this); - + QMenu *guidedDrawingMenu = addMenu(tr("Vector Guided Drawing")); + int guidedDrawingStatus = Preferences::instance()->getGuidedDrawing(); + action = guidedDrawingMenu->addAction(tr("Off")); + action->setCheckable(true); + action->setChecked(guidedDrawingStatus == 0); + ret = ret && + parent->connect(action, SIGNAL(triggered()), this, + SLOT(setGuidedDrawingOff())); + action = guidedDrawingMenu->addAction(tr("Closest Drawing")); + action->setCheckable(true); + action->setChecked(guidedDrawingStatus == 1); + ret = ret && + parent->connect(action, SIGNAL(triggered()), this, + SLOT(setGuidedDrawingClosest())); + action = guidedDrawingMenu->addAction(tr("Farthest Drawing")); + action->setCheckable(true); + action->setChecked(guidedDrawingStatus == 2); + ret = ret && + parent->connect(action, SIGNAL(triggered()), this, + SLOT(setGuidedDrawingFarthest())); + action = guidedDrawingMenu->addAction(tr("All Drawings")); + action->setCheckable(true); + action->setChecked(guidedDrawingStatus == 3); + ret = ret && + parent->connect(action, SIGNAL(triggered()), this, + SLOT(setGuidedDrawingAll())); // Zero Thick if (!parent->isPreviewEnabled()) ZeroThickToggleGui::addZeroThickCommand(this); @@ -386,6 +411,26 @@ void SceneViewerContextMenu::onSetCurrent() { } //----------------------------------------------------------------------------- +void SceneViewerContextMenu::setGuidedDrawingOff() { + Preferences::instance()->setGuidedDrawing(0); +} + +//----------------------------------------------------------------------------- +void SceneViewerContextMenu::setGuidedDrawingClosest() { + Preferences::instance()->setGuidedDrawing(1); +} + +//----------------------------------------------------------------------------- +void SceneViewerContextMenu::setGuidedDrawingFarthest() { + Preferences::instance()->setGuidedDrawing(2); +} + +//----------------------------------------------------------------------------- +void SceneViewerContextMenu::setGuidedDrawingAll() { + Preferences::instance()->setGuidedDrawing(3); +} + +//----------------------------------------------------------------------------- void SceneViewerContextMenu::savePreviewedFrames() { Previewer::instance(m_viewer->getPreviewMode() == diff --git a/toonz/sources/toonz/sceneviewercontextmenu.h b/toonz/sources/toonz/sceneviewercontextmenu.h index 09de03f..b4e05b0 100644 --- a/toonz/sources/toonz/sceneviewercontextmenu.h +++ b/toonz/sources/toonz/sceneviewercontextmenu.h @@ -31,6 +31,10 @@ public slots: void enterVectorImageGroup(); void exitVectorImageGroup(); + void setGuidedDrawingOff(); + void setGuidedDrawingClosest(); + void setGuidedDrawingFarthest(); + void setGuidedDrawingAll(); void onShowHide(); void onSetCurrent(); diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index 9256842..8edd6d6 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -322,6 +322,8 @@ Preferences::Preferences() , m_useArrowKeyToShiftCellSelection(false) , m_inputCellsWithoutDoubleClickingEnabled(false) , m_importPolicy(0) + , m_guidedDrawingType(0) + , m_animatedGuidedDrawing(false) , m_ignoreImageDpi(false) , m_watchFileSystem(true) , m_shortcutCommandsWhileRenamingCellEnabled(false) { @@ -612,6 +614,8 @@ Preferences::Preferences() getValue(*m_settings, "interfaceFontWeight", m_interfaceFontWeight); getValue(*m_settings, "useNumpadForSwitchingStyles", m_useNumpadForSwitchingStyles); + getValue(*m_settings, "guidedDrawingType", m_guidedDrawingType); + getValue(*m_settings, "animatedGuidedDrawing", m_animatedGuidedDrawing); getValue(*m_settings, "newLevelSizeToCameraSizeEnabled", m_newLevelSizeToCameraSizeEnabled); getValue(*m_settings, "showXSheetToolbar", m_showXSheetToolbar); @@ -1450,6 +1454,20 @@ void Preferences::enableUseNumpadForSwitchingStyles(bool on) { //----------------------------------------------------------------- +void Preferences::setGuidedDrawing(int status) { + m_guidedDrawingType = status; + m_settings->setValue("guidedDrawingType", status); +} + +//----------------------------------------------------------------- + +void Preferences::setAnimatedGuidedDrawing(bool status) { + m_animatedGuidedDrawing = status; + m_settings->setValue("animatedGuidedDrawing", status); +} + +//----------------------------------------------------------------- + void Preferences::enableNewLevelSizeToCameraSize(bool on) { m_newLevelSizeToCameraSizeEnabled = on; m_settings->setValue("newLevelSizeToCameraSizeEnabled", on ? "1" : "0"); diff --git a/toonz/sources/toonzlib/stage.cpp b/toonz/sources/toonzlib/stage.cpp index 44801ac..cb9be4a 100644 --- a/toonz/sources/toonzlib/stage.cpp +++ b/toonz/sources/toonzlib/stage.cpp @@ -76,7 +76,8 @@ namespace { void updateOnionSkinSize(const PlayerSet &players) { assert(Player::m_onionSkinFrontSize == 0 && Player::m_onionSkinBackSize == 0); int i; - int maxOnionSkinFrontValue = 0, maxOnionSkinBackValue = 0; + int maxOnionSkinFrontValue = 0, maxOnionSkinBackValue = 0, + firstBackOnionSkin = 0, lastBackVisibleSkin = 0; for (i = 0; i < (int)players.size(); i++) { Player player = players[i]; if (player.m_onionSkinDistance == c_noOnionSkin) continue; @@ -86,9 +87,20 @@ void updateOnionSkinSize(const PlayerSet &players) { if (player.m_onionSkinDistance < 0 && maxOnionSkinBackValue > player.m_onionSkinDistance) maxOnionSkinBackValue = player.m_onionSkinDistance; + if (firstBackOnionSkin == 0 && player.m_onionSkinDistance < 0) + firstBackOnionSkin = player.m_onionSkinDistance; + else if (player.m_onionSkinDistance < 0 && + firstBackOnionSkin < player.m_onionSkinDistance) + firstBackOnionSkin = player.m_onionSkinDistance; + // Level Editing Mode can send players at a depth beyond what is visible. + if (player.m_onionSkinDistance < lastBackVisibleSkin && + player.m_isVisibleinOSM) + lastBackVisibleSkin = player.m_onionSkinDistance; } - Player::m_onionSkinFrontSize = maxOnionSkinFrontValue; - Player::m_onionSkinBackSize = maxOnionSkinBackValue; + Player::m_onionSkinFrontSize = maxOnionSkinFrontValue; + Player::m_onionSkinBackSize = maxOnionSkinBackValue; + Player::m_firstBackOnionSkin = firstBackOnionSkin; + Player::m_lastBackVisibleSkin = lastBackVisibleSkin; } //----------------------------------------------------------------------------- @@ -184,6 +196,9 @@ public: int m_currentXsheetLevel; // level of the current xsheet, see: editInPlace int m_xsheetLevel; // xsheet-level of the column being processed + // for guided drawing + TFrameId m_currentFrameId; + int m_isGuidedDrawingEnabled; std::vector<TXshColumn *> m_ancestors; const ImagePainter::VisualSettings *m_vs; @@ -356,11 +371,13 @@ void StageBuilder::addCell(PlayerSet &players, ToonzScene *scene, TXsheet *xsh, // Build and store a player Player player; - player.m_sl = sl; - player.m_fid = cell.m_frameId; - player.m_xsh = xsh; - player.m_column = col; - player.m_frame = row; + player.m_sl = sl; + player.m_fid = cell.m_frameId; + player.m_xsh = xsh; + player.m_column = col; + player.m_frame = row; + player.m_currentFrameId = m_currentFrameId; + player.m_isGuidedDrawingEnabled = m_isGuidedDrawingEnabled; player.m_dpiAff = sl ? getDpiAffine(sl, cell.m_frameId) : TAffine(); player.m_onionSkinDistance = m_onionSkinDistance; player.m_isCurrentColumn = (m_currentColumnIndex == col); @@ -632,12 +649,16 @@ void StageBuilder::addSimpleLevelFrame(PlayerSet &players, const TFrameId &fid2 = level->index2fid(rows[i]); if (fid2 == fid) continue; players.push_back(Player()); - Player &player = players.back(); - player.m_sl = level; - player.m_frame = level->guessIndex(fid); - player.m_fid = fid2; - player.m_isCurrentColumn = true; - player.m_isCurrentXsheetLevel = true; + Player &player = players.back(); + player.m_sl = level; + player.m_frame = level->guessIndex(fid); + player.m_fid = fid2; + player.m_isCurrentColumn = true; + player.m_isCurrentXsheetLevel = true; + player.m_isEditingLevel = true; + player.m_currentFrameId = m_currentFrameId; + player.m_isGuidedDrawingEnabled = m_isGuidedDrawingEnabled; + player.m_isVisibleinOSM = rows[i] >= 0; #ifdef NUOVO_ONION player.m_onionSkinDistance = rows[i] - row; #else @@ -655,6 +676,7 @@ void StageBuilder::addSimpleLevelFrame(PlayerSet &players, player.m_onionSkinDistance = 0; player.m_isCurrentColumn = true; player.m_isCurrentXsheetLevel = true; + player.m_isEditingLevel = true; player.m_ancestorColumnIndex = -1; player.m_dpiAff = getDpiAffine(level, fid); } @@ -713,18 +735,22 @@ void Stage::visit(Visitor &visitor, const VisitArgs &args) { bool isPlaying = args.m_isPlaying; StageBuilder sb; - sb.m_vs = &visitor.m_vs; - TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId(); - TStageObject *camera = xsh->getStageObject(cameraId); - TAffine cameraAff = camera->getPlacement(row); - double z = camera->getZ(row); - sb.m_cameraPlacement = ZPlacement(cameraAff, z); - sb.m_camera3d = camera3d; - sb.m_currentColumnIndex = col; - sb.m_xsheetLevel = xsheetLevel; - sb.m_onionSkinMask = *osm; - Player::m_onionSkinFrontSize = 0; - Player::m_onionSkinBackSize = 0; + sb.m_vs = &visitor.m_vs; + TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId(); + TStageObject *camera = xsh->getStageObject(cameraId); + TAffine cameraAff = camera->getPlacement(row); + double z = camera->getZ(row); + sb.m_cameraPlacement = ZPlacement(cameraAff, z); + sb.m_camera3d = camera3d; + sb.m_currentColumnIndex = col; + sb.m_xsheetLevel = xsheetLevel; + sb.m_onionSkinMask = *osm; + sb.m_currentFrameId = args.m_currentFrameId; + sb.m_isGuidedDrawingEnabled = args.m_isGuidedDrawingEnabled; + Player::m_onionSkinFrontSize = 0; + Player::m_onionSkinBackSize = 0; + Player::m_firstBackOnionSkin = 0; + Player::m_lastBackVisibleSkin = 0; sb.addFrame(sb.m_players, scene, xsh, row, 0, args.m_onlyVisible, args.m_checkPreviewVisibility); @@ -753,12 +779,17 @@ void Stage::visit(Visitor &visitor, ToonzScene *scene, TXsheet *xsh, int row) { and \b StageBuilder::visit(). */ void Stage::visit(Visitor &visitor, TXshSimpleLevel *level, const TFrameId &fid, - const OnionSkinMask &osm, bool isPlaying) { + const OnionSkinMask &osm, bool isPlaying, + int isGuidedDrawingEnabled) { StageBuilder sb; - sb.m_vs = &visitor.m_vs; - sb.m_onionSkinMask = osm; - Player::m_onionSkinFrontSize = 0; - Player::m_onionSkinBackSize = 0; + sb.m_vs = &visitor.m_vs; + sb.m_onionSkinMask = osm; + sb.m_currentFrameId = fid; + sb.m_isGuidedDrawingEnabled = isGuidedDrawingEnabled; + Player::m_onionSkinFrontSize = 0; + Player::m_onionSkinBackSize = 0; + Player::m_firstBackOnionSkin = 0; + Player::m_lastBackVisibleSkin = 0; sb.addSimpleLevelFrame(sb.m_players, level, fid); updateOnionSkinSize(sb.m_players); sb.visit(sb.m_players, visitor, isPlaying); @@ -767,7 +798,9 @@ void Stage::visit(Visitor &visitor, TXshSimpleLevel *level, const TFrameId &fid, //----------------------------------------------------------------------------- void Stage::visit(Visitor &visitor, TXshLevel *level, const TFrameId &fid, - const OnionSkinMask &osm, bool isPlaying) { + const OnionSkinMask &osm, bool isPlaying, + double isGuidedDrawingEnabled) { if (level && level->getSimpleLevel()) - visit(visitor, level->getSimpleLevel(), fid, osm, isPlaying); + visit(visitor, level->getSimpleLevel(), fid, osm, isPlaying, + (int)isGuidedDrawingEnabled); } diff --git a/toonz/sources/toonzlib/stageplayer.cpp b/toonz/sources/toonzlib/stageplayer.cpp index 4419746..f7ea268 100644 --- a/toonz/sources/toonzlib/stageplayer.cpp +++ b/toonz/sources/toonzlib/stageplayer.cpp @@ -19,8 +19,10 @@ using namespace Stage; // Stage::Player implementation //***************************************************************************************** -double Player::m_onionSkinFrontSize = 0; -double Player::m_onionSkinBackSize = 0; +double Player::m_onionSkinFrontSize = 0; +double Player::m_onionSkinBackSize = 0; +double Player::m_firstBackOnionSkin = 0; +double Player::m_lastBackVisibleSkin = 0; //----------------------------------------------------------------------------- @@ -32,6 +34,8 @@ Stage::Player::Player() , m_ancestorColumnIndex(-1) , m_isCurrentColumn(false) , m_isCurrentXsheetLevel(false) + , m_isEditingLevel(false) + , m_isVisibleinOSM(false) , m_sl() , m_xsh() , m_column(-1) diff --git a/toonz/sources/toonzlib/stagevisitor.cpp b/toonz/sources/toonzlib/stagevisitor.cpp index 29ccf07..8c7e4ce 100644 --- a/toonz/sources/toonzlib/stagevisitor.cpp +++ b/toonz/sources/toonzlib/stagevisitor.cpp @@ -48,6 +48,7 @@ #include "toonz/autoclose.h" #include "toonz/txshleveltypes.h" #include "imagebuilders.h" +#include "toonz/tframehandle.h" // Qt includes #include <QImage> @@ -789,7 +790,7 @@ void RasterPainter::onVectorImage(TVectorImage *vi, const Preferences &prefs = *Preferences::instance(); - TColorFunction *cf = 0; + TColorFunction *cf = 0, *guidedCf = 0; TPalette *vPalette = vi->getPalette(); TPixel32 bgColor = TPixel32::White; @@ -833,13 +834,55 @@ void RasterPainter::onVectorImage(TVectorImage *vi, true // alpha enabled ); - rd.m_drawRegions = !inksOnly; - rd.m_inkCheckEnabled = tc & ToonzCheck::eInk; - rd.m_paintCheckEnabled = tc & ToonzCheck::ePaint; - rd.m_blackBgEnabled = tc & ToonzCheck::eBlackBg; - rd.m_colorCheckIndex = ToonzCheck::instance()->getColorIndex(); - rd.m_show0ThickStrokes = prefs.getShow0ThickLines(); - rd.m_regionAntialias = prefs.getRegionAntialias(); + rd.m_drawRegions = !inksOnly; + rd.m_inkCheckEnabled = tc & ToonzCheck::eInk; + rd.m_paintCheckEnabled = tc & ToonzCheck::ePaint; + rd.m_blackBgEnabled = tc & ToonzCheck::eBlackBg; + rd.m_colorCheckIndex = ToonzCheck::instance()->getColorIndex(); + rd.m_show0ThickStrokes = prefs.getShow0ThickLines(); + rd.m_regionAntialias = prefs.getRegionAntialias(); + rd.m_animatedGuidedDrawing = prefs.getAnimatedGuidedDrawing(); + if (player.m_onionSkinDistance < 0 && + (player.m_isCurrentColumn || player.m_isCurrentXsheetLevel)) { + if (player.m_isGuidedDrawingEnabled == 3 // show guides on all + || (player.m_isGuidedDrawingEnabled == 1 && // show guides on closest + player.m_onionSkinDistance == player.m_firstBackOnionSkin) || + (player.m_isGuidedDrawingEnabled == 2 && // show guides on farthest + player.m_onionSkinDistance == player.m_onionSkinBackSize) || + (player.m_isEditingLevel && // fix for level editing mode sending extra + // players + player.m_isGuidedDrawingEnabled == 2 && + player.m_onionSkinDistance == player.m_lastBackVisibleSkin)) { + rd.m_showGuidedDrawing = player.m_isGuidedDrawingEnabled > 0; + int currentStrokeCount = 0; + int totalStrokes = vi->getStrokeCount(); + TXshSimpleLevel *sl = player.m_sl; + + if (sl) { + TImageP image = sl->getFrame(player.m_currentFrameId, false); + TVectorImageP vecImage = image; + if (vecImage) currentStrokeCount = vecImage->getStrokeCount(); + if (currentStrokeCount < totalStrokes) + rd.m_indexToHighlight = currentStrokeCount; + + double guidedM[4] = {1.0, 1.0, 1.0, 1.0}, guidedC[4]; + TPixel32 bgColor = TPixel32::Blue; + guidedM[3] = + 1.0 - + ((player.m_onionSkinDistance == 0) + ? 0.1 + : OnionSkinMask::getOnionSkinFade(player.m_onionSkinDistance)); + + guidedC[0] = (1.0 - guidedM[3]) * bgColor.r, + guidedC[1] = (1.0 - guidedM[3]) * bgColor.g, + guidedC[2] = (1.0 - guidedM[3]) * bgColor.b; + guidedC[3] = 0.0; + + guidedCf = new TGenericColorFunction(guidedM, guidedC); + rd.m_guidedCf = guidedCf; + } + } + } if (tc & (ToonzCheck::eTransparency | ToonzCheck::eGap)) { TPixel dummy; @@ -874,6 +917,7 @@ void RasterPainter::onVectorImage(TVectorImage *vi, vPalette->setFrame(oldFrame); delete cf; + delete guidedCf; } //-----------------------------------------------------