Merge branch 'master' into multicam

This commit is contained in:
itsmattkc
2022-09-25 16:39:03 -07:00
100 changed files with 2450 additions and 977 deletions
+1 -3
View File
@@ -64,8 +64,6 @@ QString PanNode::Description() const
void PanNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
Q_UNUSED(globals)
// Create a sample job
SampleBuffer samples = value[kSamplesInput].toSamples();
if (samples.is_allocated()) {
@@ -85,7 +83,7 @@ void PanNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV
table->Push(NodeValue(NodeValue::kSamples, samples, this));
} else {
// Requires job
table->Push(NodeValue::kSamples, SampleJob(kSamplesInput, value), this);
table->Push(NodeValue::kSamples, SampleJob(globals.time(), kSamplesInput, value), this);
}
} else {
// Pass right through
+1 -3
View File
@@ -63,8 +63,6 @@ QString VolumeNode::Description() const
void VolumeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
Q_UNUSED(globals)
// Create a sample job
SampleBuffer buffer = value[kSamplesInput].toSamples();
@@ -80,7 +78,7 @@ void VolumeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, No
table->Push(NodeValue::kSamples, QVariant::fromValue(buffer), this);
} else {
// Requires job
SampleJob job(kSamplesInput, value);
SampleJob job(globals.time(), kSamplesInput, value);
job.Insert(kVolumeInput, value);
table->Push(NodeValue::kSamples, QVariant::fromValue(job), this);
}
@@ -56,9 +56,9 @@ ShaderCode DipToColorTransition::GetShaderCode(const ShaderRequest &request) con
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/diptoblack.frag"), QString());
}
void DipToColorTransition::ShaderJobEvent(const NodeValueRow &value, ShaderJob &job) const
void DipToColorTransition::ShaderJobEvent(const NodeValueRow &value, ShaderJob *job) const
{
job.Insert(kColorInput, value);
job->Insert(kColorInput, value);
}
}
@@ -43,7 +43,7 @@ public:
static const QString kColorInput;
protected:
virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const override;
virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob *job) const override;
};
+2 -2
View File
@@ -182,10 +182,10 @@ void TransitionBlock::Value(const NodeValueRow &value, const NodeGlobals &global
double time = globals.time().in().toDouble();
InsertTransitionTimes(&job, time);
ShaderJobEvent(value, job);
ShaderJobEvent(value, &job);
job_type = NodeValue::kTexture;
push_job = QVariant::fromValue(job);
push_job = QVariant::fromValue(Texture::Job(globals.vparams(), job));
} else if (data_type == NodeValue::kSamples) {
// This must be an audio transition
SampleBuffer from_samples = out_buffer.toSamples();
+1 -1
View File
@@ -73,7 +73,7 @@ public:
static const QString kCenterInput;
protected:
virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob& job) const {}
virtual void ShaderJobEvent(const NodeValueRow &value, ShaderJob *job) const {}
virtual void SampleJobEvent(const SampleBuffer &from_samples, const SampleBuffer &to_samples, SampleBuffer &out_samples, double time_in) const {}
+5 -3
View File
@@ -60,13 +60,15 @@ void OCIOBaseNode::RemovedFromGraph()
void OCIOBaseNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
if (value[kTextureInput].toTexture() && processor_) {
auto tex_met = value[kTextureInput];
TexturePtr t = tex_met.toTexture();
if (t && processor_) {
ColorTransformJob job;
job.SetColorProcessor(processor_);
job.SetInputTexture(value[kTextureInput].toTexture());
job.SetInputTexture(tex_met);
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
table->Push(NodeValue::kTexture, t->toJob(job), this);
}
}
@@ -155,50 +155,50 @@ void OCIOGradingTransformLinearNode::GenerateProcessor()
void OCIOGradingTransformLinearNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
if (value[kTextureInput].toTexture() && processor()) {
ColorTransformJob job;
if (TexturePtr tex = value[kTextureInput].toTexture()) {
if (processor()) {
ColorTransformJob job(value);
job.SetColorProcessor(processor());
job.SetInputTexture(value[kTextureInput].toTexture());
job.SetColorProcessor(processor());
job.SetInputTexture(value[kTextureInput]);
job.Insert(value);
const int MASTER_CHANNEL = 0;
const int RED_CHANNEL = 1;
const int GREEN_CHANNEL = 2;
const int BLUE_CHANNEL = 3;
const int MASTER_CHANNEL = 0;
const int RED_CHANNEL = 1;
const int GREEN_CHANNEL = 2;
const int BLUE_CHANNEL = 3;
// Oddly, OCIO uses RGBMs when setting the GradingPrimary on the CPU, but uses vec3s on the GPU.
// Even more oddly, the conversion from RGBM to vec3 does not appear to have a public API.
// Therefore, this code has been duplicated from OCIO here:
// https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/3abbe5b20521169580fcfe3692aca81859859953/src/OpenColorIO/ops/gradingprimary/GradingPrimary.cpp#L157
QVector4D offset = value[kOffsetInput].toVec4();
offset[RED_CHANNEL] += offset[MASTER_CHANNEL];
offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL];
offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL];
job.Insert(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL])));
// Oddly, OCIO uses RGBMs when setting the GradingPrimary on the CPU, but uses vec3s on the GPU.
// Even more oddly, the conversion from RGBM to vec3 does not appear to have a public API.
// Therefore, this code has been duplicated from OCIO here:
// https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/3abbe5b20521169580fcfe3692aca81859859953/src/OpenColorIO/ops/gradingprimary/GradingPrimary.cpp#L157
QVector4D offset = value[kOffsetInput].toVec4();
offset[RED_CHANNEL] += offset[MASTER_CHANNEL];
offset[GREEN_CHANNEL] += offset[MASTER_CHANNEL];
offset[BLUE_CHANNEL] += offset[MASTER_CHANNEL];
job.Insert(kOffsetInput, NodeValue(NodeValue::kVec3, QVector3D(offset[RED_CHANNEL], offset[GREEN_CHANNEL], offset[BLUE_CHANNEL])));
QVector4D exposure = value[kExposureInput].toVec4();
exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]);
exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]);
exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]);
job.Insert(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL])));
QVector4D exposure = value[kExposureInput].toVec4();
exposure[RED_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[RED_CHANNEL]);
exposure[GREEN_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[GREEN_CHANNEL]);
exposure[BLUE_CHANNEL] = std::pow(2.0f, exposure[MASTER_CHANNEL] + exposure[BLUE_CHANNEL]);
job.Insert(kExposureInput, NodeValue(NodeValue::kVec3, QVector3D(exposure[RED_CHANNEL], exposure[GREEN_CHANNEL], exposure[BLUE_CHANNEL])));
QVector4D contrast = value[kContrastInput].toVec4();
contrast[RED_CHANNEL] *= contrast[MASTER_CHANNEL];
contrast[GREEN_CHANNEL] *= contrast[MASTER_CHANNEL];
contrast[BLUE_CHANNEL] *= contrast[MASTER_CHANNEL];
job.Insert(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL])));
QVector4D contrast = value[kContrastInput].toVec4();
contrast[RED_CHANNEL] *= contrast[MASTER_CHANNEL];
contrast[GREEN_CHANNEL] *= contrast[MASTER_CHANNEL];
contrast[BLUE_CHANNEL] *= contrast[MASTER_CHANNEL];
job.Insert(kContrastInput, NodeValue(NodeValue::kVec3, QVector3D(contrast[RED_CHANNEL], contrast[GREEN_CHANNEL], contrast[BLUE_CHANNEL])));
if (!value[kClampBlackEnableInput].toBool()) {
job.Insert(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack()));
}
if (!value[kClampBlackEnableInput].toBool()) {
job.Insert(kClampBlackInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampBlack()));
if (!value[kClampWhiteEnableInput].toBool()) {
job.Insert(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite()));
}
table->Push(NodeValue::kTexture, tex->toJob(job), this);
}
if (!value[kClampWhiteEnableInput].toBool()) {
job.Insert(kClampWhiteInput, NodeValue(NodeValue::kFloat, OCIO::GradingPrimary::NoClampWhite()));
}
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
}
}
+4
View File
@@ -18,7 +18,11 @@ add_subdirectory(cornerpin)
add_subdirectory(crop)
add_subdirectory(flip)
add_subdirectory(mask)
add_subdirectory(ripple)
add_subdirectory(swirl)
add_subdirectory(tile)
add_subdirectory(transform)
add_subdirectory(wave)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
@@ -69,40 +69,39 @@ void CornerPinDistortNode::Retranslate()
void CornerPinDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this));
// Convert slider values to their pixel values and then convert to clip space (-1.0 ... 1.0) for overriding the
// vertex coordinates.
const QVector2D &resolution = globals.resolution();
QVector2D half_resolution = resolution * 0.5;
QVector2D top_left = QVector2D(ValueToPixel(0, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
QVector2D top_right = QVector2D(ValueToPixel(1, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
QVector2D bottom_right = QVector2D(ValueToPixel(2, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
QVector2D bottom_left = QVector2D(ValueToPixel(3, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
// Override default vertex coordinates.
QVector<float> adjusted_vertices = {top_left.x(), top_left.y(), 0.0f,
top_right.x(), top_right.y(), 0.0f,
bottom_right.x(), bottom_right.y(), 0.0f,
top_left.x(), top_left.y(), 0.0f,
bottom_left.x(), bottom_left.y(), 0.0f,
bottom_right.x(), bottom_right.y(), 0.0f};
job.SetVertexCoordinates(adjusted_vertices);
// If no texture do nothing
if (job.Get(kTextureInput).toTexture()) {
if (TexturePtr tex = value[kTextureInput].toTexture()) {
// In the special case that all sliders are in their default position just
// push the texture.
if (!(job.Get(kTopLeftInput).toVec2().isNull()
&& job.Get(kTopRightInput).toVec2().isNull() &&
job.Get(kBottomRightInput).toVec2().isNull() &&
job.Get(kBottomLeftInput).toVec2().isNull())) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (!(value[kTopLeftInput].toVec2().isNull()
&& value[kTopRightInput].toVec2().isNull() &&
value[kBottomRightInput].toVec2().isNull() &&
value[kBottomLeftInput].toVec2().isNull())) {
ShaderJob job(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this));
// Convert slider values to their pixel values and then convert to clip space (-1.0 ... 1.0) for overriding the
// vertex coordinates.
const QVector2D &resolution = tex->virtual_resolution();
QVector2D half_resolution = resolution * 0.5;
QVector2D top_left = QVector2D(ValueToPixel(0, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
QVector2D top_right = QVector2D(ValueToPixel(1, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
QVector2D bottom_right = QVector2D(ValueToPixel(2, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
QVector2D bottom_left = QVector2D(ValueToPixel(3, value, resolution)) / half_resolution - QVector2D(1.0, 1.0);
// Override default vertex coordinates.
QVector<float> adjusted_vertices = {top_left.x(), top_left.y(), 0.0f,
top_right.x(), top_right.y(), 0.0f,
bottom_right.x(), bottom_right.y(), 0.0f,
top_left.x(), top_left.y(), 0.0f,
bottom_left.x(), bottom_left.y(), 0.0f,
bottom_right.x(), bottom_right.y(), 0.0f};
job.SetVertexCoordinates(adjusted_vertices);
table->Push(NodeValue::kTexture, tex->toJob(job), this);
} else {
table->Push(job.Get(kTextureInput));
table->Push(value[kTextureInput]);
}
}
}
@@ -151,27 +150,29 @@ void CornerPinDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardM
void CornerPinDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals)
{
const QVector2D &resolution = globals.resolution();
if (TexturePtr tex = row[kTextureInput].toTexture()) {
const QVector2D &resolution = tex->virtual_resolution();
QPointF top_left = ValueToPixel(0, row, resolution);
QPointF top_right = ValueToPixel(1, row, resolution);
QPointF bottom_right = ValueToPixel(2, row, resolution);
QPointF bottom_left = ValueToPixel(3, row, resolution);
QPointF top_left = ValueToPixel(0, row, resolution);
QPointF top_right = ValueToPixel(1, row, resolution);
QPointF bottom_right = ValueToPixel(2, row, resolution);
QPointF bottom_left = ValueToPixel(3, row, resolution);
// Add the correct offset to each slider
SetInputProperty(kTopLeftInput, QStringLiteral("offset"), QVector2D(0.0, 0.0));
SetInputProperty(kTopRightInput, QStringLiteral("offset"), QVector2D(resolution.x() , 0.0));
SetInputProperty(kBottomRightInput, QStringLiteral("offset"), resolution);
SetInputProperty(kBottomLeftInput, QStringLiteral("offset"), QVector2D(0.0, resolution.y()));
// Add the correct offset to each slider
SetInputProperty(kTopLeftInput, QStringLiteral("offset"), QVector2D(0.0, 0.0));
SetInputProperty(kTopRightInput, QStringLiteral("offset"), QVector2D(resolution.x() , 0.0));
SetInputProperty(kBottomRightInput, QStringLiteral("offset"), resolution);
SetInputProperty(kBottomLeftInput, QStringLiteral("offset"), QVector2D(0.0, resolution.y()));
// Draw bounding box
gizmo_whole_rect_->SetPolygon(QPolygonF({top_left, top_right, bottom_right, bottom_left, top_left}));
// Draw bounding box
gizmo_whole_rect_->SetPolygon(QPolygonF({top_left, top_right, bottom_right, bottom_left, top_left}));
// Create handles
gizmo_resize_handle_[0]->SetPoint(top_left);
gizmo_resize_handle_[1]->SetPoint(top_right);
gizmo_resize_handle_[2]->SetPoint(bottom_right);
gizmo_resize_handle_[3]->SetPoint(bottom_left);
// Create handles
gizmo_resize_handle_[0]->SetPoint(top_left);
gizmo_resize_handle_[1]->SetPoint(top_right);
gizmo_resize_handle_[2]->SetPoint(bottom_right);
gizmo_resize_handle_[3]->SetPoint(bottom_left);
}
}
}
+21 -19
View File
@@ -79,7 +79,6 @@ void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global
{
ShaderJob job;
job.Insert(value);
job.SetWillChangeImageSize(false);
if (TexturePtr texture = job.Get(kTextureInput).toTexture()) {
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture->params().width(), texture->params().height()), this));
@@ -88,7 +87,7 @@ void CropDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global
|| !qIsNull(job.Get(kRightInput).toDouble())
|| !qIsNull(job.Get(kTopInput).toDouble())
|| !qIsNull(job.Get(kBottomInput).toDouble())) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
table->Push(NodeValue::kTexture, texture->toJob(job), this);
} else {
table->Push(job.Get(kTextureInput));
}
@@ -103,32 +102,35 @@ ShaderCode CropDistortNode::GetShaderCode(const ShaderRequest &request) const
void CropDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals)
{
const QVector2D &resolution = globals.resolution();
if (TexturePtr tex = row[kTextureInput].toTexture()) {
const QVector2D &resolution = tex->virtual_resolution();
temp_resolution_ = resolution;
double left_pt = resolution.x() * row[kLeftInput].toDouble();
double top_pt = resolution.y() * row[kTopInput].toDouble();
double right_pt = resolution.x() * (1.0 - row[kRightInput].toDouble());
double bottom_pt = resolution.y() * (1.0 - row[kBottomInput].toDouble());
double center_x_pt = mid(left_pt, right_pt);
double center_y_pt = mid(top_pt, bottom_pt);
double left_pt = resolution.x() * row[kLeftInput].toDouble();
double top_pt = resolution.y() * row[kTopInput].toDouble();
double right_pt = resolution.x() * (1.0 - row[kRightInput].toDouble());
double bottom_pt = resolution.y() * (1.0 - row[kBottomInput].toDouble());
double center_x_pt = mid(left_pt, right_pt);
double center_y_pt = mid(top_pt, bottom_pt);
point_gizmo_[kGizmoScaleTopLeft]->SetPoint(QPointF(left_pt, top_pt));
point_gizmo_[kGizmoScaleTopCenter]->SetPoint(QPointF(center_x_pt, top_pt));
point_gizmo_[kGizmoScaleTopRight]->SetPoint(QPointF(right_pt, top_pt));
point_gizmo_[kGizmoScaleBottomLeft]->SetPoint(QPointF(left_pt, bottom_pt));
point_gizmo_[kGizmoScaleBottomCenter]->SetPoint(QPointF(center_x_pt, bottom_pt));
point_gizmo_[kGizmoScaleBottomRight]->SetPoint(QPointF(right_pt, bottom_pt));
point_gizmo_[kGizmoScaleCenterLeft]->SetPoint(QPointF(left_pt, center_y_pt));
point_gizmo_[kGizmoScaleCenterRight]->SetPoint(QPointF(right_pt, center_y_pt));
point_gizmo_[kGizmoScaleTopLeft]->SetPoint(QPointF(left_pt, top_pt));
point_gizmo_[kGizmoScaleTopCenter]->SetPoint(QPointF(center_x_pt, top_pt));
point_gizmo_[kGizmoScaleTopRight]->SetPoint(QPointF(right_pt, top_pt));
point_gizmo_[kGizmoScaleBottomLeft]->SetPoint(QPointF(left_pt, bottom_pt));
point_gizmo_[kGizmoScaleBottomCenter]->SetPoint(QPointF(center_x_pt, bottom_pt));
point_gizmo_[kGizmoScaleBottomRight]->SetPoint(QPointF(right_pt, bottom_pt));
point_gizmo_[kGizmoScaleCenterLeft]->SetPoint(QPointF(left_pt, center_y_pt));
point_gizmo_[kGizmoScaleCenterRight]->SetPoint(QPointF(right_pt, center_y_pt));
poly_gizmo_->SetPolygon(QRectF(left_pt, top_pt, right_pt - left_pt, bottom_pt - top_pt));
poly_gizmo_->SetPolygon(QRectF(left_pt, top_pt, right_pt - left_pt, bottom_pt - top_pt));
}
}
void CropDistortNode::GizmoDragMove(double x_diff, double y_diff, const Qt::KeyboardModifiers &modifiers)
{
DraggableGizmo *gizmo = static_cast<DraggableGizmo*>(sender());
QVector2D res = gizmo->GetGlobals().resolution();
QVector2D res = temp_resolution_;
x_diff /= res.x();
y_diff /= res.y();
+1
View File
@@ -82,6 +82,7 @@ private:
// Gizmo variables
PointGizmo *point_gizmo_[kGizmoScaleCount];
PolygonGizmo *poly_gizmo_;
QVector2D temp_resolution_;
};
+5 -10
View File
@@ -77,21 +77,16 @@ ShaderCode FlipDistortNode::GetShaderCode(const ShaderRequest &request) const
void FlipDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
// If there's no texture, no need to run an operation
if (job.Get(kTextureInput).toTexture()) {
if (TexturePtr tex = value[kTextureInput].toTexture()) {
// Only run shader if at least one of flip or flop are selected
if (job.Get(kHorizontalInput).toBool() || job.Get(kVerticalInput).toBool()) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (value[kHorizontalInput].toBool() || value[kVerticalInput].toBool()) {
table->Push(NodeValue::kTexture, tex->toJob(ShaderJob(value)), this);
} else {
// If we're not flipping or flopping just push the texture
table->Push(job.Get(kTextureInput));
// If we're not flipping or flopping just push the texture
table->Push(value[kTextureInput]);
}
}
}
}
+25 -7
View File
@@ -27,12 +27,15 @@ namespace olive {
#define super PolygonGenerator
const QString MaskDistortNode::kFeatherInput = QStringLiteral("feather_in");
const QString MaskDistortNode::kInvertInput = QStringLiteral("invert_in");
MaskDistortNode::MaskDistortNode()
{
// Mask should always be (1.0, 1.0, 1.0) for multiply to work correctly
SetInputFlags(kColorInput, InputFlags(GetInputFlags(kColorInput) | kInputFlagHidden));
AddInput(kInvertInput, NodeValue::kBoolean, false);
AddInput(kFeatherInput, NodeValue::kFloat, 0.0);
SetInputProperty(kFeatherInput, QStringLiteral("min"), 0.0);
}
@@ -43,6 +46,8 @@ ShaderCode MaskDistortNode::GetShaderCode(const ShaderRequest &request) const
return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/multiply.frag")));
} else if (request.id == QStringLiteral("feather")) {
return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/blur.frag")));
} else if (request.id == QStringLiteral("invert")) {
return ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/invertrgb.frag")));
} else {
return super::GetShaderCode(request);
}
@@ -53,14 +58,25 @@ void MaskDistortNode::Retranslate()
super::Retranslate();
SetInputName(kBaseInput, tr("Texture"));
SetInputName(kInvertInput, tr("Invert"));
SetInputName(kFeatherInput, tr("Feather"));
}
void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job = GetGenerateJob(value);
TexturePtr texture = value[kBaseInput].toTexture();
if (value[kBaseInput].toTexture()) {
VideoParams job_params = texture ? texture->params() : globals.vparams();
NodeValue job(NodeValue::kTexture, Texture::Job(job_params, GetGenerateJob(value, job_params)), this);
if (value[kInvertInput].toBool()) {
ShaderJob invert;
invert.SetShaderID(QStringLiteral("invert"));
invert.Insert(QStringLiteral("tex_in"), job);
job.set_value(Texture::Job(job_params, invert));
}
if (texture) {
// Push as merge node
ShaderJob merge;
@@ -72,21 +88,23 @@ void MaskDistortNode::Value(const NodeValueRow &value, const NodeGlobals &global
ShaderJob feather;
feather.SetShaderID(QStringLiteral("feather"));
feather.Insert(BlurFilterNode::kTextureInput, NodeValue(NodeValue::kTexture, job, this));
feather.Insert(BlurFilterNode::kTextureInput, job);
feather.Insert(BlurFilterNode::kMethodInput, NodeValue(NodeValue::kInt, int(BlurFilterNode::kGaussian), this));
feather.Insert(BlurFilterNode::kHorizInput, NodeValue(NodeValue::kBoolean, true, this));
feather.Insert(BlurFilterNode::kVertInput, NodeValue(NodeValue::kBoolean, true, this));
feather.Insert(BlurFilterNode::kRepeatEdgePixelsInput, NodeValue(NodeValue::kBoolean, true, this));
feather.Insert(BlurFilterNode::kRadiusInput, NodeValue(NodeValue::kFloat, value[kFeatherInput].toDouble(), this));
feather.SetIterations(2, BlurFilterNode::kTextureInput);
feather.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this));
feather.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, texture ? texture->virtual_resolution() : globals.square_resolution(), this));
merge.Insert(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, feather, this));
merge.Insert(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, Texture::Job(job_params, feather), this));
} else {
merge.Insert(QStringLiteral("tex_b"), NodeValue(NodeValue::kTexture, job, this));
merge.Insert(QStringLiteral("tex_b"), job);
}
table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this);
table->Push(NodeValue::kTexture, Texture::Job(job_params, merge), this);
} else {
table->Push(job);
}
}
+1
View File
@@ -59,6 +59,7 @@ public:
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
static const QString kInvertInput;
static const QString kFeatherInput;
};
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2022 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/distort/ripple/rippledistortnode.cpp
node/distort/ripple/rippledistortnode.h
PARENT_SCOPE
)
@@ -0,0 +1,128 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "rippledistortnode.h"
namespace olive {
const QString RippleDistortNode::kTextureInput = QStringLiteral("tex_in");
const QString RippleDistortNode::kEvolutionInput = QStringLiteral("evolution_in");
const QString RippleDistortNode::kIntensityInput = QStringLiteral("intensity_in");
const QString RippleDistortNode::kFrequencyInput = QStringLiteral("frequency_in");
const QString RippleDistortNode::kPositionInput = QStringLiteral("position_in");
const QString RippleDistortNode::kStretchInput = QStringLiteral("stretch_in");
#define super Node
RippleDistortNode::RippleDistortNode()
{
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
AddInput(kEvolutionInput, NodeValue::kFloat, 0);
AddInput(kIntensityInput, NodeValue::kFloat, 100);
AddInput(kFrequencyInput, NodeValue::kFloat, 1);
SetInputProperty(kFrequencyInput, QStringLiteral("base"), 0.01);
AddInput(kPositionInput, NodeValue::kVec2, QVector2D(0, 0));
AddInput(kStretchInput, NodeValue::kBoolean, false);
SetFlags(kVideoEffect);
SetEffectInput(kTextureInput);
gizmo_ = AddDraggableGizmo<PointGizmo>({
NodeKeyframeTrackReference(NodeInput(this, kPositionInput), 0),
NodeKeyframeTrackReference(NodeInput(this, kPositionInput), 1),
});
gizmo_->SetShape(PointGizmo::kAnchorPoint);
}
QString RippleDistortNode::Name() const
{
return tr("Ripple");
}
QString RippleDistortNode::id() const
{
return QStringLiteral("org.oliveeditor.Olive.ripple");
}
QVector<Node::CategoryID> RippleDistortNode::Category() const
{
return {kCategoryDistort};
}
QString RippleDistortNode::Description() const
{
return tr("Distorts an image with a ripple effect.");
}
void RippleDistortNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
SetInputName(kFrequencyInput, tr("Frequency"));
SetInputName(kIntensityInput, tr("Intensity"));
SetInputName(kEvolutionInput, tr("Evolution"));
SetInputName(kPositionInput, tr("Position"));
SetInputName(kStretchInput, tr("Stretch"));
}
ShaderCode RippleDistortNode::GetShaderCode(const ShaderRequest &request) const
{
Q_UNUSED(request)
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/ripple.frag"));
}
void RippleDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
// If there's no texture, no need to run an operation
if (TexturePtr tex = value[kTextureInput].toTexture()) {
// Only run shader if at least one of flip or flop are selected
if (!qIsNull(value[kIntensityInput].toDouble())) {
ShaderJob job(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this));
table->Push(NodeValue::kTexture, tex->toJob(job), this);
} else {
// If we're not flipping or flopping just push the texture
table->Push(value[kTextureInput]);
}
}
}
void RippleDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals)
{
if (TexturePtr tex = row[kTextureInput].toTexture()) {
QPointF half_res(tex->virtual_resolution().x()/2, tex->virtual_resolution().y()/2);
gizmo_->SetPoint(half_res + row[kPositionInput].toVec2().toPointF());
}
}
void RippleDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers)
{
NodeInputDragger &x_drag = gizmo_->GetDraggers()[0];
NodeInputDragger &y_drag = gizmo_->GetDraggers()[1];
x_drag.Drag(x_drag.GetStartValue().toDouble() + x);
y_drag.Drag(y_drag.GetStartValue().toDouble() + y);
}
}
@@ -0,0 +1,66 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef RIPPLEDISTORTNODE_H
#define RIPPLEDISTORTNODE_H
#include "node/gizmo/point.h"
#include "node/node.h"
namespace olive {
class RippleDistortNode : public Node
{
Q_OBJECT
public:
RippleDistortNode();
NODE_DEFAULT_FUNCTIONS(RippleDistortNode)
virtual QString Name() const override;
virtual QString id() const override;
virtual QVector<CategoryID> Category() const override;
virtual QString Description() const override;
virtual void Retranslate() override;
virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override;
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override;
static const QString kTextureInput;
static const QString kEvolutionInput;
static const QString kIntensityInput;
static const QString kFrequencyInput;
static const QString kPositionInput;
static const QString kStretchInput;
protected slots:
virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) override;
private:
PointGizmo *gizmo_;
};
}
#endif // RIPPLEDISTORTNODE_H
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2022 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/distort/swirl/swirldistortnode.cpp
node/distort/swirl/swirldistortnode.h
PARENT_SCOPE
)
+122
View File
@@ -0,0 +1,122 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "swirldistortnode.h"
namespace olive {
const QString SwirlDistortNode::kTextureInput = QStringLiteral("tex_in");
const QString SwirlDistortNode::kRadiusInput = QStringLiteral("radius_in");
const QString SwirlDistortNode::kAngleInput = QStringLiteral("angle_in");
const QString SwirlDistortNode::kPositionInput = QStringLiteral("pos_in");
#define super Node
SwirlDistortNode::SwirlDistortNode()
{
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
AddInput(kRadiusInput, NodeValue::kFloat, 200);
SetInputProperty(kRadiusInput, QStringLiteral("min"), 0);
AddInput(kAngleInput, NodeValue::kFloat, 10);
SetInputProperty(kAngleInput, QStringLiteral("base"), 0.1);
AddInput(kPositionInput, NodeValue::kVec2, QVector2D(0, 0));
SetFlags(kVideoEffect);
SetEffectInput(kTextureInput);
gizmo_ = AddDraggableGizmo<PointGizmo>({
NodeKeyframeTrackReference(NodeInput(this, kPositionInput), 0),
NodeKeyframeTrackReference(NodeInput(this, kPositionInput), 1),
});
gizmo_->SetShape(PointGizmo::kAnchorPoint);
}
QString SwirlDistortNode::Name() const
{
return tr("Swirl");
}
QString SwirlDistortNode::id() const
{
return QStringLiteral("org.oliveeditor.Olive.swirl");
}
QVector<Node::CategoryID> SwirlDistortNode::Category() const
{
return {kCategoryDistort};
}
QString SwirlDistortNode::Description() const
{
return tr("Distorts an image along a sine wave.");
}
void SwirlDistortNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
SetInputName(kRadiusInput, tr("Radius"));
SetInputName(kAngleInput, tr("Angle"));
SetInputName(kPositionInput, tr("Position"));
}
ShaderCode SwirlDistortNode::GetShaderCode(const ShaderRequest &request) const
{
Q_UNUSED(request)
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/swirl.frag"));
}
void SwirlDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
// If there's no texture, no need to run an operation
if (TexturePtr tex = value[kTextureInput].toTexture()) {
// Only run shader if at least one of flip or flop are selected
if (!qIsNull(value[kAngleInput].toDouble()) && !qIsNull(value[kRadiusInput].toDouble())) {
ShaderJob job(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this));
table->Push(NodeValue::kTexture, tex->toJob(job), this);
} else {
// If we're not flipping or flopping just push the texture
table->Push(value[kTextureInput]);
}
}
}
void SwirlDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals)
{
QPointF half_res(globals.square_resolution().x()/2, globals.square_resolution().y()/2);
gizmo_->SetPoint(half_res + row[kPositionInput].toVec2().toPointF());
}
void SwirlDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers)
{
NodeInputDragger &x_drag = gizmo_->GetDraggers()[0];
NodeInputDragger &y_drag = gizmo_->GetDraggers()[1];
x_drag.Drag(x_drag.GetStartValue().toDouble() + x);
y_drag.Drag(y_drag.GetStartValue().toDouble() + y);
}
}
+64
View File
@@ -0,0 +1,64 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef SWIRLDISTORTNODE_H
#define SWIRLDISTORTNODE_H
#include "node/gizmo/point.h"
#include "node/node.h"
namespace olive {
class SwirlDistortNode : public Node
{
Q_OBJECT
public:
SwirlDistortNode();
NODE_DEFAULT_FUNCTIONS(SwirlDistortNode)
virtual QString Name() const override;
virtual QString id() const override;
virtual QVector<CategoryID> Category() const override;
virtual QString Description() const override;
virtual void Retranslate() override;
virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override;
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override;
static const QString kTextureInput;
static const QString kRadiusInput;
static const QString kAngleInput;
static const QString kPositionInput;
protected slots:
virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) override;
private:
PointGizmo *gizmo_;
};
}
#endif // SWIRLDISTORTNODE_H
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2022 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/distort/tile/tiledistortnode.cpp
node/distort/tile/tiledistortnode.h
PARENT_SCOPE
)
+164
View File
@@ -0,0 +1,164 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "tiledistortnode.h"
#include "widget/slider/floatslider.h"
namespace olive {
const QString TileDistortNode::kTextureInput = QStringLiteral("tex_in");
const QString TileDistortNode::kScaleInput = QStringLiteral("scale_in");
const QString TileDistortNode::kPositionInput = QStringLiteral("position_in");
const QString TileDistortNode::kAnchorInput = QStringLiteral("anchor_in");
const QString TileDistortNode::kMirrorXInput = QStringLiteral("mirrorx_in");
const QString TileDistortNode::kMirrorYInput = QStringLiteral("mirrory_in");
#define super Node
TileDistortNode::TileDistortNode()
{
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
AddInput(kScaleInput, NodeValue::kFloat, 0.5);
SetInputProperty(kScaleInput, QStringLiteral("min"), 0);
SetInputProperty(kScaleInput, QStringLiteral("view"), FloatSlider::kPercentage);
AddInput(kPositionInput, NodeValue::kVec2, QVector2D(0, 0));
AddInput(kAnchorInput, NodeValue::kCombo, kMiddleCenter);
AddInput(kMirrorXInput, NodeValue::kBoolean, false);
AddInput(kMirrorYInput, NodeValue::kBoolean, false);
SetFlags(kVideoEffect);
SetEffectInput(kTextureInput);
gizmo_ = AddDraggableGizmo<PointGizmo>({
NodeKeyframeTrackReference(NodeInput(this, kPositionInput), 0),
NodeKeyframeTrackReference(NodeInput(this, kPositionInput), 1),
});
gizmo_->SetShape(PointGizmo::kAnchorPoint);
}
QString TileDistortNode::Name() const
{
return tr("Tile");
}
QString TileDistortNode::id() const
{
return QStringLiteral("org.oliveeditor.Olive.tile");
}
QVector<Node::CategoryID> TileDistortNode::Category() const
{
return {kCategoryDistort};
}
QString TileDistortNode::Description() const
{
return tr("Infinitely tile an image horizontally and vertically.");
}
void TileDistortNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
SetInputName(kScaleInput, tr("Scale"));
SetInputName(kPositionInput, tr("Position"));
SetInputName(kMirrorXInput, tr("Mirror Horizontally"));
SetInputName(kMirrorYInput, tr("Mirror Vertically"));
SetInputName(kAnchorInput, tr("Anchor"));
SetComboBoxStrings(kAnchorInput, {
tr("Top-Left"),
tr("Top-Center"),
tr("Top-Right"),
tr("Middle-Left"),
tr("Middle-Center"),
tr("Middle-Right"),
tr("Bottom-Left"),
tr("Bottom-Center"),
tr("Bottom-Right"),
});
}
ShaderCode TileDistortNode::GetShaderCode(const ShaderRequest &request) const
{
Q_UNUSED(request)
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/tile.frag"));
}
void TileDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
// If there's no texture, no need to run an operation
if (TexturePtr tex = value[kTextureInput].toTexture()) {
// Only run shader if at least one of flip or flop are selected
if (!qFuzzyCompare(value[kScaleInput].toDouble(), 1.0)) {
ShaderJob job(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this));
table->Push(NodeValue::kTexture, tex->toJob(job), this);
} else {
// If we're not flipping or flopping just push the texture
table->Push(value[kTextureInput]);
}
}
}
void TileDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals)
{
if (TexturePtr tex = row[kTextureInput].toTexture()) {
QPointF res = tex->virtual_resolution().toPointF();
QPointF pos = row[kPositionInput].toVec2().toPointF();
qreal x = pos.x();
qreal y = pos.y();
Anchor a = static_cast<Anchor>(row[kAnchorInput].toInt());
if (a == kTopLeft || a == kTopCenter || a == kTopRight) {
// Do nothing
} else if (a == kMiddleLeft || a == kMiddleCenter || a == kMiddleRight) {
y += res.y()/2;
} else if (a == kBottomLeft || a == kBottomCenter || a == kBottomRight) {
y += res.y();
}
if (a == kTopLeft || a == kMiddleLeft || a == kBottomLeft) {
// Do nothing
} else if (a == kTopCenter || a == kMiddleCenter || a == kBottomCenter) {
x += res.x()/2;
} else if (a == kTopRight || a == kMiddleRight || a == kBottomRight) {
x += res.x();
}
gizmo_->SetPoint(QPointF(x, y));
}
}
void TileDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers)
{
NodeInputDragger &x_drag = gizmo_->GetDraggers()[0];
NodeInputDragger &y_drag = gizmo_->GetDraggers()[1];
x_drag.Drag(x_drag.GetStartValue().toDouble() + x);
y_drag.Drag(y_drag.GetStartValue().toDouble() + y);
}
}
+78
View File
@@ -0,0 +1,78 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef TILEDISTORTNODE_H
#define TILEDISTORTNODE_H
#include "node/gizmo/point.h"
#include "node/node.h"
namespace olive {
class TileDistortNode : public Node
{
Q_OBJECT
public:
TileDistortNode();
NODE_DEFAULT_FUNCTIONS(TileDistortNode)
virtual QString Name() const override;
virtual QString id() const override;
virtual QVector<CategoryID> Category() const override;
virtual QString Description() const override;
virtual void Retranslate() override;
virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override;
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override;
static const QString kTextureInput;
static const QString kScaleInput;
static const QString kPositionInput;
static const QString kAnchorInput;
static const QString kMirrorXInput;
static const QString kMirrorYInput;
protected slots:
virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) override;
private:
enum Anchor {
kTopLeft,
kTopCenter,
kTopRight,
kMiddleLeft,
kMiddleCenter,
kMiddleRight,
kBottomLeft,
kBottomCenter,
kBottomRight
};
PointGizmo *gizmo_;
};
}
#endif // TILEDISTORTNODE_H
@@ -89,7 +89,7 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g
// Pop texture
NodeValue texture_meta = value[kTextureInput];
QVariant job_to_push;
TexturePtr job_to_push = nullptr;
// If we have a texture, generate a matrix and make it happen
if (TexturePtr texture = texture_meta.toTexture()) {
@@ -99,17 +99,18 @@ void TransformDistortNode::Value(const NodeValueRow &value, const NodeGlobals &g
if (!real_matrix.isIdentity()) {
// The matrix will transform things
ShaderJob job;
job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture), this));
job.Insert(QStringLiteral("ove_maintex"), texture_meta);
job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, real_matrix, this));
job.SetInterpolation(QStringLiteral("ove_maintex"), static_cast<Texture::Interpolation>(value[kInterpolationInput].toInt()));
job_to_push = QVariant::fromValue(job);
// Use global resolution rather than texture resolution because this may result in a size change
job_to_push = Texture::Job(globals.vparams(), job);
}
}
table->Push(NodeValue::kMatrix, QVariant::fromValue(generated_matrix), this);
if (job_to_push.isNull()) {
if (!job_to_push) {
// Re-push whatever value we received
table->Push(texture_meta);
} else {
@@ -142,7 +143,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou
}
gizmo_scale_uniform_ = row[kUniformScaleInput].toBool();
gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().resolution()/2).toPointF();
gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().nonsquare_resolution()/2).toPointF();
if (gizmo == point_gizmo_[kGizmoScaleTopLeft] || gizmo == point_gizmo_[kGizmoScaleTopRight]
|| gizmo == point_gizmo_[kGizmoScaleBottomLeft] || gizmo == point_gizmo_[kGizmoScaleBottomRight]) {
@@ -177,7 +178,7 @@ void TransformDistortNode::GizmoDragStart(const NodeValueRow &row, double x, dou
} else if (gizmo == rotation_gizmo_) {
gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().resolution()/2).toPointF();
gizmo_anchor_pt_ = (row[kAnchorInput].toVec2() + gizmo->GetGlobals().nonsquare_resolution()/2).toPointF();
gizmo_start_angle_ = qAtan2(y - gizmo_anchor_pt_.y(), x - gizmo_anchor_pt_.x());
gizmo_last_angle_ = gizmo_start_angle_;
gizmo_last_alt_angle_ = qAtan2(x - gizmo_anchor_pt_.x(), y - gizmo_anchor_pt_.y());
@@ -343,7 +344,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N
}
// Get the sequence resolution
const QVector2D &sequence_res = globals.resolution();
const QVector2D &sequence_res = globals.nonsquare_resolution();
QVector2D sequence_half_res = sequence_res * 0.5;
QPointF sequence_half_res_pt = sequence_half_res.toPointF();
@@ -418,7 +419,7 @@ QPointF TransformDistortNode::CreateScalePoint(double x, double y, const QPointF
QMatrix4x4 TransformDistortNode::GenerateAutoScaledMatrix(const QMatrix4x4& generated_matrix, const NodeValueRow& value, const NodeGlobals &globals, const VideoParams& texture_params) const
{
const QVector2D &sequence_res = globals.resolution();
const QVector2D &sequence_res = globals.nonsquare_resolution();
QVector2D texture_res(texture_params.square_pixel_width(), texture_params.height());
AutoScaleType autoscale = static_cast<AutoScaleType>(value[kAutoscaleInput].toInt());
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2022 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/distort/wave/wavedistortnode.cpp
node/distort/wave/wavedistortnode.h
PARENT_SCOPE
)
+100
View File
@@ -0,0 +1,100 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "wavedistortnode.h"
namespace olive {
const QString WaveDistortNode::kTextureInput = QStringLiteral("tex_in");
const QString WaveDistortNode::kFrequencyInput = QStringLiteral("frequency_in");
const QString WaveDistortNode::kIntensityInput = QStringLiteral("intensity_in");
const QString WaveDistortNode::kEvolutionInput = QStringLiteral("evolution_in");
const QString WaveDistortNode::kVerticalInput = QStringLiteral("vertical_in");
#define super Node
WaveDistortNode::WaveDistortNode()
{
AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable));
AddInput(kFrequencyInput, NodeValue::kFloat, 10);
AddInput(kIntensityInput, NodeValue::kFloat, 10);
AddInput(kEvolutionInput, NodeValue::kFloat, 0);
AddInput(kVerticalInput, NodeValue::kCombo, false);
SetFlags(kVideoEffect);
SetEffectInput(kTextureInput);
}
QString WaveDistortNode::Name() const
{
return tr("Wave");
}
QString WaveDistortNode::id() const
{
return QStringLiteral("org.oliveeditor.Olive.wave");
}
QVector<Node::CategoryID> WaveDistortNode::Category() const
{
return {kCategoryDistort};
}
QString WaveDistortNode::Description() const
{
return tr("Distorts an image along a sine wave.");
}
void WaveDistortNode::Retranslate()
{
super::Retranslate();
SetInputName(kTextureInput, tr("Input"));
SetInputName(kFrequencyInput, tr("Frequency"));
SetInputName(kIntensityInput, tr("Intensity"));
SetInputName(kEvolutionInput, tr("Evolution"));
SetInputName(kVerticalInput, tr("Direction"));
SetComboBoxStrings(kVerticalInput, {tr("Horizontal"), tr("Vertical")});
}
ShaderCode WaveDistortNode::GetShaderCode(const ShaderRequest &request) const
{
Q_UNUSED(request)
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/wave.frag"));
}
void WaveDistortNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
// If there's no texture, no need to run an operation
if (TexturePtr texture = value[kTextureInput].toTexture()) {
// Only run shader if at least one of flip or flop are selected
if (!qIsNull(value[kIntensityInput].toDouble())) {
table->Push(NodeValue::kTexture, Texture::Job(texture->params(), ShaderJob(value)), this);
} else {
// If we're not flipping or flopping just push the texture
table->Push(value[kTextureInput]);
}
}
}
}
+56
View File
@@ -0,0 +1,56 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef WAVEDISTORTNODE_H
#define WAVEDISTORTNODE_H
#include "node/node.h"
namespace olive {
class WaveDistortNode : public Node
{
Q_OBJECT
public:
WaveDistortNode();
NODE_DEFAULT_FUNCTIONS(WaveDistortNode)
virtual QString Name() const override;
virtual QString id() const override;
virtual QVector<CategoryID> Category() const override;
virtual QString Description() const override;
virtual void Retranslate() override;
virtual ShaderCode GetShaderCode(const ShaderRequest &request) const override;
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
static const QString kTextureInput;
static const QString kFrequencyInput;
static const QString kIntensityInput;
static const QString kEvolutionInput;
static const QString kVerticalInput;
};
}
#endif // WAVEDISTORTNODE_H
+4 -8
View File
@@ -45,17 +45,13 @@ ShaderCode OpacityEffect::GetShaderCode(const ShaderRequest &request) const
void OpacityEffect::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
// If there's no texture, no need to run an operation
if (job.Get(kTextureInput).toTexture()) {
if (!qFuzzyCompare(job.Get(kValueInput).toDouble(), 1.0)) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (TexturePtr tex = value[kTextureInput].toTexture()) {
if (!qFuzzyCompare(value[kValueInput].toDouble(), 1.0)) {
table->Push(NodeValue::kTexture, tex->toJob(ShaderJob(value)), this);
} else {
// 1.0 float is a no-op, so just push the texture
table->Push(job.Get(kTextureInput));
table->Push(value[kTextureInput]);
}
}
}
+12
View File
@@ -35,7 +35,11 @@
#include "distort/crop/cropdistortnode.h"
#include "distort/flip/flipdistortnode.h"
#include "distort/mask/mask.h"
#include "distort/ripple/rippledistortnode.h"
#include "distort/swirl/swirldistortnode.h"
#include "distort/tile/tiledistortnode.h"
#include "distort/transform/transformdistortnode.h"
#include "distort/wave/wavedistortnode.h"
#include "effect/opacity/opacityeffect.h"
#include "filter/blur/blur.h"
#include "filter/dropshadow/dropshadowfilter.h"
@@ -295,6 +299,14 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
return new DropShadowFilter();
case kTimeFormat:
return new TimeFormatNode();
case kWaveDistort:
return new WaveDistortNode();
case kTileDistort:
return new TileDistortNode();
case kSwirlDistort:
return new SwirlDistortNode();
case kRippleDistort:
return new RippleDistortNode();
case kMulticamNode:
return new MultiCamNode();
+4
View File
@@ -76,6 +76,10 @@ public:
kMaskDistort,
kDropShadowFilter,
kTimeFormat,
kWaveDistort,
kRippleDistort,
kTileDistort,
kSwirlDistort,
kMulticamNode,
// Count value
+22 -22
View File
@@ -120,33 +120,28 @@ ShaderCode BlurFilterNode::GetShaderCode(const ShaderRequest &request) const
void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
// If there's no texture, no need to run an operation
if (value[kTextureInput].toTexture()) {
ShaderJob job;
job.Insert(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this));
Method method = static_cast<Method>(job.Get(kMethodInput).toInt());
if (TexturePtr tex = value[kTextureInput].toTexture()) {
Method method = static_cast<Method>(value[kMethodInput].toInt());
bool can_push_job = true;
int iterations = 1;
// Check if radius is > 0
if (job.Get(kRadiusInput).toDouble() > 0.0) {
if (value[kRadiusInput].toDouble() > 0.0) {
// Method-specific considerations
switch (method) {
case kBox:
case kGaussian:
{
bool horiz = job.Get(kHorizInput).toBool();
bool vert = job.Get(kVertInput).toBool();
bool horiz = value[kHorizInput].toBool();
bool vert = value[kVertInput].toBool();
if (!horiz && !vert) {
// Disable job if horiz and vert are unchecked
can_push_job = false;
} else if (horiz && vert) {
// Set iteration count to 2 if we're blurring both horizontally and vertically
job.SetIterations(2, kTextureInput);
iterations = 2;
}
break;
}
@@ -159,10 +154,13 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals
}
if (can_push_job) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
ShaderJob job(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this));
job.SetIterations(iterations, kTextureInput);
table->Push(NodeValue::kTexture, tex->toJob(job), this);
} else {
// If we're not performing the blur job, just push the texture
table->Push(job.Get(kTextureInput));
table->Push(value[kTextureInput]);
}
}
@@ -170,16 +168,18 @@ void BlurFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals
void BlurFilterNode::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals)
{
if (row[kMethodInput].toInt() == kRadial) {
const QVector2D &sequence_res = globals.resolution();
QVector2D sequence_half_res = sequence_res * 0.5;
if (TexturePtr tex = row[kTextureInput].toTexture()) {
if (row[kMethodInput].toInt() == kRadial) {
const QVector2D &sequence_res = tex->virtual_resolution();
QVector2D sequence_half_res = sequence_res * 0.5;
radial_center_gizmo_->SetVisible(true);
radial_center_gizmo_->SetPoint(sequence_half_res.toPointF() + row[kRadialCenterInput].toVec2().toPointF());
radial_center_gizmo_->SetVisible(true);
radial_center_gizmo_->SetPoint(sequence_half_res.toPointF() + row[kRadialCenterInput].toVec2().toPointF());
SetInputProperty(kRadialCenterInput, QStringLiteral("offset"), sequence_half_res);
} else{
radial_center_gizmo_->SetVisible(false);
SetInputProperty(kRadialCenterInput, QStringLiteral("offset"), sequence_half_res);
} else{
radial_center_gizmo_->SetVisible(false);
}
}
}
@@ -78,20 +78,19 @@ ShaderCode DropShadowFilter::GetShaderCode(const ShaderRequest &request) const
void DropShadowFilter::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
if (value[kTextureInput].toTexture()) {
ShaderJob job;
if (TexturePtr tex = value[kTextureInput].toTexture()) {
ShaderJob job(value);
QString iterative = QStringLiteral("previous_iteration_in");
job.Insert(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this));
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this));
job.Insert(iterative, value[kTextureInput]);
if (!qIsNull(value[kSoftnessInput].toDouble())) {
job.SetIterations(3, iterative);
}
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
table->Push(NodeValue::kTexture, tex->toJob(job), this);
}
}
+10 -14
View File
@@ -53,22 +53,18 @@ void MosaicFilterNode::Retranslate()
void MosaicFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
// Mipmapping makes this look weird, so we just use bilinear for finding the color of each block
job.SetInterpolation(kTextureInput, Texture::kLinear);
if (job.Get(kTextureInput).toTexture()) {
TexturePtr texture = job.Get(kTextureInput).toTexture();
if (TexturePtr texture = value[kTextureInput].toTexture()) {
if (texture
&& job.Get(kHorizInput).toInt() != texture->width()
&& job.Get(kVertInput).toInt() != texture->height()) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
&& value[kHorizInput].toInt() != texture->width()
&& value[kVertInput].toInt() != texture->height()) {
ShaderJob job(value);
// Mipmapping makes this look weird, so we just use bilinear for finding the color of each block
job.SetInterpolation(kTextureInput, Texture::kLinear);
table->Push(NodeValue::kTexture, texture->toJob(job), this);
} else {
table->Push(job.Get(kTextureInput));
table->Push(value[kTextureInput]);
}
}
}
+7 -10
View File
@@ -86,17 +86,14 @@ void StrokeFilterNode::Retranslate()
void StrokeFilterNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this));
if (job.Get(kTextureInput).toTexture()) {
if (job.Get(kRadiusInput).toDouble() > 0.0
&& job.Get(kOpacityInput).toDouble() > 0.0) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (TexturePtr tex = value[kTextureInput].toTexture()) {
if (value[kRadiusInput].toDouble() > 0.0
&& value[kOpacityInput].toDouble() > 0.0) {
ShaderJob job(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, tex->virtual_resolution(), this));
table->Push(NodeValue::kTexture, tex->toJob(job), this);
} else {
table->Push(job.Get(kTextureInput));
table->Push(value[kTextureInput]);
}
}
}
+4 -2
View File
@@ -80,11 +80,13 @@ ShaderCode NoiseGeneratorNode::GetShaderCode(const ShaderRequest &request) const
void NoiseGeneratorNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
ShaderJob job(value);
job.Insert(value);
job.Insert(QStringLiteral("time_in"), NodeValue(NodeValue::kFloat, globals.time().in().toDouble(), this));
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
TexturePtr base = value[kBaseIn].toTexture();
table->Push(NodeValue::kTexture, Texture::Job(base ? base->params() : globals.vparams(), job), this);
}
}
+13 -9
View File
@@ -87,12 +87,11 @@ void PolygonGenerator::Retranslate()
SetInputName(kColorInput, tr("Color"));
}
ShaderJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value) const
ShaderJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value, const VideoParams &params) const
{
GenerateJob job;
job.Insert(value);
job.SetRequestedFormat(VideoParams::kFormatUnsigned8);
VideoParams p = params;
p.set_format(VideoParams::kFormatUnsigned8);
auto job = Texture::Job(p, GenerateJob(value));
// Conversion to RGB
ShaderJob rgb;
@@ -105,9 +104,7 @@ ShaderJob PolygonGenerator::GetGenerateJob(const NodeValueRow &value) const
void PolygonGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job = GetGenerateJob(value);
PushMergableJob(value, QVariant::fromValue(job), table);
PushMergableJob(value, Texture::Job(globals.vparams(), GetGenerateJob(value, globals.vparams())), table);
}
void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) const
@@ -169,7 +166,14 @@ void PolygonGenerator::ValidateGizmoVectorSize(QVector<T*> &vec, int new_sz)
void PolygonGenerator::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals)
{
QPointF half_res(globals.resolution_by_par().x()/2, globals.resolution_by_par().y()/2);
QVector2D res;
if (TexturePtr tex = row[kBaseInput].toTexture()) {
res = tex->virtual_resolution();
} else {
res = globals.square_resolution();
}
QPointF half_res = res.toPointF()/2;
auto points = row[kPointsInput].toArray();
+1 -1
View File
@@ -60,7 +60,7 @@ public:
static const QString kColorInput;
protected:
ShaderJob GetGenerateJob(const NodeValueRow &value) const;
ShaderJob GetGenerateJob(const NodeValueRow &value, const VideoParams &params) const;
protected slots:
virtual void GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) override;
@@ -51,17 +51,17 @@ ShaderCode GeneratorWithMerge::GetShaderCode(const ShaderRequest &request) const
return ShaderCode();
}
void GeneratorWithMerge::PushMergableJob(const NodeValueRow &value, const QVariant &job, NodeValueTable *table) const
void GeneratorWithMerge::PushMergableJob(const NodeValueRow &value, TexturePtr job, NodeValueTable *table) const
{
if (value[kBaseInput].toTexture()) {
if (TexturePtr base = value[kBaseInput].toTexture()) {
// Push as merge node
ShaderJob merge;
merge.SetShaderID(QStringLiteral("mrg"));
merge.Insert(MergeNode::kBaseIn, value[kBaseInput]);
merge.Insert(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, job, this));
merge.Insert(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, base->toJob(*job->job()), this));
table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this);
table->Push(NodeValue::kTexture, base->toJob(merge), this);
} else {
// Just push generate job
table->Push(NodeValue::kTexture, job, this);
@@ -38,7 +38,7 @@ public:
static const QString kBaseInput;
protected:
void PushMergableJob(const NodeValueRow &value, const QVariant &job, NodeValueTable *table) const;
void PushMergableJob(const NodeValueRow &value, TexturePtr job, NodeValueTable *table) const;
};
+5 -4
View File
@@ -77,13 +77,14 @@ ShaderCode ShapeNode::GetShaderCode(const ShaderRequest &request) const
void ShapeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
TexturePtr base = value[kBaseInput].toTexture();
job.Insert(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, globals.resolution(), this));
ShaderJob job(value);
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, base ? base->virtual_resolution() : globals.square_resolution(), this));
job.SetShaderID(QStringLiteral("shape"));
PushMergableJob(value, QVariant::fromValue(job), table);
PushMergableJob(value, Texture::Job(base ? base->params() : globals.vparams(), job), table);
}
void ShapeNode::InputValueChangedEvent(const QString &input, int element)
+2 -2
View File
@@ -77,7 +77,7 @@ void ShapeNodeBase::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlob
{
// Use offsets to make the appearance of values that start in the top left, even though we
// really anchor around the center
QVector2D center_pt = globals.resolution() * 0.5;
QVector2D center_pt = globals.square_resolution() * 0.5;
SetInputProperty(kPositionInput, QStringLiteral("offset"), center_pt);
QVector2D pos = row[kPositionInput].toVec2();
@@ -137,7 +137,7 @@ void ShapeNodeBase::GizmoDragMove(double x, double y, const Qt::KeyboardModifier
QVector2D gizmo_sz_start(w_drag.GetStartValue().toDouble(), h_drag.GetStartValue().toDouble());
QVector2D gizmo_pos_start(x_drag.GetStartValue().toDouble(), y_drag.GetStartValue().toDouble());
QVector2D gizmo_half_res = gizmo->GetGlobals().resolution()/2;
QVector2D gizmo_half_res = gizmo->GetGlobals().square_resolution()/2;
QVector2D adjusted_pt(x, y);
QVector2D new_size;
QVector2D new_pos;
+1 -3
View File
@@ -63,9 +63,7 @@ void SolidGenerator::Retranslate()
void SolidGenerator::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
table->Push(NodeValue::kTexture, Texture::Job(globals.vparams(), ShaderJob(value)), this);
}
ShaderCode SolidGenerator::GetShaderCode(const ShaderRequest &request) const
+2 -5
View File
@@ -92,11 +92,8 @@ void TextGeneratorV1::Retranslate()
void TextGeneratorV1::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
GenerateJob job;
job.Insert(value);
if (!job.Get(kTextInput).toString().isEmpty()) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (!value[kTextInput].toString().isEmpty()) {
table->Push(NodeValue::kTexture, Texture::Job(globals.vparams(), GenerateJob(value)), this);
}
}
+5 -6
View File
@@ -94,12 +94,11 @@ void TextGeneratorV2::Retranslate()
void TextGeneratorV2::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
GenerateJob job;
job.Insert(value);
job.SetRequestedFormat(VideoParams::kFormatFloat32);
if (!job.Get(kTextInput).toString().isEmpty()) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (!value[kTextInput].toString().isEmpty()) {
GenerateJob job(value);
auto text_params = globals.vparams();
text_params.set_format(VideoParams::kFormatFloat32);
table->Push(NodeValue::kTexture, Texture::Job(text_params, job), this);
}
}
+12 -10
View File
@@ -98,9 +98,7 @@ void TextGeneratorV3::Retranslate()
void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
GenerateJob job;
job.Insert(value);
job.SetRequestedFormat(VideoParams::kFormatUnsigned8);
QString text = value[kTextInput].toString();
if (value[kUseArgsInput].toBool()) {
auto args = value[kArgsInput].toArray();
@@ -111,17 +109,21 @@ void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &global
list.append(args[i].toString());
}
NodeValue v = job.Get(kTextInput);
v.set_value(FormatString(v.toString(), list));
job.Insert(kTextInput, v);
text = FormatString(text, list);
}
}
// FIXME: Provide user override for this
job.SetColorspace(project()->color_manager()->GetDefaultInputColorSpace());
if (!text.isEmpty()) {
TexturePtr base = value[kTextInput].toTexture();
if (!job.Get(kTextInput).toString().isEmpty()) {
PushMergableJob(value, QVariant::fromValue(job), table);
VideoParams text_params = base ? base->params() : globals.vparams();
text_params.set_format(VideoParams::kFormatUnsigned8);
text_params.set_colorspace(project()->color_manager()->GetDefaultInputColorSpace());
GenerateJob job(value);
job.Insert(kTextInput, NodeValue(NodeValue::kText, text));
PushMergableJob(value, Texture::Job(text_params, job), table);
} else if (value[kBaseInput].toTexture()) {
table->Push(value[kBaseInput]);
}
+8 -34
View File
@@ -24,6 +24,7 @@
#include <QVector2D>
#include "common/timerange.h"
#include "render/videoparams.h"
namespace olive {
@@ -32,46 +33,19 @@ class NodeGlobals
public:
NodeGlobals(){}
NodeGlobals(const QVector2D &resolution, const rational &pixel_aspect, const TimeRange &time) :
resolution_(resolution),
pixel_aspect_(pixel_aspect),
NodeGlobals(const VideoParams &vparam, const TimeRange &time) :
video_params_(vparam),
time_(time)
{
resolution_by_par_ = QVector2D(resolution_.x() * pixel_aspect_.toDouble(), resolution_.y());
}
const QVector2D &resolution() const
{
return resolution_;
}
const QVector2D &resolution_by_par() const
{
return resolution_by_par_;
}
const rational &pixel_aspect() const
{
return pixel_aspect_;
}
const TimeRange &time() const
{
return time_;
}
void set_time(const TimeRange &time)
{
time_ = time;
}
QVector2D square_resolution() const { return video_params_.square_resolution(); }
QVector2D nonsquare_resolution() const { return video_params_.resolution(); }
const VideoParams &vparams() const { return video_params_; }
const TimeRange &time() const { return time_; }
private:
QVector2D resolution_;
rational pixel_aspect_;
QVector2D resolution_by_par_;
VideoParams video_params_;
TimeRange time_;
};
+13 -8
View File
@@ -24,6 +24,7 @@ namespace olive {
const QString ChromaKeyNode::kColorInput = QStringLiteral("color_key");
const QString ChromaKeyNode::kMaskOnlyInput = QStringLiteral("mask_only_in");
const QString ChromaKeyNode::kInvertInput = QStringLiteral("invert_in");
const QString ChromaKeyNode::kUpperToleranceInput = QStringLiteral("upper_tolerence_in");
const QString ChromaKeyNode::kLowerToleranceInput = QStringLiteral("lower_tolerence_in");
const QString ChromaKeyNode::kGarbageMatteInput = QStringLiteral("garbage_in");
@@ -59,6 +60,8 @@ ChromaKeyNode::ChromaKeyNode()
SetInputProperty(kShadowsInput, QStringLiteral("min"), 0.0);
SetInputProperty(kShadowsInput, QStringLiteral("base"), 0.1);
AddInput(kInvertInput, NodeValue::kBoolean, false);
AddInput(kMaskOnlyInput, NodeValue::kBoolean, false);
}
@@ -93,6 +96,7 @@ void ChromaKeyNode::Retranslate()
SetInputName(kHighlightsInput, tr("Highlights"));
SetInputName(kUpperToleranceInput, tr("Upper Tolerance"));
SetInputName(kLowerToleranceInput, tr("Lower Tolerance"));
SetInputName(kInvertInput, tr("Invert Mask"));
SetInputName(kMaskOnlyInput, tr("Show Mask Only"));
}
@@ -128,16 +132,17 @@ void ChromaKeyNode::GenerateProcessor()
void ChromaKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
if (value[kTextureInput].toTexture() && processor()) {
ColorTransformJob job;
if (TexturePtr tex = value[kTextureInput].toTexture()) {
if (processor()) {
ColorTransformJob job(value);
job.Insert(value);
job.SetColorProcessor(processor());
job.SetInputTexture(value[kTextureInput].toTexture());
job.SetNeedsCustomShader(this);
job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65"));
job.SetColorProcessor(processor());
job.SetInputTexture(value[kTextureInput]);
job.SetNeedsCustomShader(this);
job.SetFunctionName(QStringLiteral("SceneLinearToCIEXYZ_d65"));
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
table->Push(NodeValue::kTexture, tex->toJob(job), this);
}
}
}
+1
View File
@@ -42,6 +42,7 @@ class ChromaKeyNode : public OCIOBaseNode {
virtual void ConfigChanged() override;
static const QString kColorInput;
static const QString kInvertInput;
static const QString kMaskOnlyInput;
static const QString kUpperToleranceInput;
static const QString kLowerToleranceInput;
@@ -93,12 +93,11 @@ ShaderCode ColorDifferenceKeyNode::GetShaderCode(const ShaderRequest &request) c
void ColorDifferenceKeyNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
// If there's no texture, no need to run an operation
if (job.Get(kTextureInput).toTexture()) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (TexturePtr tex = value[kTextureInput].toTexture()) {
ShaderJob job;
job.Insert(value);
table->Push(NodeValue::kTexture, tex->toJob(job), this);
}
}
+2 -2
View File
@@ -91,8 +91,8 @@ void DespillNode::Value(const NodeValueRow &value, const NodeGlobals &globals, N
NodeValue(NodeValue::kVec3, QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2])));
// If there's no texture, no need to run an operation
if (job.Get(kTextureInput).toTexture()) {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
if (TexturePtr tex = job.Get(kTextureInput).toTexture()) {
table->Push(NodeValue::kTexture, tex->toJob(job), this);
}
}
+3 -3
View File
@@ -358,7 +358,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt
}
} else if (pairing == kPairTextureMatrix) {
// Only allow matrix multiplication
const QVector2D &sequence_res = globals.resolution();
const QVector2D &sequence_res = globals.nonsquare_resolution();
QVector2D texture_res(texture->params().width() * texture->pixel_aspect_ratio().toDouble(), texture->params().height());
QMatrix4x4 adjusted_matrix = TransformDistortNode::AdjustMatrixByResolutions(number_val.toMatrix(),
@@ -380,7 +380,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt
output->Push(texture_val);
} else {
// Push shader job
output->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
output->Push(NodeValue::kTexture, Texture::Job(globals.vparams(), job), this);
}
break;
}
@@ -410,7 +410,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt
output->Push(NodeValue::kSamples, QVariant::fromValue(buffer), this);
} else {
SampleJob job(val_a.type() == NodeValue::kSamples ? val_a : val_b);
SampleJob job(globals.time(), val_a.type() == NodeValue::kSamples ? val_a : val_b);
job.Insert(number_param, NodeValue(NodeValue::kFloat, number, this));
output->Push(NodeValue::kSamples, QVariant::fromValue(job), this);
}
+5 -7
View File
@@ -76,21 +76,19 @@ ShaderCode MergeNode::GetShaderCode(const ShaderRequest &request) const
void MergeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
{
ShaderJob job;
job.Insert(value);
TexturePtr base_tex = job.Get(kBaseIn).toTexture();
TexturePtr blend_tex = job.Get(kBlendIn).toTexture();
TexturePtr base_tex = value[kBaseIn].toTexture();
TexturePtr blend_tex = value[kBlendIn].toTexture();
if (base_tex || blend_tex) {
if (!base_tex || (blend_tex && blend_tex->channel_count() < VideoParams::kRGBAChannelCount)) {
// We only have a blend texture or the blend texture is RGB only, no need to alpha over
table->Push(job.Get(kBlendIn));
table->Push(value[kBlendIn]);
} else if (!blend_tex) {
// We only have a base texture, no need to alpha over
table->Push(job.Get(kBaseIn));
table->Push(value[kBaseIn]);
} else {
table->Push(NodeValue::kTexture, QVariant::fromValue(job), this);
table->Push(NodeValue::kTexture, base_tex->toJob(ShaderJob(value)), this);
}
}
}
+12 -7
View File
@@ -265,9 +265,7 @@ void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV
// Push each stream as a footage job
for (int i=0; i<GetTotalStreamCount(); i++) {
Track::Reference ref = GetReferenceFromRealIndex(i);
FootageJob job(decoder_, filename(), ref.type(), GetLength());
NodeValue::Type type;
FootageJob job(globals.time(), decoder_, filename(), ref.type(), GetLength());
if (ref.type() == Track::kVideo) {
VideoParams vp = GetVideoParams(ref.index());
@@ -275,18 +273,25 @@ void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV
// Ensure the colorspace is valid and not empty
vp.set_colorspace(GetColorspaceToUse(vp));
// Adjust footage job's divider
if (globals.vparams().divider() > 1) {
// Use a divider appropriate for this target resolution
vp.set_divider(VideoParams::GetDividerForTargetResolution(vp.width(), vp.height(), globals.vparams().effective_width(), globals.vparams().effective_height()));
} else {
// Render everything at full res
vp.set_divider(1);
}
job.set_video_params(vp);
type = NodeValue::kTexture;
table->Push(NodeValue::kTexture, Texture::Job(vp, job), this, ref.ToString());
} else {
AudioParams ap = GetAudioParams(ref.index());
job.set_audio_params(ap);
job.set_cache_path(project()->cache_path());
type = NodeValue::kSamples;
table->Push(NodeValue::kSamples, QVariant::fromValue(job), this, ref.ToString());
}
table->Push(type, QVariant::fromValue(job), this, ref.ToString());
}
}
}
+142 -166
View File
@@ -61,7 +61,15 @@ NodeValueRow NodeTraverser::GenerateRow(NodeValueDatabase *database, const Node
row.insert(it.key(), value);
}
PreProcessRow(range, row);
// TEMP: Audio needs to be refactored to work with new job system. But refactoring hasn't been
// done yet, so we emulate old behavior here JUST FOR AUDIO.
for (auto it=row.begin(); it!=row.end(); it++) {
NodeValue &val = it.value();
if (val.type() == NodeValue::kSamples) {
ResolveJobs(val);
}
}
// END TEMP
return row;
}
@@ -109,14 +117,16 @@ NodeValue NodeTraverser::GenerateRowValueElement(const Node *node, const QString
NodeValue value = table->TakeAt(value_index);
if (value.type() == NodeValue::kTexture) {
QMutexLocker locker(node->video_frame_cache()->mutex());
if (value.type() == NodeValue::kTexture && UseCache()) {
if (TexturePtr tex = value.toTexture()) {
QMutexLocker locker(node->video_frame_cache()->mutex());
node->video_frame_cache()->LoadState();
node->video_frame_cache()->LoadState();
QString cache = node->video_frame_cache()->GetValidCacheFilename(time.in());
if (!cache.isEmpty()) {
value.set_value(CacheJob(cache, value.data()));
QString cache = node->video_frame_cache()->GetValidCacheFilename(time.in());
if (!cache.isEmpty()) {
value.set_value(tex->toJob(CacheJob(cache, value)));
}
}
}
@@ -171,26 +181,7 @@ void NodeTraverser::Transform(QTransform *transform, const Node *start, const No
NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams &params, const TimeRange &time)
{
return NodeGlobals(QVector2D(params.width(), params.height()), params.pixel_aspect_ratio(), time);
}
int NodeTraverser::GetChannelCountFromJob(const GenerateJob &job)
{
return VideoParams::kRGBAChannelCount;
}
TexturePtr NodeTraverser::GetMainTextureFromJob(const GenerateJob &job)
{
// FIXME: Should probably take Node::GetEffectInput into account here
for (auto it=job.GetValues().cbegin(); it!=job.GetValues().cend(); it++) {
if (it.value().type() == NodeValue::kTexture) {
if (TexturePtr t = it.value().toTexture()) {
return t;
}
}
}
return nullptr;
return NodeGlobals(params, time);
}
NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& input, const TimeRange& range)
@@ -284,7 +275,13 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang
// NOTE: Times how long a node takes to process, useful for profiling.
//GTTTime gtt(n);Q_UNUSED(gtt);
// FIXME: Cache certain values here if we've already processed them before
// Use table cache to skip processing where available
if (value_cache_.contains(n)) {
QHash<TimeRange, NodeValueTable> &node_value_map = value_cache_[n];
if (node_value_map.contains(range)) {
return node_value_map.value(range);
}
}
// Generate row for node
NodeValueDatabase database = GenerateDatabase(n, range);
@@ -298,11 +295,13 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang
is_enabled = database[Node::kEnabledInput].Get(NodeValue::kBoolean).toBool();
}
NodeValueTable table;
if (is_enabled) {
NodeValueRow row = GenerateRow(&database, n, range);
// Generate output table
NodeValueTable table = database.Merge();
table = database.Merge();
// By this point, the node should have all the inputs it needs to render correctly
NodeGlobals globals = GenerateGlobals(video_params_, range);
@@ -323,8 +322,6 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang
transform_now_ = next_node;
}
}
return table;
} else {
// If this node has an effect input, ensure that is pushed last
NodeValueTable primary;
@@ -332,13 +329,16 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang
primary = database.Take(n->GetEffectInputID());
}
NodeValueTable m = database.Merge();
m.Push(primary);
return m;
table = database.Merge();
table.Push(primary);
}
value_cache_[n][range] = table;
return table;
}
TexturePtr NodeTraverser::ProcessVideoCacheJob(const CacheJob &val)
TexturePtr NodeTraverser::ProcessVideoCacheJob(const CacheJob *val)
{
return nullptr;
}
@@ -348,153 +348,129 @@ QVector2D NodeTraverser::GenerateResolution() const
return QVector2D(video_params_.square_pixel_width(), video_params_.height());
}
void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range)
void NodeTraverser::ResolveJobs(NodeValue &val)
{
if (val.type() == NodeValue::kTexture || val.type() == NodeValue::kSamples) {
if (val.canConvert<CacheJob>()) {
CacheJob job = val.value<CacheJob>();
TexturePtr tex = ProcessVideoCacheJob(job);
if (tex) {
val.set_value(tex);
} else {
val.set_value(job.GetFallback());
if (val.type() == NodeValue::kTexture) {
if (TexturePtr job_tex = val.toTexture()) {
if (AcceleratedJob *base_job = job_tex->job()) {
if (resolved_texture_cache_.contains(job_tex.get())) {
val.set_value(resolved_texture_cache_.value(job_tex.get()));
} else {
// Resolve any sub-jobs
for (auto it=base_job->GetValues().begin(); it!=base_job->GetValues().end(); it++) {
// Jobs will almost always be submitted with one of these types
NodeValue &subval = it.value();
ResolveJobs(subval);
}
if (CacheJob *cj = dynamic_cast<CacheJob*>(base_job)) {
TexturePtr tex = ProcessVideoCacheJob(cj);
if (tex) {
val.set_value(tex);
} else {
val.set_value(cj->GetFallback());
}
} else if (ColorTransformJob *ctj = dynamic_cast<ColorTransformJob*>(base_job)) {
VideoParams ctj_params = job_tex->params();
ctj_params.set_format(GetCacheVideoParams().format());
TexturePtr dest = CreateTexture(ctj_params);
// Resolve input texture
NodeValue v = ctj->GetInputTexture();
ResolveJobs(v);
ctj->SetInputTexture(v);
ProcessColorTransform(dest, val.source(), ctj);
val.set_value(dest);
} else if (ShaderJob *sj = dynamic_cast<ShaderJob*>(base_job)) {
VideoParams tex_params = job_tex->params();
TexturePtr tex = CreateTexture(tex_params);
ProcessShader(tex, val.source(), sj);
val.set_value(tex);
} else if (GenerateJob *gj = dynamic_cast<GenerateJob*>(base_job)) {
VideoParams tex_params = job_tex->params();
TexturePtr tex = CreateTexture(tex_params);
ProcessFrameGeneration(tex, val.source(), gj);
// Convert to reference space
const QString &colorspace = tex_params.colorspace();
if (!colorspace.isEmpty()) {
// Set format to primary format
tex_params.set_format(GetCacheVideoParams().format());
TexturePtr dest = CreateTexture(tex_params);
ConvertToReferenceSpace(dest, tex, colorspace);
tex = dest;
}
val.set_value(tex);
} else if (FootageJob *fj = dynamic_cast<FootageJob*>(base_job)) {
rational footage_time = Footage::AdjustTimeByLoopMode(fj->time().in(), loop_mode_, fj->length(), fj->video_params().video_type(), fj->video_params().frame_rate_as_time_base());
TexturePtr tex;
if (footage_time.isNaN()) {
// Push dummy texture
tex = CreateDummyTexture(fj->video_params());
} else {
VideoParams managed_params = fj->video_params();
managed_params.set_format(GetCacheVideoParams().format());
tex = CreateTexture(managed_params);
ProcessVideoFootage(tex, fj, footage_time);
}
val.set_value(tex);
}
// Cache resolved value
resolved_texture_cache_.insert(job_tex.get(), val.toTexture());
}
}
}
if (val.canConvert<ShaderJob>()) {
} else if (val.type() == NodeValue::kSamples) {
ShaderJob job = val.value<ShaderJob>();
if (val.canConvert<SampleJob>()) {
PreProcessRow(range, job.GetValues());
VideoParams tex_params = GetCacheVideoParams();
tex_params.set_channel_count(GetChannelCountFromJob(job));
if (!job.GetWillChangeImageSize()) {
if (TexturePtr texture = GetMainTextureFromJob(job)) {
tex_params.set_width(texture->params().width());
tex_params.set_height(texture->params().height());
tex_params.set_divider(texture->params().divider());
}
}
TexturePtr tex = CreateTexture(tex_params);
ProcessShader(tex, val.source(), range, job);
val.set_value(tex);
} else if (val.canConvert<GenerateJob>()) {
GenerateJob job = val.value<GenerateJob>();
VideoParams tex_params = GetCacheVideoParams();
tex_params.set_channel_count(GetChannelCountFromJob(job));
VideoParams upload_params = tex_params;
if (job.GetRequestedFormat() != VideoParams::kFormatInvalid) {
upload_params.set_format(job.GetRequestedFormat());
}
TexturePtr tex = CreateTexture(upload_params);
PreProcessRow(range, job.GetValues());
ProcessFrameGeneration(tex, val.source(), job);
if (!job.GetColorspace().isEmpty()) {
// Convert to reference space
TexturePtr dest = CreateTexture(tex_params);
ConvertToReferenceSpace(dest, tex, job.GetColorspace());
tex = dest;
}
val.set_value(tex);
} else if (val.canConvert<ColorTransformJob>()) {
ColorTransformJob job = val.value<ColorTransformJob>();
VideoParams src_params = job.GetInputTexture()->params();
src_params.set_channel_count(GetChannelCountFromJob(job));
TexturePtr dest = CreateTexture(src_params);
ProcessColorTransform(dest, val.source(), job);
val.set_value(dest);
SampleJob job = val.value<SampleJob>();
SampleBuffer output_buffer = CreateSampleBuffer(job.samples().audio_params(), job.samples().sample_count());
ProcessSamples(output_buffer, val.source(), job.time(), job);
val.set_value(QVariant::fromValue(output_buffer));
} else if (val.canConvert<FootageJob>()) {
FootageJob job = val.value<FootageJob>();
if (job.type() == Track::kVideo) {
rational footage_time = Footage::AdjustTimeByLoopMode(range.in(), loop_mode_, job.length(), job.video_params().video_type(), job.video_params().frame_rate_as_time_base());
TexturePtr tex;
// Adjust footage job's divider
VideoParams render_params = GetCacheVideoParams();
VideoParams job_params = job.video_params();
if (render_params.divider() > 1) {
// Use a divider appropriate for this target resolution
job_params.set_divider(VideoParams::GetDividerForTargetResolution(job_params.width(), job_params.height(), render_params.effective_width(), render_params.effective_height()));
} else {
// Render everything at full res
job_params.set_divider(1);
}
job.set_video_params(job_params);
if (footage_time.isNaN()) {
// Push dummy texture
tex = CreateDummyTexture(job.video_params());
} else {
VideoParams managed_params = job.video_params();
managed_params.set_format(GetCacheVideoParams().format());
tex = CreateTexture(managed_params);
ProcessVideoFootage(tex, job, footage_time);
}
val.set_value(tex);
} else if (job.type() == Track::kAudio) {
SampleBuffer buffer = CreateSampleBuffer(GetCacheAudioParams(), range.length());
ProcessAudioFootage(buffer, job, range);
val.set_value(buffer);
}
} else if (val.canConvert<SampleJob>()) {
SampleJob job = val.value<SampleJob>();
SampleBuffer output_buffer = CreateSampleBuffer(job.samples().audio_params(), job.samples().sample_count());
ProcessSamples(output_buffer, val.source(), range, job);
val.set_value(QVariant::fromValue(output_buffer));
SampleBuffer buffer = CreateSampleBuffer(GetCacheAudioParams(), job.time().length());
ProcessAudioFootage(buffer, &job, job.time());
val.set_value(buffer);
}
}
}
void NodeTraverser::PreProcessRow(const TimeRange &range, NodeValueRow &row)
{
QByteArray cached_node_hash;
// Resolve any jobs
for (auto it=row.begin(); it!=row.end(); it++) {
// Jobs will almost always be submitted with one of these types
NodeValue &val = it.value();
ResolveJobs(val, range);
}
}
TexturePtr NodeTraverser::CreateDummyTexture(const VideoParams &p)
{
return std::make_shared<Texture>(p);
+13 -13
View File
@@ -80,30 +80,26 @@ public:
audio_params_ = params;
}
static int GetChannelCountFromJob(const GenerateJob& job);
static TexturePtr GetMainTextureFromJob(const GenerateJob& job);
protected:
NodeValueTable ProcessInput(const Node *node, const QString &input, const TimeRange &range);
void ProcessInputElement(NodeValueTableArray &array_tbl, const Node *node, const QString &input, int element, const TimeRange &range);
virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time){}
virtual void ProcessVideoFootage(TexturePtr destination, const FootageJob *stream, const rational &input_time){}
virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time){}
virtual void ProcessAudioFootage(SampleBuffer &destination, const FootageJob *stream, const TimeRange &input_time){}
virtual void ProcessShader(TexturePtr destination, const Node *node, const TimeRange &range, const ShaderJob& job){}
virtual void ProcessShader(TexturePtr destination, const Node *node, const ShaderJob *job){}
virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob& job){}
virtual void ProcessColorTransform(TexturePtr destination, const Node *node, const ColorTransformJob *job){}
virtual void ProcessSamples(SampleBuffer &destination, const Node *node, const TimeRange &range, const SampleJob &job){}
virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job){}
virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob *job){}
virtual void ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs){}
virtual TexturePtr ProcessVideoCacheJob(const CacheJob &val);
virtual TexturePtr ProcessVideoCacheJob(const CacheJob *val);
virtual TexturePtr CreateTexture(const VideoParams &p)
{
@@ -140,7 +136,8 @@ protected:
CancelAtom *GetCancelPointer() const { return cancel_; }
void SetCancelPointer(CancelAtom *cancel) { cancel_ = cancel; }
void ResolveJobs(NodeValue &value, const TimeRange &range);
void ResolveJobs(NodeValue &value);
void ResolveAudioJobs(NodeValue &value);
Block *GetCurrentBlock() const
{
@@ -149,9 +146,9 @@ protected:
Decoder::LoopMode loop_mode() const { return loop_mode_; }
private:
void PreProcessRow(const TimeRange &range, NodeValueRow &row);
virtual bool UseCache() const { return false; }
private:
TexturePtr CreateDummyTexture(const VideoParams &p);
VideoParams video_params_;
@@ -168,6 +165,9 @@ private:
Decoder::LoopMode loop_mode_;
QHash<const Node*, QHash<TimeRange, NodeValueTable> > value_cache_;
QHash<Texture*, TexturePtr> resolved_texture_cache_;
};
}
+5
View File
@@ -268,6 +268,11 @@ public:
return type_ == rhs.type_ && tag_ == rhs.tag_ && data_ == rhs.data_;
}
operator bool() const
{
return !data_.isNull();
}
static QString GetPrettyDataTypeName(Type type);
static QString GetDataTypeName(Type type);