diff --git a/app/node/graph.cpp b/app/node/graph.cpp index a5250470e..b17132fb3 100644 --- a/app/node/graph.cpp +++ b/app/node/graph.cpp @@ -22,11 +22,6 @@ OLIVE_NAMESPACE_ENTER -NodeGraph::NodeGraph() -{ - -} - void NodeGraph::Clear() { foreach (Node* node, node_children_) { diff --git a/app/node/graph.h b/app/node/graph.h index da5b78983..8ba686886 100644 --- a/app/node/graph.h +++ b/app/node/graph.h @@ -37,7 +37,7 @@ public: /** * @brief NodeGraph Constructor */ - NodeGraph(); + NodeGraph() = default; /** * @brief Destructively destroys all nodes in the graph diff --git a/app/node/input.cpp b/app/node/input.cpp index 025930760..c0f301688 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -1046,4 +1046,14 @@ QVariant NodeInput::combine_track_values_into_normal_value(const QVector& split) const; + QStringList get_combobox_strings() const; + + void set_combobox_strings(const QStringList& strings); + static QString ValueToString(const DataType& data_type, const QVariant& value); static QVariant StringToValue(const DataType &data_type, const QString &string); diff --git a/app/node/math/math.cpp b/app/node/math/math.cpp index 461058d98..4d9722173 100644 --- a/app/node/math/math.cpp +++ b/app/node/math/math.cpp @@ -23,12 +23,13 @@ #include #include +#include "render/color.h" + OLIVE_NAMESPACE_ENTER MathNode::MathNode() { - // FIXME: Make this a combobox - method_in_ = new NodeInput(QStringLiteral("method_in"), NodeParam::kText); + method_in_ = new NodeInput(QStringLiteral("method_in"), NodeParam::kCombo); method_in_->SetConnectable(false); method_in_->set_is_keyframable(false); AddInput(method_in_); @@ -72,15 +73,16 @@ void MathNode::Retranslate() method_in_->set_name(tr("Method")); param_a_in_->set_name(tr("Value")); param_b_in_->set_name(tr("Value")); + + QStringList operations = {tr("Add"), tr("Subtract"), tr("Multiply"), tr("Divide")}; + method_in_->set_combobox_strings(operations); } Node::Capabilities MathNode::GetCapabilities(const NodeValueDatabase &input) const { - QVector pair_likelihood_a = GetPairLikelihood(input[param_a_in_]); - QVector pair_likelihood_b = GetPairLikelihood(input[param_b_in_]); - Pairing most_likely_pairing = GetMostLikelyPairing(pair_likelihood_a, pair_likelihood_b); + PairingCalculator calc(input[param_a_in_], input[param_b_in_]); - switch (most_likely_pairing) { + switch (calc.GetMostLikelyPairing()) { case kPairTextureColor: case kPairTextureNumber: case kPairTextureTexture: @@ -97,24 +99,43 @@ QString MathNode::ShaderID(const NodeValueDatabase &input) const { QString method = QString::number(GetOperation()); - QVector pair_likelihood_a = GetPairLikelihood(input[param_a_in_]); - QVector pair_likelihood_b = GetPairLikelihood(input[param_b_in_]); - Pairing most_likely_pairing = GetMostLikelyPairing(pair_likelihood_a, pair_likelihood_b); + PairingCalculator calc(input[param_a_in_], input[param_b_in_]); - QString type_a = QString::number(input[param_a_in_].At(pair_likelihood_a.at(most_likely_pairing)).type()); - QString type_b = QString::number(input[param_b_in_].At(pair_likelihood_b.at(most_likely_pairing)).type()); + QString type_a = QString::number(calc.GetMostLikelyValueA().type()); + QString type_b = QString::number(calc.GetMostLikelyValueB().type()); return id().append(method).append(type_a).append(type_b); } QString MathNode::ShaderFragmentCode(const NodeValueDatabase &input) const { - QVector pair_likelihood_a = GetPairLikelihood(input[param_a_in_]); - QVector pair_likelihood_b = GetPairLikelihood(input[param_b_in_]); - Pairing most_likely_pairing = GetMostLikelyPairing(pair_likelihood_a, pair_likelihood_b); + PairingCalculator calc(input[param_a_in_], input[param_b_in_]); - NodeParam::DataType type_a = input[param_a_in_].At(pair_likelihood_a.at(most_likely_pairing)).type(); - NodeParam::DataType type_b = input[param_b_in_].At(pair_likelihood_b.at(most_likely_pairing)).type(); + NodeParam::DataType type_a = calc.GetMostLikelyValueA().type(); + NodeParam::DataType type_b = calc.GetMostLikelyValueB().type(); + + QString operation; + + switch (GetOperation()) { + case kOpAdd: + operation = QStringLiteral("%1 + %2"); + break; + case kOpSubtract: + operation = QStringLiteral("%1 - %2"); + break; + case kOpMultiply: + operation = QStringLiteral("%1 * %2"); + break; + case kOpDivide: + operation = QStringLiteral("%1 / %2"); + break; + case kOpPower: + operation = QStringLiteral("pow(%1, %2)"); + break; + } + + operation = operation.arg(GetShaderVariableCall(param_a_in_->id(), type_a), + GetShaderVariableCall(param_b_in_->id(), type_b)); return QStringLiteral("#version 110\n" "\n" @@ -124,26 +145,23 @@ QString MathNode::ShaderFragmentCode(const NodeValueDatabase &input) const "uniform %2 %4;\n" "\n" "void main(void) {\n" - " gl_FragColor = %5 + %6;\n" + " gl_FragColor = %5;\n" "}\n").arg(GetShaderUniformType(type_a), GetShaderUniformType(type_b), param_a_in_->id(), param_b_in_->id(), - GetShaderVariableCall(param_a_in_->id(), type_a), - GetShaderVariableCall(param_b_in_->id(), type_b)); + operation); } NodeValue MathNode::InputValueFromTable(NodeInput *input, const NodeValueDatabase &db) const { if (input == param_a_in_ || input == param_b_in_) { - QVector pair_likelihood_a = GetPairLikelihood(db[param_a_in_]); - QVector pair_likelihood_b = GetPairLikelihood(db[param_b_in_]); - Pairing most_likely_pairing = GetMostLikelyPairing(pair_likelihood_a, pair_likelihood_b); + PairingCalculator calc(db[param_a_in_], db[param_b_in_]); if (input == param_a_in_) { - return db[input].At(pair_likelihood_a.at(most_likely_pairing)); + return calc.GetMostLikelyValueA(); } else { - return db[input].At(pair_likelihood_b.at(most_likely_pairing)); + return calc.GetMostLikelyValueB(); } } @@ -156,28 +174,26 @@ NodeValueTable MathNode::Value(const NodeValueDatabase &value) const // Auto-detect what values to operate with // FIXME: Add manual override for this - QVector pair_likelihood_a = GetPairLikelihood(value[param_a_in_]); - QVector pair_likelihood_b = GetPairLikelihood(value[param_b_in_]); - Pairing most_likely_pairing = GetMostLikelyPairing(pair_likelihood_a, pair_likelihood_b); + PairingCalculator calc(value[param_a_in_], value[param_b_in_]); - NodeValue val_a, val_b; - if (most_likely_pairing >= 0 && most_likely_pairing < kPairCount) { - val_a = value[param_a_in_].At(pair_likelihood_a.at(most_likely_pairing)); - val_b = value[param_a_in_].At(pair_likelihood_a.at(most_likely_pairing)); + if (!calc.FoundMostLikelyPairing()) { + return output; } - switch (most_likely_pairing) { + NodeValue val_a = calc.GetMostLikelyValueA(); + NodeValue val_b = calc.GetMostLikelyValueB(); + + switch (calc.GetMostLikelyPairing()) { case kPairNumberNumber: { - if (val_a.type() == NodeParam::kRational && val_b.type() == NodeParam::kRational) { + if (val_a.type() == NodeParam::kRational && val_b.type() == NodeParam::kRational && GetOperation() != kOpPower) { // Preserve rationals - output.Push(NodeParam::kRational, QVariant::fromValue(val_a.data().value() + val_b.data().value())); + output.Push(NodeParam::kRational, + QVariant::fromValue(PerformAddSubMultDiv(val_a.data().value(), val_b.data().value()))); } else { - float flt_a = RetrieveNumber(val_a); - float flt_b = RetrieveNumber(val_b); - - output.Push(NodeParam::kFloat, flt_a + flt_b); + output.Push(NodeParam::kFloat, + PerformAll(RetrieveNumber(val_a), RetrieveNumber(val_b))); } break; } @@ -186,7 +202,9 @@ NodeValueTable MathNode::Value(const NodeValueDatabase &value) const { // We convert all vectors to QVector4D just for simplicity and exploit the fact that kVec4 is higher than kVec2 in // the enum to find the largest data type - PushVector(&output, qMax(val_a.type(), val_b.type()), RetrieveVector(val_a) + RetrieveVector(val_b)); + PushVector(&output, + qMax(val_a.type(), val_b.type()), + PerformAddSubMultDiv(RetrieveVector(val_a), RetrieveVector(val_b))); break; } @@ -195,7 +213,10 @@ NodeValueTable MathNode::Value(const NodeValueDatabase &value) const QMatrix4x4 matrix = (val_a.type() == NodeParam::kMatrix) ? val_a.data().value() : val_b.data().value(); QVector4D vec = (val_a.type() == NodeParam::kMatrix) ? RetrieveVector(val_b) : RetrieveVector(val_a); - PushVector(&output, qMax(val_a.type(), val_b.type()), vec * matrix); + // Only valid operation is multiply + PushVector(&output, + qMax(val_a.type(), val_b.type()), + PerformMult(vec, matrix)); break; } @@ -204,29 +225,44 @@ NodeValueTable MathNode::Value(const NodeValueDatabase &value) const QVector4D vec = (val_a.type() & NodeParam::kVector) ? RetrieveVector(val_a) : RetrieveVector(val_b); float number = RetrieveNumber((val_a.type() & NodeParam::kMatrix) ? val_b : val_a); - PushVector(&output, val_a.type(), vec * number); + // Only multiply and divide are valid operations + PushVector(&output, val_a.type(), PerformMultDiv(vec, number)); break; } case kPairMatrixMatrix: { - QMatrix4x4 mat_a = value[param_a_in_].At(pair_likelihood_a.at(most_likely_pairing)).data().value(); - QMatrix4x4 mat_b = value[param_b_in_].At(pair_likelihood_b.at(most_likely_pairing)).data().value(); - output.Push(NodeParam::kMatrix, mat_a + mat_b); + QMatrix4x4 mat_a = val_a.data().value(); + QMatrix4x4 mat_b = val_b.data().value(); + output.Push(NodeParam::kMatrix, PerformAddSubMult(mat_a, mat_b)); break; } case kPairColorColor: + { + Color col_a = val_a.data().value(); + Color col_b = val_b.data().value(); + + // Only add and subtract are valid operations + output.Push(NodeParam::kColor, QVariant::fromValue(PerformAddSub(col_a, col_b))); + break; + } + + case kPairNumberColor: { - // FIXME: Still undecided on the true representation of color + Color col = (val_a.type() == NodeParam::kColor) ? val_a.data().value() : val_b.data().value(); + float num = (val_a.type() == NodeParam::kColor) ? val_b.data().toFloat() : val_a.data().toFloat(); + + // Only multiply and divide are valid operations + output.Push(NodeParam::kColor, QVariant::fromValue(PerformMult(col, num))); break; } case kPairSampleSample: { - SampleBufferPtr samples_a = value[param_a_in_].Get(NodeParam::kSamples).value(); - SampleBufferPtr samples_b = value[param_b_in_].Get(NodeParam::kSamples).value(); + SampleBufferPtr samples_a = val_a.data().value(); + SampleBufferPtr samples_b = val_b.data().value(); int max_samples = qMax(samples_a->sample_count_per_channel(), samples_b->sample_count_per_channel()); int min_samples = qMin(samples_a->sample_count_per_channel(), samples_b->sample_count_per_channel()); @@ -236,7 +272,7 @@ NodeValueTable MathNode::Value(const NodeValueDatabase &value) const // Mix samples that are in both buffers for (int i=0;iaudio_params().channel_count();i++) { for (int j=0;jdata()[i][j] = samples_a->data()[i][j] + samples_b->data()[i][j]; + mixed_samples->data()[i][j] = PerformAll(samples_a->data()[i][j], samples_b->data()[i][j]); } } @@ -255,7 +291,6 @@ NodeValueTable MathNode::Value(const NodeValueDatabase &value) const break; } - case kPairNone: case kPairCount: case kPairTextureColor: @@ -272,12 +307,10 @@ NodeValueTable MathNode::Value(const NodeValueDatabase &value) const NodeInput *MathNode::ProcessesSamplesFrom(const NodeValueDatabase &value) const { - QVector pair_likelihood_a = GetPairLikelihood(value[param_a_in_]); - QVector pair_likelihood_b = GetPairLikelihood(value[param_b_in_]); - Pairing most_likely_pairing = GetMostLikelyPairing(pair_likelihood_a, pair_likelihood_b); + PairingCalculator calc(value[param_a_in_], value[param_b_in_]); - if (most_likely_pairing == kPairSampleNumber) { - if (value[param_a_in_].At(pair_likelihood_a.at(most_likely_pairing)).type() == NodeParam::kSamples) { + if (calc.GetMostLikelyPairing() == kPairSampleNumber) { + if (calc.GetMostLikelyValueA().type() == NodeParam::kSamples) { return param_a_in_; } else { return param_b_in_; @@ -295,7 +328,7 @@ void MathNode::ProcessSamples(const NodeValueDatabase &values, const AudioRender float number_flt = RetrieveNumber(number_val); for (int i=0;idata()[i][index] = input->data()[i][index] + number_flt; + output->data()[i][index] = PerformAll(input->data()[i][index], number_flt); } } @@ -311,7 +344,7 @@ NodeInput *MathNode::param_b_in() const MathNode::Operation MathNode::GetOperation() const { - return kOpAdd; + return static_cast(method_in_->get_standard_value().toInt()); } QString MathNode::GetShaderUniformType(const NodeParam::DataType &type) @@ -337,7 +370,7 @@ QString MathNode::GetShaderVariableCall(const QString &input_id, const NodeParam return input_id; } -QVector MathNode::GetPairLikelihood(const NodeValueTable &table) +QVector MathNode::PairingCalculator::GetPairLikelihood(const NodeValueTable &table) { // FIXME: When we introduce a manual override, placing it here would be the least problematic @@ -378,7 +411,7 @@ QVector MathNode::GetPairLikelihood(const NodeValueTable &table) return likelihood; } -MathNode::Pairing MathNode::GetMostLikelyPairing(const QVector &a, const QVector &b) +MathNode::Pairing MathNode::PairingCalculator::GetMostLikelyPairingInternal(const QVector &a, const QVector &b) { QVector likelihoods(kPairCount); @@ -446,4 +479,144 @@ float MathNode::RetrieveNumber(const NodeValue &val) } } +MathNode::PairingCalculator::PairingCalculator(const NodeValueTable &table_a, const NodeValueTable &table_b) +{ + table_a_ = table_a; + table_b_ = table_b; + pair_likelihood_a_ = GetPairLikelihood(table_a_); + pair_likelihood_b_ = GetPairLikelihood(table_b_); + most_likely_pairing_ = GetMostLikelyPairingInternal(pair_likelihood_a_, pair_likelihood_b_); +} + +bool MathNode::PairingCalculator::FoundMostLikelyPairing() const +{ + return (most_likely_pairing_ >= 0 && most_likely_pairing_ < kPairCount); +} + +MathNode::Pairing MathNode::PairingCalculator::GetMostLikelyPairing() const +{ + return most_likely_pairing_; +} + +NodeValue MathNode::PairingCalculator::GetMostLikelyValueA() const +{ + return GetMostLikelyValue(table_a_, pair_likelihood_a_); +} + +NodeValue MathNode::PairingCalculator::GetMostLikelyValueB() const +{ + return GetMostLikelyValue(table_b_, pair_likelihood_b_); +} + +NodeValue MathNode::PairingCalculator::GetMostLikelyValue(const NodeValueTable &table, const QVector &likelihood) const +{ + return table.At(likelihood.at(most_likely_pairing_)); +} + +template +T MathNode::PerformAll(T a, U b) const +{ + switch (GetOperation()) { + case kOpAdd: + return a + b; + case kOpSubtract: + return a - b; + case kOpMultiply: + return a * b; + case kOpDivide: + return a / b; + case kOpPower: + return qPow(a, b); + } + + return a; +} + +template +T MathNode::PerformMultDiv(T a, U b) const +{ + switch (GetOperation()) { + case kOpMultiply: + return a * b; + case kOpDivide: + return a / b; + case kOpAdd: + case kOpSubtract: + case kOpPower: + break; + } + + return a; +} + +template +T MathNode::PerformAddSub(T a, U b) const +{ + switch (GetOperation()) { + case kOpAdd: + return a + b; + case kOpSubtract: + return a - b; + case kOpMultiply: + case kOpDivide: + case kOpPower: + break; + } + + return a; +} + +template +T MathNode::PerformMult(T a, U b) const +{ + switch (GetOperation()) { + case kOpMultiply: + return a * b; + case kOpAdd: + case kOpSubtract: + case kOpDivide: + case kOpPower: + break; + } + + return a; +} + +template +T MathNode::PerformAddSubMult(T a, U b) const +{ + switch (GetOperation()) { + case kOpAdd: + return a + b; + case kOpSubtract: + return a - b; + case kOpMultiply: + return a * b; + case kOpDivide: + case kOpPower: + break; + } + + return a; +} + +template +T MathNode::PerformAddSubMultDiv(T a, U b) const +{ + switch (GetOperation()) { + case kOpAdd: + return a + b; + case kOpSubtract: + return a - b; + case kOpMultiply: + return a * b; + case kOpDivide: + return a / b; + case kOpPower: + break; + } + + return a; +} + OLIVE_NAMESPACE_EXIT diff --git a/app/node/math/math.h b/app/node/math/math.h index 2720298ce..5aa6f5cf3 100644 --- a/app/node/math/math.h +++ b/app/node/math/math.h @@ -56,9 +56,10 @@ public: private: enum Operation { kOpAdd, - kOpSubtrack, + kOpSubtract, kOpMultiply, - kOpDivide + kOpDivide, + kOpPower }; Operation GetOperation() const; @@ -84,23 +85,63 @@ private: kPairCount }; + class PairingCalculator { + public: + PairingCalculator(const NodeValueTable& table_a, const NodeValueTable& table_b); + + bool FoundMostLikelyPairing() const; + Pairing GetMostLikelyPairing() const; + + NodeValue GetMostLikelyValueA() const; + NodeValue GetMostLikelyValueB() const; + + private: + static Pairing GetMostLikelyPairingInternal(const QVector &a, const QVector &b); + + static QVector GetPairLikelihood(const NodeValueTable& table); + + NodeValue GetMostLikelyValue(const NodeValueTable& table, const QVector& likelihood) const; + + Pairing most_likely_pairing_; + + NodeValueTable table_a_; + + NodeValueTable table_b_; + + QVector pair_likelihood_a_; + + QVector pair_likelihood_b_; + + }; + template - static T OperationAdd(T a, U b); + T PerformAll(T a, U b) const; + + template + T PerformMultDiv(T a, U b) const; + + template + T PerformAddSub(T a, U b) const; + + template + T PerformMult(T a, U b) const; + + template + T PerformAddSubMult(T a, U b) const; + + template + T PerformAddSubMultDiv(T a, U b) const; static QString GetShaderUniformType(const NodeParam::DataType& type); static QString GetShaderVariableCall(const QString& input_id, const NodeParam::DataType& type); - static QVector GetPairLikelihood(const NodeValueTable& table); - - static Pairing GetMostLikelyPairing(const QVector &a, const QVector &b); - static QVector4D RetrieveVector(const NodeValue& val); - static void PushVector(NodeValueTable* output, NodeParam::DataType type, const QVector4D& vec); - static float RetrieveNumber(const NodeValue& val); + static void PushVector(NodeValueTable* output, NodeParam::DataType type, const QVector4D& vec); + NodeInput* method_in_; NodeInput* param_a_in_; diff --git a/app/node/param.cpp b/app/node/param.cpp index 79ec209e2..2e401b34a 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -201,6 +201,7 @@ QByteArray NodeParam::ValueToBytes(const NodeParam::DataType &type, const QVaria case kVec2: return ValueToBytesInternal(value); case kVec3: return ValueToBytesInternal(value); case kVec4: return ValueToBytesInternal(value); + case kCombo: return ValueToBytesInternal(value); // These types have no persistent input case kNone: @@ -223,28 +224,30 @@ NodeParam::DataType NodeParam::StringToDataType(const QString &s) { QString type_id = s.toLower(); - if (type_id == "float") { + if (type_id == QStringLiteral("float")) { return kFloat; - } else if (type_id == "int") { + } else if (type_id == QStringLiteral("int")) { return kInt; - } else if (type_id == "rational") { + } else if (type_id == QStringLiteral("rational")) { return kRational; - } else if (type_id == "bool") { + } else if (type_id == QStringLiteral("bool")) { return kBoolean; - } else if (type_id == "color") { + } else if (type_id == QStringLiteral("color")) { return kColor; - } else if (type_id == "matrix") { + } else if (type_id == QStringLiteral("matrix")) { return kMatrix; - } else if (type_id == "text") { + } else if (type_id == QStringLiteral("text")) { return kText; - } else if (type_id == "texture") { + } else if (type_id == QStringLiteral("texture")) { return kTexture; - } else if (type_id == "vec2") { + } else if (type_id == QStringLiteral("vec2")) { return kVec2; - } else if (type_id == "vec3") { + } else if (type_id == QStringLiteral("vec3")) { return kVec3; - } else if (type_id == "vec4") { + } else if (type_id == QStringLiteral("vec4")) { return kVec4; + } else if (type_id == QStringLiteral("combo")) { + return kCombo; } return kAny; diff --git a/app/node/param.h b/app/node/param.h index 46a37b0e9..167da6228 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -171,6 +171,13 @@ public: */ kVec4 = 0x4000, + /** + * ComboBox type + * + * Resolves to `int` - the index currently selected + */ + kCombo = 0x8000, + /** ****************************** BROAD IDENTIFIERS ****************************** */ diff --git a/app/render/backend/opengl/openglproxy.cpp b/app/render/backend/opengl/openglproxy.cpp index 04f6e7d43..9c1cc6f59 100644 --- a/app/render/backend/opengl/openglproxy.cpp +++ b/app/render/backend/opengl/openglproxy.cpp @@ -67,7 +67,7 @@ bool OpenGLProxy::Init() return true; } -void OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const TimeRange &range, NodeValueTable* table) +void OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table) { // Ensure stream is video or image type if (stream->type() != Stream::kVideo && stream->type() != Stream::kImage) { @@ -289,6 +289,9 @@ void OpenGLProxy::RunNodeAccelerated(const Node *node, const TimeRange &range, c case NodeInput::kMatrix: shader->setUniformValue(variable_location, value.value()); break; + case NodeInput::kCombo: + shader->setUniformValue(variable_location, value.value()); + break; case NodeInput::kColor: { Color color = value.value(); diff --git a/app/render/backend/opengl/openglproxy.h b/app/render/backend/opengl/openglproxy.h index 1203b9330..7c3a873dd 100644 --- a/app/render/backend/opengl/openglproxy.h +++ b/app/render/backend/opengl/openglproxy.h @@ -63,7 +63,7 @@ public: void Close(); - void FrameToValue(FramePtr frame, StreamPtr stream, const TimeRange &range, NodeValueTable* table); + void FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table); void RunNodeAccelerated(const Node *node, const TimeRange &range, const NodeValueDatabase &input_params, NodeValueTable* output_params); diff --git a/app/render/backend/opengl/openglworker.cpp b/app/render/backend/opengl/openglworker.cpp index b141cb3b0..ff091ba22 100644 --- a/app/render/backend/opengl/openglworker.cpp +++ b/app/render/backend/opengl/openglworker.cpp @@ -41,7 +41,7 @@ void OpenGLWorker::FrameToValue(DecoderPtr decoder, StreamPtr stream, const Time FramePtr frame = decoder->RetrieveVideo(range.in(), video_params().divider()); if (frame) { - emit RequestFrameToValue(frame, stream, range, table); + emit RequestFrameToValue(frame, stream, table); } } diff --git a/app/render/backend/opengl/openglworker.h b/app/render/backend/opengl/openglworker.h index 1ec1846e9..cfaedec80 100644 --- a/app/render/backend/opengl/openglworker.h +++ b/app/render/backend/opengl/openglworker.h @@ -38,7 +38,7 @@ public: QObject* parent = nullptr); signals: - void RequestFrameToValue(FramePtr frame, StreamPtr stream, const TimeRange &range, NodeValueTable* table); + void RequestFrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* table); void RequestRunNodeAccelerated(const Node *node, const TimeRange &range, const NodeValueDatabase &input_params, NodeValueTable* output_params); diff --git a/app/render/color.cpp b/app/render/color.cpp index 6e55eecf3..736de812e 100644 --- a/app/render/color.cpp +++ b/app/render/color.cpp @@ -204,6 +204,70 @@ QColor Color::toQColor() const return c; } +const Color &Color::operator+=(const Color &rhs) +{ + for (int i=0;iget_combobox_strings(); + foreach (const QString& s, items) { + combobox->addItem(s); + } + + widgets_.append(combobox); + connect(combobox, static_cast(&QComboBox::currentIndexChanged), this, &NodeParamViewWidgetBridge::WidgetCallback); + break; + } case NodeParam::kFile: // FIXME: File selector break; @@ -373,6 +386,12 @@ void NodeParamViewWidgetBridge::WidgetCallback() SetInputValue(QVariant::fromValue(static_cast(sender())->SelectedFootage()), 0); break; } + case NodeParam::kCombo: + { + // Widget is a QComboBox + SetInputValue(static_cast(widgets_.first())->currentIndex(), 0); + break; + } } } @@ -458,6 +477,11 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() // FIXME: Implement this break; } + case NodeParam::kCombo: + { + static_cast(widgets_.first())->setCurrentIndex(input_->get_value_at_time(node_time).toInt()); + break; + } case NodeParam::kFootage: static_cast(widgets_.first())->SetFootage(input_->get_value_at_time(node_time).value()); break; @@ -592,6 +616,33 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVaria } } } + + // ComboBox strings changing + if (input_->data_type() & NodeParam::kCombo) { + QComboBox* cb = static_cast(widgets_.first()); + + int old_index = cb->currentIndex(); + + // Block the combobox changed signals since we anticipate the index will be the same and not require a re-render + cb->blockSignals(true); + + cb->clear(); + + QStringList items = input_->get_combobox_strings(); + foreach (const QString& s, items) { + cb->addItem(s); + } + + cb->setCurrentIndex(old_index); + + cb->blockSignals(false); + + // In case the amount of items is LESS and the previous index cannot be set, NOW we trigger a re-cache since the + // value has changed + if (cb->currentIndex() != old_index) { + WidgetCallback(); + } + } } OLIVE_NAMESPACE_EXIT