.. _ogn_code_samples_cpp:

OGN Code Samples - C++
======================
This files contains a collection of examples for using the .ogn generated code from C++. There is no particular flow
to these examples, they are used as reference data for the :ref:`ogn_user_guide`.

.. contents::

.. _ogn_minimal_node_cpp:

Minimal C++ Node Implementation
-------------------------------
Every C++ node must contain an include of the file containing the generated database definition, and an implementation
of the ``compute`` method that takes the database as a parameter and returns a boolean indicating if the compute
succeeded.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-minimal
   :end-before: end-minimal

:ref:`[Python Version]<ogn_minimal_node_py>`

.. _ogn_metadata_node_cpp:

Node Type Metadata Access
-------------------------
When node types have any metadata added to them they can be accessed through the ABI node type interface.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-node-metadata
   :end-before: end-node-metadata

:ref:`[Python Version]<ogn_metadata_node_py>`

.. _ogn_node_with_icon_cpp:

Node Icon Location Access
-------------------------
Specifying the icon location and color information creates consistently named pieces of metadata that the UI can use to
present a more customized visual appearance.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-node-icon
   :end-before: end-node-icon

:ref:`[Python Version]<ogn_node_with_icon_py>`

.. _ogn_scheduling_node_cpp:

Node Type Scheduling Hints
--------------------------
Specifying scheduling hints makes it easier for the OmniGraph scheduler to optimize the scheduling of node evaluation.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-node-scheduling
   :end-before: end-node-scheduling


:ref:`[Python Version]<ogn_scheduling_node_python>`

.. _ogn_singleton_node_cpp:

C++ Singleton Node Types
------------------------
Specifying that a node type is a singleton creates a consistently named piece of metadata that can be checked to see
if multiple instances of that node type will be allowed in a graph or its child graphs. Attempting to create more than
one of such node types in the same graph or any of its child graphs will result in an error.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-node-singleton
   :end-before: end-node-singleton

:ref:`[Python Version]<ogn_singleton_node_py>`

.. _ogn_tags_node_cpp:

Node Type Tags
--------------
Specifying the node tags creates a consistently named piece of metadata that the UI can use to present a more
friendly grouping of the node types to the user.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-node-tags
   :end-before: end-node-tags

This example introduces some helper constants which contain strings set to the key values of special internal metadata.
These are metadata elements managed by the code generator. Using these name accessors ensures consistent access.

.. code-block:: text

   kOgnMetadataAllowedTokens       # On attributes of type token, a CSV formatted comma-separated list of potential legal values for the UI
   kOgnMetadataCategories          # On node types, contains a comma-separated list of categories to which the node type belongs
   kOgnMetadataDescription         # On attributes and node types, contains their description from the .ogn file
   kOgnMetadataExtension           # On node types, contains the extension that owns this node type
   kOgnMetadataHidden              # On attributes and node types, indicating to the UI that they should not be shown
   kOgnMetadataIconPath            # On node types, contains the file path to the node's icon representation in the editor
   kOgnMetadataIconBackgroundColor # On node types, overrides the background color of the node's icon
   kOgnMetadataIconBorderColor     # On node types, overrides the border color of the node's icon
   kOgnMetadataSingleton           # On node types its presence indicates that only one of the node type may be created in a graph
   kOgnMetadataTags                # On node types, a comma-separated list of tags for the type
   kOgnMetadataUiName              # On attributes and node types, user-friendly name specified in the .ogn file
   kOgnMetadataUiType              # On certain attribute types, customize how the attribute is displayed on the property panel

:ref:`[Python Version]<ogn_tags_node_py>`

.. _ogn_tokens_node_cpp:

Token Access
------------
There are two accelerators for dealing with tokens. The first is the tokens that are predefined in the generated
code. The second include a couple of methods on the database that facilitate translation between strings and
tokens.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-tokens
   :end-before: end-tokens

:ref:`[Python Version]<ogn_tokens_node_py>`

.. _ogn_uiName_node_cpp:

Node Type UI Name Access
------------------------
Specifying the node UI name creates a consistently named piece of metadata that the UI can use to present a more
friendly name of the node type to the user.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-node-uiName
   :end-before: end-node-uiName

