#pragma once #include "document/document.h" #include "foundation/result.h" #include "paint/blend.h" #include "renderer_api/renderer_api.h" #include #include #include #include #include #include #include namespace pp::paint_renderer { enum class StrokeCompositePath : std::uint8_t { fixed_function_blend, framebuffer_fetch, ping_pong_textures, }; struct LayerCompositeView { std::span pixels; float opacity = 1.0F; bool visible = true; pp::paint::BlendMode blend_mode = pp::paint::BlendMode::normal; }; struct StrokeCompositeRequest { pp::renderer::Extent2D extent {}; pp::renderer::TextureFormat target_format = pp::renderer::TextureFormat::rgba8; pp::renderer::TextureUsage target_usage = pp::renderer::TextureUsage::render_target | pp::renderer::TextureUsage::sampled | pp::renderer::TextureUsage::copy_source | pp::renderer::TextureUsage::copy_destination; pp::paint::BlendMode layer_blend_mode = pp::paint::BlendMode::normal; pp::paint::StrokeBlendMode stroke_blend_mode = pp::paint::StrokeBlendMode::normal; bool dual_brush_blend = false; bool pattern_blend = false; }; struct StrokeCompositePlan { StrokeCompositePath path = StrokeCompositePath::fixed_function_blend; pp::renderer::PaintFeedbackPlan feedback {}; pp::renderer::TextureDesc target_desc {}; std::uint64_t target_bytes = 0; std::uint64_t auxiliary_bytes = 0; std::uint64_t estimated_working_bytes = 0; bool complex_blend = false; bool reads_destination_color = false; bool requires_auxiliary_texture = false; bool requires_texture_copy = false; bool requires_render_target_blit = false; bool requires_explicit_transition = false; }; struct CanvasBlendGateRequest { pp::renderer::Extent2D extent {}; std::span layer_blend_modes; bool has_stroke_blend_mode = false; int stroke_blend_mode = 0; bool dual_brush_blend = false; bool pattern_blend = false; }; struct CanvasBlendGatePlan { bool shader_blend = false; bool complex_blend = false; bool compatibility_fallback = false; bool stroke_complex = false; bool dual_brush_complex = false; bool pattern_complex = false; int first_complex_layer_index = -1; StrokeCompositePath path = StrokeCompositePath::fixed_function_blend; bool reads_destination_color = false; bool requires_auxiliary_texture = false; bool requires_texture_copy = false; bool requires_render_target_blit = false; }; struct CanvasStrokeFeedbackPlan { StrokeCompositePath path = StrokeCompositePath::fixed_function_blend; bool reads_destination_color = false; bool requires_auxiliary_texture = false; bool requires_texture_copy = false; bool requires_render_target_blit = false; bool compatibility_fallback = false; }; struct DocumentFaceCompositeRequest { const pp::document::CanvasDocument* document = nullptr; std::size_t frame_index = 0; std::uint32_t face_index = 0; pp::paint::Rgba clear_color {}; }; struct DocumentFaceCompositeResult { pp::renderer::Extent2D extent {}; std::vector pixels; std::size_t visited_layer_count = 0; std::size_t composited_layer_count = 0; std::size_t face_payload_count = 0; }; struct DocumentFrameCompositeRequest { const pp::document::CanvasDocument* document = nullptr; std::size_t frame_index = 0; pp::paint::Rgba clear_color {}; }; struct DocumentFrameCompositeResult { pp::renderer::Extent2D extent {}; std::array faces {}; std::size_t visited_layer_count = 0; std::size_t composited_layer_face_count = 0; std::size_t face_payload_count = 0; }; struct DocumentFrameUploadRequest { const pp::document::CanvasDocument* document = nullptr; std::size_t frame_index = 0; pp::paint::Rgba clear_color {}; bool transition_to_shader_read = true; }; struct DocumentFrameUploadResult { DocumentFrameCompositeResult composite {}; std::array, pp::document::cube_face_count> face_textures {}; std::size_t texture_count = 0; std::size_t transition_count = 0; std::uint64_t uploaded_bytes = 0; }; struct RecordedDocumentFrameUploadResult { DocumentFrameUploadResult upload {}; std::size_t command_count = 0; std::size_t upload_command_count = 0; std::size_t transition_command_count = 0; }; struct DocumentFrameFacePngExportResult { DocumentFrameCompositeResult composite {}; std::array, pp::document::cube_face_count> face_pngs {}; std::size_t face_count = 0; std::uint64_t encoded_bytes = 0; }; struct DocumentFrameEquirectangularPngExportResult { pp::renderer::Extent2D face_extent {}; pp::renderer::Extent2D equirectangular_extent {}; std::vector png; std::uint64_t encoded_bytes = 0; std::size_t face_payload_count = 0; 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; pp::paint::Rgba clear_color {}; }; struct DocumentLayerEquirectangularPng { std::size_t layer_index = 0; std::string layer_name; pp::renderer::Extent2D face_extent {}; pp::renderer::Extent2D equirectangular_extent {}; std::vector png; std::uint64_t encoded_bytes = 0; std::size_t face_payload_count = 0; std::size_t composited_layer_face_count = 0; }; struct DocumentLayerEquirectangularPngExportResult { std::vector layers; std::uint64_t encoded_bytes = 0; std::size_t layer_count = 0; }; struct DocumentAnimationFrameEquirectangularPngExportRequest { const pp::document::CanvasDocument* document = nullptr; pp::paint::Rgba clear_color {}; }; struct DocumentAnimationFrameEquirectangularPng { std::size_t frame_index = 0; pp::renderer::Extent2D face_extent {}; pp::renderer::Extent2D equirectangular_extent {}; std::vector png; std::uint64_t encoded_bytes = 0; std::size_t face_payload_count = 0; std::size_t composited_layer_face_count = 0; }; struct DocumentAnimationFrameEquirectangularPngExportResult { std::vector frames; std::uint64_t encoded_bytes = 0; std::size_t frame_count = 0; }; struct DocumentFrameExportReadinessResult { RecordedDocumentFrameUploadResult recorded_upload {}; DocumentFrameFacePngExportResult face_pngs {}; }; [[nodiscard]] pp::foundation::Status composite_layer( std::span destination, pp::renderer::Extent2D extent, LayerCompositeView layer) noexcept; [[nodiscard]] pp::foundation::Result composite_document_face( DocumentFaceCompositeRequest request); [[nodiscard]] pp::foundation::Result composite_document_frame( DocumentFrameCompositeRequest request); [[nodiscard]] pp::foundation::Result upload_document_frame_faces( pp::renderer::IRenderDevice& device, DocumentFrameUploadRequest request); [[nodiscard]] pp::foundation::Result record_document_frame_upload( DocumentFrameUploadRequest request); [[nodiscard]] pp::foundation::Result export_document_frame_face_pngs( DocumentFrameCompositeRequest request); [[nodiscard]] pp::foundation::Result export_document_frame_equirectangular_png(const DocumentFrameCompositeResult& composite); [[nodiscard]] pp::foundation::Result export_document_frame_equirectangular_png(DocumentFrameCompositeRequest request); [[nodiscard]] pp::foundation::Result plan_document_depth_export_render( DocumentDepthExportRenderPlanRequest request) noexcept; [[nodiscard]] pp::foundation::Result export_document_layers_equirectangular_pngs(DocumentLayerEquirectangularPngExportRequest request); [[nodiscard]] pp::foundation::Result export_document_animation_frames_equirectangular_pngs( DocumentAnimationFrameEquirectangularPngExportRequest request); [[nodiscard]] pp::foundation::Result prepare_document_frame_export_readiness( DocumentFrameCompositeRequest request); [[nodiscard]] bool stroke_composite_requires_feedback( pp::paint::BlendMode layer_blend_mode, pp::paint::StrokeBlendMode stroke_blend_mode, bool dual_brush_blend, bool pattern_blend) noexcept; [[nodiscard]] pp::foundation::Result plan_stroke_composite( pp::renderer::RenderDeviceFeatures features, StrokeCompositeRequest request) noexcept; [[nodiscard]] pp::foundation::Result plan_canvas_blend_gate( pp::renderer::RenderDeviceFeatures features, CanvasBlendGateRequest request) noexcept; [[nodiscard]] pp::foundation::Result plan_canvas_stroke_feedback( pp::renderer::RenderDeviceFeatures features, pp::renderer::Extent2D extent) noexcept; [[nodiscard]] const char* stroke_composite_path_name(StrokeCompositePath path) noexcept; }