// 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.

#include "impeller/entity/contents/solid_rrect_blur_contents.h"
#include <optional>

#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/geometry/color.h"
#include "impeller/geometry/constants.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/vertex_buffer_builder.h"

namespace impeller {

namespace {
// Generous padding to make sure blurs with large sigmas are fully visible. Used
// to expand the geometry around the rrect.  Larger sigmas have more subtle
// gradients so they need larger padding to avoid hard cutoffs.  Sigma is
// maximized to 3.5 since that should cover 99.95% of all samples.  3.0 should
// cover 99.7% but that was seen to be not enough for large sigmas.
Scalar PadForSigma(Scalar sigma) {
  Scalar scalar = std::min((1.0f / 47.6f) * sigma + 2.5f, 3.5f);
  return sigma * scalar;
}
}  // namespace

SolidRRectBlurContents::SolidRRectBlurContents() = default;

SolidRRectBlurContents::~SolidRRectBlurContents() = default;

void SolidRRectBlurContents::SetRRect(std::optional<Rect> rect,
                                      Size corner_radii) {
  rect_ = rect;
  corner_radii_ = corner_radii;
}

void SolidRRectBlurContents::SetSigma(Sigma sigma) {
  sigma_ = sigma;
}

void SolidRRectBlurContents::SetColor(Color color) {
  color_ = color.Premultiply();
}

Color SolidRRectBlurContents::GetColor() const {
  return color_;
}

std::optional<Rect> SolidRRectBlurContents::GetCoverage(
    const Entity& entity) const {
  if (!rect_.has_value()) {
    return std::nullopt;
  }

  Scalar radius = PadForSigma(sigma_.sigma);

  return rect_->Expand(radius).TransformBounds(entity.GetTransform());
}

bool SolidRRectBlurContents::Render(const ContentContext& renderer,
                                    const Entity& entity,
                                    RenderPass& pass) const {
  if (!rect_.has_value()) {
    return true;
  }

  using VS = RRectBlurPipeline::VertexShader;
  using FS = RRectBlurPipeline::FragmentShader;

  VertexBufferBuilder<VS::PerVertexData> vtx_builder;

  // Clamp the max kernel width/height to 1000 to limit the extent
  // of the blur and to kEhCloseEnough to prevent NaN calculations
  // trying to evaluate a Guassian distribution with a sigma of 0.
  auto blur_sigma = std::clamp(sigma_.sigma, kEhCloseEnough, 250.0f);
  // Increase quality by making the radius a bit bigger than the typical
  // sigma->radius conversion we use for slower blurs.
  auto blur_radius = PadForSigma(blur_sigma);
  auto positive_rect = rect_->GetPositive();
  {
    auto left = -blur_radius;
    auto top = -blur_radius;
    auto right = positive_rect.GetWidth() + blur_radius;
    auto bottom = positive_rect.GetHeight() + blur_radius;

    vtx_builder.AddVertices({
        {Point(left, top)},
        {Point(right, top)},
        {Point(left, bottom)},
        {Point(right, bottom)},
    });
  }

  ContentContextOptions opts = OptionsFromPassAndEntity(pass, entity);
  opts.primitive_type = PrimitiveType::kTriangleStrip;
  Color color = color_;
  if (entity.GetBlendMode() == BlendMode::kClear) {
    opts.is_for_rrect_blur_clear = true;
    color = Color::White();
  }

  VS::FrameInfo frame_info;
  frame_info.mvp = Entity::GetShaderTransform(
      entity.GetShaderClipDepth(), pass,
      entity.GetTransform() *
          Matrix::MakeTranslation(positive_rect.GetOrigin()));

  FS::FragInfo frag_info;
  frag_info.color = color;
  frag_info.blur_sigma = blur_sigma;
  frag_info.rect_size = Point(positive_rect.GetSize());
  frag_info.corner_radii = {std::clamp(corner_radii_.width, kEhCloseEnough,
                                       positive_rect.GetWidth() * 0.5f),
                            std::clamp(corner_radii_.height, kEhCloseEnough,
                                       positive_rect.GetHeight() * 0.5f)};

  pass.SetCommandLabel("RRect Shadow");
  pass.SetPipeline(renderer.GetRRectBlurPipeline(opts));
  pass.SetVertexBuffer(
      vtx_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()));
  VS::BindFrameInfo(pass,
                    renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
  FS::BindFragInfo(pass,
                   renderer.GetTransientsBuffer().EmplaceUniform(frag_info));

  if (!pass.Draw().ok()) {
    return false;
  }

  return true;
}

bool SolidRRectBlurContents::ApplyColorFilter(
    const ColorFilterProc& color_filter_proc) {
  color_ = color_filter_proc(color_);
  return true;
}

}  // namespace impeller
