From 14bf515d3f00e6bb76c8fb94686261c4758d254a Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 1 Oct 2022 16:57:46 -0700 Subject: [PATCH] multicam: various improvements --- app/panel/multicam/multicampanel.h | 8 +-- app/panel/viewer/viewerbase.cpp | 1 + app/panel/viewer/viewerbase.h | 11 +++- app/widget/multicam/multicamwidget.cpp | 77 ++++++++++++++++---------- app/widget/multicam/multicamwidget.h | 2 + app/widget/viewer/viewer.cpp | 63 ++++++++++++++++++--- app/widget/viewer/viewer.h | 23 +++++++- app/window/mainwindow/mainwindow.cpp | 63 ++------------------- app/window/mainwindow/mainwindow.h | 4 -- 9 files changed, 142 insertions(+), 110 deletions(-) diff --git a/app/panel/multicam/multicampanel.h b/app/panel/multicam/multicampanel.h index 86137f2bd..ffa9616d0 100644 --- a/app/panel/multicam/multicampanel.h +++ b/app/panel/multicam/multicampanel.h @@ -14,13 +14,11 @@ public: MulticamWidget *GetMulticamWidget() const { return static_cast(GetTimeBasedWidget()); } - void SetMulticamNode(MultiCamNode *n) +public slots: + void SetMulticamNode(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip) { + ConnectViewerNode(viewer); GetMulticamWidget()->SetMulticamNode(n); - } - - void SetClip(ClipBlock* clip) - { GetMulticamWidget()->SetClip(clip); } diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index 5d1bf7b95..ac575699e 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -100,6 +100,7 @@ void ViewerPanelBase::SetViewerWidget(ViewerWidget *vw) connect(vw, &ViewerWidget::TextureChanged, this, &ViewerPanelBase::TextureChanged); connect(vw, &ViewerWidget::ColorProcessorChanged, this, &ViewerPanelBase::ColorProcessorChanged); connect(vw, &ViewerWidget::ColorManagerChanged, this, &ViewerPanelBase::ColorManagerChanged); + connect(vw, &ViewerWidget::MulticamNodeDetected, this, &ViewerPanelBase::MulticamNodeDetected); SetTimeBasedWidget(vw); } diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index feaf4045e..41925a537 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -72,9 +72,14 @@ public: GetViewerWidget()->AddPlaybackDevice(vw); } - void SetMulticamNode(MultiCamNode *n) + void SetTimelineSelectedBlocks(const QVector &b) { - GetViewerWidget()->SetMulticamNode(n); + GetViewerWidget()->SetTimelineSelectedBlocks(b); + } + + void ConnectMulticamPanel(MulticamPanel *p) + { + GetViewerWidget()->ConnectMulticamPanel(p); } public slots: @@ -105,6 +110,8 @@ signals: */ void ColorManagerChanged(ColorManager* color_manager); + void MulticamNodeDetected(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip); + protected: void SetViewerWidget(ViewerWidget *vw); diff --git a/app/widget/multicam/multicamwidget.cpp b/app/widget/multicam/multicamwidget.cpp index 3ac92c20e..9d77b6a7c 100644 --- a/app/widget/multicam/multicamwidget.cpp +++ b/app/widget/multicam/multicamwidget.cpp @@ -19,6 +19,7 @@ ***/ #include "multicamwidget.h" +#include "qshortcut.h" #include "widget/nodeparamview/nodeparamviewundo.h" #include "widget/timeruler/timeruler.h" #include "widget/timelinewidget/undo/timelineundosplit.h" @@ -48,6 +49,11 @@ MulticamWidget::MulticamWidget(QWidget *parent) : layout->addWidget(this->ruler()); layout->addWidget(this->scrollbar()); + + for (int i=0; i<9; i++) { + new QShortcut(QStringLiteral("Ctrl+%1").arg(QString::number(i+1)), this, this, [this, i]{Switch(i, false);}); + new QShortcut(QString::number(i+1), this, this, [this, i]{Switch(i, true);}); + } } void MulticamWidget::SetMulticamNode(MultiCamNode *n) @@ -77,6 +83,45 @@ void MulticamWidget::DisconnectNodeEvent(ViewerOutput *n) disconnect(n, &ViewerOutput::PixelAspectChanged, sizer_, &ViewerSizer::SetPixelAspectRatio); } +void MulticamWidget::Switch(int source, bool split_clip) +{ + if (!node_) { + return; + } + + MultiUndoCommand *command = new MultiUndoCommand(); + + MultiCamNode *cam = node_; + ClipBlock *clip = clip_; + + if (clip_ && split_clip && clip_->in() < GetTime() && clip_->out() > GetTime()) { + QVector blocks; + + blocks.append(clip_); + blocks.append(clip_->block_links()); + + auto split = new BlockSplitPreservingLinksCommand(blocks, {GetTime()}); + split->redo_now(); + command->add_child(split); + + clip = static_cast(split->GetSplit(clip_, 0)); + + cam = clip->FindMulticam(); + } + + command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(NodeInput(cam, cam->kCurrentInput)), source)); + Core::instance()->undo_stack()->push(command); + + if (cam != node_) { + SetMulticamNode(cam); + } + if (clip != clip_) { + SetClip(clip); + } + + display_->update(); +} + void MulticamWidget::DisplayClicked(const QPoint &p) { if (!node_) { @@ -99,37 +144,9 @@ void MulticamWidget::DisplayClicked(const QPoint &p) int c = click.x() / (width/multi); int r = click.y() / (height/multi); - MultiUndoCommand *command = new MultiUndoCommand(); + int source = node_->RowsColsToIndex(r, c, rows, cols); - const bool enable_split = true; - - MultiCamNode *cam = node_; - ClipBlock *clip = clip_; - - if (clip_ && enable_split && clip_->in() < GetTime() && clip_->out() > GetTime()) { - QVector blocks; - - blocks.append(clip_); - blocks.append(clip_->block_links()); - - auto split = new BlockSplitPreservingLinksCommand(blocks, {GetTime()}); - split->redo_now(); - command->add_child(split); - - clip = static_cast(split->GetSplit(clip_, 0)); - - cam = clip->FindMulticam(); - } - - command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(NodeInput(cam, cam->kCurrentInput)), cam->RowsColsToIndex(r, c, rows, cols))); - Core::instance()->undo_stack()->push(command); - - if (cam != node_) { - SetMulticamNode(cam); - } - if (clip != clip_) { - SetClip(clip); - } + Switch(source, true); } } diff --git a/app/widget/multicam/multicamwidget.h b/app/widget/multicam/multicamwidget.h index 36380861b..c68b1945a 100644 --- a/app/widget/multicam/multicamwidget.h +++ b/app/widget/multicam/multicamwidget.h @@ -44,6 +44,8 @@ protected: virtual void DisconnectNodeEvent(ViewerOutput *n) override; private: + void Switch(int source, bool split_clip); + ViewerSizer *sizer_; MulticamDisplay *display_; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 7382a2b3f..ac741f9da 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -40,6 +40,8 @@ #include "node/block/gap/gap.h" #include "node/generator/shape/shapenodebase.h" #include "node/project/project.h" +#include "panel/multicam/multicampanel.h" +#include "panel/panelmanager.h" #include "render/rendermanager.h" #include "viewerpreventsleep.h" #include "widget/audiomonitor/audiomonitor.h" @@ -75,7 +77,8 @@ ViewerWidget::ViewerWidget(ViewerDisplayWidget *display, QWidget *parent) : first_requeue_watcher_(nullptr), enable_audio_scrubbing_(true), waveform_mode_(kWFAutomatic), - ignore_scrub_(0) + ignore_scrub_(0), + multicam_panel_(nullptr) { // Set up main layout QVBoxLayout* layout = new QVBoxLayout(this); @@ -604,6 +607,53 @@ void ViewerWidget::SetWaveformMode(WaveformMode wf) UpdateWaveformViewFromMode(); } +void ViewerWidget::DetectMulticamNode(const rational &time) +{ + // Look for multicam node + MultiCamNode *multicam = nullptr; + ClipBlock *clip = nullptr; + + // Faster way to do this + if (multicam_panel_ && multicam_panel_->isVisible()) { + if (Sequence *s = dynamic_cast(GetConnectedNode())) { + // Prefer selected blocks + for (Block *b : timeline_selected_blocks_) { + if (b->range().Contains(time)) { + if ((clip = dynamic_cast(b))) { + if ((multicam = clip->FindMulticam())) { + break; + } + } + } + } + + if (!multicam) { + const QVector &tracks = s->GetTracks(); + for (Track *t : tracks) { + if (t->IsLocked()) { + continue; + } + + Block *b = t->NearestBlockBeforeOrAt(time); + if ((clip = dynamic_cast(b))) { + if ((multicam = clip->FindMulticam())) { + break; + } + } + } + } + } + } + + if (multicam) { + emit MulticamNodeDetected(GetConnectedNode(), multicam, clip); + auto_cacher()->SetMulticamNode(multicam); + } else { + auto_cacher()->SetMulticamNode(nullptr); + emit MulticamNodeDetected(nullptr, nullptr, nullptr); + } +} + void ViewerWidget::UpdateWaveformViewFromMode() { bool prefer_waveform = ShouldForceWaveform(); @@ -790,6 +840,8 @@ void ViewerWidget::UpdateTextureFromNode() // Clear queue because we want this frame more than any others auto_cacher_->ClearSingleFrameRenders(); + DetectMulticamNode(time); + watcher->SetTicket(GetFrame(time)); } else { // There is definitely no frame here, we can immediately flip to showing nothing @@ -799,14 +851,6 @@ void ViewerWidget::UpdateTextureFromNode() } } -void ViewerWidget::SetMulticamNode(MultiCamNode *n) -{ - auto_cacher()->SetMulticamNode(n); - if (!IsPlaying()) { - UpdateTextureFromNode(); - } -} - void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) { Q_ASSERT(speed != 0); @@ -1035,6 +1079,7 @@ RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(bool increment) watcher = new RenderTicketWatcher(); watcher->setProperty("time", QVariant::fromValue(next_time)); + DetectMulticamNode(next_time); connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue); queue_watchers_.append(watcher); watcher->SetTicket(GetFrame(next_time)); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 5acff6cc3..35ce4147a 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -43,6 +43,8 @@ namespace olive { +class MulticamPanel; + /** * @brief An OpenGL-based viewer widget with playback controls (a PlaybackControls widget). */ @@ -109,7 +111,18 @@ public: playback_devices_.push_back(vw); } - void SetMulticamNode(MultiCamNode *n); + void SetTimelineSelectedBlocks(const QVector &b) + { + timeline_selected_blocks_ = b; + + if (!IsPlaying()) { + // If is playing, this will happen by the next frame automatically + DetectMulticamNode(GetTime()); + UpdateTextureFromNode(); + } + } + + void ConnectMulticamPanel(MulticamPanel *p) { multicam_panel_ = p; } public slots: void Play(bool in_to_out_only); @@ -167,6 +180,8 @@ signals: */ void ColorManagerChanged(ColorManager* color_manager); + void MulticamNodeDetected(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip); + protected: ViewerWidget(ViewerDisplayWidget *display, QWidget* parent = nullptr); @@ -256,6 +271,8 @@ private: void SetWaveformMode(WaveformMode wf); + void DetectMulticamNode(const rational &time); + ViewerSizer* sizer_; int playback_speed_; @@ -324,6 +341,10 @@ private: int ignore_scrub_; + QVector timeline_selected_blocks_; + + MulticamPanel *multicam_panel_; + private slots: void PlaybackTimerUpdate(); diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 256f6abab..813bab9aa 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -38,8 +38,7 @@ namespace olive { MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - last_multicam_panel_(nullptr) + QMainWindow(parent) { // Resizes main window to desktop geometry on startup. Fixes the following issues: // * Qt on Windows has a bug that "de-maximizes" the window when widgets are added, resizing the @@ -119,6 +118,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(PanelManager::instance(), &PanelManager::FocusedPanelChanged, this, &MainWindow::FocusedPanelChanged); sequence_viewer_panel_->AddPlaybackDevice(multicam_panel_->GetMulticamWidget()->GetDisplayWidget()); + sequence_viewer_panel_->ConnectMulticamPanel(multicam_panel_); + connect(sequence_viewer_panel_, &ViewerPanelBase::MulticamNodeDetected, multicam_panel_, &MulticamPanel::SetMulticamNode); scope_panel_->SetViewerPanel(sequence_viewer_panel_); @@ -492,58 +493,7 @@ void MainWindow::TimelinePanelSelectionChanged(const QVector &blocks) if (PanelManager::instance()->CurrentlyFocused(false) == panel) { UpdateNodePanelContextFromTimelinePanel(panel); - - last_multicam_panel_ = panel; - UpdateMulticamNode(); - } -} - -void MainWindow::UpdateMulticamNode() -{ - TimelinePanel *panel = last_multicam_panel_; - if (!panel) { - return; - } - - ClipBlock *clip = nullptr; - MultiCamNode *multicam = nullptr; - - for (Block *b : panel->GetSelectedBlocks()) { - if (b->range().Contains(panel->GetTime())) { - if ((clip = dynamic_cast(b))) { - if ((multicam = clip->FindMulticam())) { - break; - } - } - } - } - - if (!multicam && panel->GetSequence()) { - const QVector &tracks = panel->GetSequence()->GetTracks(); - for (Track *t : tracks) { - if (t->IsLocked()) { - continue; - } - - Block *b = t->NearestBlockBeforeOrAt(panel->GetTime()); - if ((clip = dynamic_cast(b))) { - if ((multicam = clip->FindMulticam())) { - break; - } - } - } - } - - if (multicam) { - multicam_panel_->SetMulticamNode(multicam); - sequence_viewer_panel_->SetMulticamNode(multicam); - multicam_panel_->SetClip(clip); - multicam_panel_->ConnectViewerNode(panel->GetConnectedViewer()); - } else { - multicam_panel_->ConnectViewerNode(nullptr); - sequence_viewer_panel_->SetMulticamNode(nullptr); - multicam_panel_->SetMulticamNode(nullptr); - multicam_panel_->SetClip(nullptr); + sequence_viewer_panel_->SetTimelineSelectedBlocks(blocks); } } @@ -659,8 +609,6 @@ void MainWindow::UpdateMainTimePanels(const rational &r) p->SetTime(r); } } - - UpdateMulticamNode(); } TimelinePanel* MainWindow::AppendTimelinePanel() @@ -693,9 +641,6 @@ ProjectPanel *MainWindow::AppendProjectPanel() void MainWindow::RemoveTimelinePanel(TimelinePanel *panel) { // Stop showing this timeline in the viewer - if (last_multicam_panel_ == panel) { - last_multicam_panel_ = nullptr; - } TimelineFocused(nullptr); panel->ConnectViewerNode(nullptr); diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index 7b0e8979c..7f319e4b1 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -147,8 +147,6 @@ private: void SelectFootageForProjectPanel(const QVector &e, ProjectPanel *p); - void UpdateMulticamNode(); - void AddMainTimePanel(TimeBasedPanel *p); QByteArray premaximized_state_; @@ -180,8 +178,6 @@ private: QVector main_time_panels_; - TimelinePanel *last_multicam_panel_; - private slots: void FocusedPanelChanged(PanelWidget* panel);