diff --git a/toonz/sources/toonz/pane.cpp b/toonz/sources/toonz/pane.cpp index b6679691..e50ce0be 100644 --- a/toonz/sources/toonz/pane.cpp +++ b/toonz/sources/toonz/pane.cpp @@ -55,6 +55,13 @@ extern TEnv::IntVar ShowFieldGuide; extern TEnv::IntVar GuideOpacity; extern TEnv::IntVar HorizontalOffset; extern TEnv::IntVar VerticalOffset; +extern TEnv::IntVar ShowHorizon; +extern TEnv::IntVar HorizonAngle; +extern TEnv::IntVar HorizonStep; +extern TEnv::IntVar HorizonOffset; +extern TEnv::IntVar ShowVanishingPointRays; +extern TEnv::IntVar VanishingPointRayAngles; +extern TEnv::IntVar VanishingPointRayOpacity; //============================================================================= // TPanel @@ -453,6 +460,52 @@ TPanelTitleBarButtonForGrids::TPanelTitleBarButtonForGrids( emit updateViewer(); }); + QGroupBox* vanishingCheckbox = new QGroupBox(tr("Vanishing Point Rays"), this); + vanishingCheckbox->setCheckable(true); + vanishingCheckbox->setChecked(ShowVanishingPointRays != 0); + connect(vanishingCheckbox, &QGroupBox::toggled, [=](bool value) { + ShowVanishingPointRays = value == true ? 1 : 0; + emit updateViewer(); + }); + + QSlider* vanishingAngleSlider = new QSlider(this); + vanishingAngleSlider->setRange(5, 90); + vanishingAngleSlider->setValue(VanishingPointRayAngles); + vanishingAngleSlider->setOrientation(Qt::Horizontal); + vanishingAngleSlider->setMinimumWidth(300); + QLabel* vanishingAngleLabel = new QLabel(this); + vanishingAngleLabel->setText(tr("Angle: ") + + QString::number(VanishingPointRayAngles)); + connect(vanishingAngleSlider, &QSlider::valueChanged, [=](int value) { + VanishingPointRayAngles = value; + vanishingAngleLabel->setText(tr("Angle: ") + + QString::number(VanishingPointRayAngles)); + emit updateViewer(); + }); + + QSlider* vanishingOpacitySlider = new QSlider(this); + vanishingOpacitySlider->setRange(1, 100); + vanishingOpacitySlider->setValue(VanishingPointRayOpacity); + vanishingOpacitySlider->setOrientation(Qt::Horizontal); + QLabel* vanishingOpacityLabel = new QLabel(this); + vanishingOpacityLabel->setText(tr("Opacity: ") + + QString::number(VanishingPointRayOpacity)); + connect(vanishingOpacitySlider, &QSlider::valueChanged, [=](int value) { + VanishingPointRayOpacity = value; + vanishingOpacityLabel->setText(tr("Opacity: ") + + QString::number(VanishingPointRayOpacity)); + emit updateViewer(); + }); + + QGridLayout* vanishingLayout = new QGridLayout(this); + vanishingLayout->addWidget(vanishingAngleLabel, 0, 0, Qt::AlignRight); + vanishingAngleLabel->setFixedWidth(110); + vanishingAngleLabel->setAlignment(Qt::AlignRight); + vanishingLayout->addWidget(vanishingAngleSlider, 0, 1); + vanishingLayout->addWidget(vanishingOpacityLabel, 1, 0, Qt::AlignRight); + vanishingLayout->addWidget(vanishingOpacitySlider, 1, 1); + vanishingCheckbox->setLayout(vanishingLayout); + QGroupBox *horizontalCheckbox = new QGroupBox(tr("Horizontal Grid"), this); horizontalCheckbox->setCheckable(true); horizontalCheckbox->setChecked(ShowHorizontalGrid != 0); @@ -544,6 +597,70 @@ TPanelTitleBarButtonForGrids::TPanelTitleBarButtonForGrids( verticalLayout->addWidget(verticalOffsetSlider, 1, 1); verticalCheckbox->setLayout(verticalLayout); + + QGroupBox* horizonCheckbox = new QGroupBox(tr("Horizon"), this); + horizonCheckbox->setCheckable(true); + horizonCheckbox->setChecked(ShowHorizon != 0); + connect(horizonCheckbox, &QGroupBox::toggled, [=](bool value) { + ShowHorizon = value == true ? 1 : 0; + emit updateViewer(); + }); + + QSlider* horizonAngleSlider = new QSlider(this); + horizonAngleSlider->setRange(-90, 90); + horizonAngleSlider->setValue(HorizonAngle); + horizonAngleSlider->setOrientation(Qt::Horizontal); + horizonAngleSlider->setMinimumWidth(300); + QLabel* horizonAngleLabel = new QLabel(this); + horizonAngleLabel->setText(tr("Angle: ") + + QString::number(HorizonAngle)); + connect(horizonAngleSlider, &QSlider::valueChanged, [=](int value) { + HorizonAngle = value; + horizonAngleLabel->setText(tr("Angle: ") + + QString::number(HorizonAngle)); + emit updateViewer(); + }); + + QSlider* horizonStepSlider = new QSlider(this); + horizonStepSlider->setRange(2, 100); + horizonStepSlider->setValue(HorizonStep); + horizonStepSlider->setOrientation(Qt::Horizontal); + QLabel* horizonStepLabel = new QLabel(this); + horizonStepLabel->setText(tr("Step: ") + + QString::number(HorizonStep)); + connect(horizonStepSlider, &QSlider::valueChanged, [=](int value) { + HorizonStep = value; + horizonStepLabel->setText(tr("Step: ") + + QString::number(HorizonStep)); + emit updateViewer(); + }); + + QSlider* horizonOffsetSlider = new QSlider(this); + horizonOffsetSlider->setRange(-500, 500); + horizonOffsetSlider->setValue(HorizonOffset); + horizonOffsetSlider->setOrientation(Qt::Horizontal); + QLabel* horizonOffsetLabel = new QLabel(this); + horizonOffsetLabel->setText(tr("Offset: ") + + QString::number(HorizonOffset)); + connect(horizonOffsetSlider, &QSlider::valueChanged, [=](int value) { + HorizonOffset = value; + horizonOffsetLabel->setText(tr("Offset: ") + + QString::number(HorizonOffset)); + emit updateViewer(); + }); + + QGridLayout* horizonLayout = new QGridLayout(this); + horizonLayout->addWidget(horizonAngleLabel, 0, 0, Qt::AlignRight); + horizonAngleLabel->setFixedWidth(110); + horizonAngleLabel->setAlignment(Qt::AlignRight); + horizonLayout->addWidget(horizonAngleSlider, 0, 1); + horizonLayout->addWidget(horizonStepLabel, 1, 0, Qt::AlignRight); + horizonLayout->addWidget(horizonStepSlider, 1, 1); + horizonLayout->addWidget(horizonOffsetLabel, 2, 0, Qt::AlignRight); + horizonLayout->addWidget(horizonOffsetSlider, 2, 1); + horizonCheckbox->setLayout(horizonLayout); + + QGroupBox *isometricCheckbox = new QGroupBox(tr("Isometric Grid"), this); isometricCheckbox->setCheckable(true); isometricCheckbox->setChecked(ShowIsometricGrid != 0); @@ -639,10 +756,13 @@ TPanelTitleBarButtonForGrids::TPanelTitleBarButtonForGrids( gridLayout->addWidget(fieldGuideCheckbox, 2, 0, 1, 2); gridLayout->addWidget(horizontalCheckbox, 3, 0, 1, 2); gridLayout->addWidget(verticalCheckbox, 4, 0, 1, 2); - gridLayout->addWidget(isometricCheckbox, 5, 0, 1, 2); - gridLayout->addWidget(guideOpacityLabel, 6, 0); - gridLayout->addWidget(guideOpacitySlider, 6, 1); + gridLayout->addWidget(horizonCheckbox, 5, 0, 1, 2); + gridLayout->addWidget(isometricCheckbox, 6, 0, 1, 2); + gridLayout->addWidget(vanishingCheckbox, 7, 0, 1, 2); + + gridLayout->addWidget(guideOpacityLabel, 8, 0); + gridLayout->addWidget(guideOpacitySlider, 8, 1); gridWidget->setLayout(gridLayout); gridsAction->setDefaultWidget(gridWidget); m_menu->addAction(gridsAction); diff --git a/toonz/sources/toonz/sceneviewer.cpp b/toonz/sources/toonz/sceneviewer.cpp index dc0872ee..56f0b9df 100644 --- a/toonz/sources/toonz/sceneviewer.cpp +++ b/toonz/sources/toonz/sceneviewer.cpp @@ -780,7 +780,6 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent) , m_toolDisableReason("") , m_editPreviewSubCamera(false) , m_locator(NULL) - , m_showPerspectiveGrids(ShowPerspectiveGrids) , m_isLocator(false) , m_isBusyOnTabletMove(false) { m_visualSettings.m_sceneProperties = @@ -1724,7 +1723,7 @@ void SceneViewer::drawOverlay() { // draw tool gadgets TTool *tool = app->getCurrentTool()->getTool(); TXshSimpleLevel *sl = app->getCurrentLevel()->getSimpleLevel(); - if (sl && m_showPerspectiveGrids) { + if (sl) { std::vector assistantPoints = sl->getProperties()->getVanishingPoints(); if (assistantPoints.size() > 0) { @@ -3360,11 +3359,4 @@ void SceneViewer::registerContext() { TGlContext tglContext(tglGetCurrentContext()); TGLDisplayListsManager::instance()->attachContext(displayListId, tglContext); l_contexts.insert(tglContext); -} - -//----------------------------------------------------------------------------- - -void SceneViewer::setShowPerspectiveGrids(bool show) { - m_showPerspectiveGrids = show; - ShowPerspectiveGrids = show ? 1 : 0; } \ No newline at end of file diff --git a/toonz/sources/toonz/sceneviewer.h b/toonz/sources/toonz/sceneviewer.h index 8fe727a1..dfaad18c 100644 --- a/toonz/sources/toonz/sceneviewer.h +++ b/toonz/sources/toonz/sceneviewer.h @@ -167,7 +167,6 @@ class SceneViewer final : public GLWidgetForHighDpi, TRectD m_clipRect; bool m_isPicking; - bool m_showPerspectiveGrids = true; bool m_canShowPerspectiveGrids = false; TRaster32P m_3DSideL; @@ -266,9 +265,6 @@ public: m_vRuler = v; m_hRuler = h; } - bool getShowPerspectiveGrids() { return m_showPerspectiveGrids; } - void setShowPerspectiveGrids(bool show); - bool getCanShowPerspectiveGrids() { return m_canShowPerspectiveGrids; } bool is3DView() const override; TDimension getViewportSize() const { return TDimension(width(), height()); } diff --git a/toonz/sources/toonz/sceneviewercontextmenu.cpp b/toonz/sources/toonz/sceneviewercontextmenu.cpp index 292f2acb..a86112a2 100644 --- a/toonz/sources/toonz/sceneviewercontextmenu.cpp +++ b/toonz/sources/toonz/sceneviewercontextmenu.cpp @@ -137,13 +137,6 @@ SceneViewerContextMenu::SceneViewerContextMenu(SceneViewer *parent) if (Preferences::instance()->isOnionSkinEnabled() && !parent->isPreviewEnabled()) OnioniSkinMaskGUI::addOnionSkinCommand(this); - if (parent->getCanShowPerspectiveGrids()) { - action = new QAction(tr("Toggle Perspective Grid"), this); - connect(action, &QAction::triggered, [=]() { - parent->setShowPerspectiveGrids(!parent->getShowPerspectiveGrids()); - }); - addAction(action); - } if (tool->getTargetType() & TTool::VectorImage) { auto addOptionAction = [](const QString &label, const int data, diff --git a/toonz/sources/toonz/viewerdraw.cpp b/toonz/sources/toonz/viewerdraw.cpp index a8e58d9b..8486881d 100644 --- a/toonz/sources/toonz/viewerdraw.cpp +++ b/toonz/sources/toonz/viewerdraw.cpp @@ -52,6 +52,13 @@ TEnv::IntVar HorizontalOffset("HorizontalOffset", 0); TEnv::IntVar VerticalOffset("VerticalOffset", 0); TEnv::IntVar ShowFieldGuide("ShowFieldGuide", 0); TEnv::IntVar GuideOpacity("GuideOpacity", 70); +TEnv::IntVar ShowHorizon("ShowHorizon", 0); +TEnv::IntVar HorizonAngle("HorizonAngle", 0); +TEnv::IntVar HorizonStep("HorizonStep", 5); +TEnv::IntVar HorizonOffset("HorizonOffset", 0); +TEnv::IntVar ShowVanishingPointRays("ShowVanishingPointRays", 1); +TEnv::IntVar VanishingPointRayAngles("VanishingPointRayAngles", 10); +TEnv::IntVar VanishingPointRayOpacity("VanishingPointRayOpacity", 80); /* TODO, move to include */ void getSafeAreaSizeList(QList> &_sizeList); @@ -395,6 +402,8 @@ void ViewerDraw::drawGridAndGuides(SceneViewer *viewer, double sc, Ruler *vr, void ViewerDraw::drawPerspectiveGuides(SceneViewer *viewer, double sc, std::vector assistantPoints) { + + if (ShowVanishingPointRays == 0) return; int x1, x2, y1, y2; viewer->rect().getCoords(&x1, &y1, &x2, &y2); TRect clipRect = TRect(x1, y1, x2 + 1, y2 + 1); @@ -441,7 +450,7 @@ void ViewerDraw::drawPerspectiveGuides(SceneViewer *viewer, double sc, TPointD p = assistantPoints.at(j); if (j < 5) glColor4d(reds.at(j), greens.at(j), blues.at(j), - (double)GuideOpacity / 100.0); + (double)VanishingPointRayOpacity / 100.0); TPointD end; double distanceToLeft = std::abs(p.x - bounds.x0); double distanceToRight = std::abs(p.x - bounds.x1); @@ -451,7 +460,7 @@ void ViewerDraw::drawPerspectiveGuides(SceneViewer *viewer, double sc, double yDistance = std::max(distanceToTop, distanceToBottom); double totalDistance = std::sqrt(std::pow(xDistance, 2) + std::pow(yDistance, 2)); - for (int i = 0; i < 360; i += 5) { + for (int i = 0; i < 360; i += VanishingPointRayAngles) { double yLength = std::sin(i * (3.14159 / 180)) * totalDistance; double xLength = std::cos(i * (3.14159 / 180)) * totalDistance; end.x = p.x + xLength; @@ -781,6 +790,37 @@ void ViewerDraw::drawGridsAndOverlays(SceneViewer *viewer, double pixelSize) { } } + if (ShowHorizon) { + double theta = (double)HorizonAngle * (3.14159 / 180); + double step = HorizonStep; + double run = std::cos(theta) * step; + double rise = std::sin(theta) * step; + double slope = rise / run; + double distance = step; + { + // find the first y value + double startY = (slope * bounds.x0) + (HorizonOffset / Stage::standardDpi * Stage::inch); + double endY = (slope * bounds.x1) + (HorizonOffset / Stage::standardDpi * Stage::inch); + + if (slope == 0.0) { + startY = (rect.y0 + ((rect.y1 - rect.y0) / 2)) + (HorizonOffset / Stage::standardDpi * Stage::inch); + endY = startY; + } + + double i = 1.5; + while (endY > bounds.y0 || startY > bounds.y0) { + glBegin(GL_LINES); + glVertex2d(bounds.x0, startY); + glVertex2d(bounds.x1, endY); + glEnd(); + endY -= distance / Stage::standardDpi * Stage::inch; + startY -= distance / Stage::standardDpi * Stage::inch; + distance += step * i; + step = step * i; + } + } + } + if (ShowIsometricGrid) { double rightTheta = (double)IsometricRightAngle * (3.14159 / 180); double rightStep = IsometricRightStep;