Attributes
==========

Attributes are containers for data associated with a ``GeoInfo`` in NUKE. NUKE
allows for per-point, per-vertex, per-primitive and per-object attributes.
These are described in the :ref:`attribute-groups` section. Attributes can also
hold different types of value. We go into this in the as described in the
:ref:`attribute-types` section. 

Although attributes belong to individual ``GeoInfo`` objects, they are stored
as part of a ``GeometryList`` so that they can be packed and accessed more
efficiently.


.. _attribute-groups:

Attribute groups
----------------

There are 6 attribute groups in NUKE's 3D system:

Primitives
  The shapes which make up the object. These can be triangles, individual
  points, polygons, and so on.

Vertices
  A point on a primitive. Vertices aren't shared between primitives, but they
  don't store a position directly - instead they have an index into the points
  list. So primitives cannot share a vertex, but they can each have a vertex
  that exists at the same point in space.

Points
  Coordinates of points in 3D space, usually stored in the object's local
  coordinate system.

Object
  A single 3D object.

Matrix
  The transformation matrix from the object's local coordinate system to world
  coordinates.

Attributes
  Any other data associated with the object. Attributes themselves are
  associated with one of the other groups, which will determine the
  cardinality of the attribute. To put it another way, a point attribute will
  have one item per point; a vertex attribute will have one item per vertex;
  and an object attribute will only ever have one item.

These groups are defined by an enum in ``GeoInfo.h``::

    enum GroupType {
      Group_None       = -1,
      //
      Group_Primitives = 0,
      Group_Vertices   = 1,
      Group_Points     = 2,
      Group_Object     = 3,
      //
      Group_Matrix     = 4,
      Group_Attributes = 5,
      //
      Group_Last = 6
    };

The special value ``Group_None`` is used to indicate an unknown or invalid
group; ``Group_Last`` will always be the total number of groups and is useful
for defining array sizes or when iterating over all groups (for example).

There's also a set of bitmasks defined for the groups. These are mainly used
for the rebuild flags on the object. They are defined in ``GeoInfo.h`` like
this::

  enum {
    Mask_No_Geometry  = 0x00000000,
    Mask_Primitives   = 0x00000001, //!< Primitive list
    Mask_Vertices     = 0x00000002, //!< Vertex group
    Mask_Points       = 0x00000004, //!< Point list
    Mask_Geometry     = Mask_Primitives | Mask_Vertices | Mask_Points,
    //
    Mask_Object       = 0x00000008, //!< The Object
    Mask_Matrix       = 0x00000010, //!< Local->World Transform Matrix
    Mask_Attributes   = 0x00000020, //!< Attribute list
    //
    Mask_All_Geometry = Mask_Geometry | Mask_Attributes | Mask_Object | Mask_Matrix,
  };

  typedef unsigned GeometryMask;

Note that some of the flags are just combinations of others, defined for
convenience: ``Mask_Geometry`` and ``Mask_All_Geometry``.


.. _attribute-types:

Attribute types
---------------

These are the attribute types NUKE knows about:

**Float**
  A single floating point value.

**Vector2**
  A pair of floats.

**Vector3**
  Three floats.

**Vector4**
  Four floats.

**Normal**
  Three floats, like a Vector3, but transformed differently.

**Int**
  A single integer value.

**String**
  A ``char*`` value. *TODO: does NUKE manage the memory for these or is it up to
  client code?*

**Pointer**
  A ``void*`` value. You can use this to store a pointer to any data you like;
  NUKE will never try to do anything with these other than passing them along
  the DAG for you. **This means you have to manage the memory it points to
  yourself.**

**Matrix3**
  A 3x3 matrix, 9 floats altogether.

**Matrix4**
  A 4x4 matrix, 16 floats altogether.

There's an enumeration defining these types in ``DDImage/Attribute.h``::

  /*! Attribute data type enumerations. */
  enum AttribType {
    INVALID_ATTRIB = -1, //!< Data type not set

    FLOAT_ATTRIB,   //!< 1 float
    VECTOR2_ATTRIB, //!< Vector2(2 floats)
    VECTOR3_ATTRIB, //!< Vector3(3 floats)
    VECTOR4_ATTRIB, //!< Vector4(4 floats)
    NORMAL_ATTRIB,  //!< Normal vector - Vector3(3 floats)

    INT_ATTRIB,     //!< Int
    STRING_ATTRIB,  //!< Char*
    POINTER_ATTRIB, //!< Void*
      
    MATRIX3_ATTRIB, //!< Matrix3 (9 floats)
    MATRIX4_ATTRIB  //!< Matrix4 (16 floats)
  };


Attribute contexts
------------------

An ``Attribute`` object in the NDK is merely a data store: it knows the type
and number of values it holds, its name and nothing else. It doesn't have any
information about its wider context, such as the attribute group it belongs to.
DDImage provides the ``AttribContext`` class to handle this.

