Plan document export snapshot routing

This commit is contained in:
2026-06-06 11:03:28 +02:00
parent 6c772a1c84
commit 7575f51c45
8 changed files with 494 additions and 80 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include "app_core/app_dialog.h"
#include "app_core/document_canvas.h"
#include "document/document.h"
#include "foundation/result.h"
@@ -137,6 +138,11 @@ enum class DocumentExportExecutionKind {
timelapse,
};
enum class DocumentExportSnapshotRouteAction {
use_document_snapshot_writer,
use_legacy_export,
};
struct DocumentExportMenuPlan {
DocumentExportMenuKind kind = DocumentExportMenuKind::jpeg;
DocumentExportMenuAction action = DocumentExportMenuAction::show_jpeg_dialog;
@@ -156,6 +162,16 @@ struct DocumentExportSuccessDialogPlan {
bool show_dialog = false;
};
struct DocumentExportSnapshotRoutePlan {
DocumentExportExecutionKind kind = DocumentExportExecutionKind::equirectangular_file;
DocumentExportSnapshotRouteAction action = DocumentExportSnapshotRouteAction::use_legacy_export;
bool payload_complete = false;
bool target_supported = false;
bool platform_supported = false;
bool uses_document_snapshot_writer = false;
std::string_view fallback_reason;
};
class DocumentExportMenuServices {
public:
virtual ~DocumentExportMenuServices() = default;
@@ -408,6 +424,38 @@ public:
return "Document export failed";
}
[[nodiscard]] constexpr DocumentExportSnapshotRoutePlan plan_document_export_snapshot_route(
DocumentExportExecutionKind kind,
DocumentCanvasSaveSnapshotReport report,
bool target_supported,
bool platform_supported) noexcept
{
DocumentExportSnapshotRoutePlan plan;
plan.kind = kind;
plan.payload_complete = report.payload_complete;
plan.target_supported = target_supported;
plan.platform_supported = platform_supported;
if (!platform_supported) {
plan.fallback_reason = "document snapshot export is disabled on this platform";
return plan;
}
if (!target_supported) {
plan.fallback_reason = "document snapshot export does not support this target";
return plan;
}
if (!report.payload_complete) {
plan.fallback_reason = "document snapshot still requires renderer payload readback";
return plan;
}
plan.action = DocumentExportSnapshotRouteAction::use_document_snapshot_writer;
plan.uses_document_snapshot_writer = true;
return plan;
}
[[nodiscard]] constexpr DocumentExportCollectionTargetPlan plan_document_export_collection_target(
DocumentExportCollectionKind kind,
bool use_work_directory_collection) noexcept

View File

@@ -202,6 +202,37 @@ void prepare_legacy_document_export_snapshot_or_continue(App& app, const char* c
}
}
bool use_legacy_document_snapshot_writer(
const char* context,
pp::app::DocumentExportExecutionKind kind,
const LegacyDocumentExportSnapshotReports& reports,
bool target_supported,
bool platform_supported)
{
const auto report = pp::app::make_document_canvas_save_snapshot_report(reports.snapshot);
const auto route = pp::app::plan_document_export_snapshot_route(
kind,
report,
target_supported,
platform_supported);
if (!route.uses_document_snapshot_writer) {
LOG(
"%s document export writer retained legacy export: %.*s",
context,
static_cast<int>(route.fallback_reason.size()),
route.fallback_reason.data());
return false;
}
LOG(
"%s document export writer route: document-snapshot payloadComplete=%s capturedFaces=%zu pendingFaces=%zu",
context,
route.payload_complete ? "true" : "false",
report.captured_face_payloads,
report.pending_face_payloads);
return true;
}
pp::foundation::Status export_cube_faces_from_document_snapshot(
App& app,
std::string_view document_name,
@@ -377,20 +408,27 @@ public:
if (is_png_export_target(target.path) || is_jpeg_export_target(target.path)) {
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-equirectangular");
if (prepared) {
const auto exported = export_equirectangular_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::equirectangular,
pp::app::document_export_equirectangular_platform_destination(),
app_.work_path));
return;
}
if (use_legacy_document_snapshot_writer(
"export-equirectangular",
pp::app::DocumentExportExecutionKind::equirectangular_file,
prepared.value(),
true,
true)) {
const auto exported = export_equirectangular_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::equirectangular,
pp::app::document_export_equirectangular_platform_destination(),
app_.work_path));
return;
}
LOG(
"export-equirectangular document export writer retained legacy export after failure: %s",
exported.message);
LOG(
"export-equirectangular document export writer retained legacy export after failure: %s",
exported.message);
}
} else {
LOG(
"export-equirectangular document export snapshot bridge retained legacy export after failure: %s",
@@ -427,18 +465,25 @@ public:
const auto collection_target = pp::app::DocumentExportCollectionTarget {
.stem_path = target.stem_path,
};
const auto exported = export_layers_from_document_snapshot(app_, collection_target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::layers,
pp::app::DocumentExportSuccessDestination::path,
target.stem_path));
return;
}
if (use_legacy_document_snapshot_writer(
"export-layers",
pp::app::DocumentExportExecutionKind::layers_stem,
prepared.value(),
true,
true)) {
const auto exported = export_layers_from_document_snapshot(app_, collection_target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::layers,
pp::app::DocumentExportSuccessDestination::path,
target.stem_path));
return;
}
LOG("export-layers document export writer retained legacy export after failure: %s", exported.message);
LOG("export-layers document export writer retained legacy export after failure: %s", exported.message);
}
} else {
LOG(
"export-layers document export snapshot bridge retained legacy export after failure: %s",
@@ -463,17 +508,24 @@ public:
#if !__WEB__
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-layers");
if (prepared) {
const auto exported = export_layers_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::layers,
pp::app::DocumentExportSuccessDestination::files_panopainter));
return;
}
if (use_legacy_document_snapshot_writer(
"export-layers",
pp::app::DocumentExportExecutionKind::layers_collection,
prepared.value(),
true,
true)) {
const auto exported = export_layers_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::layers,
pp::app::DocumentExportSuccessDestination::files_panopainter));
return;
}
LOG("export-layers document export writer retained legacy export after failure: %s", exported.message);
LOG("export-layers document export writer retained legacy export after failure: %s", exported.message);
}
} else {
LOG(
"export-layers document export snapshot bridge retained legacy export after failure: %s",
@@ -500,23 +552,30 @@ public:
const auto collection_target = pp::app::DocumentExportCollectionTarget {
.stem_path = target.stem_path,
};
const auto exported = export_animation_frames_from_document_snapshot(
app_,
collection_target,
prepared.value());
if (exported.ok()) {
show_export_success_dialog(
if (use_legacy_document_snapshot_writer(
"export-animation-frames",
pp::app::DocumentExportExecutionKind::animation_frames_stem,
prepared.value(),
true,
true)) {
const auto exported = export_animation_frames_from_document_snapshot(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::animation_frames,
pp::app::DocumentExportSuccessDestination::path,
target.stem_path));
return;
}
collection_target,
prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::animation_frames,
pp::app::DocumentExportSuccessDestination::path,
target.stem_path));
return;
}
LOG(
"export-animation-frames document export writer retained legacy export after failure: %s",
exported.message);
LOG(
"export-animation-frames document export writer retained legacy export after failure: %s",
exported.message);
}
} else {
LOG(
"export-animation-frames document export snapshot bridge retained legacy export after failure: %s",
@@ -541,19 +600,26 @@ public:
#if !__WEB__
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-animation-frames");
if (prepared) {
const auto exported = export_animation_frames_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::animation_frames,
pp::app::DocumentExportSuccessDestination::files_panopainter));
return;
}
if (use_legacy_document_snapshot_writer(
"export-animation-frames",
pp::app::DocumentExportExecutionKind::animation_frames_collection,
prepared.value(),
true,
true)) {
const auto exported = export_animation_frames_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::animation_frames,
pp::app::DocumentExportSuccessDestination::files_panopainter));
return;
}
LOG(
"export-animation-frames document export writer retained legacy export after failure: %s",
exported.message);
LOG(
"export-animation-frames document export writer retained legacy export after failure: %s",
exported.message);
}
} else {
LOG(
"export-animation-frames document export snapshot bridge retained legacy export after failure: %s",
@@ -631,20 +697,27 @@ public:
auto* app = &app_;
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-cube-faces");
if (prepared) {
const auto exported = export_cube_faces_from_document_snapshot(app_, document_name, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::cube_faces,
pp::app::document_export_media_platform_destination(),
app_.work_path));
return;
}
if (use_legacy_document_snapshot_writer(
"export-cube-faces",
pp::app::DocumentExportExecutionKind::cube_faces,
prepared.value(),
true,
true)) {
const auto exported = export_cube_faces_from_document_snapshot(app_, document_name, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::cube_faces,
pp::app::document_export_media_platform_destination(),
app_.work_path));
return;
}
LOG(
"export-cube-faces document export writer retained legacy export after failure: %s",
exported.message);
LOG(
"export-cube-faces document export writer retained legacy export after failure: %s",
exported.message);
}
} else {
LOG(
"export-cube-faces document export snapshot bridge retained legacy export after failure: %s",