#include "paint_renderer/compositor.h" #include namespace pp::paint_renderer { namespace { [[nodiscard]] pp::foundation::Result expected_pixel_count(pp::renderer::Extent2D extent) noexcept { const auto extent_status = pp::renderer::validate_extent(extent); if (!extent_status.ok()) { return pp::foundation::Result::failure(extent_status); } const auto width = static_cast(extent.width); const auto height = static_cast(extent.height); if (width > std::numeric_limits::max() / height) { return pp::foundation::Result::failure( pp::foundation::Status::out_of_range("pixel count overflows uint64")); } const auto count = width * height; if (count > static_cast(std::numeric_limits::max())) { return pp::foundation::Result::failure( pp::foundation::Status::out_of_range("pixel count exceeds addressable memory")); } return pp::foundation::Result::success(static_cast(count)); } } pp::foundation::Status composite_layer( std::span destination, pp::renderer::Extent2D extent, LayerCompositeView layer) noexcept { const auto pixel_count = expected_pixel_count(extent); if (!pixel_count) { return pixel_count.status(); } if (destination.size() != pixel_count.value() || layer.pixels.size() != pixel_count.value()) { return pp::foundation::Status::invalid_argument("composite buffers must match the render extent"); } if (layer.opacity < 0.0F || layer.opacity > 1.0F) { return pp::foundation::Status::out_of_range("layer opacity must be between 0 and 1"); } if (!layer.visible || layer.opacity == 0.0F) { return pp::foundation::Status::success(); } for (std::size_t i = 0; i < destination.size(); ++i) { auto stroke = layer.pixels[i]; stroke.a *= layer.opacity; destination[i] = pp::paint::blend_pixels(destination[i], stroke, layer.blend_mode); } return pp::foundation::Status::success(); } }