This commit is contained in:
2026-05-23 20:49:32 +08:00
parent 12ea7273ef
commit f78de517ec
5 changed files with 245 additions and 310 deletions
+80 -23
View File
@@ -687,8 +687,11 @@ void EditorCanvas::setEntities(const QVector<core::Project::Entity>& entities,
const QString prevSelectedId =
(m_selectedEntity >= 0 && m_selectedEntity < m_entities.size()) ? m_entities[m_selectedEntity].id : QString();
m_blackholeOverlayImageCache.clear();
m_projectDirAbs = projectDirAbs;
if (m_entityRasterCacheProjectDir != projectDirAbs) {
m_entityRasterImageCache.clear();
m_entityRasterCacheProjectDir = projectDirAbs;
}
m_entities.clear();
m_entities.reserve(entities.size());
@@ -761,37 +764,87 @@ void EditorCanvas::setEntities(const QVector<core::Project::Entity>& entities,
v.color = QColor(255, 120, 0, 70);
if (!e.runtimeImagePng.isEmpty()) {
QImage img;
img.loadFromData(e.runtimeImagePng, "PNG");
if (!img.isNull() && img.format() != QImage::Format_ARGB32_Premultiplied) {
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
const QString cacheKey = QStringLiteral("rt:%1:%2:%3")
.arg(e.id)
.arg(e.runtimeImagePng.size())
.arg(qHash(e.runtimeImagePng));
auto cit = m_entityRasterImageCache.constFind(cacheKey);
if (cit != m_entityRasterImageCache.cend() && !cit->isNull()) {
v.image = cit.value();
} else {
QImage img;
img.loadFromData(e.runtimeImagePng, "PNG");
if (!img.isNull() && img.format() != QImage::Format_ARGB32_Premultiplied) {
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
if (!img.isNull()) {
m_entityRasterImageCache.insert(cacheKey, img);
}
v.image = img;
}
v.image = img;
} else {
const QString imgRel = e.imagePath;
if (imgRel.startsWith(QStringLiteral("pngb64:"))) {
const QByteArray b64 = imgRel.mid(QStringLiteral("pngb64:").size()).toLatin1();
const QByteArray raw = QByteArray::fromBase64(b64);
QImage img;
img.loadFromData(raw, "PNG");
if (!img.isNull() && img.format() != QImage::Format_ARGB32_Premultiplied) {
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
v.image = img;
} else if (!imgRel.isEmpty() && !projectDirAbs.isEmpty()) {
const QString abs = QDir(projectDirAbs).filePath(imgRel);
if (QFileInfo::exists(abs)) {
QImage img(abs);
const QString cacheKey =
QStringLiteral("b64:%1:%2").arg(raw.size()).arg(qHash(raw));
auto cit = m_entityRasterImageCache.constFind(cacheKey);
if (cit != m_entityRasterImageCache.cend() && !cit->isNull()) {
v.image = cit.value();
} else {
QImage img;
img.loadFromData(raw, "PNG");
if (!img.isNull() && img.format() != QImage::Format_ARGB32_Premultiplied) {
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
if (!img.isNull()) {
m_entityRasterImageCache.insert(cacheKey, img);
}
v.image = img;
}
} else if (!imgRel.isEmpty() && !projectDirAbs.isEmpty()) {
const QString abs = QDir::cleanPath(QDir(projectDirAbs).filePath(imgRel));
if (QFileInfo::exists(abs)) {
auto cit = m_entityRasterImageCache.constFind(abs);
if (cit != m_entityRasterImageCache.cend() && !cit->isNull()) {
v.image = cit.value();
} else {
QImage img(abs);
if (!img.isNull() && img.format() != QImage::Format_ARGB32_Premultiplied) {
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
if (!img.isNull()) {
m_entityRasterImageCache.insert(abs, img);
}
v.image = img;
}
}
}
}
m_entities.push_back(v);
}
constexpr int kMaxEntityRasterCacheEntries = 768;
if (m_entityRasterImageCache.size() > kMaxEntityRasterCacheEntries) {
m_entityRasterImageCache.clear();
}
if (!m_blackholeOverlayImageCache.isEmpty()) {
QSet<QString> aliveIds;
aliveIds.reserve(m_entities.size());
for (const auto& ent : m_entities) {
aliveIds.insert(ent.id);
}
for (auto it = m_blackholeOverlayImageCache.begin(); it != m_blackholeOverlayImageCache.end();) {
if (!aliveIds.contains(it.key())) {
it = m_blackholeOverlayImageCache.erase(it);
} else {
++it;
}
}
}
// 绘制/命中顺序:
// - priority 小(低)先画,大(高)后画,高优先级盖住低优先级
// - priority 相同:深度小(远)先画,大(近)后画,近处盖住远处(等价于按距离缩放决定上下层)
@@ -816,13 +869,15 @@ void EditorCanvas::setEntities(const QVector<core::Project::Entity>& entities,
}
}
if (m_selectedEntity >= 0) {
const auto& ent = m_entities[m_selectedEntity];
const QPointF origin =
ent.polygonWorld.isEmpty() ? ent.rect.center() : entity_cutout::polygonCentroid(ent.polygonWorld);
emit selectedEntityChanged(true, ent.id, ent.depth, origin);
} else if (!prevSelectedId.isEmpty()) {
emit selectedEntityChanged(false, QString(), 0, QPointF());
if (!m_suppressSelectionSignals) {
if (m_selectedEntity >= 0) {
const auto& ent = m_entities[m_selectedEntity];
const QPointF origin =
ent.polygonWorld.isEmpty() ? ent.rect.center() : entity_cutout::polygonCentroid(ent.polygonWorld);
emit selectedEntityChanged(true, ent.id, ent.depth, origin);
} else if (!prevSelectedId.isEmpty()) {
emit selectedEntityChanged(false, QString(), 0, QPointF());
}
}
if (!m_selectedBlackholeEntityId.isEmpty()) {
@@ -3375,6 +3430,8 @@ void EditorCanvas::mouseReleaseEvent(QMouseEvent* e) {
e->button() == Qt::LeftButton) {
const auto& cam = m_cameraOverlays[m_selectedCameraIndex];
const QPointF delta = cam.centerWorld - m_cameraDragStartCenterWorld;
// 先于 requestMoveCamera 清除:MainWindow::refreshEditorPage 需刷新 overlays,否则会误判“仍在拖动”而跳过 setCameraOverlays
m_draggingCamera = false;
if (!cam.id.isEmpty() && (!qFuzzyIsNull(delta.x()) || !qFuzzyIsNull(delta.y()))) {
emit requestMoveCamera(cam.id, delta);
} else if (!cam.id.isEmpty()) {
+8
View File
@@ -95,6 +95,8 @@ public:
void setEntities(const QVector<core::Project::Entity>& entities,
const QVector<double>& opacities01,
const QString& projectDirAbs);
/// 播放/时间轴轻量刷帧时置 true,避免 setEntities 每帧 emit selectedEntityChanged 拖垮主线程
void setSuppressSelectionSignals(bool on) { m_suppressSelectionSignals = on; }
void setTools(const QVector<core::Project::Tool>& tools, const QVector<double>& opacities01);
void setCameraOverlays(const QVector<core::Project::Camera>& cameras,
const QString& selectedId,
@@ -107,6 +109,8 @@ public:
int currentFrame() const { return m_currentFrame; }
bool isDraggingEntity() const { return m_draggingEntity; }
/// 正在拖动摄像机中心手柄(Move 工具);此时 overlays 由画布更新,勿用工作区求值覆盖
bool isDraggingCamera() const { return m_draggingCamera; }
void selectEntityById(const QString& id);
void clearEntitySelection();
@@ -252,6 +256,10 @@ private:
private:
QString m_projectDirAbs;
/// 实体抠图贴图缓存(键:磁盘绝对路径或 runtime/png 内容摘要),避免播放时每帧 QImage(path) 读盘
QHash<QString, QImage> m_entityRasterImageCache;
QString m_entityRasterCacheProjectDir;
bool m_suppressSelectionSignals = false;
QHash<QString, QImage> m_blackholeOverlayImageCache;
QString m_bgAbsPath;
bool m_backgroundVisible = true;