// Add.C
// Copyright (c) 2009 The Foundry Visionmongers Ltd.  All Rights Reserved.

static const char* const HELP = "Adds a constant to a set of channels";

#include "DDImage/PixelIop.h"
#include "DDImage/Row.h"
#include "DDImage/Knobs.h"

using namespace DD::Image;

class Add : public PixelIop
{
  float value[4];
public:
  void in_channels(int input, ChannelSet& mask) const override;
  Add(Node* node) : PixelIop(node)
  {
    value[0] = value[1] = value[2] = value[3] = 0;
  }
  bool pass_transform() const override { return true; }
  void pixel_engine(const Row &in, int y, int x, int r, ChannelMask, Row & out) override;
  void knobs(Knob_Callback) override;
  static const Iop::Description d;
  const char* Class() const override { return d.name; }
  const char* node_help() const override { return HELP; }
  void _validate(bool) override;
};

void Add::_validate(bool for_real)
{
  copy_info();
  for (unsigned i = 0; i < 4; i++) {
    if (value[i]) {
      set_out_channels(Mask_All);
      info_.black_outside(false);
      return;
    }
  }
  set_out_channels(Mask_None);
}

void Add::in_channels(int input, ChannelSet& mask) const
{
  // mask is unchanged
}

void Add::pixel_engine(const Row& in, int y, int x, int r,
                       ChannelMask channels, Row& out)
{
  foreach (z, channels) {
    const float c = value[colourIndex(z)];
    const float* inptr = in[z] + x;
    const float* END = inptr + (r - x);
    float* outptr = out.writable(z) + x;
    while (inptr < END)
      *outptr++ = *inptr++ + c;
  }
}

void Add::knobs(Knob_Callback f)
{
  AColor_knob(f, value, IRange(0, 4), "value");
}

#include "DDImage/NukeWrapper.h"

static Iop* build(Node* node) { return new NukeWrapper(new Add(node)); }
const Iop::Description Add::d("Add", "Color/Math/Add", build);