update
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
#include "persistence/AnimationBundleStore.h"
|
||||
|
||||
#include "persistence/JsonFileAtomic.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace core::persistence {
|
||||
namespace {
|
||||
|
||||
QJsonObject keyToJson(const Project::AnimationKey& k, Project::AnimationValueType t) {
|
||||
QJsonObject o;
|
||||
o.insert("frame", k.frame);
|
||||
switch (t) {
|
||||
case Project::AnimationValueType::Vec2:
|
||||
o.insert("x", k.vec2Value.x());
|
||||
o.insert("y", k.vec2Value.y());
|
||||
break;
|
||||
case Project::AnimationValueType::Double:
|
||||
o.insert("value", k.numberValue);
|
||||
break;
|
||||
case Project::AnimationValueType::Bool:
|
||||
o.insert("value", k.boolValue);
|
||||
break;
|
||||
case Project::AnimationValueType::ImagePath:
|
||||
o.insert("value", k.stringValue);
|
||||
break;
|
||||
case Project::AnimationValueType::PngBytes:
|
||||
o.insert("value", QString::fromLatin1(k.bytesValue.toBase64()));
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
bool keyFromJson(const QJsonObject& o, Project::AnimationValueType t, Project::AnimationKey& out) {
|
||||
out = Project::AnimationKey{};
|
||||
out.frame = o.value("frame").toInt(0);
|
||||
switch (t) {
|
||||
case Project::AnimationValueType::Vec2:
|
||||
out.vec2Value = QPointF(o.value("x").toDouble(0.0), o.value("y").toDouble(0.0));
|
||||
break;
|
||||
case Project::AnimationValueType::Double:
|
||||
out.numberValue = o.value("value").toDouble(0.0);
|
||||
break;
|
||||
case Project::AnimationValueType::Bool:
|
||||
out.boolValue = o.value("value").toBool(true);
|
||||
break;
|
||||
case Project::AnimationValueType::ImagePath:
|
||||
out.stringValue = o.value("value").toString();
|
||||
break;
|
||||
case Project::AnimationValueType::PngBytes: {
|
||||
const QByteArray b64 = o.value("value").toString().toLatin1();
|
||||
out.bytesValue = QByteArray::fromBase64(b64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QString AnimationBundleStore::bundleRelativeDir(const QString& animationId) {
|
||||
if (animationId.isEmpty()) return {};
|
||||
return QStringLiteral("assets/animations/%1").arg(animationId);
|
||||
}
|
||||
|
||||
bool AnimationBundleStore::save(const QString& projectDirAbs, const Project::Animation& animation) {
|
||||
if (projectDirAbs.isEmpty() || animation.id.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const QString relDir = bundleRelativeDir(animation.id);
|
||||
if (relDir.isEmpty()) return false;
|
||||
const QString absDir = QDir(projectDirAbs).filePath(relDir);
|
||||
QDir().mkpath(absDir);
|
||||
|
||||
QJsonObject root;
|
||||
root.insert("id", animation.id);
|
||||
root.insert("name", animation.name);
|
||||
root.insert("fps", animation.fps);
|
||||
root.insert("lengthFrames", animation.lengthFrames);
|
||||
root.insert("loop", animation.loop);
|
||||
|
||||
QJsonArray tracks;
|
||||
for (const auto& t : animation.tracks) {
|
||||
QJsonObject to;
|
||||
to.insert("id", t.id);
|
||||
to.insert("targetKind", int(t.targetKind));
|
||||
to.insert("targetId", t.targetId);
|
||||
to.insert("property", int(t.property));
|
||||
to.insert("valueType", int(t.valueType));
|
||||
to.insert("interpolation", int(t.interpolation));
|
||||
QJsonArray keys;
|
||||
for (const auto& k : t.keys) {
|
||||
keys.append(keyToJson(k, t.valueType));
|
||||
}
|
||||
to.insert("keys", keys);
|
||||
tracks.append(to);
|
||||
}
|
||||
root.insert("tracks", tracks);
|
||||
|
||||
return writeJsonAtomic(QDir(absDir).filePath(QStringLiteral("anim.json")), root, true);
|
||||
}
|
||||
|
||||
bool AnimationBundleStore::load(const QString& projectDirAbs, Project::Animation& inOutAnimation) {
|
||||
if (projectDirAbs.isEmpty() || inOutAnimation.id.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const QString relDir = inOutAnimation.payloadPath;
|
||||
if (relDir.isEmpty()) return false;
|
||||
const QString absDir = QDir(projectDirAbs).filePath(relDir);
|
||||
if (!QFileInfo(absDir).exists()) return false;
|
||||
|
||||
QJsonObject root;
|
||||
if (!readJsonObject(QDir(absDir).filePath(QStringLiteral("anim.json")), root)) {
|
||||
return false;
|
||||
}
|
||||
const QString id = root.value("id").toString();
|
||||
if (id.isEmpty() || id != inOutAnimation.id) {
|
||||
return false;
|
||||
}
|
||||
Project::Animation a = inOutAnimation;
|
||||
a.name = root.value("name").toString();
|
||||
a.fps = std::max(1, root.value("fps").toInt(30));
|
||||
a.lengthFrames = std::max(1, root.value("lengthFrames").toInt(Project::kClipFixedFrames));
|
||||
a.loop = root.value("loop").toBool(true);
|
||||
|
||||
a.tracks.clear();
|
||||
const QJsonValue tracksVal = root.value("tracks");
|
||||
if (tracksVal.isArray()) {
|
||||
for (const auto& it : tracksVal.toArray()) {
|
||||
if (!it.isObject()) continue;
|
||||
const QJsonObject to = it.toObject();
|
||||
Project::AnimationTrack t;
|
||||
t.id = to.value("id").toString();
|
||||
t.targetKind = Project::AnimationTargetKind(to.value("targetKind").toInt(0));
|
||||
t.targetId = to.value("targetId").toString();
|
||||
t.property = Project::AnimationProperty(to.value("property").toInt(0));
|
||||
t.valueType = Project::AnimationValueType(to.value("valueType").toInt(0));
|
||||
t.interpolation = Project::AnimationInterpolation(to.value("interpolation").toInt(1));
|
||||
const QJsonValue keysVal = to.value("keys");
|
||||
if (keysVal.isArray()) {
|
||||
for (const auto& kv : keysVal.toArray()) {
|
||||
if (!kv.isObject()) continue;
|
||||
Project::AnimationKey k;
|
||||
keyFromJson(kv.toObject(), t.valueType, k);
|
||||
t.keys.push_back(k);
|
||||
}
|
||||
}
|
||||
if (!t.targetId.isEmpty()) {
|
||||
a.tracks.push_back(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inOutAnimation = std::move(a);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace core::persistence
|
||||
|
||||
Reference in New Issue
Block a user