From BlenderWiki

Jump to: navigation, search
Note: This is an archived version of the Blender Developer Wiki. The current and active wiki is available on wiki.blender.org.

Overview of node changes in 2.60

This is an overview of the bigger changes and sub-projects implemented in the particles-2010 branch. For the purpose of merging with trunk, all the particle and modifier trees and nodes have been stripped. There are still many small changes and additions that don't directly relate to any of these projects, but here you will only find the bigger ones.

Internal Changes

Type Structures and Templates

  • Node Trees get their own type struct

Node trees were defining specific behavior by switch statements in core node code, which makes code hard to read and maintain, especially when adding new tree types. Now trees get their own type struct (bNodeTreeType) as well, which makes core code more generic.

  • Node socket type meaning changes

The existing bNodeSocketType struct was used to define static lists of sockets used for a node type. This struct has been renamed to bNodeSocketTemplate now. A new struct named bNodeSocketType has been added, which works much like node and tree types, providing basic parameters (such as the circle color) used for a socket of that type.

  • Node templates

bNodeTemplate is a simple collection of data that's needed to define an actual node. For group nodes it also holds a pointer to the node tree that makes up the actual group type. Can be extended by other parameters in future if required. Avoids a long list of unused arbitrary parameters in the API for adding nodes.

Socket Input Buttons

Old sockets had a bNodeStack struct to store input button values. This is too restrictive when adding new socket data types, e.g. ints or matrices. Sockets now have a generic void *default_value, which points to one of several simple structs bNodeSocketValueInt, bNodeSocketValueFloat, etc. In addition to the actual input value, these also store custom limits and a RNA property subtype (if it's meaningful for the data type). This way node buttons can make full use of the new interface possibilities.

Display vs. Execution order

Nodes were previously always sorted in their execution order, even in the UI. The only exception was that selected nodes were drawn on top of unselected nodes. As part of a new "frame" node feature (#Frames), a stable Z-order of nodes has been implemented. Front/back ordering does not depend on node links in any way now, only selecting nodes will bring them on top of others. During execution a separate list of nodes is used, which is sorted by dependencies as before.

File structure changes

A couple of new files have been added to better organize the code.

  • Each tree has its own file now (e.g. CMP_nodetree.c), to define the tree type struct.
  • Group node code is now in its own file (currently ***_common.h/.c, in order to share static functions with loop nodes). The idea is that the core code should not contain any reference to specific node types or tree types. All special behavior of group nodes should be behind the abstract interface provided by the node type struct. (Note: this is still ongoing work, some parts may need to be cleaned up further).
  • node_socket.h/.c contains socket type definitions.
  • Shared functions for execution of cmp/mat/tex nodes are in node_exec.h/.c. These are basic functions that define socket stack indices and prepare threaded data stacks. In the future the current tree types will be replaced by more sophisticated implementations, at which point this file will be obsolete.

The file structure could be improved further by creating own directories for each of the tree types. I did not do this yet simply because it breaks each and every merge operation with SVN when one of the nodes is changed.

Execution Data

One of the most problematic design parts of the old code is the close integration of execution data into the node trees: Each tree directly stores all data produced during execution (in the stack and threadstack pointers). This is a big problem because:

  • It won't work for advanced tree types, which have no use for the old, simple bNodeStack data storage.
  • It is bound to break parallel execution. While it still works for threaded sample calculations in material nodes, it causes trouble with node groups and possible multiple calls for the same tree.

The solution is to keep execution data strictly separate from the node trees themselves. Most new node-driven features already apply this principle by adding an intermediate node representation, which is "translated" from the original tree in a preparation step. This resembles a compiler translating a source code file (the visible node tree) into machine instructions (the internal execution structures).

At this moment the node tree still stores a pointer to the classic execution data used for compo/material/texture trees (collected in a single bNodeTreeExec pointer), for the sole reason that the render pipeline currently does not store execution instances, but needs to get those from the material or texture (via the node tree).

Frames

Frame nodes are a special new node type without any actual execution function. They are a pure UI layout helper feature, which is meant to provide lightweight grouping features. Nodes that are dragged on top of a frame node are then attached to that frame. This way frames are an easy way of grouping nodes without creating a full blown group node type. Frames always stay behind other node types (but keep their relative order like all nodes do now). They can also be attached to other frames, effectively building a hierarchy of frame nodes.

Here's a video demonstrating frames: