How to program a custom Nodekit node
1 Introduction
The creation of a custom node for the Nodekit is quite simple but there are a few things that must be understood before we can start to create our own node.
The first thing is to know how the nodes and the slots work together and what a connection between slots means. The picture shows the simplified architectural design of nodes and slots.
As you can see a node contains one or more input- and output slots. The most important method of a node is the Update(…) method which calculates the values of all the output slots when any of the inputs change.
Connections can be made between input and output slots where one output slot can be connected to any number of input slots. Note that one input slot can have only one connection.
Not shown in the diagram but also important is that input slots have a member property which indicates this slot as an “active” slot meaning it activates a call of the Update(…) method of the node when the value of the slot has changed. So it is possible to create slots which are called “passive” meaning a change of their values does not update the outputs of the node owning the slot.
Now if two slots are connected a change of an output slot´s value triggers the a call of Update(…) method of all connected nodes.
2 A simple node for calculating a modulus of a given number
As we know the modulus calculates the remainder of a division operation. Because this operation needs two arguments we know that our node will get two input slots and one for the result of the calculation.
This formula shows what we want to do:
result = number % modulus
The following steps must be performed before we can start:
Set up a new Library (.dll) project in your preferred C# editor. The Nodekit uses the the last part of the file name of the library as the new group name containing the nodes.
For example:
The file name “part1.part2.dll” will cause that Nodekit names the new node group “part2”.
Add the TagTool.Core.dll in the references of your project. You can find it in the installation folder of the Nodekit.
Now we can start to type our code for the node:
/*
* Created by O.M.A
* User: Richard Radlherr
* Date: 19.03.2008
* Time: 16:46
*
* published under GNU Public License 2.0.
*/
using System;
// It is important to import the TagTool core classes which defines
// the BaseNode class
using TagTool.Core;
namespace TestNodeCollection.MyNodes
{
/**
* Example of a simple custom node which is calculating the modulus
* of a number.
* The information attribute lets you set the name
* and a description of the node you are intended to program.
*
* All nodes must be derived from the BaseNode class.
*/
[Information("Modulo", ToolTipText = "Calculates the modulus.")]
public class MyClass : BaseNode
{
// declare neccessary input slots
InputSlot number;
InputSlot modulus;
// declare neccessary output slots
OutputSlot result;
/**
* Each node must have a standard constructor.
*/
public MyClass()
{
// this is the name of this instance of the modulo node.
Name = "Molulo";
// Create the slot for the argument from which we calculate
// the modulus.
// The default value is zero
// to be compatible to the most nodes from the Nodekit we use
// the double datatype instead of an integer.
// For the modulo calulation we use only the fixed part of the
// number.
number = new InputSlot(this, "Number", 0.0);
// Let the slot update the node if its value changes.
number.Active = true;
// set a callback for parsing values - this enables a text
// field for entering the value.
number.ParseCallback = ParseDouble;
// Similarly to the number input slot we set up the
// modulus input slot.
// Note that zero is not allowed in a modulo operation.
modulus = new InputSlot(this, "Modulus", 1.0);
modulus.Active = true;
modulus.ParseCallback = ParseDouble;
// create the slot containing the result of the calculation.
result = new OutputSlot(this, "Result", typeof(double));
// set an initial value for the output.
result.Value = 0.0;
}
/**
* Parse callback for the numbers.
*/
private static Object ParseDouble(String description)
{
return Convert.ToDouble(description);
}
/**
* The update method is where the work is done.
*/
public override void Update(Object sender)
{
// prevent from division by zero
if((int)(double)modulus.Value > 0)
{
result.Value = (double) ((int)(double)number.Value %
(int)(double)modulus.Value);
}
}
/**
* On initializatoin (called after loading the node) we have nothing
* to do.
*/
public override void Initialize()
{
}
/**
* Expose each slot as property member of the class.
*´The node attribute is necessary for creating the GUI
* automatically
* by traversing over the properties.
*/
[NodeAttribute(SlotType.Input, Show = true)]
public InputSlot Number
{
get { return number; }
}
[NodeAttribute(SlotType.Input, Show = true)]
public InputSlot Modulus
{
get { return modulus; }
}
[NodeAttribute(SlotType.Output, Show = true)]
public OutputSlot Result
{
get { return result; }
}
}
}
Now compile your project and put the resulting dynamic link library file into the “plugins” folder of your Nodekit installation. When started Nodekit will load all libraries containing additional Nodes from there.
Note that now a new group containing our new node appears in the menu on the left side of the editing panel:
By dragging the node into the editing pane an instance of the node is created. You can now try to enter some input values manually and look what happens. Then you could try to draw in some other nodes from the “Math” section and connect them (by dragging lines from output slots to input slots) to the Modulo node. Enter some values in the other nodes.
For example:
3 Creating a custom node representing graphics
Now we know how to set up a simple node for calculations. But how can we create custom shapes shown on the screen?
The next example shows an implementation of a node drawing the OpenGl “standard teapot”. Therefore we derive a class from the DirectShape class which is defined in the TagTool.Graphics library. The DirectShape class offers a Render() method in which the drawing of the object has to be done.
In our case we simple call the “glutWireTeapot “ function there.
Note that your project must reference the TagTool.Graphics.dll (from the Nodekit installation folder) and the CsGl – library (can be found in the global assembly cache).
Now we can implement a node which has one output slot with the created shape as value. The code example shows both the Teapot shape class and the teapot node class.
using System;
using TagTool.Core;
using TagTool.Graphics;
using CsGL.OpenGL;
/**
* Example of a simple node creating a graphical shape.
*/
namespace TestNodeCollection.MyNodes
{
/**
* We wanna create a simple predefined Teapot.
* Nodekit define a set of classes regarding to graphics construction.
* One of them is the firect shape which is intended to be renderend
* in immediate mode (ie. call glVertex, glColor... in the render method).
* Note that all datatypes used in nodekit must be marked as serializable.
*/
[Serializable()]
public class Teapot : DirectShape
{
/**
* Create a teapot with a given scale.
*/
public Teapot(double scale)
{
this.scale = scale;
}
/**
* Create a teapot with a scale of one.
*/
public Teapot()
{
}
// the scale of out teapot.
private double scale = 1.0;
/**
* Gets or sets the scale of the teapot.
*/
public double Scale {
get {
return scale;
}
set {
scale = value;
}
}
/**
* Render the teapot.
*/
public override void Render()
{
CsGL.OpenGL.GLUT.glutWireTeapot(scale);
}
/**
* Create a copy of the teapot.
*/
public override Object Clone()
{
return new Teapot(scale);
}
}
/**
* Now the node representing the teapot...
*/
public class TeapotNode : BaseNode
{
// inputslot for the scale of the teapot
InputSlot size;
// the outputslot then holds our teapot shape
OutputSlot shape;
public TeapotNode()
{
Name = "Teapot";
size = new InputSlot(this, "Size", 1.0);
size.Active = true;
size.ParseCallback = ParseDouble;
shape = new OutputSlot(this, "Shape", typeof(ShapePrototype));
shape.Value = new Teapot();
}
private static Object ParseDouble(String description)
{
return Convert.ToDouble(description);
}
/**
* In the update method create a teapot with the given size.
*/
public override void Update(Object sender)
{
shape.Value = new Shape(new Teapot((double)size.Value),
new LinearTransformation());
}
/**
* no initializeation have to be done.
*/
public override void Initialize()
{
}
// expose slots for GUI creation.
[NodeAttribute(SlotType.Input, Show = true)]
public InputSlot Size
{
get { return size; }
}
[NodeAttribute(SlotType.Output, Show = true)]
public OutputSlot Shape
{
get { return shape; }
}
}
}
Compile your project and copy the result to the Nodekit “plugin” folder again and restart the nodekit.
For example you could create a patch that looks like this:
The result of the that network is a Teapot that can be rotated by the mouse:





