NodeSubclassing

Version 2 (coder, 04/09/2014 22:03)

1 1 coder
h1. Deriving a New Node Class in C++
2 1 coder
3 2 coder
{{>toc}}
4 2 coder
5 1 coder
This page explains how to create your own node class. The number of libavg internals you need to know to do this isn't large. There are several base-class methods which need to be overridden in a derived class. They manage setup and destruction of the node as well as performing the actual rendering. In addition, you probably need to define a python API that your node exposes.
6 1 coder
7 1 coder
Any node that shows the contents of a bitmap should be derived from @RasterNode@ - this is probably the most common case. Alternatively, nodes that display geometric forms can be derived from @VectorNode@ or @FilledVectorNode@.
8 1 coder
9 1 coder
If you derive from @RasterNode@, rendering proceeds using an @OGLSurface@. The main task of the derived class is to associate one or more textures with the surface and fill the textures with data. Setting vertex positions, rendering the surface and applying FXNodes is mostly handled by the base class. @CameraNode@ provides a simple sample that you can build upon.
10 1 coder
11 1 coder
Deriving from @VectorNode@ or @FilledVectorNode@ is different. The derived class is responsible for setting vertex positions, while the base class manages basic vector attributes like stroke width and color/texture of the node. As sample, use e.g. @LineNode@.
12 1 coder
13 1 coder
h2. Lifecycle
14 1 coder
15 1 coder
Node construction proceeds in several phases. In the constructor, neither a connection to the root of the node tree nor an OpenGL context are available. At this point, Python arguments are transferred to C++ member variables and everything that doesn't need an OpenGL context or a connection to the tree root is setup. 
16 1 coder
17 1 coder
Second, @connect()@ is called. This signifies a connection to the root of the node tree and might cause the @mediadir@ to change (making a media reload necessary). Also, at this point, the on-canvas coordinates of the node are known. Finally, @connectDisplay()@ is called when the window has been opened and the node can access OpenGL functionality. This allows, e.g., upload of texture data to the GPU. 
18 1 coder
19 1 coder
Conversely, when the node is removed from the tree (or when playback ends), @disconnect()@ is called. Any data on the GPU (e.g. textures) should be discarded in @disconnect()@. @RasterNode::disconnect()@ deletes the OpenGL objects managed by the base class, including the @OGLSurface@ and any FX objects. If lbKill == true@, the node will never be reconnected. All data can be discarded.
20 1 coder
21 1 coder
In the destructor, delete anything left - as usual :).
22 1 coder
23 1 coder
24 1 coder
h2. Rendering
25 1 coder
26 1 coder
libavg renders in two passes. Each pass does a depth-first traversal through the node tree. In the first pass, @preRender()@ is called for each node. During this pass, no OpenGL functions should be called. In @RasterNode@-derived classes, @preRender()@ needs to make sure all textures are updated by calling @scheduleTexUpload()@ with correct bitmap data if necessary. It should also call @scheduleFXRender()@ if the texture has changed - this causes a possible FXNode to be applied. In addition, it always needs to call @calcVertexArray()@ to generate the vertexes that will be rendered.
27 1 coder
28 1 coder
The second pass is responsible for sending all data to the GPU, and if there are multiple windows open, it will actually traverse the node tree multiple times, each time with a different current OpenGL context. In this pass, @render()@ is called for each visible node. Usually, the derived class only needs to call @RasterNode::blt32()@ (or @blta8()@) appropriately.
29 1 coder
30 1 coder
One other function that some nodes need to override is @getMediaSize()@. This returns the native size of the node, e.g. the bitmap size for an @ImageNode@.
31 1 coder
32 1 coder
@VectorNodes@ simply need to override calcVertexes and submit appropriate vertexes in that function. A number of auxilliary functions are available in the base classes and in @VertexData@.
33 1 coder
34 1 coder
h2. Python Interface
35 1 coder
36 1 coder
The python interface exported by a node is defined using boost::python. The @ColorNode@ plugin contains some boost::python code. For node classes in the core library, the python interface is defined in the @src/wrapper@ directory.