/*** 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 . ***/ #include "value.h" #include #include #include #include #include #include "common/tohex.h" #include "render/subtitleparams.h" #include "render/videoparams.h" namespace olive { QString NodeValue::ValueToString(Type data_type, const QVariant &value, bool value_is_a_key_track) { if (!value_is_a_key_track && data_type == kVec2) { QVector2D vec = value.value(); return QStringLiteral("%1:%2").arg(QString::number(vec.x()), QString::number(vec.y())); } else if (!value_is_a_key_track && data_type == kVec3) { QVector3D vec = value.value(); return QStringLiteral("%1:%2:%3").arg(QString::number(vec.x()), QString::number(vec.y()), QString::number(vec.z())); } else if (!value_is_a_key_track && data_type == kVec4) { QVector4D vec = value.value(); return QStringLiteral("%1:%2:%3:%4").arg(QString::number(vec.x()), QString::number(vec.y()), QString::number(vec.z()), QString::number(vec.w())); } else if (!value_is_a_key_track && data_type == kColor) { Color c = value.value(); return QStringLiteral("%1:%2:%3:%4").arg(QString::number(c.red()), QString::number(c.green()), QString::number(c.blue()), QString::number(c.alpha())); } else if (!value_is_a_key_track && data_type == kBezier) { Bezier b = value.value(); return QStringLiteral("%1:%2:%3:%4:%5:%6").arg(QString::number(b.x()), QString::number(b.y()), QString::number(b.cp1_x()), QString::number(b.cp1_y()), QString::number(b.cp2_x()), QString::number(b.cp2_y())); } else if (data_type == kRational) { return QString::fromStdString(value.value().toString()); } else if (data_type == kTexture || data_type == kSamples || data_type == kNone) { // These data types need no XML representation return QString(); } else if (data_type == kInt) { return QString::number(value.value()); } else { if (value.canConvert()) { return value.toString(); } if (!value.isNull()) { qWarning() << "Failed to convert type" << ToHex(data_type) << "to string"; } return QString(); } } QVector NodeValue::split_normal_value_into_track_values(Type type, const QVariant &value) { QVector vals(get_number_of_keyframe_tracks(type)); switch (type) { case kVec2: { QVector2D vec = value.value(); vals.replace(0, vec.x()); vals.replace(1, vec.y()); break; } case kVec3: { QVector3D vec = value.value(); vals.replace(0, vec.x()); vals.replace(1, vec.y()); vals.replace(2, vec.z()); break; } case kVec4: { QVector4D vec = value.value(); vals.replace(0, vec.x()); vals.replace(1, vec.y()); vals.replace(2, vec.z()); vals.replace(3, vec.w()); break; } case kColor: { Color c = value.value(); vals.replace(0, c.red()); vals.replace(1, c.green()); vals.replace(2, c.blue()); vals.replace(3, c.alpha()); break; } case kBezier: { Bezier b = value.value(); vals.replace(0, b.x()); vals.replace(1, b.y()); vals.replace(2, b.cp1_x()); vals.replace(3, b.cp1_y()); vals.replace(4, b.cp2_x()); vals.replace(5, b.cp2_y()); break; } default: vals.replace(0, value); } return vals; } QVariant NodeValue::combine_track_values_into_normal_value(Type type, const QVector &split) { if (split.isEmpty()) { return QVariant(); } switch (type) { case kVec2: { return QVector2D(split.at(0).toFloat(), split.at(1).toFloat()); } case kVec3: { return QVector3D(split.at(0).toFloat(), split.at(1).toFloat(), split.at(2).toFloat()); } case kVec4: { return QVector4D(split.at(0).toFloat(), split.at(1).toFloat(), split.at(2).toFloat(), split.at(3).toFloat()); } case kColor: { return QVariant::fromValue(Color(split.at(0).toFloat(), split.at(1).toFloat(), split.at(2).toFloat(), split.at(3).toFloat())); } case kBezier: return QVariant::fromValue(Bezier(split.at(0).toDouble(), split.at(1).toDouble(), split.at(2).toDouble(), split.at(3).toDouble(), split.at(4).toDouble(), split.at(5).toDouble())); default: return split.first(); } } int NodeValue::get_number_of_keyframe_tracks(Type type) { switch (type) { case NodeValue::kVec2: return 2; case NodeValue::kVec3: return 3; case NodeValue::kVec4: case NodeValue::kColor: return 4; case NodeValue::kBezier: return 6; default: return 1; } } QVariant NodeValue::StringToValue(Type data_type, const QString &string, bool value_is_a_key_track) { if (!value_is_a_key_track && data_type == kVec2) { QStringList vals = string.split(':'); ValidateVectorString(&vals, 2); return QVector2D(vals.at(0).toFloat(), vals.at(1).toFloat()); } else if (!value_is_a_key_track && data_type == kVec3) { QStringList vals = string.split(':'); ValidateVectorString(&vals, 3); return QVector3D(vals.at(0).toFloat(), vals.at(1).toFloat(), vals.at(2).toFloat()); } else if (!value_is_a_key_track && data_type == kVec4) { QStringList vals = string.split(':'); ValidateVectorString(&vals, 4); return QVector4D(vals.at(0).toFloat(), vals.at(1).toFloat(), vals.at(2).toFloat(), vals.at(3).toFloat()); } else if (!value_is_a_key_track && data_type == kColor) { QStringList vals = string.split(':'); ValidateVectorString(&vals, 4); return QVariant::fromValue(Color(vals.at(0).toDouble(), vals.at(1).toDouble(), vals.at(2).toDouble(), vals.at(3).toDouble())); } else if (!value_is_a_key_track && data_type == kBezier) { QStringList vals = string.split(':'); ValidateVectorString(&vals, 6); return QVariant::fromValue(Bezier(vals.at(0).toDouble(), vals.at(1).toDouble(), vals.at(2).toDouble(), vals.at(3).toDouble(), vals.at(4).toDouble(), vals.at(5).toDouble())); } else if (data_type == kInt) { return QVariant::fromValue(string.toLongLong()); } else if (data_type == kRational) { return QVariant::fromValue(rational::fromString(string.toStdString())); } else { return string; } } void NodeValue::ValidateVectorString(QStringList* list, int count) { while (list->size() < count) { list->append(QStringLiteral("0")); } } QString NodeValue::GetPrettyDataTypeName(Type type) { switch (type) { case kNone: return QCoreApplication::translate("NodeValue", "None"); case kInt: case kCombo: return QCoreApplication::translate("NodeValue", "Integer"); case kFloat: return QCoreApplication::translate("NodeValue", "Float"); case kRational: return QCoreApplication::translate("NodeValue", "Rational"); case kBoolean: return QCoreApplication::translate("NodeValue", "Boolean"); case kColor: return QCoreApplication::translate("NodeValue", "Color"); case kMatrix: return QCoreApplication::translate("NodeValue", "Matrix"); case kText: return QCoreApplication::translate("NodeValue", "Text"); case kFont: return QCoreApplication::translate("NodeValue", "Font"); case kFile: return QCoreApplication::translate("NodeValue", "File"); case kTexture: return QCoreApplication::translate("NodeValue", "Texture"); case kSamples: return QCoreApplication::translate("NodeValue", "Samples"); case kVec2: return QCoreApplication::translate("NodeValue", "Vector 2D"); case kVec3: return QCoreApplication::translate("NodeValue", "Vector 3D"); case kVec4: return QCoreApplication::translate("NodeValue", "Vector 4D"); case kBezier: return QCoreApplication::translate("NodeValue", "Bezier"); case kVideoParams: return QCoreApplication::translate("NodeValue", "Video Parameters"); case kAudioParams: return QCoreApplication::translate("NodeValue", "Audio Parameters"); case kSubtitleParams: return QCoreApplication::translate("NodeValue", "Subtitle Parameters"); case kDataTypeCount: break; } return QCoreApplication::translate("NodeValue", "Unknown"); } QString NodeValue::GetDataTypeName(Type type) { switch (type) { case kNone: return QStringLiteral("none"); case kInt: return QStringLiteral("int"); case kCombo: return QStringLiteral("combo"); case kFloat: return QStringLiteral("float"); case kRational: return QStringLiteral("rational"); case kBoolean: return QStringLiteral("bool"); case kColor: return QStringLiteral("color"); case kMatrix: return QStringLiteral("matrix"); case kText: return QStringLiteral("text"); case kFont: return QStringLiteral("font"); case kFile: return QStringLiteral("file"); case kTexture: return QStringLiteral("texture"); case kSamples: return QStringLiteral("samples"); case kVec2: return QStringLiteral("vec2"); case kVec3: return QStringLiteral("vec3"); case kVec4: return QStringLiteral("vec4"); case kBezier: return QStringLiteral("bezier"); case kVideoParams: return QStringLiteral("vparam"); case kAudioParams: return QStringLiteral("aparam"); case kSubtitleParams: return QStringLiteral("sparam"); case kDataTypeCount: break; } return QString(); } NodeValue::Type NodeValue::GetDataTypeFromName(const QString &n) { // Slow but easy to maintain for (int i=0; i(i); if (GetDataTypeName(t) == n) { return t; } } return NodeValue::kNone; } NodeValue NodeValueTable::Get(const QVector &type, const QString &tag) const { int value_index = GetValueIndex(type, tag); if (value_index >= 0) { return values_.at(value_index); } return NodeValue(); } NodeValue NodeValueTable::Take(const QVector &type, const QString &tag) { int value_index = GetValueIndex(type, tag); if (value_index >= 0) { return values_.takeAt(value_index); } return NodeValue(); } bool NodeValueTable::Has(NodeValue::Type type) const { for (int i=values_.size() - 1;i>=0;i--) { const NodeValue& v = values_.at(i); if (v.type() & type) { return true; } } return false; } void NodeValueTable::Remove(const NodeValue &v) { for (int i=values_.size() - 1;i>=0;i--) { const NodeValue& compare = values_.at(i); if (compare == v) { values_.removeAt(i); return; } } } NodeValueTable NodeValueTable::Merge(QList tables) { if (tables.size() == 1) { return tables.first(); } int row = 0; NodeValueTable merged_table; // Slipstreams all tables together while (true) { bool all_merged = true; foreach (const NodeValueTable& t, tables) { if (row < t.Count()) { all_merged = false; } else { continue; } int row_index = t.Count() - 1 - row; merged_table.Prepend(t.at(row_index)); } row++; if (all_merged) { break; } } return merged_table; } int NodeValueTable::GetValueIndex(const QVector& types, const QString &tag) const { int index = -1; for (int i=values_.size() - 1;i>=0;i--) { const NodeValue& v = values_.at(i); if (types.contains(v.type())) { index = i; if (tag.isEmpty() || tag == v.tag()) { break; } } } return index; } }