Plan depth export through document renderer
This commit is contained in:
@@ -37,10 +37,20 @@ struct DocumentCubeFaceExportTarget {
|
||||
std::size_t face_count = 0;
|
||||
};
|
||||
|
||||
struct DocumentDepthExportTarget {
|
||||
std::string image_path;
|
||||
std::string depth_path;
|
||||
};
|
||||
|
||||
struct DocumentCubeFaceExportPayload {
|
||||
std::span<const std::byte> bytes;
|
||||
};
|
||||
|
||||
struct DocumentDepthExportPayload {
|
||||
std::span<const std::byte> image_bytes;
|
||||
std::span<const std::byte> depth_bytes;
|
||||
};
|
||||
|
||||
struct DocumentExportCollectionPngPayload {
|
||||
std::string path_suffix;
|
||||
std::span<const std::byte> bytes;
|
||||
@@ -195,6 +205,16 @@ public:
|
||||
virtual void publish_exported_image(std::string_view path) = 0;
|
||||
};
|
||||
|
||||
class DocumentDepthExportWriteServices {
|
||||
public:
|
||||
virtual ~DocumentDepthExportWriteServices() = default;
|
||||
|
||||
virtual pp::foundation::Status write_binary_file(
|
||||
std::string_view path,
|
||||
std::span<const std::byte> bytes) = 0;
|
||||
virtual void publish_exported_image(std::string_view path) = 0;
|
||||
};
|
||||
|
||||
class DocumentExportCollectionWriteServices {
|
||||
public:
|
||||
virtual ~DocumentExportCollectionWriteServices() = default;
|
||||
@@ -623,6 +643,34 @@ document_cube_face_export_names() noexcept
|
||||
return pp::foundation::Result<DocumentCubeFaceExportTarget>::success(std::move(target));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Result<DocumentDepthExportTarget> make_document_depth_export_target(
|
||||
std::string_view work_directory,
|
||||
std::string_view document_name)
|
||||
{
|
||||
if (work_directory.empty()) {
|
||||
return pp::foundation::Result<DocumentDepthExportTarget>::failure(
|
||||
pp::foundation::Status::invalid_argument("work directory must not be empty"));
|
||||
}
|
||||
|
||||
if (document_name.empty()) {
|
||||
return pp::foundation::Result<DocumentDepthExportTarget>::failure(
|
||||
pp::foundation::Status::invalid_argument("document name must not be empty"));
|
||||
}
|
||||
|
||||
DocumentDepthExportTarget target;
|
||||
target.image_path.reserve(work_directory.size() + document_name.size() + 5U);
|
||||
target.image_path += work_directory;
|
||||
target.image_path += "/";
|
||||
target.image_path += document_name;
|
||||
target.image_path += ".png";
|
||||
target.depth_path.reserve(work_directory.size() + document_name.size() + 11U);
|
||||
target.depth_path += work_directory;
|
||||
target.depth_path += "/";
|
||||
target.depth_path += document_name;
|
||||
target.depth_path += "_depth.png";
|
||||
return pp::foundation::Result<DocumentDepthExportTarget>::success(std::move(target));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string document_export_two_digit_index(std::size_t index)
|
||||
{
|
||||
auto value = std::to_string(index);
|
||||
@@ -706,6 +754,33 @@ document_cube_face_export_names() noexcept
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_document_depth_export_write(
|
||||
const DocumentDepthExportTarget& target,
|
||||
DocumentDepthExportPayload payload,
|
||||
DocumentDepthExportWriteServices& services)
|
||||
{
|
||||
if (target.image_path.empty() || target.depth_path.empty()) {
|
||||
return pp::foundation::Status::invalid_argument("depth export target requires image and depth paths");
|
||||
}
|
||||
if (payload.image_bytes.empty() || payload.depth_bytes.empty()) {
|
||||
return pp::foundation::Status::invalid_argument("depth export payload requires image and depth bytes");
|
||||
}
|
||||
|
||||
const auto image_status = services.write_binary_file(target.image_path, payload.image_bytes);
|
||||
if (!image_status.ok()) {
|
||||
return image_status;
|
||||
}
|
||||
services.publish_exported_image(target.image_path);
|
||||
|
||||
const auto depth_status = services.write_binary_file(target.depth_path, payload.depth_bytes);
|
||||
if (!depth_status.ok()) {
|
||||
return depth_status;
|
||||
}
|
||||
services.publish_exported_image(target.depth_path);
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_document_export_collection_write(
|
||||
const DocumentExportCollectionTarget& target,
|
||||
std::span<const DocumentExportCollectionPngPayload> payloads,
|
||||
|
||||
@@ -67,6 +67,7 @@ pp::foundation::Status write_export_binary_file(std::string_view path, std::span
|
||||
|
||||
class LegacyExportWriteServices final
|
||||
: public pp::app::DocumentCubeFaceExportWriteServices
|
||||
, public pp::app::DocumentDepthExportWriteServices
|
||||
, public pp::app::DocumentExportCollectionWriteServices {
|
||||
public:
|
||||
explicit LegacyExportWriteServices(App& app) noexcept
|
||||
@@ -519,6 +520,48 @@ public:
|
||||
void export_depth(std::string_view document_name) override
|
||||
{
|
||||
auto* app = &app_;
|
||||
#if !__WEB__
|
||||
const auto target = pp::app::make_document_depth_export_target(app_.work_path, document_name);
|
||||
if (target) {
|
||||
LOG(
|
||||
"export-depth document export target: image=%s depth=%s",
|
||||
target.value().image_path.c_str(),
|
||||
target.value().depth_path.c_str());
|
||||
} else {
|
||||
LOG("export-depth document export target planning failed: %s", target.status().message);
|
||||
}
|
||||
|
||||
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-depth");
|
||||
if (prepared) {
|
||||
const auto plan = pp::paint_renderer::plan_document_depth_export_render(
|
||||
pp::paint_renderer::DocumentDepthExportRenderPlanRequest {
|
||||
.document = &prepared.value().snapshot.document,
|
||||
.frame_index = prepared.value().snapshot.document.active_frame_index(),
|
||||
});
|
||||
if (plan) {
|
||||
LOG(
|
||||
"export-depth document export render plan: output=%ux%u mergedFaceDraws=%zu layerDepthDraws=%zu visitedLayers=%zu visibleLayers=%zu facePayloads=%zu requiresRendererReadback=%s",
|
||||
plan.value().output_extent.width,
|
||||
plan.value().output_extent.height,
|
||||
plan.value().merged_face_draw_count,
|
||||
plan.value().layer_depth_draw_count,
|
||||
plan.value().visited_layer_count,
|
||||
plan.value().visible_layer_count,
|
||||
plan.value().face_payload_count,
|
||||
plan.value().requires_renderer_readback ? "true" : "false");
|
||||
} else {
|
||||
LOG(
|
||||
"export-depth document export render plan retained legacy export after failure: %s",
|
||||
plan.status().message);
|
||||
}
|
||||
} else {
|
||||
LOG(
|
||||
"export-depth document export snapshot bridge retained legacy export after failure: %s",
|
||||
prepared.status().message);
|
||||
}
|
||||
#else
|
||||
prepare_legacy_document_export_snapshot_or_continue(app_, "export-depth");
|
||||
#endif
|
||||
app_.canvas->m_canvas->export_depth(std::string(document_name), [app] {
|
||||
show_export_success_dialog(
|
||||
*app,
|
||||
|
||||
@@ -683,6 +683,57 @@ export_document_frame_equirectangular_png(DocumentFrameCompositeRequest request)
|
||||
return export_document_frame_equirectangular_png(composite.value());
|
||||
}
|
||||
|
||||
pp::foundation::Result<DocumentDepthExportRenderPlan> plan_document_depth_export_render(
|
||||
DocumentDepthExportRenderPlanRequest request) noexcept
|
||||
{
|
||||
if (request.document == nullptr) {
|
||||
return pp::foundation::Result<DocumentDepthExportRenderPlan>::failure(
|
||||
pp::foundation::Status::invalid_argument("document depth export request requires a document"));
|
||||
}
|
||||
|
||||
if (request.frame_index >= request.document->frames().size()) {
|
||||
return pp::foundation::Result<DocumentDepthExportRenderPlan>::failure(
|
||||
pp::foundation::Status::out_of_range("document depth export frame index is outside the document"));
|
||||
}
|
||||
|
||||
const auto output_pixels = expected_pixel_count(request.output_extent);
|
||||
if (!output_pixels) {
|
||||
return pp::foundation::Result<DocumentDepthExportRenderPlan>::failure(output_pixels.status());
|
||||
}
|
||||
|
||||
DocumentDepthExportRenderPlan plan;
|
||||
plan.output_extent = request.output_extent;
|
||||
plan.merged_face_draw_count = pp::document::cube_face_count;
|
||||
plan.visited_layer_count = request.document->layers().size();
|
||||
|
||||
for (const auto& layer : request.document->layers()) {
|
||||
if (!layer.visible || layer.opacity == 0.0F || request.frame_index >= layer.frames.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++plan.visible_layer_count;
|
||||
std::array<bool, pp::document::cube_face_count> layer_faces {};
|
||||
const auto& frame = layer.frames[request.frame_index];
|
||||
for (const auto& payload : frame.face_pixels) {
|
||||
if (payload.face_index >= pp::document::cube_face_count) {
|
||||
return pp::foundation::Result<DocumentDepthExportRenderPlan>::failure(
|
||||
pp::foundation::Status::out_of_range("document depth export face index is outside the cube"));
|
||||
}
|
||||
|
||||
layer_faces[payload.face_index] = true;
|
||||
++plan.face_payload_count;
|
||||
}
|
||||
|
||||
for (const auto has_payload : layer_faces) {
|
||||
if (has_payload) {
|
||||
++plan.layer_depth_draw_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pp::foundation::Result<DocumentDepthExportRenderPlan>::success(plan);
|
||||
}
|
||||
|
||||
pp::foundation::Result<DocumentLayerEquirectangularPngExportResult>
|
||||
export_document_layers_equirectangular_pngs(DocumentLayerEquirectangularPngExportRequest request)
|
||||
{
|
||||
|
||||
@@ -156,6 +156,29 @@ struct DocumentFrameEquirectangularPngExportResult {
|
||||
std::size_t composited_layer_face_count = 0;
|
||||
};
|
||||
|
||||
struct DocumentDepthExportRenderPlanRequest {
|
||||
const pp::document::CanvasDocument* document = nullptr;
|
||||
std::size_t frame_index = 0;
|
||||
pp::renderer::Extent2D output_extent {
|
||||
.width = 1024,
|
||||
.height = 1024,
|
||||
};
|
||||
};
|
||||
|
||||
struct DocumentDepthExportRenderPlan {
|
||||
pp::renderer::Extent2D output_extent {
|
||||
.width = 1024,
|
||||
.height = 1024,
|
||||
};
|
||||
std::size_t merged_face_draw_count = 0;
|
||||
std::size_t layer_depth_draw_count = 0;
|
||||
std::size_t visited_layer_count = 0;
|
||||
std::size_t visible_layer_count = 0;
|
||||
std::size_t face_payload_count = 0;
|
||||
bool uses_perspective_camera = true;
|
||||
bool requires_renderer_readback = true;
|
||||
};
|
||||
|
||||
struct DocumentLayerEquirectangularPngExportRequest {
|
||||
const pp::document::CanvasDocument* document = nullptr;
|
||||
std::size_t frame_index = 0;
|
||||
@@ -232,6 +255,9 @@ export_document_frame_equirectangular_png(const DocumentFrameCompositeResult& co
|
||||
[[nodiscard]] pp::foundation::Result<DocumentFrameEquirectangularPngExportResult>
|
||||
export_document_frame_equirectangular_png(DocumentFrameCompositeRequest request);
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<DocumentDepthExportRenderPlan> plan_document_depth_export_render(
|
||||
DocumentDepthExportRenderPlanRequest request) noexcept;
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<DocumentLayerEquirectangularPngExportResult>
|
||||
export_document_layers_equirectangular_pngs(DocumentLayerEquirectangularPngExportRequest request);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user