.. _knobs-value-provider:

Value provider (output knobs)
=============================

Sometimes a node has an intermediate calculation that it wishes to expose to users.  For example, NUKE's
3D nodes find it useful to provide an "output knob" for the transformation matrix that has been calculated
from the translate/scale/rotate knobs. 

In order to allow this, NUKE lets you set a "ValueProvider" on certain knobs (namely those inheriting from
the Array knob type). ValueProvider differs from
standard knob linking in the sense that it provides a Model-View type interface, so that the value of the
new knob is actually directly dependent on the ValueProvider and thus the source data, as opposed to both
knobs maintaining storage and state, and simply updating each other when they change.

As such, a ValueProvider linked knob is 'OUTPUT_ONLY' both in terms of the knob flag, and in that an 
end user is only able to view the value and not change it. Let's take a look at some of the details.


.. code-block:: c

  void knobs(Knob_Callback f)
  {
    Float_knob(f, &_c, "output");
    SetValueProvider(f, this);
  }

The object pointed to by the second parameter of SetValueParameter has to be an implementation
of the ArrayKnobI::ValueProviderI class.  In the example above it is assumed that the Op itself is
an implementation of ValueProviderI.  It needs to implement the following methods:

.. cpp:function:: bool ArrayKnobI::ValueProviderI::provideValuesEnabled(const DD::Image::ArrayKnobI*, const DD::Image::OutputContext& oc) const

  This is given the pointer to the knob in question, and an OutputContext and should return true if the ValueProviderI
  wishes to provide the value at this context, or false if the internal value from the ArrayKnob should be used.

.. cpp:function:: std::vector<double> ArrayKnobI::ValueProviderI::provideValues(const ArrayKnobI* arrayKnob, const DD::Image::OutputContext& oc) const
 
  This function is called if provideValuesEnabled() has returned true already.  It is given the arrayKnob and the context
  and should return a vector corresponding in size to the number of elements in the ArrayKnob (e.g. 1 for a Float_knob, 2
  for an XY_knob), etc.  It should calculate the values to be displayed/exposed, and return them.  For example:

  .. code-block:: c

    virtual std::vector<double> provideValues(const ArrayKnobI* arrayKnob, const DD::Image::OutputContext& oc) const {
      std::vector<double> values;
      values.push_back(knob("a")->get_value_at(oc.frame(), oc.view()) * knob("b")->get_value_at(oc.frame(), oc.view()));
      return values;
    }

  If multiple knobs are using the same value provider then it can distinguish between them from the first parameter.
  Note that when provideValues() is called on an object which is also an Op, you cannot rely on the state of that Op
  being valid or up-to-date for the passed-in-context.  This is why this function fetches the knob values itself, 
  making sure to specify the time and view from the OutputContext. Note additionally that provideValues cannot take
  its source from, for example, image data and so forth.



The NDK contains a 'ValueProviderOp' sample which demonstrates a simple case using a ValueProvider to link a :ref:`knobs-knobtypes-color_knob`
and a :ref:`knobs-knobtypes-multifloat_knob`. If you're looking to link non-axis knob types then you may want to check out the :ref:`knobs-knob_changed`
section.
