blob: 43d2af2512b7fe868f297335b2bc524cbee73ed1 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <memory>
#include <optional>
#include <variant>
#include <vector>
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/entity.h"
#include "impeller/renderer/formats.h"
namespace impeller {
class Pipeline;
class FilterContents : public Contents {
public:
enum class BlurStyle {
/// Blurred inside and outside.
kNormal,
/// Solid inside, blurred outside.
kSolid,
/// Nothing inside, blurred outside.
kOuter,
/// Blurred inside, nothing outside.
kInner,
};
/// For filters that use a Gaussian distribution, this is the `Radius` size to
/// use per `Sigma` (standard deviation).
///
/// This cutoff (sqrt(3)) is taken from Flutter and Skia (where the
/// multiplicative inverse of this constant is used (1 / sqrt(3)):
/// https://api.flutter.dev/flutter/dart-ui/Shadow/convertRadiusToSigma.html
///
/// In practice, this value is somewhat arbitrary, and can be changed to a
/// higher number to integrate more of the Gaussian function and render higher
/// quality blurs (with exponentially diminishing returns for the same sigma
/// input). Making this value any lower results in a noticable loss of
/// quality in the blur.
constexpr static float kKernelRadiusPerSigma = 1.73205080757;
struct Radius;
/// @brief In filters that use Gaussian distributions, "sigma" is a size of
/// one standard deviation in terms of the local space pixel grid of
/// the filter input. In other words, this determines how wide the
/// distribution stretches.
struct Sigma {
Scalar sigma = 0.0;
constexpr Sigma() = default;
explicit constexpr Sigma(Scalar p_sigma) : sigma(p_sigma) {}
constexpr operator Radius() const {
return Radius{sigma > 0.5f ? (sigma - 0.5f) * kKernelRadiusPerSigma
: 0.0f};
};
};
/// @brief For convolution filters, the "radius" is the size of the
/// convolution kernel to use on the local space pixel grid of the
/// filter input.
/// For Gaussian blur kernels, this unit has a linear
/// relationship with `Sigma`. See `kKernelRadiusPerSigma` for
/// details on how this relationship works.
struct Radius {
Scalar radius = 0.0;
constexpr Radius() = default;
explicit constexpr Radius(Scalar p_radius) : radius(p_radius) {}
constexpr operator Sigma() const {
return Sigma{radius > 0 ? radius / kKernelRadiusPerSigma + 0.5f : 0.0f};
};
};
static std::shared_ptr<FilterContents> MakeBlend(
Entity::BlendMode blend_mode,
FilterInput::Vector inputs,
std::optional<Color> foreground_color = std::nullopt);
static std::shared_ptr<FilterContents> MakeDirectionalGaussianBlur(
FilterInput::Ref input,
Sigma sigma,
Vector2 direction,
BlurStyle blur_style = BlurStyle::kNormal,
FilterInput::Ref alpha_mask = nullptr);
static std::shared_ptr<FilterContents> MakeGaussianBlur(
FilterInput::Ref input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style = BlurStyle::kNormal);
static std::shared_ptr<FilterContents> MakeBorderMaskBlur(
FilterInput::Ref input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style = BlurStyle::kNormal);
FilterContents();
~FilterContents() override;
/// @brief The input texture sources for this filter. Each input's emitted
/// texture is expected to have premultiplied alpha colors.
///
/// The number of required or optional textures depends on the
/// particular filter's implementation.
void SetInputs(FilterInput::Vector inputs);
/// @brief Screen space bounds to use for cropping the filter output.
void SetCoverageCrop(std::optional<Rect> coverage_crop);
// |Contents|
bool Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const override;
// |Contents|
std::optional<Rect> GetCoverage(const Entity& entity) const override;
// |Contents|
std::optional<Snapshot> RenderToSnapshot(const ContentContext& renderer,
const Entity& entity) const override;
virtual Matrix GetLocalTransform() const;
Matrix GetTransform(const Matrix& parent_transform) const;
private:
virtual std::optional<Rect> GetFilterCoverage(
const FilterInput::Vector& inputs,
const Entity& entity) const;
/// @brief Takes a set of zero or more input textures and writes to an output
/// texture.
virtual bool RenderFilter(const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
RenderPass& pass,
const Rect& coverage) const = 0;
std::optional<Rect> GetLocalCoverage(const Entity& local_entity) const;
FilterInput::Vector inputs_;
std::optional<Rect> coverage_crop_;
FML_DISALLOW_COPY_AND_ASSIGN(FilterContents);
};
} // namespace impeller