An ``AttribContext`` contains an ``Attribute``, a group type (e.g.
``Group_Points``, ``Group_Vertices`` and additional information about how the
attribute is to be processed such as whether it should be interpolated or not.


Finding out what attributes are available
-----------------------------------------

The ``GeoInfo`` class has two methods to help find out what attributes it has:

.. cpp:function:: int GeoInfo::get_attribcontext_count() const

  Get the number of attributes (and hence the number of ``AttributeContext``
  objects) on this ``GeoInfo``.

.. cpp:function:: const AttribContext* GeoInfo::get_attribcontext(int index) const

  Get an ``AttribContext`` using it's list position rather than it's name, type
  and group.

Using these you can iterate over all the available attributes for a GeoInfo.


Getting attributes
------------------

The ``GeoInfo`` class provides read-only access to all of its attributes via
various lookup methods, detailed below. Some of these methods allow you to
specify a group for the attribute; others do not. For the methods where you don't 
specify a group it will search through a number of the groups in the following
order:

#. ``Group_Vertices``
#. ``Group_Points``
#. ``Group_Primitives``
#. ``Group_Object``


The ``GeoInfo`` class provides the following methods for getting an
``Attribute``:

.. cpp:function:: const Attribute* GeoInfo::get_attribute(const char* name) const

  Returns an ``Attribute`` with the specified name and any type, using the
  search order above.

.. cpp:function:: const Attribute* GeoInfo::get_typed_attribute(const char* name, int type) const

  Returns any ``Attribute`` with the specified name and type, using the search
  order above. If there is an attribute with a matching name but a different
  type, this will return ``NULL``.

.. cpp:function:: const Attribute* GeoInfo::get_group_attribute(int group, const char* name) const

  Returns an ``Attribute``, if one exists, with the specified name and any
  type. This will only look in the specified group and will return ``NULL`` if
  it doesnt' find one there.
  
.. cpp:function:: const Attribute* GeoInfo::get_typed_group_attribute(int group, const char* name, int type) const

  Returns an ``Attribute``, if one exists, with the specified name and type.
  This will only look in the specified group and will return ``NULL`` if it
  doesn't find a matching attribute there.


There are equivalent methods for getting an ``AttribContext``:

.. cpp:function:: const AttribContext* GeoInfo::get_attribcontext(const char* name) const

  Returns an ``AttribContext`` with the specified name and any type, using the
  search order above.

.. cpp:function:: const AttribContext* GeoInfo::get_typed_attribcontext(const char* name, int type) const

  Returns any ``AttribContext`` with the specified name and type, using the
  search order above. If there is an attribute with a matching name but a
  different type, this will return ``NULL``.

.. cpp:function:: const AttribContext* GeoInfo::get_group_attribcontext(int group, const char* name) const

  Returns an ``AttribContext``, if one exists, with the specified name and any
  type.  This will only look in the specified group and wil return ``NULL`` if
  it doesn't find one there.

.. cpp:function:: const AttribContext* GeoInfo::get_typed_group_attribcontext(int group, const char* name, int type) const

  Returns an ``Attribute``, if one exists, with the specified name and type.
  This will only look in the specified group and will return ``NULL`` if it
  doesn't find a matching attribute there.


Adding attributes
-----------------

To add an attribute to an object, use:

.. cpp:function:: const AttribContext* GeoInfo::writable_attribcontext(int obj, GroupType group, const char* name, AttribType type) const

  Get or create an attribute on a particular object and return an
  ``AttribContext`` for it. The ``AttribContext`` will have the group ID,
  attribute name and item type specified by the ``group``, ``name`` and
  ``type`` parameters respectively.


Deleting attributes
-------------------

The ``GeoInfo`` class provides this method:

.. cpp:function:: void GeoInfo::delete_group_attribute(int group, const char* name, int type = INVALID_ATTRIB)

If you leave the type set to the default value, ``INVALID_ATTRIB``, it will not
take the attribute type into consideration when finding the attribute to
delete. Otherwise, it will only delete an attribute of that type.


Standard attributes
-------------------

There are a number of predefined attributes that NUKE recognises:

+-----------------+-------------------+-----------------------------------+
| Attribute name  | Group             | Meaning                           |
+=================+===================+===================================+
| "uv"            | Group_Points      | Texture coordinates, stored as a  |
|                 | Group_Vertices    | vector4.                          |
+-----------------+-------------------+-----------------------------------+
| "N"             | Group_Points      | Point, vertex and surface normals |
|                 | Group_Vertices    | stored as a vector4.              |
|                 | Group_Primitives  |                                   |
+-----------------+-------------------+-----------------------------------+
| "Cf"            | Group_Points      | Surface colour.                   |
+-----------------+-------------------+-----------------------------------+
| "pw"            | Group_Points      | World-space point.                |
+-----------------+-------------------+-----------------------------------+
| "vel"           | Group_Points      | Per-point velocity, used by the   |
|                 |                   | ScanlineRenderer for motion blur. |
+-----------------+-------------------+-----------------------------------+

