/* SPDX-FileCopyrightText: 2017 Blender Authors
 *
 * SPDX-License-Identifier: GPL-2.0-or-later */

#include "COM_algorithm_smaa.hh"
#include "COM_node_operation.hh"

#include "node_composite_util.hh"

namespace blender::nodes::node_composite_anti_aliasing_cc {

static void node_declare(NodeDeclarationBuilder &b)
{
  b.use_custom_socket_order();
  b.allow_any_socket_order();
  b.add_input<decl::Color>("Image"_ustr)
      .default_value({1.0f, 1.0f, 1.0f, 1.0f})
      .hide_value()
      .structure_type(StructureType::Dynamic);
  b.add_output<decl::Color>("Image"_ustr)
      .structure_type(StructureType::Dynamic)
      .align_with_previous();

  b.add_input<decl::Float>("Threshold"_ustr)
      .default_value(0.2f)
      .subtype(PROP_FACTOR)
      .min(0.0f)
      .max(1.0f)
      .description(
          "Specifies the threshold or sensitivity to edges. Lowering this value you will be able "
          "to detect more edges at the expense of performance");
  b.add_input<decl::Float>("Contrast Limit"_ustr)
      .default_value(2.0f)
      .min(0.0f)
      .description(
          "If there is an neighbor edge that has a Contrast Limit times bigger contrast than "
          "current edge, current edge will be discarded. This allows to eliminate spurious "
          "crossing edges");
  b.add_input<decl::Float>("Corner Rounding"_ustr)
      .default_value(0.25f)
      .subtype(PROP_FACTOR)
      .min(0.0f)
      .max(1.0f)
      .description("Specifies how much sharp corners will be rounded");
}

using namespace blender::compositor;

class AntiAliasingOperation : public NodeOperation {
 public:
  using NodeOperation::NodeOperation;

  void execute() override
  {
    smaa(this->context(),
         this->get_input("Image"),
         this->get_result("Image"),
         this->get_threshold(),
         this->get_local_contrast_adaptation_factor(),
         this->get_corner_rounding());
  }

  /* We encode the threshold in the [0, 1] range, while the SMAA algorithm expects it in the
   * [0, 0.5] range. */
  float get_threshold()
  {
    return math::clamp(
               this->get_input("Threshold").get_single_value_default<float>(), 0.0f, 1.0f) /
           2.0f;
  }

  float get_local_contrast_adaptation_factor()
  {
    return math::max(0.0f, this->get_input("Contrast Limit").get_single_value_default<float>());
  }

  /* We encode the corner rounding factor in the float [0, 1] range, while the SMAA algorithm
   * expects it in the integer [0, 100] range. */
  int get_corner_rounding()
  {
    return int(math::clamp(this->get_input("Corner Rounding").get_single_value_default<float>(),
                           0.0f,
                           1.0f) *
               100.0f);
  }
};

static NodeOperation *get_compositor_operation(Context &context, const bNode &node)
{
  return new AntiAliasingOperation(context, node);
}

static void node_register()
{
  static bke::bNodeType ntype;

  cmp_node_type_base(&ntype, "CompositorNodeAntiAliasing"_ustr, CMP_NODE_ANTIALIASING);
  ntype.ui_name = "Anti-Aliasing";
  ntype.ui_description = "Smooth away jagged edges";
  ntype.enum_name_legacy = "ANTIALIASING";
  ntype.nclass = NODE_CLASS_OP_FILTER;
  ntype.declare = node_declare;
  ntype.flag |= NODE_PREVIEW;
  ntype.default_width = bke::NodeWidth::_180;
  ntype.get_compositor_operation = get_compositor_operation;

  bke::node_register_type(ntype);
}
NOD_REGISTER_NODE(node_register)

}  // namespace blender::nodes::node_composite_anti_aliasing_cc
