修复动画问题
This commit is contained in:
@@ -1348,6 +1348,26 @@ bool ProjectWorkspace::setEntityImageFrame(const QString& id, int frame, const Q
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProjectWorkspace::setEntityImageFramePath(const QString& id, int frame, const QString& relativePath) {
|
||||||
|
if (m_projectDir.isEmpty() || id.isEmpty() || frame < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const QString rel = relativePath.trimmed();
|
||||||
|
if (rel.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto ents = m_project.entities();
|
||||||
|
bool found = false;
|
||||||
|
for (auto& e : ents) {
|
||||||
|
if (e.id != id) continue;
|
||||||
|
found = true;
|
||||||
|
upsertFrame(e.imageFrames, frame, rel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found) return false;
|
||||||
|
return applyEntities(ents, true, QStringLiteral("插入关键帧(图像)"));
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool removeLocationKeyAtFrame(QVector<Project::Entity::KeyframeVec2>& keys, int frame) {
|
bool removeLocationKeyAtFrame(QVector<Project::Entity::KeyframeVec2>& keys, int frame) {
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ public:
|
|||||||
bool setEntityDepthScaleKey(const QString& id, int frame, double value01);
|
bool setEntityDepthScaleKey(const QString& id, int frame, double value01);
|
||||||
bool setEntityUserScaleKey(const QString& id, int frame, double userScale);
|
bool setEntityUserScaleKey(const QString& id, int frame, double userScale);
|
||||||
bool setEntityImageFrame(const QString& id, int frame, const QImage& image, QString* outRelPath = nullptr);
|
bool setEntityImageFrame(const QString& id, int frame, const QImage& image, QString* outRelPath = nullptr);
|
||||||
|
// 仅更新 imageFrames 中某帧的图像路径(不读图、不写盘),用于高性能地“切断”Hold 区间
|
||||||
|
bool setEntityImageFramePath(const QString& id, int frame, const QString& relativePath);
|
||||||
bool removeEntityLocationKey(const QString& id, int frame);
|
bool removeEntityLocationKey(const QString& id, int frame);
|
||||||
bool removeEntityDepthScaleKey(const QString& id, int frame);
|
bool removeEntityDepthScaleKey(const QString& id, int frame);
|
||||||
bool removeEntityUserScaleKey(const QString& id, int frame);
|
bool removeEntityUserScaleKey(const QString& id, int frame);
|
||||||
|
|||||||
@@ -185,6 +185,34 @@ void FrameAnimationDialog::onReplaceCurrentFrame() {
|
|||||||
auto* it = m_list->currentItem();
|
auto* it = m_list->currentItem();
|
||||||
if (!it) return;
|
if (!it) return;
|
||||||
const int f = it->data(Qt::UserRole).toInt();
|
const int f = it->data(Qt::UserRole).toInt();
|
||||||
|
|
||||||
|
// 在真正替换前先记录当前帧/下一帧的旧图像来源,用于“只影响当前帧”:
|
||||||
|
// 对于原本只在区间端点设置了关键帧、使用 Hold 采样的情况,
|
||||||
|
// 若直接改写关键帧会导致后续所有帧都跟着换图,这里通过在 f+1 上补一帧旧图像来“切断”区间。
|
||||||
|
QString prevRelPathForF;
|
||||||
|
QString prevRelPathForFPlus1;
|
||||||
|
bool hasExplicitKeyAtFPlus1 = false;
|
||||||
|
if (m_workspace.isOpen()) {
|
||||||
|
const auto& ents = m_workspace.entities();
|
||||||
|
const core::Project::Entity* hit = nullptr;
|
||||||
|
for (const auto& e : ents) {
|
||||||
|
if (e.id == m_entityId) {
|
||||||
|
hit = &e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hit) {
|
||||||
|
// 是否已有精确关键帧
|
||||||
|
for (const auto& k : hit->imageFrames) {
|
||||||
|
if (k.frame == f + 1) {
|
||||||
|
hasExplicitKeyAtFPlus1 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevRelPathForF = core::sampleImagePath(hit->imageFrames, f, hit->imagePath);
|
||||||
|
prevRelPathForFPlus1 = core::sampleImagePath(hit->imageFrames, f + 1, hit->imagePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const QString path = QFileDialog::getOpenFileName(
|
const QString path = QFileDialog::getOpenFileName(
|
||||||
this,
|
this,
|
||||||
QStringLiteral("选择该帧图像"),
|
QStringLiteral("选择该帧图像"),
|
||||||
@@ -195,6 +223,14 @@ void FrameAnimationDialog::onReplaceCurrentFrame() {
|
|||||||
QMessageBox::warning(this, QStringLiteral("动画帧"), QStringLiteral("写入该帧失败。"));
|
QMessageBox::warning(this, QStringLiteral("动画帧"), QStringLiteral("写入该帧失败。"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// “单帧替换”的强语义:无论 f 原本是否是关键帧,都不应影响 f+1 之后的帧。
|
||||||
|
// 因此在 f+1 上补一个“替换前 f+1 使用的来源”,以切断 Hold 区间(不覆盖已有关键帧)。
|
||||||
|
// 性能:这里直接写入相对路径,不读图不写盘。
|
||||||
|
if (!hasExplicitKeyAtFPlus1 && !prevRelPathForFPlus1.isEmpty()) {
|
||||||
|
m_workspace.setEntityImageFramePath(m_entityId, f + 1, prevRelPathForFPlus1);
|
||||||
|
}
|
||||||
|
|
||||||
rebuildFrameList();
|
rebuildFrameList();
|
||||||
updatePreviewForFrame(f);
|
updatePreviewForFrame(f);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user