Merge branch 'master' into nodeview-redux
This commit is contained in:
@@ -60,10 +60,19 @@ void ColorPreviewBox::paintEvent(QPaintEvent *e)
|
||||
|
||||
QPainter p(this);
|
||||
|
||||
QRect draw_rect = rect().adjusted(0, 0, -1, -1);
|
||||
|
||||
p.setPen(Qt::black);
|
||||
|
||||
if (color_.alpha() < 1.0) {
|
||||
// Draw black background so the background isn't the window color
|
||||
p.setBrush(Qt::black);
|
||||
p.drawRect(draw_rect);
|
||||
}
|
||||
|
||||
// Draw with color over the top
|
||||
p.setBrush(c);
|
||||
|
||||
p.drawRect(rect().adjusted(0, 0, -1, -1));
|
||||
p.drawRect(draw_rect);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,13 @@ namespace olive {
|
||||
PixelSamplerWidget::PixelSamplerWidget(QWidget *parent) :
|
||||
QGroupBox(parent)
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
|
||||
box_ = new ColorPreviewBox();
|
||||
QFontMetrics fm = fontMetrics();
|
||||
int box_sz = fm.height() * 2;
|
||||
box_->setFixedSize(box_sz, box_sz);
|
||||
layout->addWidget(box_);
|
||||
|
||||
label_ = new QLabel();
|
||||
layout->addWidget(label_);
|
||||
@@ -45,6 +51,8 @@ void PixelSamplerWidget::SetValues(const Color &color)
|
||||
|
||||
void PixelSamplerWidget::UpdateLabelInternal()
|
||||
{
|
||||
box_->SetColor(color_);
|
||||
|
||||
label_->setText(tr("<html>"
|
||||
"<font color='#FF8080'>R: %1</font><br>"
|
||||
"<font color='#80FF80'>G: %2</font><br>"
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "render/color.h"
|
||||
#include "widget/colorwheel/colorpreviewbox.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -43,6 +44,8 @@ private:
|
||||
|
||||
Color color_;
|
||||
|
||||
ColorPreviewBox *box_;
|
||||
|
||||
QLabel* label_;
|
||||
|
||||
};
|
||||
|
||||
@@ -28,23 +28,22 @@ namespace olive {
|
||||
|
||||
ScopeBase::ScopeBase(QWidget* parent) :
|
||||
super(parent),
|
||||
buffer_(nullptr)
|
||||
texture_(nullptr),
|
||||
managed_tex_up_to_date_(false)
|
||||
{
|
||||
EnableDefaultContextMenu();
|
||||
}
|
||||
|
||||
void ScopeBase::SetBuffer(Frame *frame)
|
||||
void ScopeBase::SetBuffer(TexturePtr frame)
|
||||
{
|
||||
buffer_ = frame;
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
texture_ = frame;
|
||||
managed_tex_up_to_date_ = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void ScopeBase::showEvent(QShowEvent* e)
|
||||
{
|
||||
super::showEvent(e);
|
||||
|
||||
UploadTextureFromBuffer();
|
||||
}
|
||||
|
||||
void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
|
||||
@@ -58,32 +57,6 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
|
||||
VideoParams::kInternalChannelCount));
|
||||
}
|
||||
|
||||
void ScopeBase::UploadTextureFromBuffer()
|
||||
{
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer_) {
|
||||
makeCurrent();
|
||||
|
||||
if (!texture_ || texture_->params() != buffer_->video_params()) {
|
||||
texture_ = nullptr;
|
||||
managed_tex_ = nullptr;
|
||||
|
||||
texture_ = renderer()->CreateTexture(buffer_->video_params(),
|
||||
buffer_->data(), buffer_->linesize_pixels());
|
||||
managed_tex_ = renderer()->CreateTexture(buffer_->video_params());
|
||||
} else {
|
||||
texture_->Upload(buffer_->data(), buffer_->linesize_pixels());
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ScopeBase::OnInit()
|
||||
{
|
||||
super::OnInit();
|
||||
@@ -96,13 +69,13 @@ void ScopeBase::OnPaint()
|
||||
// Clear display surface
|
||||
renderer()->ClearDestination();
|
||||
|
||||
if (buffer_) {
|
||||
if (texture_) {
|
||||
// Convert reference frame to display space
|
||||
if (!texture_ || !managed_tex_) {
|
||||
UploadTextureFromBuffer();
|
||||
makeCurrent(); // UploadTextureFromBuffer calls "doneCurrent", so we re-call "makeCurrent"
|
||||
if (!managed_tex_ || !managed_tex_up_to_date_
|
||||
|| managed_tex_->params() != texture_->params()) {
|
||||
managed_tex_ = renderer()->CreateTexture(texture_->params());
|
||||
renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get());
|
||||
}
|
||||
renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get());
|
||||
|
||||
DrawScope(managed_tex_, pipeline_);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
MANAGEDDISPLAYWIDGET_DEFAULT_DESTRUCTOR(ScopeBase)
|
||||
|
||||
public slots:
|
||||
void SetBuffer(Frame* frame);
|
||||
void SetBuffer(TexturePtr frame);
|
||||
|
||||
protected slots:
|
||||
virtual void OnInit() override;
|
||||
@@ -57,15 +57,13 @@ protected:
|
||||
virtual void DrawScope(TexturePtr managed_tex, QVariant pipeline);
|
||||
|
||||
private:
|
||||
void UploadTextureFromBuffer();
|
||||
|
||||
QVariant pipeline_;
|
||||
|
||||
TexturePtr texture_;
|
||||
|
||||
TexturePtr managed_tex_;
|
||||
|
||||
Frame* buffer_;
|
||||
bool managed_tex_up_to_date_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -463,7 +463,6 @@ public:
|
||||
Q_ASSERT(i == 0 || time > times_.at(i-1));
|
||||
|
||||
QVector<Block*> splits(blocks_.size());
|
||||
commands_.resize(blocks_.size());
|
||||
|
||||
for (int j=0;j<blocks_.size();j++) {
|
||||
Block* b = blocks_.at(j);
|
||||
@@ -472,7 +471,7 @@ public:
|
||||
BlockSplitCommand* split_command = new BlockSplitCommand(b, time);
|
||||
split_command->redo();
|
||||
splits.replace(j, split_command->new_block());
|
||||
commands_.replace(j, split_command);
|
||||
commands_.append(split_command);
|
||||
} else {
|
||||
splits.replace(j, nullptr);
|
||||
}
|
||||
@@ -2045,8 +2044,8 @@ public:
|
||||
}
|
||||
|
||||
foreach (auto add_gap, gaps_added_) {
|
||||
add_gap.gap->setParent(add_gap.before->parent());
|
||||
add_gap.before->track()->InsertBlockAfter(add_gap.gap, add_gap.before);
|
||||
add_gap.gap->setParent(add_gap.track->parent());
|
||||
add_gap.track->InsertBlockAfter(add_gap.gap, add_gap.before);
|
||||
}
|
||||
|
||||
foreach (Track* track, working_tracks_) {
|
||||
@@ -2121,6 +2120,7 @@ private:
|
||||
|
||||
QVector<Block*> blocks_to_split;
|
||||
QVector<Block*> blocks_to_append_gap_to;
|
||||
QVector<Track*> tracks_to_append_gap_to;
|
||||
|
||||
foreach (Track* track, working_tracks_) {
|
||||
foreach (Block* b, track->Blocks()) {
|
||||
@@ -2129,11 +2129,24 @@ private:
|
||||
gaps_to_extend_.append(b);
|
||||
break;
|
||||
} else if (dynamic_cast<ClipBlock*>(b) && b->out() >= point_) {
|
||||
if (b->out() > point_) {
|
||||
bool append_gap = true;
|
||||
|
||||
if (b->in() == point_) {
|
||||
// The only reason we should be here is if this block is at the start of the track,
|
||||
// in which case no split needs to occur
|
||||
b = nullptr;
|
||||
} else if (b->out() > point_) {
|
||||
// Block must be split as well as having a gap appended to it
|
||||
blocks_to_split.append(b);
|
||||
} else if (!b->next()) {
|
||||
// At the end of a track, no gap needs to be added at all
|
||||
append_gap = false;
|
||||
}
|
||||
|
||||
blocks_to_append_gap_to.append(b);
|
||||
if (append_gap) {
|
||||
tracks_to_append_gap_to.append(track);
|
||||
blocks_to_append_gap_to.append(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2143,11 +2156,11 @@ private:
|
||||
split_command_ = new BlockSplitPreservingLinksCommand(blocks_to_split, {point_});
|
||||
}
|
||||
|
||||
foreach (Block* block, blocks_to_append_gap_to) {
|
||||
for (int i=0; i<blocks_to_append_gap_to.size(); i++) {
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length_and_media_out(length_);
|
||||
gap->setParent(&memory_manager_);
|
||||
gaps_added_.append({gap, block});
|
||||
gaps_added_.append({gap, blocks_to_append_gap_to.at(i), tracks_to_append_gap_to.at(i)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2166,6 +2179,7 @@ private:
|
||||
struct AddGap {
|
||||
GapBlock* gap;
|
||||
Block* before;
|
||||
Track* track;
|
||||
};
|
||||
|
||||
QVector<AddGap> gaps_added_;
|
||||
|
||||
@@ -56,8 +56,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
color_menu_enabled_(true),
|
||||
time_changed_from_timer_(false),
|
||||
prequeuing_(false),
|
||||
last_loaded_buffer_(nullptr),
|
||||
last_loaded_buffer_is_empty_(false),
|
||||
active_queue_jobs_(0),
|
||||
cache_time_(rational::NaN)
|
||||
{
|
||||
@@ -83,6 +81,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
connect(display_widget_, &ViewerDisplayWidget::DragEntered, this, &ViewerWidget::DragEntered);
|
||||
connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped);
|
||||
connect(display_widget_, &ViewerDisplayWidget::VisibilityChanged, this, &ViewerWidget::Pause);
|
||||
connect(display_widget_, &ViewerDisplayWidget::TextureChanged, this, &ViewerWidget::TextureChanged);
|
||||
connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom);
|
||||
connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate);
|
||||
connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove);
|
||||
@@ -249,7 +248,7 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
|
||||
disconnect(n->audio_playback_cache(), &AudioPlaybackCache::Validated, this, &ViewerWidget::AudioCacheValidated);
|
||||
disconnect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateStack);
|
||||
|
||||
SetDisplayImage(nullptr);
|
||||
SetDisplayImage(QVariant());
|
||||
|
||||
ruler()->SetPlaybackCache(nullptr);
|
||||
|
||||
@@ -351,7 +350,7 @@ void ViewerWidget::SetFullScreen(QScreen *screen)
|
||||
vw->display_widget()->SetDeinterlacing(vw->display_widget()->IsDeinterlacing());
|
||||
}
|
||||
|
||||
vw->display_widget()->SetImage(last_loaded_buffer_);
|
||||
vw->display_widget()->SetImage(QVariant::fromValue(display_widget()->GetCurrentTexture()));
|
||||
|
||||
windows_.insert(screen, vw);
|
||||
}
|
||||
@@ -420,33 +419,10 @@ bool ViewerWidget::ShouldForceWaveform() const
|
||||
|
||||
void ViewerWidget::SetEmptyImage()
|
||||
{
|
||||
FramePtr frame = nullptr;
|
||||
display_widget()->SetBlank();
|
||||
|
||||
if (GetConnectedNode()) {
|
||||
frame = last_loaded_buffer_;
|
||||
|
||||
if (!frame) {
|
||||
frame = Frame::Create();
|
||||
}
|
||||
|
||||
if (frame->video_params() != GetConnectedNode()->GetVideoParams()) {
|
||||
frame->destroy();
|
||||
frame->set_video_params(GetConnectedNode()->GetVideoParams());
|
||||
}
|
||||
|
||||
if (!frame->is_allocated()) {
|
||||
frame->allocate();
|
||||
}
|
||||
|
||||
if (!last_loaded_buffer_is_empty_) {
|
||||
memset(frame->data(), 0, frame->allocated_size());
|
||||
}
|
||||
}
|
||||
|
||||
SetDisplayImage(frame);
|
||||
|
||||
if (frame) {
|
||||
last_loaded_buffer_is_empty_ = true;
|
||||
foreach (ViewerWindow *vw, windows_) {
|
||||
vw->display_widget()->SetBlank();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,6 +530,7 @@ void ViewerWidget::UpdateTextureFromNode()
|
||||
} else {
|
||||
// Not playing, run a task to get the frame either from the cache or the renderer
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
watcher->setProperty("time", QVariant::fromValue(time));
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
|
||||
nonqueue_watchers_.append(watcher);
|
||||
watcher->SetTicket(GetFrame(time, true));
|
||||
@@ -723,7 +700,7 @@ bool ViewerWidget::ViewerMightBeAStill()
|
||||
return GetConnectedNode() && GetConnectedNode()->GetConnectedTextureOutput().IsValid() && GetConnectedNode()->GetVideoLength().isNull();
|
||||
}
|
||||
|
||||
void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
|
||||
void ViewerWidget::SetDisplayImage(QVariant frame, bool main_only)
|
||||
{
|
||||
display_widget_->SetImage(frame);
|
||||
|
||||
@@ -732,10 +709,6 @@ void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
|
||||
vw->display_widget()->SetImage(frame);
|
||||
}
|
||||
}
|
||||
|
||||
last_loaded_buffer_ = frame;
|
||||
last_loaded_buffer_is_empty_ = false;
|
||||
emit LoadedBuffer(frame.get());
|
||||
}
|
||||
|
||||
void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
|
||||
@@ -749,6 +722,7 @@ void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
|
||||
}
|
||||
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
watcher->setProperty("time", QVariant::fromValue(next_time));
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
|
||||
watcher->SetTicket(GetFrame(next_time, prioritize));
|
||||
active_queue_jobs_++;
|
||||
@@ -886,8 +860,6 @@ void ViewerWidget::RendererGeneratedFrame()
|
||||
RenderTicketWatcher* ticket = static_cast<RenderTicketWatcher*>(sender());
|
||||
|
||||
if (ticket->HasResult()) {
|
||||
FramePtr frame = ticket->Get().value<FramePtr>();
|
||||
|
||||
if (nonqueue_watchers_.contains(ticket)) {
|
||||
while (!nonqueue_watchers_.isEmpty()) {
|
||||
if (nonqueue_watchers_.takeFirst() == ticket) {
|
||||
@@ -895,7 +867,7 @@ void ViewerWidget::RendererGeneratedFrame()
|
||||
}
|
||||
}
|
||||
|
||||
SetDisplayImage(frame);
|
||||
SetDisplayImage(ticket->Get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,14 +879,16 @@ void ViewerWidget::RendererGeneratedFrameForQueue()
|
||||
RenderTicketWatcher* watcher = static_cast<RenderTicketWatcher*>(sender());
|
||||
|
||||
if (watcher->HasResult()) {
|
||||
FramePtr frame = watcher->Get().value<FramePtr>();
|
||||
QVariant frame = watcher->Get();
|
||||
|
||||
// Ignore this signal if we've paused now
|
||||
if (IsPlaying() || prequeuing_) {
|
||||
playback_queue_.AppendTimewise({frame->timestamp(), frame}, playback_speed_);
|
||||
rational ts = watcher->property("time").value<rational>();
|
||||
|
||||
playback_queue_.AppendTimewise({ts, frame}, playback_speed_);
|
||||
|
||||
foreach (ViewerWindow* window, windows_) {
|
||||
window->queue()->AppendTimewise({frame->timestamp(), frame}, playback_speed_);
|
||||
window->queue()->AppendTimewise({ts, frame}, playback_speed_);
|
||||
}
|
||||
|
||||
if (prequeuing_ && int(playback_queue_.size()) == prequeue_length_) {
|
||||
|
||||
@@ -128,7 +128,7 @@ signals:
|
||||
/**
|
||||
* @brief Signal emitted when a new frame is loaded
|
||||
*/
|
||||
void LoadedBuffer(Frame* load_buffer);
|
||||
void TextureChanged(TexturePtr t);
|
||||
|
||||
/**
|
||||
* @brief Request a scope panel
|
||||
@@ -185,7 +185,7 @@ private:
|
||||
|
||||
bool ViewerMightBeAStill();
|
||||
|
||||
void SetDisplayImage(FramePtr frame, bool main_only = false);
|
||||
void SetDisplayImage(QVariant frame, bool main_only = false);
|
||||
|
||||
void RequestNextFrameForQueue(bool prioritize = false, bool increment = true);
|
||||
|
||||
@@ -251,9 +251,6 @@ private:
|
||||
|
||||
QTimer audio_restart_timer_;
|
||||
|
||||
FramePtr last_loaded_buffer_;
|
||||
bool last_loaded_buffer_is_empty_;
|
||||
|
||||
int active_queue_jobs_;
|
||||
|
||||
rational cache_time_;
|
||||
|
||||
@@ -45,13 +45,12 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
|
||||
signal_cursor_color_(false),
|
||||
gizmos_(nullptr),
|
||||
gizmo_click_(false),
|
||||
last_loaded_buffer_(nullptr),
|
||||
hand_dragging_(false),
|
||||
deinterlace_(false),
|
||||
show_fps_(false),
|
||||
frames_skipped_(0),
|
||||
show_widget_background_(false),
|
||||
texture_equal_to_frame_(false)
|
||||
push_mode_(kPushNull)
|
||||
{
|
||||
connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::UpdateCursor);
|
||||
|
||||
@@ -100,17 +99,26 @@ void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
|
||||
inner_widget()->setMouseTracking(e);
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
|
||||
void ViewerDisplayWidget::SetImage(const QVariant &buffer)
|
||||
{
|
||||
if (last_loaded_buffer_ != in_buffer) {
|
||||
last_loaded_buffer_ = in_buffer;
|
||||
load_frame_ = buffer;
|
||||
|
||||
texture_equal_to_frame_ = false;
|
||||
if (load_frame_.isNull()) {
|
||||
push_mode_ = kPushNull;
|
||||
} else {
|
||||
push_mode_ = kPushFrame;
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetBlank()
|
||||
{
|
||||
push_mode_ = kPushBlank;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ViewerDisplayWidget::SetDeinterlacing(bool e)
|
||||
{
|
||||
deinterlace_ = e;
|
||||
@@ -318,51 +326,73 @@ void ViewerDisplayWidget::OnPaint()
|
||||
{
|
||||
// Clear background to empty
|
||||
QColor bg_color = show_widget_background_ ? palette().window().color() : Qt::black;
|
||||
renderer()->ClearDestination(bg_color.redF(), bg_color.greenF(), bg_color.blueF());
|
||||
renderer()->ClearDestination(nullptr, bg_color.redF(), bg_color.greenF(), bg_color.blueF());
|
||||
|
||||
// We only draw if we have a pipeline
|
||||
if (last_loaded_buffer_ && color_service()) {
|
||||
if (!texture_
|
||||
|| texture_->width() != last_loaded_buffer_->width()
|
||||
|| texture_->height() != last_loaded_buffer_->height()
|
||||
|| texture_->format() != last_loaded_buffer_->format()
|
||||
|| texture_->channel_count() != last_loaded_buffer_->channel_count()) {
|
||||
texture_ = renderer()->CreateTexture(last_loaded_buffer_->video_params(), last_loaded_buffer_->data(), last_loaded_buffer_->linesize_pixels());
|
||||
} else if (!texture_equal_to_frame_) {
|
||||
texture_->Upload(last_loaded_buffer_->data(), last_loaded_buffer_->linesize_pixels());
|
||||
}
|
||||
texture_equal_to_frame_ = true;
|
||||
|
||||
TexturePtr texture_to_draw = texture_;
|
||||
|
||||
if (deinterlace_) {
|
||||
if (deinterlace_shader_.isNull()) {
|
||||
deinterlace_shader_ = renderer()->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace.frag"))));
|
||||
}
|
||||
|
||||
if (!deinterlace_texture_
|
||||
|| deinterlace_texture_->params() != texture_to_draw->params()) {
|
||||
// (Re)create texture
|
||||
deinterlace_texture_ = renderer()->CreateTexture(texture_to_draw->params());
|
||||
}
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw)));
|
||||
|
||||
renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get());
|
||||
|
||||
texture_to_draw = deinterlace_texture_;
|
||||
}
|
||||
|
||||
if (push_mode_ != kPushNull) {
|
||||
// Draw texture through color transform
|
||||
int device_width = width() * devicePixelRatioF();
|
||||
int device_height = height() * devicePixelRatioF();
|
||||
VideoParams::Format device_format = static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt());
|
||||
VideoParams device_params(device_width, device_height, device_format, VideoParams::kInternalChannelCount);
|
||||
|
||||
renderer()->BlitColorManaged(color_service(), texture_to_draw, true, device_params, false,
|
||||
combined_matrix_flipped_, crop_matrix_);
|
||||
if (push_mode_ == kPushBlank) {
|
||||
if (blank_shader_.isNull()) {
|
||||
blank_shader_ = renderer()->CreateNativeShader(ShaderCode());
|
||||
}
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, combined_matrix_flipped_));
|
||||
job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix_));
|
||||
|
||||
renderer()->Blit(blank_shader_, job, device_params, false);
|
||||
} else if (color_service()) {
|
||||
if (FramePtr frame = load_frame_.value<FramePtr>()) {
|
||||
// This is a CPU frame, upload it now
|
||||
if (!texture_
|
||||
|| texture_->renderer() != renderer() // Some implementations don't like it if we upload to a texture created in another (albeit shared) context
|
||||
|| texture_->width() != frame->width()
|
||||
|| texture_->height() != frame->height()
|
||||
|| texture_->format() != frame->format()
|
||||
|| texture_->channel_count() != frame->channel_count()) {
|
||||
texture_ = renderer()->CreateTexture(frame->video_params(), frame->data(), frame->linesize_pixels());
|
||||
} else {
|
||||
texture_->Upload(frame->data(), frame->linesize_pixels());
|
||||
}
|
||||
} else if (TexturePtr texture = load_frame_.value<TexturePtr>()) {
|
||||
// This is a GPU texture, switch to it directly
|
||||
texture_ = texture;
|
||||
}
|
||||
|
||||
emit TextureChanged(texture_);
|
||||
|
||||
push_mode_ = kPushUnnecessary;
|
||||
|
||||
TexturePtr texture_to_draw = texture_;
|
||||
|
||||
if (deinterlace_) {
|
||||
if (deinterlace_shader_.isNull()) {
|
||||
deinterlace_shader_ = renderer()->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace.frag"))));
|
||||
}
|
||||
|
||||
if (!deinterlace_texture_
|
||||
|| deinterlace_texture_->params() != texture_to_draw->params()) {
|
||||
// (Re)create texture
|
||||
deinterlace_texture_ = renderer()->CreateTexture(texture_to_draw->params());
|
||||
}
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw)));
|
||||
|
||||
renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get());
|
||||
|
||||
texture_to_draw = deinterlace_texture_;
|
||||
}
|
||||
|
||||
renderer()->BlitColorManaged(color_service(), texture_to_draw, true, device_params, false,
|
||||
combined_matrix_flipped_, crop_matrix_);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw gizmos if we have any
|
||||
@@ -452,12 +482,20 @@ void ViewerDisplayWidget::OnPaint()
|
||||
|
||||
void ViewerDisplayWidget::OnDestroy()
|
||||
{
|
||||
renderer()->DestroyNativeShader(deinterlace_shader_);
|
||||
deinterlace_shader_.clear();
|
||||
renderer()->DestroyNativeShader(blank_shader_);
|
||||
blank_shader_.clear();
|
||||
|
||||
super::OnDestroy();
|
||||
|
||||
texture_ = nullptr;
|
||||
deinterlace_texture_ = nullptr;
|
||||
if (load_frame_.isNull()) {
|
||||
push_mode_ = kPushNull;
|
||||
} else {
|
||||
push_mode_ = kPushFrame;
|
||||
}
|
||||
}
|
||||
|
||||
QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos)
|
||||
@@ -542,12 +580,11 @@ void ViewerDisplayWidget::EmitColorAtCursor(QMouseEvent *e)
|
||||
if (signal_cursor_color_) {
|
||||
Color reference, display;
|
||||
|
||||
if (last_loaded_buffer_) {
|
||||
if (texture_) {
|
||||
QPointF pixel_pos = GenerateGizmoTransform().inverted().map(e->pos());
|
||||
pixel_pos /= texture_->params().divider();
|
||||
|
||||
pixel_pos /= last_loaded_buffer_->video_params().divider();
|
||||
|
||||
reference = last_loaded_buffer_->get_pixel(qRound(pixel_pos.x()), qRound(pixel_pos.y()));
|
||||
reference = renderer()->GetPixelFromTexture(texture_.get(), pixel_pos);
|
||||
display = color_service()->ConvertColor(reference);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,11 @@ public:
|
||||
fps_timer_update_count_++;
|
||||
}
|
||||
|
||||
TexturePtr GetCurrentTexture() const
|
||||
{
|
||||
return texture_;
|
||||
}
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Set the transformation matrix to draw with
|
||||
@@ -126,13 +131,9 @@ public slots:
|
||||
*/
|
||||
void SetSignalCursorColorEnabled(bool e);
|
||||
|
||||
/**
|
||||
* @brief Overrides the image with the load buffer of another ViewerGLWidget
|
||||
*
|
||||
* If there are multiple ViewerGLWidgets showing the same thing, this is faster than decoding the image from file
|
||||
* each time.
|
||||
*/
|
||||
void SetImage(FramePtr in_buffer);
|
||||
void SetImage(const QVariant &buffer);
|
||||
|
||||
void SetBlank();
|
||||
|
||||
/**
|
||||
* @brief Changes the pointer type if the tool is changed to the hand tool. Otherwise resets the pointer to it's
|
||||
@@ -181,6 +182,8 @@ signals:
|
||||
|
||||
void VisibilityChanged(bool visible);
|
||||
|
||||
void TextureChanged(TexturePtr texture);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Override the mouse press event for the DragStarted() signal and gizmos
|
||||
@@ -249,6 +252,11 @@ private:
|
||||
*/
|
||||
QVariant deinterlace_shader_;
|
||||
|
||||
/**
|
||||
* @brief Blank shader
|
||||
*/
|
||||
QVariant blank_shader_;
|
||||
|
||||
/**
|
||||
* @brief Translation only matrix (defaults to identity).
|
||||
*/
|
||||
@@ -283,8 +291,6 @@ private:
|
||||
|
||||
rational time_;
|
||||
|
||||
FramePtr last_loaded_buffer_;
|
||||
|
||||
/**
|
||||
* @brief Position of mouse to calculate delta from.
|
||||
*/
|
||||
@@ -304,7 +310,23 @@ private:
|
||||
|
||||
bool show_widget_background_;
|
||||
|
||||
bool texture_equal_to_frame_;
|
||||
QVariant load_frame_;
|
||||
|
||||
enum PushMode {
|
||||
/// New frame to push to internal texture
|
||||
kPushFrame,
|
||||
|
||||
/// Internal texture reference is up to date, keep showing it
|
||||
kPushUnnecessary,
|
||||
|
||||
/// Draw blank/black screen
|
||||
kPushBlank,
|
||||
|
||||
/// Draw nothing (not even a black frame)
|
||||
kPushNull,
|
||||
};
|
||||
|
||||
PushMode push_mode_;
|
||||
|
||||
private slots:
|
||||
void EmitColorAtCursor(QMouseEvent* e);
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace olive {
|
||||
|
||||
struct ViewerPlaybackFrame {
|
||||
rational timestamp;
|
||||
FramePtr frame;
|
||||
QVariant frame;
|
||||
};
|
||||
|
||||
class ViewerQueue : public std::list<ViewerPlaybackFrame> {
|
||||
|
||||
Reference in New Issue
Block a user