Files
xod/docs/guide/nodes-for-xod-in-cpp/README.md
2017-12-14 19:11:44 +03:00

139 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Creating Nodes for XOD in C++
---
# Creating Nodes for XOD in C++
When you need a new node that cannot be easily expressed as a
[patch node](../nodes-for-xod-in-xod), you may implement it in C\++. Another case
to choose C\++ is when performance matters much.
The process outline is:
1. Create a new patch.
2. Place input/output terminals the same way you do when making patch nodes.
3. Add a `xod/patch-nodes/not-implemented-in-xod` marker node.
4. Double click the marker and write down C\++ code.
## The task
Imagine there is no `cos` node to compute an angle cosine in XOD yet. Lets make
one.
To thoroughly understand the example it is expected youre familiar with the
process of creation regular [patch nodes](../nodes-for-xod-in-xod).
## Prepare a dummy
Start with a clear project or open a project with your utilities. Create a new
patch (Ctrl+N) and name it `cos`. Thats the name the new node will get.
Now, we need to create input and output terminals. The cosine function takes one
argument (angle) and returns a single result. So we need an `input-number` and
`output-number`.
When nodes pins meaning is utterly apparent, we recommend omitting pin labels
to reduce visual clutter. In our case the meaning of output is obvious, but the
input is not so simple. The angle could be in radians or degrees. For this
example, were going to choose [radians](https://en.wikipedia.org/wiki/Radian)
because they are often more convenient in mathematical computations and they are
SI units. To make it clear, lets give label `RAD` to the input terminal.
![Cosine terminals](./step1.patch.png)
<div class="ui segment note">
<span class="ui ribbon label">Note</span>
Despite the recommendation, many standard XOD nodes include labels even in
trivial cases. It is legacy; well fix them in future.
</div>
## Declare its a C\++ node
The next step is placing `not-implemented-in-xod` node from `xod/patch-nodes`.
Its a dummy node that tells XOD: “Ignore all regular nodes on this patch, I
have a C\++ implementation, use it.”
![not-implemented-in-xod node](./step2.patch.png)
Double click the `not-implemented-in-xod` node to drill-down. Youll see an
embedded code editor with a template for a start.
## Write down the code
In most cases, when you implement a C\++ node you want to read values from
inputs, do something useful with them, and put some values into outputs. To
communicate with inputs and outputs, XOD provides C\++ functions `getValue` and
`emitValue`. Theyre better demonstrated with an example of complete `cos`
implementation:
```cpp
// Ignore this for now. The definition is required by XOD but we
// not use it for cos
struct State { };
// This is an obligatory marker. XOD will put pin definitions there
\{{ GENERATED_CODE }}
// The `evaluate` function is the nodes entry point. It is the only
// function XOD requires to implement. The context parameter is a
// black-box object youll pass to various API functions.
void evaluate(Context ctx) {
// `getValue` function reads a pin. In angle brackets, it takes a
// name of the pin in form input_PINLABEL (input_RAD in our case)
Number x = getValue<input_RAD>(ctx);
// Next, we use regular C++ to perform some actions. Our case is trivial.
// All we have to do is to call the standard C++ cos function.
// Note the data type `Number`. Its the type XOD uses to represent numbers
// on the current platform.
Number result = cos(x);
// `emitValue` is like `getValue`, but it writes values rather than read.
// Note we use `OUT` label to access our unlabeled output terminal.
// `OUT` is the default name when you omit the label.
emitValue<output_OUT>(ctx, result);
}
```
You may wonder why we used `output_OUT` to refer our unlabeled output terminal.
Thats a default name when you omit the label. Likewise, if you omit a label for
an input, use `input_IN` to refer to it. And if you have got several unnamed
terminals use `input_IN1`, `input_IN2`, `output_OUT1`, `output_OUT2`, etc. The
index assigned according to a terminal position counting from left to right.
Hover a pin label in the inspector window to get a tooltip with the identifier
if youre in doubt.
You could think theres quite much boilerplate code to wrap a simple call to
C\++ `cos` function. Its because the implementation in our example is trivial.
When C\++ implementation does a bigger job, few calls to `getValue` in the
beginning and `emitValue` at the end is not a big deal.
## Use it, test it
Now, our `cos` node is ready. Lets use it. Create a new patch `test-cos`. Use
[`system-time`](/libs/xod/core/system-time/) as an input and a `watch` node to
observe the result. Upload the patch with the debugger and see how the watched
value swings from 1 to -1.
![Cos watch](./cos-watch.gif)
Congratulations! Youve done your first C\++ node.
## Document the node
When the node works as expected, it is a good idea to complete the task by
adding a description for the `cos` node and its pins. Describing C\++ nodes
doesnt differ anyhow from [documenting any other node](../documenting-nodes/):
* Select nothing and put patch description in the Inspector.
* Select terminal nodes one by one and fill the description in the Inspector.
## Whats next
Youve used few C\++ functions and objects to communicate with the node. For
detailed formal help on what functions available, how pin names are generated,
etc see the [C\++ Node API reference](/docs/reference/node-cpp-api/).
Also, make sure to learn how to manage [state](../cpp-state/) and
[time](../cpp-time/) in C\++.