:ref:`[Python Version]<ogn_uiName_node_py>`

.. _ogn_simple_node_cpp:

Simple Attribute Data Type
--------------------------
Accessors are created on the generated database class that return a reference to the underlying attribute data, which
lives in Fabric. You can use ``auto&` and ``const auto&`` type declarations to provide local names to clarify your
code, or you can specify the exact types that are referenced, so long as they are compatible. e.g. if you have a local
typedef ``Byte`` that is a ``uint8_t`` then you can use that type to get a reference to the data. This will be more
useful with more complex data types later.

.. tip::

   For convenience in debugging the actual typedefs for the data are included in the database. They can be found
   in the same location as the attributes, but with a *_t* suffix. For example the attribute ``db.outputs.length``
   will have a corresponding typedef of ``db.outputs.length_t``, which resolves to ``int64_t``.

References to Fabric are actually done through lightweight accessor classes, which provide extra functionality
such as the ability to check if an attribute value is valid or not - ``compute()`` will not be called if any of
the required attributes are invalid. For example with the simple data types the accessor implements
``operator()`` to directly return a reference to the Fabric memory, as seen in the example.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-simple
   :end-before: end-simple

.. tip::

   As these accessor types may be subject to change it's best to avoid exposing their types (i.e. the data type of
   ``db.inputs.token``). If you must pass around attribute data, use the direct references returned from ``operator()``.

:ref:`[Python Version]<ogn_simple_node_py>`

.. _ogn_tuple_node_cpp:

Tuple Attribute Data Type
-------------------------
The wrappers for tuple-types are largely the same as for simple types. The main difference is the underlying data type
that they are wrapping. By default, the ``pxr::GfVec`` types are the types returned from ``operator()`` on tuple types.
Their memory layout is the same as their equivalent POD types, e.g. ``pxr::GfVec3f`` -> ``float[3]`` so you can cast
them to any other equivalent types from your favourite math library.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-tuple
   :end-before: end-tuple

:ref:`[Python Version]<ogn_tuple_node_py>`

.. _ogn_role_node_cpp:

Role Attribute Data Type
------------------------
The wrappers for role-types are identical to their underlying tuple types. The only distinction between the types is
the value that will be returned from the wrapper's ``role()`` method.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-role
   :end-before: end-role

:ref:`[Python Version]<ogn_role_node_py>`

.. _ogn_array_node_cpp:

Array Attribute Data Type
-------------------------
Array attributes are stored in a wrapper that mirrors the functionality of ``std::span``. The memory being managed
belongs to Fabric, with the wrapper providing the functionality to seamlessly manage the memory when the array size
changes (on writable attributes only).

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-array
   :end-before: end-array

:ref:`[Python Version]<ogn_array_node_py>`

.. _ogn_tuple_array_node_cpp:

Tuple-Array Attribute Data Type
-------------------------------
The wrappers for tuple-array types are largely the same as for simple array types. The main difference is the
underlying data type that they are wrapping. See the :ref:`ogn_tuple_node_cpp` section for details on accessing
tuple data.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-tuple-array
   :end-before: end-tuple-array

:ref:`[Python Version]<ogn_tuple_array_node_py>`

.. _ogn_string_node_cpp:

String Attribute Data Type
--------------------------
As the normal operations applied to strings involve size changes, and Fabric requires new allocations every time an
array's size changes, it is best to use a local variable for string manipulations rather than modifying the string
directly. Doing so also gives you the ability to access the wealth of string manipulation library functions.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-string
   :end-before: end-string

:ref:`[Python Version]<ogn_string_node_py>`

.. _ogn_any_node_cpp:

Extended Attribute Data Type - Any
----------------------------------
Extended attributes, of type "any" and union, have data types that are resolved at runtime. This requires extra
information that identifies the resolved types and provides methods for extracting the actual data from the wrapper
around the extended attribute.

In C++ this is accomplished with prudent use of templated methods and operator overloads. The wrapper around the
extended attribute types uses this to provide access to a layered wrapper for the resolved data type, which in turn
provides wrapped access to the underlying Fabric functionality.

This is the documentation for the interface of the extended attribute wrapper class, taken directly from the
implementation file:

.. literalinclude:: ../../../../include/omni/graph/core/ogn/RuntimeAttribute.h
   :language: cpp
   :start-after: begin-extended-attribute-interface-description
   :end-before: end-extended-attribute-interface-description

The first extended type, **any**, is allowed to resolve to any other attribute type.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-union
   :end-before: end-union

:ref:`[Python Version]<ogn_any_node_py>`

.. _ogn_union_node_cpp:

Extended Attribute Data Type - Union
------------------------------------
The access pattern for the union attribute types is exactly the same as for the **any** type. There is just a tacit
agreement that the resolved types will always be one of the ones listed in the union type description.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-union
   :end-before: end-union

:ref:`[Python Version]<ogn_union_node_py>`

.. _ogn_bundle_node_cpp:

Extended Attribute Type Resolution using `ogn::compute`
-------------------------------------------------------

As you might see, resolving attributes manually in c++ results in a lot of repeated code that is difficult to read.
the `ogn::compute` api, defined in `<omni/graph/core/ogn/ComputeHelpers.h>` aims to make this easier for developers.

.. literalinclude:: ../../../../include/omni/graph/core/ogn/ComputeHelpers.h
   :language: cpp
   :start-after: begin-compute-helpers-interface-description
   :end-before: end-compute-helpers-interface-description

For a complete code sample, see the implementation of the `OgnAdd` node:

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-compute-helpers
   :end-before: end-compute-helpers

Bundle Attribute Data Type
--------------------------
Bundle attribute information is accessed the same way as information for any other attribute type. As an aggregate,
the bundle can be treated as a container for attributes, without any data itself.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-bundle
   :end-before: end-bundle

:ref:`[Python Version]<ogn_bundle_node_py>`

.. _ogn_bundle_data_cpp:

When you want to get at the actual data, you use the bundle API to extract the runtime attribute accessors from the
bundle for those attributes you wish to process.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-bundle-data
   :end-before: end-bundle-data

.. tip::

   Although you access them in completely different ways the attributes that are bundle members use the same accessors
   as the extended attribute types. See further information in :ref:`ogn_any_node_cpp`

This documentation for bundle access is pulled directly from the code. It removes the extra complication in the
accessors required to provide proper typing information for bundle members and shows the appropriate calls in the
bundle attribute API.

.. literalinclude:: ../../../../include/omni/graph/core/ogn/Bundle.h
   :language: cpp
   :start-after: begin-bundle-interface-description
   :end-before: end-bundle-interface-description

:ref:`[Python Version]<ogn_bundle_data_py>`

.. _ogn_attribute_memory_type_cpp:

Attribute Memory Location
-------------------------
In C++ nodes the GPU calculations will typically be done by CUDA code. The important thing to remember for this code
is that the CPU, where the node ``compute()`` method lives, cannot dereference pointers in the GPU memory space.
For this reason, all of the APIs that provide access to attribute data values return pointers to the actual data
when it lives on the GPU.

For example, if an attribute has a float value

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-memory-type
   :end-before: end-memory-type

:ref:`[Python Version]<ogn_attribute_memory_type_py>`

.. _ogn_node_cudaPointers_cpp:

Attribute CPU Pointers to GPU Data
----------------------------------
.. note::

   Although this value takes effect at the attribute level the keyword is only valid at the node level. All
   attributes in a node will use the same type of CUDA array pointer referencing.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-cuda-pointers
   :end-before: end-cuda-pointers

:ref:`[Python Version]<ogn_node_cudaPointers_py>`

.. _ogn_node_categories_cpp:

Node Type Categories
--------------------
Categories are added as metadata to the node and can be accessed through the standard metadata interface.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-node-categories
   :end-before: end-node-categories

:ref:`[Python Version]<ogn_node_categories_py>`

.. _ogn_metadata_attribute_cpp:

Attribute Metadata Access
-------------------------
When attributes have metadata added to them they can be accessed through the ABI attribute interface. This works
basically the same as with metadata on node types, just with different accessors.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-attribute-metadata
   :end-before: end-attribute-metadata

:ref:`[Python Version]<ogn_metadata_attribute_py>`

.. _ogn_optional_cpp:

Required vs. Optional Attributes
--------------------------------
For most attributes the generated code will check to see if the attribute is valid before it calls the `compute()`
function. Optional attributes will not have this check made. If you end up using their value then you must make the
call to the `isValid()` method yourself first and react appropriately if invalid values are found. Further, the
existence of these attributes within the compute method is not guaranteed.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-optional
   :end-before: end-optional

:ref:`[Python Version]<ogn_optional_py>`

.. caution::

   Optional attributes may not even appear on the node. This puts the onus on the node writer to completely validate
   the attributes, and provide their own ABI-based access to the attribute data. Use of such attributes should be rare.

.. _ogn_uiName_attribute_cpp:

Attribute UI Name Access
------------------------
Specifying the attribute **uiName** creates a consistently named piece of metadata that the UI can use to present a more
friendly version of the attribute name to the user. It can be accessed through the regular metadata ABI, with some
constants provided for easier access.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-attribute-uiName
   :end-before: end-attribute-uiName

Another access point is shown here. As the attribute patterns defined in the .ogn are unchanging the generated code
provides access to the name of the attribute through a data member so that you don't have to replicate the string.
The access is through local namespaces **inputs::**, **outputs::**, and **state::**, mirroring the database structure.

.. code-block:: cpp

   inputs::x.token() // The name of the input attribute "x" as a token
   inputs::x.name()  // The name of the input attribute "x" as a static string


:ref:`[Python Version]<ogn_uiName_attribute_py>`

.. _ogn_uiType_attribute_cpp:

Attribute Type UI Type Access
-----------------------------
Specifying the attribute **uiType** tells the property panel that this attribute should be shown with custom widgets.
- For path, string, and token attributes, a ui type of "filePath" will show file browser widgets
- For 3- and 4-component numeric tuples, a ui type of "color" will show the color picker widget
in the property panel.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-attribute-uiType
   :end-before: end-attribute-uiType

:ref:`[Python Version]<ogn_uiType_attribute_py>`

.. _ogn_unvalidated_cpp:

Unvalidated Attributes
----------------------
For most attributes the generated code will check to see if the attribute is valid before it calls the `compute()`
function. unvalidated attributes will not have this check made. If you end up using their value then you must make the
call to the `isValid()` method yourself first and react appropriately if invalid values are found. Further, for
attributes with extended types you must verify that they have successfully resolved to a legal type.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-unvalidated
   :end-before: end-unvalidated

:ref:`[Python Version]<ogn_unvalidated_py>`

.. _ogn_state_node_cpp:

Nodes With Internal State
-------------------------

The easiest way to add internal state information is by adding data members to your node class. The presence of any
member variables automatically marks the node as having internal state information, allocating and destroying it
when the node itself is initialized and released. Once the internal state has been constructed it is not modified by
OmniGraph until the node is released, it is entirely up to the node how and when to modify the data.

The data can be easily retrieved with the templated method *internalState<>* on the database class.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-state-node
   :end-before: end-state-node

.. note::

   As access to internal state data is templated you can also store your state data in some external structure,
   however when you do so you must also be sure to override the `setHasState()` ABI method to always return true.
   Unless absolutely necessary it's always easier to make the state a member variable of your node.

:ref:`[Python Version]<ogn_state_node_py>`

.. _ogn_versioned_node_cpp:

Nodes With Version Upgrades
---------------------------

To provide code to upgrade a node from a previous version to the current version you must override the ABI function
`updateNodeVersion()`. The current context and node to be upgraded are passed in, as well as the old version at which
the node was created and the new version to which it should be upgraded. Passing both values allows you to upgrade
nodes at multiple versions in the same code.

This example shows how a new attribute is added using the *INode* ABI interface.

.. literalinclude:: ogn_code_samples_cpp.cpp
   :language: cpp
   :start-after: begin-versioned-node
   :end-before: end-versioned-node

:ref:`[Python Version]<ogn_versioned_node_py>`
