新增根据帧数控制可见性
This commit is contained in:
305
client/core/library/EntityJson.cpp
Normal file
305
client/core/library/EntityJson.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
#include "library/EntityJson.h"
|
||||
|
||||
#include <functional>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
|
||||
namespace core::library {
|
||||
|
||||
namespace {
|
||||
|
||||
QJsonArray pointToJson(const QPointF& p) {
|
||||
return QJsonArray{p.x(), p.y()};
|
||||
}
|
||||
|
||||
bool pointFromJson(const QJsonValue& v, QPointF& out) {
|
||||
if (!v.isArray()) {
|
||||
return false;
|
||||
}
|
||||
const QJsonArray a = v.toArray();
|
||||
if (a.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
out = QPointF(a.at(0).toDouble(), a.at(1).toDouble());
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonArray pointsToJson(const QVector<QPointF>& pts) {
|
||||
QJsonArray a;
|
||||
for (const auto& p : pts) {
|
||||
a.append(pointToJson(p));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
bool pointsFromJson(const QJsonValue& v, QVector<QPointF>& out) {
|
||||
out.clear();
|
||||
if (!v.isArray()) {
|
||||
return false;
|
||||
}
|
||||
const QJsonArray a = v.toArray();
|
||||
out.reserve(a.size());
|
||||
for (const auto& it : a) {
|
||||
QPointF p;
|
||||
if (!pointFromJson(it, p)) {
|
||||
return false;
|
||||
}
|
||||
out.push_back(p);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
QJsonArray vecToJson(const QVector<T>& v, const std::function<QJsonObject(const T&)>& fn) {
|
||||
QJsonArray a;
|
||||
for (const auto& x : v) {
|
||||
a.append(fn(x));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QJsonObject entityToJson(const core::Project::Entity& e) {
|
||||
QJsonObject o;
|
||||
o.insert(QStringLiteral("id"), e.id);
|
||||
o.insert(QStringLiteral("displayName"), e.displayName);
|
||||
o.insert(QStringLiteral("visible"), e.visible);
|
||||
o.insert(QStringLiteral("polygonLocal"), pointsToJson(e.polygonLocal));
|
||||
o.insert(QStringLiteral("cutoutPolygonWorld"), pointsToJson(e.cutoutPolygonWorld));
|
||||
o.insert(QStringLiteral("originWorld"), pointToJson(e.originWorld));
|
||||
o.insert(QStringLiteral("depth"), e.depth);
|
||||
o.insert(QStringLiteral("imagePath"), e.imagePath);
|
||||
o.insert(QStringLiteral("imageTopLeftWorld"), pointToJson(e.imageTopLeftWorld));
|
||||
o.insert(QStringLiteral("userScale"), e.userScale);
|
||||
o.insert(QStringLiteral("distanceScaleCalibMult"), e.distanceScaleCalibMult);
|
||||
o.insert(QStringLiteral("ignoreDistanceScale"), e.ignoreDistanceScale);
|
||||
o.insert(QStringLiteral("parentId"), e.parentId);
|
||||
o.insert(QStringLiteral("parentOffsetWorld"), pointToJson(e.parentOffsetWorld));
|
||||
|
||||
o.insert(QStringLiteral("entityPayloadPath"), e.entityPayloadPath);
|
||||
o.insert(QStringLiteral("legacyAnimSidecarPath"), e.legacyAnimSidecarPath);
|
||||
|
||||
o.insert(QStringLiteral("locationKeys"),
|
||||
vecToJson<core::Project::Entity::KeyframeVec2>(
|
||||
e.locationKeys, [](const core::Project::Entity::KeyframeVec2& k) {
|
||||
QJsonObject ko;
|
||||
ko.insert(QStringLiteral("frame"), k.frame);
|
||||
ko.insert(QStringLiteral("value"), pointToJson(k.value));
|
||||
return ko;
|
||||
}));
|
||||
|
||||
o.insert(QStringLiteral("depthScaleKeys"),
|
||||
vecToJson<core::Project::Entity::KeyframeFloat01>(
|
||||
e.depthScaleKeys, [](const core::Project::Entity::KeyframeFloat01& k) {
|
||||
QJsonObject ko;
|
||||
ko.insert(QStringLiteral("frame"), k.frame);
|
||||
ko.insert(QStringLiteral("value"), k.value);
|
||||
return ko;
|
||||
}));
|
||||
|
||||
o.insert(QStringLiteral("userScaleKeys"),
|
||||
vecToJson<core::Project::Entity::KeyframeDouble>(
|
||||
e.userScaleKeys, [](const core::Project::Entity::KeyframeDouble& k) {
|
||||
QJsonObject ko;
|
||||
ko.insert(QStringLiteral("frame"), k.frame);
|
||||
ko.insert(QStringLiteral("value"), k.value);
|
||||
return ko;
|
||||
}));
|
||||
|
||||
o.insert(QStringLiteral("imageFrames"),
|
||||
vecToJson<core::Project::Entity::ImageFrame>(
|
||||
e.imageFrames, [](const core::Project::Entity::ImageFrame& k) {
|
||||
QJsonObject ko;
|
||||
ko.insert(QStringLiteral("frame"), k.frame);
|
||||
ko.insert(QStringLiteral("imagePath"), k.imagePath);
|
||||
return ko;
|
||||
}));
|
||||
|
||||
o.insert(QStringLiteral("visibilityKeys"),
|
||||
vecToJson<core::Project::ToolKeyframeBool>(
|
||||
e.visibilityKeys, [](const core::Project::ToolKeyframeBool& k) {
|
||||
QJsonObject ko;
|
||||
ko.insert(QStringLiteral("frame"), k.frame);
|
||||
ko.insert(QStringLiteral("value"), k.value);
|
||||
return ko;
|
||||
}));
|
||||
|
||||
{
|
||||
QJsonObject intro;
|
||||
intro.insert(QStringLiteral("title"), e.intro.title);
|
||||
intro.insert(QStringLiteral("bodyText"), e.intro.bodyText);
|
||||
QJsonArray imgs;
|
||||
for (const auto& p : e.intro.imagePathsRelative) {
|
||||
imgs.append(p);
|
||||
}
|
||||
intro.insert(QStringLiteral("imagePathsRelative"), imgs);
|
||||
intro.insert(QStringLiteral("videoPathRelative"), e.intro.videoPathRelative);
|
||||
o.insert(QStringLiteral("intro"), intro);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
bool entityFromJson(const QJsonObject& o, core::Project::Entity& out) {
|
||||
core::Project::Entity e;
|
||||
e.id = o.value(QStringLiteral("id")).toString();
|
||||
e.displayName = o.value(QStringLiteral("displayName")).toString();
|
||||
e.visible = o.value(QStringLiteral("visible")).toBool(true);
|
||||
if (!pointsFromJson(o.value(QStringLiteral("polygonLocal")), e.polygonLocal)) {
|
||||
return false;
|
||||
}
|
||||
if (!pointsFromJson(o.value(QStringLiteral("cutoutPolygonWorld")), e.cutoutPolygonWorld)) {
|
||||
// cutout 允许不存在:按空处理
|
||||
e.cutoutPolygonWorld.clear();
|
||||
}
|
||||
{
|
||||
QPointF p;
|
||||
if (!pointFromJson(o.value(QStringLiteral("originWorld")), p)) {
|
||||
p = QPointF();
|
||||
}
|
||||
e.originWorld = p;
|
||||
}
|
||||
e.depth = o.value(QStringLiteral("depth")).toInt(0);
|
||||
e.imagePath = o.value(QStringLiteral("imagePath")).toString();
|
||||
{
|
||||
QPointF p;
|
||||
if (!pointFromJson(o.value(QStringLiteral("imageTopLeftWorld")), p)) {
|
||||
p = QPointF();
|
||||
}
|
||||
e.imageTopLeftWorld = p;
|
||||
}
|
||||
e.userScale = o.value(QStringLiteral("userScale")).toDouble(1.0);
|
||||
e.distanceScaleCalibMult = o.value(QStringLiteral("distanceScaleCalibMult")).toDouble(0.0);
|
||||
e.ignoreDistanceScale = o.value(QStringLiteral("ignoreDistanceScale")).toBool(false);
|
||||
e.parentId = o.value(QStringLiteral("parentId")).toString();
|
||||
{
|
||||
QPointF p;
|
||||
if (!pointFromJson(o.value(QStringLiteral("parentOffsetWorld")), p)) {
|
||||
p = QPointF();
|
||||
}
|
||||
e.parentOffsetWorld = p;
|
||||
}
|
||||
e.entityPayloadPath = o.value(QStringLiteral("entityPayloadPath")).toString();
|
||||
e.legacyAnimSidecarPath = o.value(QStringLiteral("legacyAnimSidecarPath")).toString();
|
||||
|
||||
auto parseKeyframesVec2 = [&](const QString& key, QVector<core::Project::Entity::KeyframeVec2>& dst) -> bool {
|
||||
dst.clear();
|
||||
const QJsonValue v = o.value(key);
|
||||
if (!v.isArray()) {
|
||||
return true;
|
||||
}
|
||||
const QJsonArray a = v.toArray();
|
||||
dst.reserve(a.size());
|
||||
for (const auto& it : a) {
|
||||
if (!it.isObject()) return false;
|
||||
const QJsonObject ko = it.toObject();
|
||||
core::Project::Entity::KeyframeVec2 k;
|
||||
k.frame = ko.value(QStringLiteral("frame")).toInt(0);
|
||||
QPointF pv;
|
||||
if (!pointFromJson(ko.value(QStringLiteral("value")), pv)) {
|
||||
return false;
|
||||
}
|
||||
k.value = pv;
|
||||
dst.push_back(k);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto parseKeyframesFloat01 = [&](const QString& key, QVector<core::Project::Entity::KeyframeFloat01>& dst) -> bool {
|
||||
dst.clear();
|
||||
const QJsonValue v = o.value(key);
|
||||
if (!v.isArray()) {
|
||||
return true;
|
||||
}
|
||||
const QJsonArray a = v.toArray();
|
||||
dst.reserve(a.size());
|
||||
for (const auto& it : a) {
|
||||
if (!it.isObject()) return false;
|
||||
const QJsonObject ko = it.toObject();
|
||||
core::Project::Entity::KeyframeFloat01 k;
|
||||
k.frame = ko.value(QStringLiteral("frame")).toInt(0);
|
||||
k.value = ko.value(QStringLiteral("value")).toDouble(0.5);
|
||||
dst.push_back(k);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto parseKeyframesDouble = [&](const QString& key, QVector<core::Project::Entity::KeyframeDouble>& dst) -> bool {
|
||||
dst.clear();
|
||||
const QJsonValue v = o.value(key);
|
||||
if (!v.isArray()) {
|
||||
return true;
|
||||
}
|
||||
const QJsonArray a = v.toArray();
|
||||
dst.reserve(a.size());
|
||||
for (const auto& it : a) {
|
||||
if (!it.isObject()) return false;
|
||||
const QJsonObject ko = it.toObject();
|
||||
core::Project::Entity::KeyframeDouble k;
|
||||
k.frame = ko.value(QStringLiteral("frame")).toInt(0);
|
||||
k.value = ko.value(QStringLiteral("value")).toDouble(1.0);
|
||||
dst.push_back(k);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto parseImageFrames = [&](const QString& key, QVector<core::Project::Entity::ImageFrame>& dst) -> bool {
|
||||
dst.clear();
|
||||
const QJsonValue v = o.value(key);
|
||||
if (!v.isArray()) {
|
||||
return true;
|
||||
}
|
||||
const QJsonArray a = v.toArray();
|
||||
dst.reserve(a.size());
|
||||
for (const auto& it : a) {
|
||||
if (!it.isObject()) return false;
|
||||
const QJsonObject ko = it.toObject();
|
||||
core::Project::Entity::ImageFrame k;
|
||||
k.frame = ko.value(QStringLiteral("frame")).toInt(0);
|
||||
k.imagePath = ko.value(QStringLiteral("imagePath")).toString();
|
||||
dst.push_back(k);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!parseKeyframesVec2(QStringLiteral("locationKeys"), e.locationKeys)) return false;
|
||||
if (!parseKeyframesFloat01(QStringLiteral("depthScaleKeys"), e.depthScaleKeys)) return false;
|
||||
if (!parseKeyframesDouble(QStringLiteral("userScaleKeys"), e.userScaleKeys)) return false;
|
||||
if (!parseImageFrames(QStringLiteral("imageFrames"), e.imageFrames)) return false;
|
||||
|
||||
// visibilityKeys:可缺省(默认永远可见)
|
||||
e.visibilityKeys.clear();
|
||||
if (o.value(QStringLiteral("visibilityKeys")).isArray()) {
|
||||
const QJsonArray a = o.value(QStringLiteral("visibilityKeys")).toArray();
|
||||
e.visibilityKeys.reserve(a.size());
|
||||
for (const auto& it : a) {
|
||||
if (!it.isObject()) return false;
|
||||
const QJsonObject ko = it.toObject();
|
||||
core::Project::ToolKeyframeBool k;
|
||||
k.frame = ko.value(QStringLiteral("frame")).toInt(0);
|
||||
k.value = ko.value(QStringLiteral("value")).toBool(true);
|
||||
e.visibilityKeys.push_back(k);
|
||||
}
|
||||
}
|
||||
|
||||
if (o.contains(QStringLiteral("intro")) && o.value(QStringLiteral("intro")).isObject()) {
|
||||
const QJsonObject intro = o.value(QStringLiteral("intro")).toObject();
|
||||
e.intro.title = intro.value(QStringLiteral("title")).toString();
|
||||
e.intro.bodyText = intro.value(QStringLiteral("bodyText")).toString();
|
||||
e.intro.videoPathRelative = intro.value(QStringLiteral("videoPathRelative")).toString();
|
||||
e.intro.imagePathsRelative.clear();
|
||||
if (intro.value(QStringLiteral("imagePathsRelative")).isArray()) {
|
||||
const QJsonArray imgs = intro.value(QStringLiteral("imagePathsRelative")).toArray();
|
||||
e.intro.imagePathsRelative.reserve(imgs.size());
|
||||
for (const auto& iv : imgs) {
|
||||
e.intro.imagePathsRelative.push_back(iv.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out = e;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace core::library
|
||||
|
||||
Reference in New Issue
Block a user