Merge of the PyNodes branch (aka "custom nodes") into trunk.
authorLukas Toenne <lukas.toenne@googlemail.com>
Mon, 18 Mar 2013 16:34:57 +0000 (16:34 +0000)
committerLukas Toenne <lukas.toenne@googlemail.com>
Mon, 18 Mar 2013 16:34:57 +0000 (16:34 +0000)
PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements.

=== Dynamic node type registration ===
Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes.

Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2].

=== Node group improvements ===
Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3].

The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there.

[1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes
[2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender
[3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/

293 files changed:
doc/python_api/examples/bpy.types.NodeTree.py [new file with mode: 0644]
intern/cycles/blender/blender_python.cpp
intern/cycles/blender/blender_shader.cpp
intern/cycles/blender/blender_util.h
intern/cycles/render/graph.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
release/scripts/modules/bpy_types.py
release/scripts/startup/bl_operators/node.py
release/scripts/startup/bl_ui/space_node.py
release/scripts/templates_py/custom_nodes.py [new file with mode: 0644]
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/image.c
source/blender/blenkernel/intern/mask.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/movieclip.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/texture.c
source/blender/blenlib/BLI_ghash.h
source/blender/blenlib/CMakeLists.txt
source/blender/blenlib/intern/BLI_ghash.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/readfile.h
source/blender/blenloader/intern/versioning_250.c
source/blender/blenloader/intern/writefile.c
source/blender/compositor/intern/COM_CompositorContext.cpp
source/blender/compositor/intern/COM_CompositorContext.h
source/blender/compositor/intern/COM_Converter.cpp
source/blender/compositor/intern/COM_ExecutionSystem.cpp
source/blender/compositor/intern/COM_ExecutionSystemHelper.cpp
source/blender/compositor/intern/COM_ExecutionSystemHelper.h
source/blender/compositor/intern/COM_InputSocket.cpp
source/blender/compositor/intern/COM_InputSocket.h
source/blender/compositor/intern/COM_Node.cpp
source/blender/compositor/intern/COM_Node.h
source/blender/compositor/intern/COM_NodeBase.h
source/blender/compositor/intern/COM_Socket.cpp
source/blender/compositor/intern/COM_Socket.h
source/blender/compositor/intern/COM_compositor.cpp
source/blender/compositor/nodes/COM_BlurNode.cpp
source/blender/compositor/nodes/COM_BokehBlurNode.cpp
source/blender/compositor/nodes/COM_ColorCurveNode.cpp
source/blender/compositor/nodes/COM_ColorNode.cpp
source/blender/compositor/nodes/COM_GroupNode.cpp
source/blender/compositor/nodes/COM_LensDistortionNode.cpp
source/blender/compositor/nodes/COM_NormalNode.cpp
source/blender/compositor/nodes/COM_SocketProxyNode.cpp
source/blender/compositor/nodes/COM_ValueNode.cpp
source/blender/compositor/operations/COM_PreviewOperation.cpp
source/blender/compositor/operations/COM_PreviewOperation.h
source/blender/editors/include/ED_node.h
source/blender/editors/include/UI_interface.h
source/blender/editors/include/UI_resources.h
source/blender/editors/include/UI_view2d.h
source/blender/editors/interface/interface_draw.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_templates.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/interface/resources.c
source/blender/editors/interface/view2d.c
source/blender/editors/object/object_add.c
source/blender/editors/render/render_preview.c
source/blender/editors/render/render_shading.c
source/blender/editors/render/render_update.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_buttons/buttons_texture.c
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_node/node_add.c
source/blender/editors/space_node/node_buttons.c
source/blender/editors/space_node/node_draw.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_group.c
source/blender/editors/space_node/node_header.c
source/blender/editors/space_node/node_intern.h
source/blender/editors/space_node/node_ops.c
source/blender/editors/space_node/node_relationships.c
source/blender/editors/space_node/node_select.c
source/blender/editors/space_node/node_templates.c
source/blender/editors/space_node/node_view.c
source/blender/editors/space_node/space_node.c
source/blender/editors/uvedit/uvedit_ops.c
source/blender/makesdna/DNA_node_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_define.h
source/blender/makesrna/RNA_enum_types.h
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_color.c
source/blender/makesrna/intern/rna_define.c
source/blender/makesrna/intern/rna_lamp.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_material.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_texture.c
source/blender/makesrna/intern/rna_ui_api.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/makesrna/intern/rna_world.c
source/blender/nodes/CMakeLists.txt
source/blender/nodes/NOD_common.h [new file with mode: 0644]
source/blender/nodes/NOD_composite.h
source/blender/nodes/NOD_shader.h
source/blender/nodes/NOD_socket.h
source/blender/nodes/NOD_static_types.h [moved from source/blender/makesrna/intern/rna_nodetree_types.h with 91% similarity]
source/blender/nodes/NOD_texture.h
source/blender/nodes/composite/node_composite_tree.c
source/blender/nodes/composite/node_composite_util.c [new file with mode: 0644]
source/blender/nodes/composite/node_composite_util.h
source/blender/nodes/composite/nodes/node_composite_alphaOver.c
source/blender/nodes/composite/nodes/node_composite_bilateralblur.c
source/blender/nodes/composite/nodes/node_composite_blur.c
source/blender/nodes/composite/nodes/node_composite_bokehblur.c
source/blender/nodes/composite/nodes/node_composite_bokehimage.c
source/blender/nodes/composite/nodes/node_composite_boxmask.c
source/blender/nodes/composite/nodes/node_composite_brightness.c
source/blender/nodes/composite/nodes/node_composite_channelMatte.c
source/blender/nodes/composite/nodes/node_composite_chromaMatte.c
source/blender/nodes/composite/nodes/node_composite_colorMatte.c
source/blender/nodes/composite/nodes/node_composite_colorSpill.c
source/blender/nodes/composite/nodes/node_composite_colorbalance.c
source/blender/nodes/composite/nodes/node_composite_colorcorrection.c
source/blender/nodes/composite/nodes/node_composite_common.c
source/blender/nodes/composite/nodes/node_composite_composite.c
source/blender/nodes/composite/nodes/node_composite_crop.c
source/blender/nodes/composite/nodes/node_composite_curves.c
source/blender/nodes/composite/nodes/node_composite_defocus.c
source/blender/nodes/composite/nodes/node_composite_despeckle.c
source/blender/nodes/composite/nodes/node_composite_diffMatte.c
source/blender/nodes/composite/nodes/node_composite_dilate.c
source/blender/nodes/composite/nodes/node_composite_directionalblur.c
source/blender/nodes/composite/nodes/node_composite_displace.c
source/blender/nodes/composite/nodes/node_composite_distanceMatte.c
source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.c
source/blender/nodes/composite/nodes/node_composite_ellipsemask.c
source/blender/nodes/composite/nodes/node_composite_filter.c
source/blender/nodes/composite/nodes/node_composite_flip.c
source/blender/nodes/composite/nodes/node_composite_gamma.c
source/blender/nodes/composite/nodes/node_composite_glare.c
source/blender/nodes/composite/nodes/node_composite_hueSatVal.c
source/blender/nodes/composite/nodes/node_composite_huecorrect.c
source/blender/nodes/composite/nodes/node_composite_idMask.c
source/blender/nodes/composite/nodes/node_composite_image.c
source/blender/nodes/composite/nodes/node_composite_inpaint.c
source/blender/nodes/composite/nodes/node_composite_invert.c
source/blender/nodes/composite/nodes/node_composite_keying.c
source/blender/nodes/composite/nodes/node_composite_keyingscreen.c
source/blender/nodes/composite/nodes/node_composite_lensdist.c
source/blender/nodes/composite/nodes/node_composite_levels.c
source/blender/nodes/composite/nodes/node_composite_lummaMatte.c
source/blender/nodes/composite/nodes/node_composite_mapRange.c
source/blender/nodes/composite/nodes/node_composite_mapUV.c
source/blender/nodes/composite/nodes/node_composite_mapValue.c
source/blender/nodes/composite/nodes/node_composite_mask.c
source/blender/nodes/composite/nodes/node_composite_math.c
source/blender/nodes/composite/nodes/node_composite_mixrgb.c
source/blender/nodes/composite/nodes/node_composite_movieclip.c
source/blender/nodes/composite/nodes/node_composite_moviedistortion.c
source/blender/nodes/composite/nodes/node_composite_normal.c
source/blender/nodes/composite/nodes/node_composite_normalize.c
source/blender/nodes/composite/nodes/node_composite_outputFile.c
source/blender/nodes/composite/nodes/node_composite_pixelate.c
source/blender/nodes/composite/nodes/node_composite_premulkey.c
source/blender/nodes/composite/nodes/node_composite_rgb.c
source/blender/nodes/composite/nodes/node_composite_rotate.c
source/blender/nodes/composite/nodes/node_composite_scale.c
source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.c
source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.c
source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.c
source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.c
source/blender/nodes/composite/nodes/node_composite_setalpha.c
source/blender/nodes/composite/nodes/node_composite_splitViewer.c
source/blender/nodes/composite/nodes/node_composite_stabilize2d.c
source/blender/nodes/composite/nodes/node_composite_switch.c
source/blender/nodes/composite/nodes/node_composite_texture.c
source/blender/nodes/composite/nodes/node_composite_tonemap.c
source/blender/nodes/composite/nodes/node_composite_trackpos.c
source/blender/nodes/composite/nodes/node_composite_transform.c
source/blender/nodes/composite/nodes/node_composite_translate.c
source/blender/nodes/composite/nodes/node_composite_valToRgb.c
source/blender/nodes/composite/nodes/node_composite_value.c
source/blender/nodes/composite/nodes/node_composite_vecBlur.c
source/blender/nodes/composite/nodes/node_composite_viewer.c
source/blender/nodes/composite/nodes/node_composite_zcombine.c
source/blender/nodes/intern/node_common.c
source/blender/nodes/intern/node_common.h
source/blender/nodes/intern/node_exec.c
source/blender/nodes/intern/node_exec.h
source/blender/nodes/intern/node_socket.c
source/blender/nodes/intern/node_util.c
source/blender/nodes/intern/node_util.h
source/blender/nodes/shader/node_shader_tree.c
source/blender/nodes/shader/node_shader_util.c
source/blender/nodes/shader/node_shader_util.h
source/blender/nodes/shader/nodes/node_shader_add_shader.c
source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
source/blender/nodes/shader/nodes/node_shader_attribute.c
source/blender/nodes/shader/nodes/node_shader_background.c
source/blender/nodes/shader/nodes/node_shader_brightness.c
source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c
source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
source/blender/nodes/shader/nodes/node_shader_bump.c
source/blender/nodes/shader/nodes/node_shader_camera.c
source/blender/nodes/shader/nodes/node_shader_common.c
source/blender/nodes/shader/nodes/node_shader_curves.c
source/blender/nodes/shader/nodes/node_shader_emission.c
source/blender/nodes/shader/nodes/node_shader_fresnel.c
source/blender/nodes/shader/nodes/node_shader_gamma.c
source/blender/nodes/shader/nodes/node_shader_geom.c
source/blender/nodes/shader/nodes/node_shader_geometry.c
source/blender/nodes/shader/nodes/node_shader_hair_info.c
source/blender/nodes/shader/nodes/node_shader_holdout.c
source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
source/blender/nodes/shader/nodes/node_shader_invert.c
source/blender/nodes/shader/nodes/node_shader_layer_weight.c
source/blender/nodes/shader/nodes/node_shader_light_falloff.c
source/blender/nodes/shader/nodes/node_shader_light_path.c
source/blender/nodes/shader/nodes/node_shader_mapping.c
source/blender/nodes/shader/nodes/node_shader_material.c
source/blender/nodes/shader/nodes/node_shader_math.c
source/blender/nodes/shader/nodes/node_shader_mixRgb.c
source/blender/nodes/shader/nodes/node_shader_mix_shader.c
source/blender/nodes/shader/nodes/node_shader_normal.c
source/blender/nodes/shader/nodes/node_shader_normal_map.c
source/blender/nodes/shader/nodes/node_shader_object_info.c
source/blender/nodes/shader/nodes/node_shader_output.c
source/blender/nodes/shader/nodes/node_shader_output_lamp.c
source/blender/nodes/shader/nodes/node_shader_output_material.c
source/blender/nodes/shader/nodes/node_shader_output_world.c
source/blender/nodes/shader/nodes/node_shader_particle_info.c
source/blender/nodes/shader/nodes/node_shader_rgb.c
source/blender/nodes/shader/nodes/node_shader_script.c
source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
source/blender/nodes/shader/nodes/node_shader_squeeze.c
source/blender/nodes/shader/nodes/node_shader_tangent.c
source/blender/nodes/shader/nodes/node_shader_tex_brick.c
source/blender/nodes/shader/nodes/node_shader_tex_checker.c
source/blender/nodes/shader/nodes/node_shader_tex_coord.c
source/blender/nodes/shader/nodes/node_shader_tex_environment.c
source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
source/blender/nodes/shader/nodes/node_shader_tex_image.c
source/blender/nodes/shader/nodes/node_shader_tex_magic.c
source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
source/blender/nodes/shader/nodes/node_shader_tex_noise.c
source/blender/nodes/shader/nodes/node_shader_tex_sky.c
source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
source/blender/nodes/shader/nodes/node_shader_tex_wave.c
source/blender/nodes/shader/nodes/node_shader_texture.c
source/blender/nodes/shader/nodes/node_shader_valToRgb.c
source/blender/nodes/shader/nodes/node_shader_value.c
source/blender/nodes/shader/nodes/node_shader_vectMath.c
source/blender/nodes/shader/nodes/node_shader_volume_isotropic.c
source/blender/nodes/shader/nodes/node_shader_volume_transparent.c
source/blender/nodes/texture/node_texture_tree.c
source/blender/nodes/texture/node_texture_util.c
source/blender/nodes/texture/node_texture_util.h
source/blender/nodes/texture/nodes/node_texture_at.c
source/blender/nodes/texture/nodes/node_texture_bricks.c
source/blender/nodes/texture/nodes/node_texture_checker.c
source/blender/nodes/texture/nodes/node_texture_common.c
source/blender/nodes/texture/nodes/node_texture_compose.c
source/blender/nodes/texture/nodes/node_texture_coord.c
source/blender/nodes/texture/nodes/node_texture_curves.c
source/blender/nodes/texture/nodes/node_texture_decompose.c
source/blender/nodes/texture/nodes/node_texture_distance.c
source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
source/blender/nodes/texture/nodes/node_texture_image.c
source/blender/nodes/texture/nodes/node_texture_invert.c
source/blender/nodes/texture/nodes/node_texture_math.c
source/blender/nodes/texture/nodes/node_texture_mixRgb.c
source/blender/nodes/texture/nodes/node_texture_output.c
source/blender/nodes/texture/nodes/node_texture_proc.c
source/blender/nodes/texture/nodes/node_texture_rotate.c
source/blender/nodes/texture/nodes/node_texture_scale.c
source/blender/nodes/texture/nodes/node_texture_texture.c
source/blender/nodes/texture/nodes/node_texture_translate.c
source/blender/nodes/texture/nodes/node_texture_valToNor.c
source/blender/nodes/texture/nodes/node_texture_valToRgb.c
source/blender/nodes/texture/nodes/node_texture_viewer.c
source/blender/python/intern/bpy_rna.c
source/blender/render/intern/source/render_texture.c
source/blenderplayer/bad_level_call_stubs/stubs.c

diff --git a/doc/python_api/examples/bpy.types.NodeTree.py b/doc/python_api/examples/bpy.types.NodeTree.py
new file mode 100644 (file)
index 0000000..401b3a0
--- /dev/null
@@ -0,0 +1,23 @@
+"""
+Poll Function
++++++++++++++++
+The :class:`NodeTree.poll` function determines if a node tree is visible
+in the given context (similar to how :class:`Panel.poll`
+and :class:`Menu.poll` define visibility). If it returns False,
+the node tree type will not be selectable in the node editor.
+
+A typical condition for shader nodes would be to check the active render engine
+of the scene and only show nodes of the renderer they are designed for.
+"""
+import bpy
+
+
+class CyclesNodeTree(bpy.types.NodeTree):
+    """ This operator is only visible when Cycles is the selected render engine"""
+    bl_label = "Cycles Node Tree"
+
+    @classmethod
+    def poll(cls, context):
+        return context.scene.render.engine == 'CYCLES'
+
+bpy.utils.register_class(CyclesNodeTree)
index a10f3b63033f92c8c25f01bcbb76a0efd2db711d..f7a05463f6602c30dd855dbd54f867cfc5c45288 100644 (file)
@@ -207,6 +207,7 @@ static PyObject *available_devices_func(PyObject *self, PyObject *args)
 }
 
 #ifdef WITH_OSL
+
 static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
 {
        PyObject *pynodegroup, *pynode;
@@ -248,17 +249,19 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
                        continue;
 
                /* determine socket type */
-               BL::NodeSocket::type_enum socket_type;
-               float default_float4[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+               std::string socket_type;
+               BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
+               float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
                float default_float = 0.0f;
                int default_int = 0;
                std::string default_string = "";
                
                if(param->isclosure) {
-                       socket_type = BL::NodeSocket::type_SHADER;
+                       socket_type = "NodeSocketShader";
                }
                else if(param->type.vecsemantics == TypeDesc::COLOR) {
-                       socket_type = BL::NodeSocket::type_RGBA;
+                       socket_type = "NodeSocketColor";
+                       data_type = BL::NodeSocket::type_RGBA;
 
                        if(param->validdefault) {
                                default_float4[0] = param->fdefault[0];
@@ -269,7 +272,8 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
                else if(param->type.vecsemantics == TypeDesc::POINT ||
                        param->type.vecsemantics == TypeDesc::VECTOR ||
                        param->type.vecsemantics == TypeDesc::NORMAL) {
-                       socket_type = BL::NodeSocket::type_VECTOR;
+                       socket_type = "NodeSocketVector";
+                       data_type = BL::NodeSocket::type_VECTOR;
 
                        if(param->validdefault) {
                                default_float4[0] = param->fdefault[0];
@@ -279,17 +283,20 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
                }
                else if(param->type.aggregate == TypeDesc::SCALAR) {
                        if(param->type.basetype == TypeDesc::INT) {
-                               socket_type = BL::NodeSocket::type_INT;
+                               socket_type = "NodeSocketInt";
+                               data_type = BL::NodeSocket::type_INT;
                                if(param->validdefault)
                                        default_int = param->idefault[0];
                        }
                        else if(param->type.basetype == TypeDesc::FLOAT) {
-                               socket_type = BL::NodeSocket::type_VALUE;
+                               socket_type = "NodeSocketFloat";
+                               data_type = BL::NodeSocket::type_VALUE;
                                if(param->validdefault)
                                        default_float = param->fdefault[0];
                        }
                        else if(param->type.basetype == TypeDesc::STRING) {
-                               socket_type =  BL::NodeSocket::type_STRING;
+                               socket_type = "NodeSocketString";
+                               data_type = BL::NodeSocket::type_STRING;
                                if(param->validdefault)
                                        default_string = param->sdefault[0];
                        }
@@ -300,38 +307,52 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
                        continue;
 
                /* find socket socket */
-               BL::NodeSocket b_sock = b_node.find_socket(param->name.c_str(), param->isoutput);
-
-               /* remove if type no longer matches */
-               if(b_sock && b_sock.type() != socket_type) {
-                       b_node.remove_socket(b_sock);
-                       b_sock = BL::NodeSocket(PointerRNA_NULL);
+               BL::NodeSocket b_sock(PointerRNA_NULL);
+               if (param->isoutput) {
+                       b_sock = b_node.outputs[param->name];
+                       
+                       /* remove if type no longer matches */
+                       if(b_sock && b_sock.bl_idname() != socket_type) {
+                               b_node.outputs.remove(b_sock);
+                               b_sock = BL::NodeSocket(PointerRNA_NULL);
+                       }
+                       
+                       if (!b_sock) {
+                               /* create new socket */
+                               b_sock = b_node.outputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
+                       }
+               }
+               else {
+                       b_sock = b_node.inputs[param->name];
+                       
+                       /* remove if type no longer matches */
+                       if(b_sock && b_sock.bl_idname() != socket_type) {
+                               b_node.inputs.remove(b_sock);
+                               b_sock = BL::NodeSocket(PointerRNA_NULL);
+                       }
+                       
+                       if (!b_sock) {
+                               /* create new socket */
+                               b_sock = b_node.inputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
+                       }
                }
 
-               /* create new socket */
-               if(!b_sock) {
-                       b_sock = b_node.add_socket(param->name.c_str(), socket_type, param->isoutput);
-
-                       /* set default value */
-                       if(socket_type == BL::NodeSocket::type_VALUE) {
-                               BL::NodeSocketFloatNone b_float_sock(b_sock.ptr);
-                               b_float_sock.default_value(default_float);
+               /* set default value */
+               if(b_sock) {
+                       if(data_type == BL::NodeSocket::type_VALUE) {
+                               set_float(b_sock.ptr, "default_value", default_float);
                        }
-                       else if(socket_type == BL::NodeSocket::type_INT) {
-                               BL::NodeSocketIntNone b_int_sock(b_sock.ptr);
-                               b_int_sock.default_value(default_int);
+                       else if(data_type == BL::NodeSocket::type_INT) {
+                               set_int(b_sock.ptr, "default_value", default_int);
                        }
-                       else if(socket_type == BL::NodeSocket::type_RGBA) {
-                               BL::NodeSocketRGBA b_rgba_sock(b_sock.ptr);
-                               b_rgba_sock.default_value(default_float4);
+                       else if(data_type == BL::NodeSocket::type_RGBA) {
+                               set_float4(b_sock.ptr, "default_value", default_float4);
                        }
-                       else if(socket_type == BL::NodeSocket::type_VECTOR) {
-                               BL::NodeSocketVectorNone b_vector_sock(b_sock.ptr);
-                               b_vector_sock.default_value(default_float4);
+                       else if(data_type == BL::NodeSocket::type_VECTOR) {
+                               set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
                        }
-                       else if(socket_type == BL::NodeSocket::type_STRING) {
-                               BL::NodeSocketStringNone b_string_sock(b_sock.ptr);
-                               b_string_sock.default_value(default_string);
+                       else if(data_type == BL::NodeSocket::type_STRING) {
+                               set_string(b_sock.ptr, "default_value", default_string);
                        }
                }
 
@@ -349,7 +370,7 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
 
                for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
                        if(used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
-                               b_node.remove_socket(*b_input);
+                               b_node.inputs.remove(*b_input);
                                removed = true;
                                break;
                        }
@@ -357,7 +378,7 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
 
                for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
                        if(used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
-                               b_node.remove_socket(*b_output);
+                               b_node.outputs.remove(*b_output);
                                removed = true;
                                break;
                        }
index 0f7dc15db19283069d2ba5fe3425b4eeb4839373..45a97f1d530e6bd8171e05a9fbba6ac9c3a101e1 100644 (file)
@@ -31,9 +31,9 @@
 
 CCL_NAMESPACE_BEGIN
 
-typedef map<void*, ShaderNode*> PtrNodeMap;
-typedef pair<ShaderNode*, std::string> SocketPair;
-typedef map<void*, SocketPair> PtrSockMap;
+typedef map<void*, ShaderInput*> PtrInputMap;
+typedef map<void*, ShaderOutput*> PtrOutputMap;
+typedef map<std::string, ProxyNode*> ProxyMap;
 
 /* Find */
 
@@ -55,83 +55,88 @@ void BlenderSync::find_shader(BL::ID id, vector<uint>& used_shaders, int default
 static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
 {
        BL::Node::outputs_iterator b_out;
-
+       
        for(b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
                if(b_out->name() == name)
                        return *b_out;
-
+       
        assert(0);
-
+       
        return *b_out;
 }
 
 static float3 get_node_output_rgba(BL::Node b_node, const string& name)
 {
-       BL::NodeSocketRGBA sock(get_node_output(b_node, name));
-       return get_float3(sock.default_value());
+       BL::NodeSocket b_sock = get_node_output(b_node, name);
+       float value[4];
+       RNA_float_get_array(&b_sock.ptr, "default_value", value);
+       return make_float3(value[0], value[1], value[2]);
 }
 
 static float get_node_output_value(BL::Node b_node, const string& name)
 {
-       BL::NodeSocketFloatNone sock(get_node_output(b_node, name));
-       return sock.default_value();
+       BL::NodeSocket b_sock = get_node_output(b_node, name);
+       return RNA_float_get(&b_sock.ptr, "default_value");
 }
 
-static ShaderSocketType convert_socket_type(BL::NodeSocket::type_enum b_type)
+static float3 get_node_output_vector(BL::Node b_node, const string& name)
 {
-       switch (b_type) {
-       case BL::NodeSocket::type_VALUE:
-               return SHADER_SOCKET_FLOAT;
-       case BL::NodeSocket::type_INT:
-               return SHADER_SOCKET_INT;
-       case BL::NodeSocket::type_VECTOR:
-               return SHADER_SOCKET_VECTOR;
-       case BL::NodeSocket::type_RGBA:
-               return SHADER_SOCKET_COLOR;
-       case BL::NodeSocket::type_SHADER:
-               return SHADER_SOCKET_CLOSURE;
-       case BL::NodeSocket::type_STRING:
-               return SHADER_SOCKET_STRING;
-       
-       case BL::NodeSocket::type_BOOLEAN:
-       case BL::NodeSocket::type_MESH:
-       default:
-               return SHADER_SOCKET_FLOAT;
+       BL::NodeSocket b_sock = get_node_output(b_node, name);
+       float value[3];
+       RNA_float_get_array(&b_sock.ptr, "default_value", value);
+       return make_float3(value[0], value[1], value[2]);
+}
+
+static ShaderSocketType convert_socket_type(BL::NodeSocket b_socket)
+{
+       switch (b_socket.type()) {
+               case BL::NodeSocket::type_VALUE:
+                       return SHADER_SOCKET_FLOAT;
+               case BL::NodeSocket::type_INT:
+                       return SHADER_SOCKET_INT;
+               case BL::NodeSocket::type_VECTOR:
+                       return SHADER_SOCKET_VECTOR;
+               case BL::NodeSocket::type_RGBA:
+                       return SHADER_SOCKET_COLOR;
+               case BL::NodeSocket::type_STRING:
+                       return SHADER_SOCKET_STRING;
+               case BL::NodeSocket::type_SHADER:
+                       return SHADER_SOCKET_CLOSURE;
+               
+               default:
+                       return SHADER_SOCKET_UNDEFINED;
        }
 }
 
-static void set_default_value(ShaderInput *input, BL::NodeSocket sock, BL::BlendData b_data, BL::ID b_id)
+static void set_default_value(ShaderInput *input, BL::Node b_node, BL::NodeSocket b_sock, BL::BlendData b_data, BL::ID b_id)
 {
        /* copy values for non linked inputs */
        switch(input->type) {
        case SHADER_SOCKET_FLOAT: {
-               BL::NodeSocketFloatNone value_sock(sock);
-               input->set(value_sock.default_value());
+               input->set(get_float(b_sock.ptr, "default_value"));
                break;
        }
        case SHADER_SOCKET_INT: {
-               BL::NodeSocketIntNone value_sock(sock);
-               input->set((float)value_sock.default_value());
+               input->set((float)get_int(b_sock.ptr, "default_value"));
                break;
        }
        case SHADER_SOCKET_COLOR: {
-               BL::NodeSocketRGBA rgba_sock(sock);
-               input->set(get_float3(rgba_sock.default_value()));
+               input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value")));
                break;
        }
        case SHADER_SOCKET_NORMAL:
        case SHADER_SOCKET_POINT:
        case SHADER_SOCKET_VECTOR: {
-               BL::NodeSocketVectorNone vec_sock(sock);
-               input->set(get_float3(vec_sock.default_value()));
+               input->set(get_float3(b_sock.ptr, "default_value"));
                break;
        }
        case SHADER_SOCKET_STRING: {
-               BL::NodeSocketStringNone string_sock(sock);
-               input->set((ustring)blender_absolute_path(b_data, b_id, string_sock.default_value()));
+               input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
                break;
        }
+       
        case SHADER_SOCKET_CLOSURE:
+       case SHADER_SOCKET_UNDEFINED:
                break;
        }
 }
@@ -171,295 +176,226 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
 {
        ShaderNode *node = NULL;
 
-       switch(b_node.type()) {
-               /* not supported */
-               case BL::ShaderNode::type_GEOMETRY: break;
-               case BL::ShaderNode::type_MATERIAL: break;
-               case BL::ShaderNode::type_MATERIAL_EXT: break;
-               case BL::ShaderNode::type_OUTPUT: break;
-               case BL::ShaderNode::type_SQUEEZE: break;
-               case BL::ShaderNode::type_TEXTURE: break;
-               case BL::ShaderNode::type_FRAME: break;
-               /* handled outside this function */
-               case BL::ShaderNode::type_GROUP: break;
-               /* existing blender nodes */
-               case BL::ShaderNode::type_REROUTE: {
-                       BL::Node::inputs_iterator b_input;
-                       b_node.inputs.begin(b_input);
-                       BL::Node::outputs_iterator b_output;
-                       b_node.outputs.begin(b_output);
-                       ProxyNode *proxy = new ProxyNode(convert_socket_type(b_input->type()), convert_socket_type(b_output->type()));
-                       node = proxy;
-                       break;
-               }
-               case BL::ShaderNode::type_CURVE_VEC: {
-                       BL::ShaderNodeVectorCurve b_curve_node(b_node);
-                       VectorCurvesNode *curves = new VectorCurvesNode();
-                       curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false);
-                       node = curves;
-                       break;
-               }
-               case BL::ShaderNode::type_CURVE_RGB: {
-                       BL::ShaderNodeRGBCurve b_curve_node(b_node);
-                       RGBCurvesNode *curves = new RGBCurvesNode();
-                       curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true);
-                       node = curves;
-                       break;
-               }
-               case BL::ShaderNode::type_VALTORGB: {
-                       RGBRampNode *ramp = new RGBRampNode();
-                       BL::ShaderNodeValToRGB b_ramp_node(b_node);
-                       colorramp_to_array(b_ramp_node.color_ramp(), ramp->ramp, RAMP_TABLE_SIZE);
-                       node = ramp;
-                       break;
-               }
-               case BL::ShaderNode::type_RGB: {
-                       ColorNode *color = new ColorNode();
-                       color->value = get_node_output_rgba(b_node, "Color");
-                       node = color;
-                       break;
-               }
-               case BL::ShaderNode::type_VALUE: {
-                       ValueNode *value = new ValueNode();
-                       value->value = get_node_output_value(b_node, "Value");
-                       node = value;
-                       break;
-               }
-               case BL::ShaderNode::type_CAMERA: {
-                       node = new CameraNode();
-                       break;
-               }
-               case BL::ShaderNode::type_INVERT: {
-                       node = new InvertNode();
-                       break;
-               }
-               case BL::ShaderNode::type_GAMMA: {
-                       node = new GammaNode();
-                       break;
-               }
-               case BL::ShaderNode::type_BRIGHTCONTRAST: {
-                       node = new BrightContrastNode();
-                       break;
-               }
-               case BL::ShaderNode::type_MIX_RGB: {
-                       BL::ShaderNodeMixRGB b_mix_node(b_node);
-                       MixNode *mix = new MixNode();
-                       mix->type = MixNode::type_enum[b_mix_node.blend_type()];
+       /* existing blender nodes */
+       if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
+               BL::ShaderNodeRGBCurve b_curve_node(b_node);
+               RGBCurvesNode *curves = new RGBCurvesNode();
+               curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true);
+               node = curves;
+       }
+       if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
+               BL::ShaderNodeVectorCurve b_curve_node(b_node);
+               VectorCurvesNode *curves = new VectorCurvesNode();
+               curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false);
+               node = curves;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
+               RGBRampNode *ramp = new RGBRampNode();
+               BL::ShaderNodeValToRGB b_ramp_node(b_node);
+               colorramp_to_array(b_ramp_node.color_ramp(), ramp->ramp, RAMP_TABLE_SIZE);
+               node = ramp;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
+               ColorNode *color = new ColorNode();
+               color->value = get_node_output_rgba(b_node, "Color");
+               node = color;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeValue)) {
+               ValueNode *value = new ValueNode();
+               value->value = get_node_output_value(b_node, "Value");
+               node = value;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
+               node = new CameraNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeInvert)) {
+               node = new InvertNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeGamma)) {
+               node = new GammaNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
+               node = new BrightContrastNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
+               BL::ShaderNodeMixRGB b_mix_node(b_node);
+               MixNode *mix = new MixNode();
+               mix->type = MixNode::type_enum[b_mix_node.blend_type()];
                        mix->use_clamp = b_mix_node.use_clamp();
-                       node = mix;
-                       break;
-               }
-               case BL::ShaderNode::type_SEPRGB: {
-                       node = new SeparateRGBNode();
-                       break;
-               }
-               case BL::ShaderNode::type_COMBRGB: {
-                       node = new CombineRGBNode();
-                       break;
-               }
-               case BL::ShaderNode::type_HUE_SAT: {
-                       node = new HSVNode();
-                       break;
-               }
-               case BL::ShaderNode::type_RGBTOBW: {
-                       node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
-                       break;
-               }
-               case BL::ShaderNode::type_MATH: {
-                       BL::ShaderNodeMath b_math_node(b_node);
-                       MathNode *math = new MathNode();
-                       math->type = MathNode::type_enum[b_math_node.operation()];
+               node = mix;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
+               node = new SeparateRGBNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
+               node = new CombineRGBNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
+               node = new HSVNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
+               node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeMath)) {
+               BL::ShaderNodeMath b_math_node(b_node);
+               MathNode *math = new MathNode();
+               math->type = MathNode::type_enum[b_math_node.operation()];
                        math->use_clamp = b_math_node.use_clamp();
-                       node = math;
-                       break;
-               }
-               case BL::ShaderNode::type_VECT_MATH: {
-                       BL::ShaderNodeVectorMath b_vector_math_node(b_node);
-                       VectorMathNode *vmath = new VectorMathNode();
-                       vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
-                       node = vmath;
-                       break;
-               }
-               case BL::ShaderNode::type_NORMAL: {
-                       BL::Node::outputs_iterator out_it;
-                       b_node.outputs.begin(out_it);
-                       BL::NodeSocketVectorNone vec_sock(*out_it);
-
-                       NormalNode *norm = new NormalNode();
-                       norm->direction = get_float3(vec_sock.default_value());
-
-                       node = norm;
-                       break;
-               }
-               case BL::ShaderNode::type_MAPPING: {
-                       BL::ShaderNodeMapping b_mapping_node(b_node);
-                       MappingNode *mapping = new MappingNode();
-
-                       get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
-
-                       node = mapping;
-                       break;
-               }
-
-               /* new nodes */
-               case BL::ShaderNode::type_OUTPUT_MATERIAL:
-               case BL::ShaderNode::type_OUTPUT_WORLD:
-               case BL::ShaderNode::type_OUTPUT_LAMP: {
-                       node = graph->output();
-                       break;
-               }
-               case BL::ShaderNode::type_FRESNEL: {
-                       node = new FresnelNode();
-                       break;
-               }
-               case BL::ShaderNode::type_LAYER_WEIGHT: {
-                       node = new LayerWeightNode();
-                       break;
-               }
-               case BL::ShaderNode::type_ADD_SHADER: {
-                       node = new AddClosureNode();
-                       break;
-               }
-               case BL::ShaderNode::type_MIX_SHADER: {
-                       node = new MixClosureNode();
-                       break;
-               }
-               case BL::ShaderNode::type_ATTRIBUTE: {
-                       BL::ShaderNodeAttribute b_attr_node(b_node);
-                       AttributeNode *attr = new AttributeNode();
-                       attr->attribute = b_attr_node.attribute_name();
-                       node = attr;
-                       break;
-               }
-               case BL::ShaderNode::type_BACKGROUND: {
-                       node = new BackgroundNode();
-                       break;
-               }
-               case BL::ShaderNode::type_HOLDOUT: {
-                       node = new HoldoutNode();
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_ANISOTROPIC: {
-                       node = new WardBsdfNode();
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_DIFFUSE: {
-                       node = new DiffuseBsdfNode();
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_GLOSSY: {
-                       BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
-                       GlossyBsdfNode *glossy = new GlossyBsdfNode();
-
-                       switch(b_glossy_node.distribution()) {
-                               case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
-                                       glossy->distribution = ustring("Sharp");
-                                       break;
-                               case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
-                                       glossy->distribution = ustring("Beckmann");
-                                       break;
-                               case BL::ShaderNodeBsdfGlossy::distribution_GGX:
-                                       glossy->distribution = ustring("GGX");
-                                       break;
-                       }
-                       node = glossy;
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_GLASS: {
-                       BL::ShaderNodeBsdfGlass b_glass_node(b_node);
-                       GlassBsdfNode *glass = new GlassBsdfNode();
-                       switch(b_glass_node.distribution()) {
-                               case BL::ShaderNodeBsdfGlass::distribution_SHARP:
-                                       glass->distribution = ustring("Sharp");
-                                       break;
-                               case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
-                                       glass->distribution = ustring("Beckmann");
-                                       break;
-                               case BL::ShaderNodeBsdfGlass::distribution_GGX:
-                                       glass->distribution = ustring("GGX");
-                                       break;
-                       }
-                       node = glass;
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_REFRACTION: {
-                       BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
-                       RefractionBsdfNode *refraction = new RefractionBsdfNode();
-                       switch(b_refraction_node.distribution()) {
-                               case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
-                                       refraction->distribution = ustring("Sharp");
-                                       break;
-                               case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
-                                       refraction->distribution = ustring("Beckmann");
-                                       break;
-                               case BL::ShaderNodeBsdfRefraction::distribution_GGX:
-                                       refraction->distribution = ustring("GGX");
-                                       break;
-                       }
-                       node = refraction;
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_TRANSLUCENT: {
-                       node = new TranslucentBsdfNode();
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_TRANSPARENT: {
-                       node = new TransparentBsdfNode();
-                       break;
-               }
-               case BL::ShaderNode::type_BSDF_VELVET: {
-                       node = new VelvetBsdfNode();
-                       break;
-               }
-               case BL::ShaderNode::type_EMISSION: {
-                       node = new EmissionNode();
-                       break;
-               }
-               case BL::ShaderNode::type_AMBIENT_OCCLUSION: {
-                       node = new AmbientOcclusionNode();
-                       break;
-               }
-               case BL::ShaderNode::type_VOLUME_ISOTROPIC: {
-                       node = new IsotropicVolumeNode();
-                       break;
-               }
-               case BL::ShaderNode::type_VOLUME_TRANSPARENT: {
-                       node = new TransparentVolumeNode();
-                       break;
-               }
-               case BL::ShaderNode::type_NEW_GEOMETRY: {
-                       node = new GeometryNode();
+               node = math;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
+               BL::ShaderNodeVectorMath b_vector_math_node(b_node);
+               VectorMathNode *vmath = new VectorMathNode();
+               vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
+               node = vmath;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
+               BL::Node::outputs_iterator out_it;
+               b_node.outputs.begin(out_it);
+               BL::NodeSocket vec_sock(*out_it);
+               
+               NormalNode *norm = new NormalNode();
+               norm->direction = get_node_output_vector(b_node, "Normal");
+               node = norm;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
+               BL::ShaderNodeMapping b_mapping_node(b_node);
+               MappingNode *mapping = new MappingNode();
+               
+               get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
+               
+               node = mapping;
+       }
+       /* new nodes */
+       else if (b_node.is_a(&RNA_ShaderNodeOutputMaterial)
+             || b_node.is_a(&RNA_ShaderNodeOutputWorld)
+             || b_node.is_a(&RNA_ShaderNodeOutputLamp)) {
+               node = graph->output();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
+               node = new FresnelNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
+               node = new LayerWeightNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeAddShader)) {
+               node = new AddClosureNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeMixShader)) {
+               node = new MixClosureNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
+               BL::ShaderNodeAttribute b_attr_node(b_node);
+               AttributeNode *attr = new AttributeNode();
+               attr->attribute = b_attr_node.attribute_name();
+               node = attr;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
+               node = new BackgroundNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
+               node = new HoldoutNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
+               node = new WardBsdfNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
+               node = new DiffuseBsdfNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
+               BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
+               GlossyBsdfNode *glossy = new GlossyBsdfNode();
+               
+               switch(b_glossy_node.distribution()) {
+               case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
+                       glossy->distribution = ustring("Sharp");
                        break;
-               }
-               case BL::ShaderNode::type_LIGHT_PATH: {
-                       node = new LightPathNode();
+               case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
+                       glossy->distribution = ustring("Beckmann");
                        break;
-               }
-               case BL::ShaderNode::type_LIGHT_FALLOFF: {
-                       node = new LightFalloffNode();
+               case BL::ShaderNodeBsdfGlossy::distribution_GGX:
+                       glossy->distribution = ustring("GGX");
                        break;
                }
-               case BL::ShaderNode::type_OBJECT_INFO: {
-                       node = new ObjectInfoNode();
+               node = glossy;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
+               BL::ShaderNodeBsdfGlass b_glass_node(b_node);
+               GlassBsdfNode *glass = new GlassBsdfNode();
+               switch(b_glass_node.distribution()) {
+               case BL::ShaderNodeBsdfGlass::distribution_SHARP:
+                       glass->distribution = ustring("Sharp");
                        break;
-               }
-               case BL::ShaderNode::type_PARTICLE_INFO: {
-                       node = new ParticleInfoNode();
+               case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
+                       glass->distribution = ustring("Beckmann");
                        break;
-               }
-               case BL::ShaderNode::type_HAIR_INFO: {
-                       node = new HairInfoNode();
+               case BL::ShaderNodeBsdfGlass::distribution_GGX:
+                       glass->distribution = ustring("GGX");
                        break;
                }
-               case BL::ShaderNode::type_BUMP: {
-                       node = new BumpNode();
-                       break;
+               node = glass;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
+               BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
+               RefractionBsdfNode *refraction = new RefractionBsdfNode();
+               switch(b_refraction_node.distribution()) {
+                       case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
+                               refraction->distribution = ustring("Sharp");
+                               break;
+                       case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
+                               refraction->distribution = ustring("Beckmann");
+                               break;
+                       case BL::ShaderNodeBsdfRefraction::distribution_GGX:
+                               refraction->distribution = ustring("GGX");
+                               break;
                }
-               case BL::ShaderNode::type_SCRIPT: {
+               node = refraction;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
+               node = new TranslucentBsdfNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
+               node = new TransparentBsdfNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
+               node = new VelvetBsdfNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeEmission)) {
+               node = new EmissionNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
+               node = new AmbientOcclusionNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeVolumeIsotropic)) {
+               node = new IsotropicVolumeNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeVolumeTransparent)) {
+               node = new TransparentVolumeNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
+               node = new GeometryNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeLightPath)) {
+               node = new LightPathNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
+               node = new LightFalloffNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
+               node = new ObjectInfoNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
+               node = new ParticleInfoNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
+               node = new HairInfoNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeBump)) {
+               node = new BumpNode();
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeScript)) {
 #ifdef WITH_OSL
-                       if(!scene->shader_manager->use_osl())
-                               break;
-
+               if(scene->shader_manager->use_osl()) {
                        /* create script node */
                        BL::ShaderNodeScript b_script_node(b_node);
                        OSLScriptNode *script_node = new OSLScriptNode();
@@ -472,29 +408,31 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
                         * Note 2: ShaderInput/ShaderOutput store shallow string copies only!
                         * Socket names must be stored in the extra lists instead. */
                        BL::Node::inputs_iterator b_input;
-
+                       
                        for (b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
                                script_node->input_names.push_back(ustring(b_input->name()));
-                               ShaderInput *input = script_node->add_input(script_node->input_names.back().c_str(), convert_socket_type(b_input->type()));
-                               set_default_value(input, *b_input, b_data, b_ntree);
+                               ShaderInput *input = script_node->add_input(script_node->input_names.back().c_str(),
+                                                                           convert_socket_type(*b_input));
+                               set_default_value(input, b_node, *b_input, b_data, b_ntree);
                        }
-
+                       
                        BL::Node::outputs_iterator b_output;
-
+                       
                        for (b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
                                script_node->output_names.push_back(ustring(b_output->name()));
-                               script_node->add_output(script_node->output_names.back().c_str(), convert_socket_type(b_output->type()));
+                               script_node->add_output(script_node->output_names.back().c_str(),
+                                                       convert_socket_type(*b_output));
                        }
-
+                       
                        /* load bytecode or filepath */
                        OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
                        string bytecode_hash = b_script_node.bytecode_hash();
-
+                       
                        if(!bytecode_hash.empty()) {
                                /* loaded bytecode if not already done */
                                if(!manager->shader_test_loaded(bytecode_hash))
                                        manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode());
-
+                               
                                script_node->bytecode_hash = bytecode_hash;
                        }
                        else {
@@ -503,173 +441,157 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
                        }
                        
                        node = script_node;
-#endif
-
-                       break;
                }
-               case BL::ShaderNode::type_TEX_IMAGE: {
-                       BL::ShaderNodeTexImage b_image_node(b_node);
-                       BL::Image b_image(b_image_node.image());
-                       ImageTextureNode *image = new ImageTextureNode();
-                       if(b_image) {
-                               /* builtin images will use callback-based reading because
-                                * they could only be loaded correct from blender side
+#endif
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexImage)) {
+               BL::ShaderNodeTexImage b_image_node(b_node);
+               BL::Image b_image(b_image_node.image());
+               ImageTextureNode *image = new ImageTextureNode();
+               if(b_image) {
+                       /* builtin images will use callback-based reading because
+                        * they could only be loaded correct from blender side
+                        */
+                       bool is_builtin = b_image.packed_file() ||
+                                         b_image.source() == BL::Image::source_GENERATED ||
+                                         b_image.source() == BL::Image::source_MOVIE;
+
+                       if(is_builtin) {
+                               /* for builtin images we're using image datablock name to find an image to
+                                * read pixels from later
+                                *
+                                * also store frame number as well, so there's no differences in handling
+                                * builtin names for packed images and movies
                                 */
-                               bool is_builtin = b_image.packed_file() ||
-                                                 b_image.source() == BL::Image::source_GENERATED ||
-                                                 b_image.source() == BL::Image::source_MOVIE;
-
-                               if(is_builtin) {
-                                       /* for builtin images we're using image datablock name to find an image to
-                                        * read pixels from later
-                                        *
-                                        * also store frame number as well, so there's no differences in handling
-                                        * builtin names for packed images and movies
-                                        */
-                                       int scene_frame = b_scene.frame_current();
-                                       int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
-                                       image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
-                                       image->builtin_data = b_image.ptr.data;
-                               }
-                               else {
-                                       image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
-                                       image->builtin_data = NULL;
-                               }
-
-                               image->animated = b_image_node.image_user().use_auto_refresh();
+                               int scene_frame = b_scene.frame_current();
+                               int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
+                               image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
+                               image->builtin_data = b_image.ptr.data;
                        }
-                       image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
-                       image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
-                       image->projection_blend = b_image_node.projection_blend();
-                       get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
-                       node = image;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_ENVIRONMENT: {
-                       BL::ShaderNodeTexEnvironment b_env_node(b_node);
-                       BL::Image b_image(b_env_node.image());
-                       EnvironmentTextureNode *env = new EnvironmentTextureNode();
-                       if(b_image) {
-                               bool is_builtin = b_image.packed_file() ||
-                                                 b_image.source() == BL::Image::source_GENERATED ||
-                                                 b_image.source() == BL::Image::source_MOVIE;
-
-                               if(is_builtin) {
-                                       int scene_frame = b_scene.frame_current();
-                                       int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
-                                       env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
-                                       env->builtin_data = b_image.ptr.data;
-                               }
-                               else {
-                                       env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
-                                       env->animated = b_env_node.image_user().use_auto_refresh();
-                                       env->builtin_data = NULL;
-                               }
+                       else {
+                               image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
+                               image->builtin_data = NULL;
                        }
-                       env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
-                       env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
-                       get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
-                       node = env;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_GRADIENT: {
-                       BL::ShaderNodeTexGradient b_gradient_node(b_node);
-                       GradientTextureNode *gradient = new GradientTextureNode();
-                       gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
-                       get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
-                       node = gradient;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_VORONOI: {
-                       BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
-                       VoronoiTextureNode *voronoi = new VoronoiTextureNode();
-                       voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
-                       get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
-                       node = voronoi;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_MAGIC: {
-                       BL::ShaderNodeTexMagic b_magic_node(b_node);
-                       MagicTextureNode *magic = new MagicTextureNode();
-                       magic->depth = b_magic_node.turbulence_depth();
-                       get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
-                       node = magic;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_WAVE: {
-                       BL::ShaderNodeTexWave b_wave_node(b_node);
-                       WaveTextureNode *wave = new WaveTextureNode();
-                       wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
-                       get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
-                       node = wave;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_CHECKER: {
-                       BL::ShaderNodeTexChecker b_checker_node(b_node);
-                       CheckerTextureNode *checker = new CheckerTextureNode();
-                       get_tex_mapping(&checker->tex_mapping, b_checker_node.texture_mapping());
-                       node = checker;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_BRICK: {
-                       BL::ShaderNodeTexBrick b_brick_node(b_node);
-                       BrickTextureNode *brick = new BrickTextureNode();
-                       brick->offset = b_brick_node.offset();
-                       brick->offset_frequency = b_brick_node.offset_frequency();
-                       brick->squash = b_brick_node.squash();
-                       brick->squash_frequency = b_brick_node.squash_frequency();
-                       get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
-                       node = brick;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_NOISE: {
-                       BL::ShaderNodeTexNoise b_noise_node(b_node);
-                       NoiseTextureNode *noise = new NoiseTextureNode();
-                       get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
-                       node = noise;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_MUSGRAVE: {
-                       BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
-                       MusgraveTextureNode *musgrave = new MusgraveTextureNode();
-                       musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
-                       get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
-                       node = musgrave;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_COORD: {
-                       BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
-                       TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
-                       tex_coord->from_dupli = b_tex_coord_node.from_dupli();
-                       node = tex_coord;
-                       break;
-               }
-               case BL::ShaderNode::type_TEX_SKY: {
-                       BL::ShaderNodeTexSky b_sky_node(b_node);
-                       SkyTextureNode *sky = new SkyTextureNode();
-                       sky->sun_direction = get_float3(b_sky_node.sun_direction());
-                       sky->turbidity = b_sky_node.turbidity();
-                       get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
-                       node = sky;
-                       break;
-               }
-               case BL::ShaderNode::type_NORMAL_MAP: {
-                       BL::ShaderNodeNormalMap b_normal_map_node(b_node);
-                       NormalMapNode *nmap = new NormalMapNode();
-                       nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
-                       nmap->attribute = b_normal_map_node.uv_map();
-                       node = nmap;
-                       break;
+
+                       image->animated = b_image_node.image_user().use_auto_refresh();
                }
-               case BL::ShaderNode::type_TANGENT: {
-                       BL::ShaderNodeTangent b_tangent_node(b_node);
-                       TangentNode *tangent = new TangentNode();
-                       tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
-                       tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
-                       tangent->attribute = b_tangent_node.uv_map();
-                       node = tangent;
-                       break;
+               image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
+               image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
+               image->projection_blend = b_image_node.projection_blend();
+               get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
+               node = image;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
+               BL::ShaderNodeTexEnvironment b_env_node(b_node);
+               BL::Image b_image(b_env_node.image());
+               EnvironmentTextureNode *env = new EnvironmentTextureNode();
+               if(b_image) {
+                       bool is_builtin = b_image.packed_file() ||
+                                         b_image.source() == BL::Image::source_GENERATED ||
+                                         b_image.source() == BL::Image::source_MOVIE;
+
+                       if(is_builtin) {
+                               int scene_frame = b_scene.frame_current();
+                               int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
+                               env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
+                               env->builtin_data = b_image.ptr.data;
+                       }
+                       else {
+                               env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
+                               env->animated = b_env_node.image_user().use_auto_refresh();
+                               env->builtin_data = NULL;
+                       }
                }
+               env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
+               env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
+               get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
+               node = env;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
+               BL::ShaderNodeTexGradient b_gradient_node(b_node);
+               GradientTextureNode *gradient = new GradientTextureNode();
+               gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
+               get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
+               node = gradient;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
+               BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
+               VoronoiTextureNode *voronoi = new VoronoiTextureNode();
+               voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
+               get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
+               node = voronoi;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
+               BL::ShaderNodeTexMagic b_magic_node(b_node);
+               MagicTextureNode *magic = new MagicTextureNode();
+               magic->depth = b_magic_node.turbulence_depth();
+               get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
+               node = magic;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
+               BL::ShaderNodeTexWave b_wave_node(b_node);
+               WaveTextureNode *wave = new WaveTextureNode();
+               wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
+               get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
+               node = wave;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
+               BL::ShaderNodeTexChecker b_checker_node(b_node);
+               CheckerTextureNode *checker = new CheckerTextureNode();
+               get_tex_mapping(&checker->tex_mapping, b_checker_node.texture_mapping());
+               node = checker;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
+               BL::ShaderNodeTexBrick b_brick_node(b_node);
+               BrickTextureNode *brick = new BrickTextureNode();
+               brick->offset = b_brick_node.offset();
+               brick->offset_frequency = b_brick_node.offset_frequency();
+               brick->squash = b_brick_node.squash();
+               brick->squash_frequency = b_brick_node.squash_frequency();
+               get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
+               node = brick;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
+               BL::ShaderNodeTexNoise b_noise_node(b_node);
+               NoiseTextureNode *noise = new NoiseTextureNode();
+               get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
+               node = noise;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
+               BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
+               MusgraveTextureNode *musgrave = new MusgraveTextureNode();
+               musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
+               get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
+               node = musgrave;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
+               BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
+               TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
+               tex_coord->from_dupli = b_tex_coord_node.from_dupli();
+               node = tex_coord;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
+               BL::ShaderNodeTexSky b_sky_node(b_node);
+               SkyTextureNode *sky = new SkyTextureNode();
+               sky->sun_direction = get_float3(b_sky_node.sun_direction());
+               sky->turbidity = b_sky_node.turbidity();
+               get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
+               node = sky;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
+               BL::ShaderNodeNormalMap b_normal_map_node(b_node);
+               NormalMapNode *nmap = new NormalMapNode();
+               nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
+               nmap->attribute = b_normal_map_node.uv_map();
+               node = nmap;
+       }
+       else if (b_node.is_a(&RNA_ShaderNodeTangent)) {
+               BL::ShaderNodeTangent b_tangent_node(b_node);
+               TangentNode *tangent = new TangentNode();
+               tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
+               tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
+               tangent->attribute = b_tangent_node.uv_map();
+               node = tangent;
        }
 
        if(node && node != graph->output())
@@ -678,18 +600,16 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
        return node;
 }
 
-static SocketPair node_socket_map_pair(PtrNodeMap& node_map, BL::Node b_node, BL::NodeSocket b_socket)
+static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::Node b_node, BL::NodeSocket b_socket)
 {
        BL::Node::inputs_iterator b_input;
-       BL::Node::outputs_iterator b_output;
        string name = b_socket.name();
        bool found = false;
        int counter = 0, total = 0;
-
-       /* find in inputs */
-       for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
-               if(b_input->name() == name) {
-                       if(!found)
+       
+       for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
+               if (b_input->name() == name) {
+                       if (!found)
                                counter++;
                        total++;
                }
@@ -697,128 +617,145 @@ static SocketPair node_socket_map_pair(PtrNodeMap& node_map, BL::Node b_node, BL
                if(b_input->ptr.data == b_socket.ptr.data)
                        found = true;
        }
+       
+       /* rename if needed */
+       if (name == "Shader")
+               name = "Closure";
+       
+       if (total > 1)
+               name = string_printf("%s%d", name.c_str(), counter);
+       
+       return node->input(name.c_str());
+}
 
-       if(!found) {
-               /* find in outputs */
-               found = false;
-               counter = 0;
-               total = 0;
-
-               for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
-                       if(b_output->name() == name) {
-                               if(!found)
-                                       counter++;
-                               total++;
-                       }
-
-                       if(b_output->ptr.data == b_socket.ptr.data)
-                               found = true;
+static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::Node b_node, BL::NodeSocket b_socket)
+{
+       BL::Node::outputs_iterator b_output;
+       string name = b_socket.name();
+       bool found = false;
+       int counter = 0, total = 0;
+       
+       for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
+               if (b_output->name() == name) {
+                       if (!found)
+                               counter++;
+                       total++;
                }
-       }
 
+               if(b_output->ptr.data == b_socket.ptr.data)
+                       found = true;
+       }
+       
        /* rename if needed */
-       if(name == "Shader")
+       if (name == "Shader")
                name = "Closure";
-
-       if(total > 1)
+       
+       if (total > 1)
                name = string_printf("%s%d", name.c_str(), counter);
-
-       return SocketPair(node_map[b_node.ptr.data], name);
+       
+       return node->output(name.c_str());
 }
 
-static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, PtrSockMap& sockets_map)
+static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, ProxyMap &proxy_map)
 {
        /* add nodes */
        BL::ShaderNodeTree::nodes_iterator b_node;
-       PtrNodeMap node_map;
-       PtrSockMap proxy_map;
+       PtrInputMap input_map;
+       PtrOutputMap output_map;
+       
+       BL::Node::inputs_iterator b_input;
+       BL::Node::outputs_iterator b_output;
 
        for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
-               if(b_node->mute()) {
-                       BL::Node::inputs_iterator b_input;
-                       BL::Node::outputs_iterator b_output;
-                       bool found_match = false;
-
-                       /* this is slightly different than blender logic, we just connect a
-                        * single pair for of input/output, but works ok for the node we have */
-                       for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
-                               if(b_input->is_linked()) {
-                                       for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
-                                               if(b_output->is_linked() && b_input->type() == b_output->type()) {
-                                                       ProxyNode *proxy = new ProxyNode(convert_socket_type(b_input->type()), convert_socket_type(b_output->type()));
-                                                       graph->add(proxy);
-
-                                                       proxy_map[b_input->ptr.data] = SocketPair(proxy, proxy->inputs[0]->name);
-                                                       proxy_map[b_output->ptr.data] = SocketPair(proxy, proxy->outputs[0]->name);
-                                                       found_match = true;
-
-                                                       break;
-                                               }
-                                       }
-                               }
-
-                               if(found_match)
-                                       break;
+               if (b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
+                       /* replace muted node with internal links */
+                       BL::Node::internal_links_iterator b_link;
+                       for (b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
+                               ProxyNode *proxy = new ProxyNode(convert_socket_type(b_link->to_socket()));
+                               
+                               input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
+                               output_map[b_link->to_socket().ptr.data] = proxy->outputs[0];
+                               
+                               graph->add(proxy);
                        }
                }
-               else if(b_node->is_a(&RNA_NodeGroup)) {
-                       /* add proxy converter nodes for inputs and outputs */
+               else if (b_node->is_a(&RNA_ShaderNodeGroup)) {
                        BL::NodeGroup b_gnode(*b_node);
                        BL::ShaderNodeTree b_group_ntree(b_gnode.node_tree());
+                       ProxyMap group_proxy_map;
+                       
                        if (!b_group_ntree)
                                continue;
-
-                       BL::Node::inputs_iterator b_input;
-                       BL::Node::outputs_iterator b_output;
                        
-                       PtrSockMap group_sockmap;
+                       add_nodes(scene, b_data, b_scene, graph, b_group_ntree, group_proxy_map);
                        
+                       /* map the outer socket to the internal proxy nodes */
                        for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
-                               ShaderSocketType extern_type = convert_socket_type(b_input->type());
-                               ShaderSocketType intern_type = convert_socket_type(b_input->group_socket().type());
-                               ShaderNode *proxy = graph->add(new ProxyNode(extern_type, intern_type));
                                
-                               /* map the external node socket to the proxy node socket */
-                               proxy_map[b_input->ptr.data] = SocketPair(proxy, proxy->inputs[0]->name);
-                               /* map the internal group socket to the proxy node socket */
-                               group_sockmap[b_input->group_socket().ptr.data] = SocketPair(proxy, proxy->outputs[0]->name);
+                               /* get internal proxy node from group proxy map */
+                               assert(group_proxy_map.find(b_input->identifier()) != group_proxy_map.end());
+                               assert(group_proxy_map[b_input->identifier()]->special_type == SHADER_SPECIAL_TYPE_PROXY);
+                               ProxyNode *proxy = group_proxy_map[b_input->identifier()];
+                               
+                               input_map[b_input->ptr.data] = proxy->inputs[0];
                                
-                               /* default input values of the group node */
-                               set_default_value(proxy->inputs[0], *b_input, b_data, b_group_ntree);
+                               /* input value for proxy inputs is defined by group node */
+                               set_default_value(proxy->inputs[0], *b_node, *b_input, b_data, b_ntree);
                        }
                        
+                       /* map the outer socket to the internal proxy nodes */
                        for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
-                               ShaderSocketType extern_type = convert_socket_type(b_output->type());
-                               ShaderSocketType intern_type = convert_socket_type(b_output->group_socket().type());
-                               ShaderNode *proxy = graph->add(new ProxyNode(intern_type, extern_type));
                                
-                               /* map the external node socket to the proxy node socket */
-                               proxy_map[b_output->ptr.data] = SocketPair(proxy, proxy->outputs[0]->name);
-                               /* map the internal group socket to the proxy node socket */
-                               group_sockmap[b_output->group_socket().ptr.data] = SocketPair(proxy, proxy->inputs[0]->name);
+                               /* get internal proxy node from group node map */
+                               assert(group_proxy_map.find(b_output->identifier()) != group_proxy_map.end());
+                               assert(group_proxy_map[b_output->identifier()]->special_type == SHADER_SPECIAL_TYPE_PROXY);
+                               ProxyNode *proxy = group_proxy_map[b_output->identifier()];
                                
-                               /* default input values of internal, unlinked group outputs */
-                               set_default_value(proxy->inputs[0], b_output->group_socket(), b_data, b_group_ntree);
+                               output_map[b_output->ptr.data] = proxy->outputs[0];
+                       }
+               }
+               else if (b_node->is_a(&RNA_NodeGroupInput)) {
+                       /* add a proxy node for each socket */
+                       for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
+                               ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_output));
+                               
+                               output_map[b_output->ptr.data] = proxy->outputs[0];
+                               
+                               /* register the proxy node for external binding */
+                               proxy_map[b_output->identifier()] = proxy;
+                               
+                               graph->add(proxy);
+                       }
+               }
+               else if (b_node->is_a(&RNA_NodeGroupOutput)) {
+                       /* add a proxy node for each socket */
+                       for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
+                               ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_input));
+                               
+                               input_map[b_input->ptr.data] = proxy->inputs[0];
+                               
+                               set_default_value(proxy->inputs[0], *b_node, *b_input, b_data, b_ntree);
+                               
+                               /* register the proxy node for external binding */
+                               proxy_map[b_input->identifier()] = proxy;
+                               
+                               graph->add(proxy);
                        }
-                       
-                       add_nodes(scene, b_data, b_scene, graph, b_group_ntree, group_sockmap);
                }
                else {
                        ShaderNode *node = add_node(scene, b_data, b_scene, graph, b_ntree, BL::ShaderNode(*b_node));
                        
                        if(node) {
-                               BL::Node::inputs_iterator b_input;
-                               
-                               node_map[b_node->ptr.data] = node;
-                               
+                               /* map node sockets for linking */
                                for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
-                                       SocketPair pair = node_socket_map_pair(node_map, *b_node, *b_input);
-                                       ShaderInput *input = pair.first->input(pair.second.c_str());
+                                       ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input);
+                                       input_map[b_input->ptr.data] = input;
                                        
-                                       assert(input);
-                                       
-                                       /* copy values for non linked inputs */
-                                       set_default_value(input, *b_input, b_data, b_ntree);
+                                       set_default_value(input, *b_node, *b_input, b_data, b_ntree);
+                               }
+                               for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
+                                       ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output);
+                                       output_map[b_output->ptr.data] = output;
                                }
                        }
                }
@@ -829,44 +766,23 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
 
        for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
                /* get blender link data */
-               BL::Node b_from_node = b_link->from_node();
-               BL::Node b_to_node = b_link->to_node();
-
                BL::NodeSocket b_from_sock = b_link->from_socket();
                BL::NodeSocket b_to_sock = b_link->to_socket();
 
-               SocketPair from_pair, to_pair;
-
-               /* links without a node pointer are connections to group inputs/outputs */
-
-               /* from sock */
-               if(b_from_node) {
-                       if (b_from_node.mute() || b_from_node.is_a(&RNA_NodeGroup))
-                               from_pair = proxy_map[b_from_sock.ptr.data];
-                       else
-                               from_pair = node_socket_map_pair(node_map, b_from_node, b_from_sock);
-               }
-               else
-                       from_pair = sockets_map[b_from_sock.ptr.data];
-
-               /* to sock */
-               if(b_to_node) {
-                       if (b_to_node.mute() || b_to_node.is_a(&RNA_NodeGroup))
-                               to_pair = proxy_map[b_to_sock.ptr.data];
-                       else
-                               to_pair = node_socket_map_pair(node_map, b_to_node, b_to_sock);
-               }
-               else
-                       to_pair = sockets_map[b_to_sock.ptr.data];
+               ShaderOutput *output = 0;
+               ShaderInput *input = 0;
+               
+               PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data);
+               if (output_it != output_map.end())
+                       output = output_it->second;
+               PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data);
+               if (input_it != input_map.end())
+                       input = input_it->second;
 
                /* either node may be NULL when the node was not exported, typically
                 * because the node type is not supported */
-               if(from_pair.first && to_pair.first) {
-                       ShaderOutput *output = from_pair.first->output(from_pair.second.c_str());
-                       ShaderInput *input = to_pair.first->input(to_pair.second.c_str());
-
+               if(output && input)
                        graph->connect(output, input);
-               }
        }
 }
 
@@ -891,10 +807,10 @@ void BlenderSync::sync_materials(bool update_all)
 
                        /* create nodes */
                        if(b_mat->use_nodes() && b_mat->node_tree()) {
-                               PtrSockMap sock_to_node;
+                               ProxyMap proxy_map;
                                BL::ShaderNodeTree b_ntree(b_mat->node_tree());
 
-                               add_nodes(scene, b_data, b_scene, graph, b_ntree, sock_to_node);
+                               add_nodes(scene, b_data, b_scene, graph, b_ntree, proxy_map);
                        }
                        else {
                                ShaderNode *closure, *out;
@@ -932,10 +848,10 @@ void BlenderSync::sync_world(bool update_all)
 
                /* create nodes */
                if(b_world && b_world.use_nodes() && b_world.node_tree()) {
-                       PtrSockMap sock_to_node;
+                       ProxyMap proxy_map;
                        BL::ShaderNodeTree b_ntree(b_world.node_tree());
 
-                       add_nodes(scene, b_data, b_scene, graph, b_ntree, sock_to_node);
+                       add_nodes(scene, b_data, b_scene, graph, b_ntree, proxy_map);
                }
                else if(b_world) {
                        ShaderNode *closure, *out;
@@ -991,10 +907,10 @@ void BlenderSync::sync_lamps(bool update_all)
                        if(b_lamp->use_nodes() && b_lamp->node_tree()) {
                                shader->name = b_lamp->name().c_str();
 
-                               PtrSockMap sock_to_node;
+                               ProxyMap proxy_map;
                                BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
 
-                               add_nodes(scene, b_data, b_scene, graph, b_ntree, sock_to_node);
+                               add_nodes(scene, b_data, b_scene, graph, b_ntree, proxy_map);
                        }
                        else {
                                ShaderNode *closure, *out;
index 976ed875211a2ccb7497ded4bd08997010930694..bd4852d08e18c4ea6051a9b111557d483515273c 100644 (file)
@@ -202,30 +202,60 @@ static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_a
        return layer;
 }
 
-#if 0
 static inline float3 get_float3(PointerRNA& ptr, const char *name)
 {
        float3 f;
        RNA_float_get_array(&ptr, name, &f.x);
        return f;
 }
-#endif
+
+static inline void set_float3(PointerRNA& ptr, const char *name, float3 value)
+{
+       RNA_float_set_array(&ptr, name, &value.x);
+}
+
+static inline float4 get_float4(PointerRNA& ptr, const char *name)
+{
+       float4 f;
+       RNA_float_get_array(&ptr, name, &f.x);
+       return f;
+}
+
+static inline void set_float4(PointerRNA& ptr, const char *name, float4 value)
+{
+       RNA_float_set_array(&ptr, name, &value.x);
+}
 
 static inline bool get_boolean(PointerRNA& ptr, const char *name)
 {
        return RNA_boolean_get(&ptr, name)? true: false;
 }
 
+static inline void set_boolean(PointerRNA& ptr, const char *name, bool value)
+{
+       RNA_boolean_set(&ptr, name, (int)value);
+}
+
 static inline float get_float(PointerRNA& ptr, const char *name)
 {
        return RNA_float_get(&ptr, name);
 }
 
+static inline void set_float(PointerRNA& ptr, const char *name, float value)
+{
+       RNA_float_set(&ptr, name, value);
+}
+
 static inline int get_int(PointerRNA& ptr, const char *name)
 {
        return RNA_int_get(&ptr, name);
 }
 
+static inline void set_int(PointerRNA& ptr, const char *name, int value)
+{
+       RNA_int_set(&ptr, name, value);
+}
+
 static inline int get_enum(PointerRNA& ptr, const char *name)
 {
        return RNA_enum_get(&ptr, name);
@@ -242,6 +272,32 @@ static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
        return string(identifier);
 }
 
+static inline void set_enum(PointerRNA& ptr, const char *name, int value)
+{
+       RNA_enum_set(&ptr, name, value);
+}
+
+static inline void set_enum(PointerRNA& ptr, const char *name, const string &identifier)
+{
+       RNA_enum_set_identifier(&ptr, name, identifier.c_str());
+}
+
+static inline string get_string(PointerRNA& ptr, const char *name)
+{
+       char cstrbuf[1024];
+       char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf));
+       string str(cstr);
+       if (cstr != cstrbuf)
+               MEM_freeN(cstr);
+       
+       return str;
+}
+
+static inline void set_string(PointerRNA& ptr, const char *name, const string &value)
+{
+       RNA_string_set(&ptr, name, value.c_str());
+}
+
 /* Relative Paths */
 
 static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
index 61b5bd835348307cf3508311974d2d3d436600b0..c6b9ae08508bf31482f1e376fde4fc67e82ea6a0 100644 (file)
@@ -43,6 +43,8 @@ class OSLCompiler;
  * Data type for inputs and outputs */
 
 enum ShaderSocketType {
+       SHADER_SOCKET_UNDEFINED,
+       
        SHADER_SOCKET_FLOAT,
        SHADER_SOCKET_INT,
        SHADER_SOCKET_COLOR,
index 8ac12242e15532ec470da6e7a5b558a4f8349cd3..398b9f0a758ac6c64436aab39c44328425955aef 100644 (file)
@@ -1242,15 +1242,14 @@ void ConvertNode::compile(OSLCompiler& compiler)
 
 /* Proxy */
 
-ProxyNode::ProxyNode(ShaderSocketType from_, ShaderSocketType to_)
+ProxyNode::ProxyNode(ShaderSocketType type_)
 : ShaderNode("proxy")
 {
-       from = from_;
-       to = to_;
+       type = type_;
        special_type = SHADER_SPECIAL_TYPE_PROXY;
 
-       add_input("Input", from);
-       add_output("Output", to);
+       add_input("Input", type);
+       add_output("Output", type);
 }
 
 void ProxyNode::compile(SVMCompiler& compiler)
index 3609497e5ceaf14f036a2ceca2aa173576fa20c5..1efe4ae076df1ae6b1558e577d2322874a507392 100644 (file)
@@ -190,10 +190,10 @@ public:
 
 class ProxyNode : public ShaderNode {
 public:
-       ProxyNode(ShaderSocketType from, ShaderSocketType to);
+       ProxyNode(ShaderSocketType type);
        SHADER_NODE_BASE_CLASS(ProxyNode)
 
-       ShaderSocketType from, to;
+       ShaderSocketType type;
 };
 
 class BsdfNode : public ShaderNode {
index 4398b1721f7ce22b6016b7c3851a8f4bb579a413..f42fd8e31072c154bd88b153d8401cd52e575262 100644 (file)
@@ -485,17 +485,6 @@ class Text(bpy_types.ID):
                      )
 
 
-class NodeSocket(StructRNA):  # , metaclass=RNAMeta
-    __slots__ = ()
-
-    @property
-    def links(self):
-        """List of node links from or to this socket"""
-        return tuple(link for link in self.id_data.links
-                     if (link.from_socket == self or
-                         link.to_socket == self))
-
-
 # values are module: [(cls, path, line), ...]
 TypeMap = {}
 
@@ -757,3 +746,147 @@ class Region(StructRNA):
 
         return None
 
+
+class NodeTree(bpy_types.ID, metaclass=RNAMetaPropGroup):
+    __slots__ = ()
+
+
+class NodeSocketTemplate():
+    type = 'UNDEFINED'
+
+    # Default implementation:
+    # Create a single property using the socket template's 'value_property' attribute
+    # value_property should be created in the __init__ function
+    #
+    # If necessary this function can be overloaded in subclasses, e.g. to create multiple value properties
+    def define_node_properties(self, node_type, prefix):
+        if hasattr(self, "value_property"):
+            setattr(node_type, prefix+"value", self.value_property)
+
+    def init_socket(self, socket):
+        socket.type = self.type
+        if hasattr(self, "value_property"):
+            socket.value_property = self.value_property[1]['attr']
+
+
+def gen_valid_identifier(seq):
+    # get an iterator
+    itr = iter(seq)
+    # pull characters until we get a legal one for first in identifer
+    for ch in itr:
+        if ch == '_' or ch.isalpha():
+            yield ch
+            break
+    # pull remaining characters and yield legal ones for identifier
+    for ch in itr:
+        if ch == '_' or ch.isalpha() or ch.isdigit():
+            yield ch
+
+def sanitize_identifier(name):
+    return ''.join(gen_valid_identifier(name))
+
+def unique_identifier(name, identifier_list):
+    # First some basic sanitation, to make a usable identifier string from the name
+    base = sanitize_identifier(name)
+    # Now make a unique identifier by appending an unused index
+    identifier = base
+    index = 0
+    while identifier in identifier_list:
+        index += 1
+        identifier = base + str(index)
+    return identifier
+
+class RNAMetaNode(RNAMetaPropGroup):
+    def __new__(cls, name, bases, classdict, **args):
+        # Wrapper for node.init, to add sockets from templates
+
+        def create_sockets(self):
+            inputs = getattr(self, 'input_templates', None)
+            if inputs:
+                for temp in inputs:
+                    socket = self.inputs.new(type=temp.bl_socket_idname, name=temp.name, identifier=temp.identifier)
+                    temp.init_socket(socket)
+            outputs = getattr(self, 'output_templates', None)
+            if outputs:
+                for temp in outputs:
+                    socket = self.outputs.new(type=temp.bl_socket_idname, name=temp.name, identifier=temp.identifier)
+                    temp.init_socket(socket)
+
+        init_base = classdict.get('init', None)
+        if init_base:
+            def init_node(self, context):
+                create_sockets(self)
+                init_base(self, context)
+        else:
+            def init_node(self, context):
+                create_sockets(self)
+
+        classdict['init'] = init_node
+
+        # Create the regular class
+        result = RNAMetaPropGroup.__new__(cls, name, bases, classdict)
+
+        # Add properties from socket templates
+        inputs = classdict.get('input_templates', None)
+        if inputs:
+            for i, temp in enumerate(inputs):
+                temp.identifier = unique_identifier(temp.name, [t.identifier for t in inputs[0:i]])
+                temp.define_node_properties(result, "input_"+temp.identifier+"_")
+        outputs = classdict.get('output_templates', None)
+        if outputs:
+            for i, temp in enumerate(outputs):
+                temp.identifier = unique_identifier(temp.name, [t.identifier for t in outputs[0:i]])
+                temp.define_node_properties(result, "output_"+temp.identifier+"_")
+
+        return result
+
+
+class Node(StructRNA, metaclass=RNAMetaNode):
+    __slots__ = ()
+
+    @classmethod
+    def poll(cls, ntree):
+           return True
+
+
+class NodeSocket(StructRNA, metaclass=RNAMetaPropGroup):
+    __slots__ = ()
+
+    @property
+    def links(self):
+        """List of node links from or to this socket"""
+        return tuple(link for link in self.id_data.links
+                     if (link.from_socket == self or
+                         link.to_socket == self))
+
+
+class NodeSocketInterface(StructRNA, metaclass=RNAMetaPropGroup):
+    __slots__ = ()
+
+
+# These are intermediate subclasses, need a bpy type too
+class CompositorNode(Node):
+    __slots__ = ()
+
+    @classmethod
+    def poll(cls, ntree):
+           return ntree.bl_idname == 'CompositorNodeTree'
+
+    def update(self):
+        self.tag_need_exec()
+
+class ShaderNode(Node):
+    __slots__ = ()
+
+    @classmethod
+    def poll(cls, ntree):
+           return ntree.bl_idname == 'ShaderNodeTree'
+
+
+class TextureNode(Node):
+    __slots__ = ()
+
+    @classmethod
+    def poll(cls, ntree):
+           return ntree.bl_idname == 'TextureNodeTree'
+
index bc0224db765de38447a29a5e20ac91ac563326c4..9839e0ee092b6c9f1ad661e7da6cdf99218c4b39 100644 (file)
@@ -100,75 +100,55 @@ class NODE_OT_add_node(NodeAddOperator, Operator):
             return result
 
 
-# XXX These node item lists should actually be generated by a callback at
-# operator execution time (see node_type_items below),
-# using the active node tree from the context.
-# Due to a difficult bug in bpy this is not possible
-# (item list memory gets freed too early),
-# so for now just copy the static item lists to these global variables.
-#
-# In the custom_nodes branch, the static per-tree-type node items are replaced
-# by a single independent type list anyway (with a poll function to limit node
-# types to the respective trees). So this workaround is only temporary.
-
-# lazy init
-node_type_items_dict = {}
-
-# Prefixes used to distinguish base node types and node groups
-node_type_prefix = 'NODE_'
-node_group_prefix = 'GROUP_'
-
-
-# Generate a list of enum items for a given node class
-# Copy existing type enum, adding a prefix to distinguish from node groups
-# Skip the base node group type,
-# node groups will be added below for all existing group trees
-def node_type_items(node_class):
-    return [(node_type_prefix + item.identifier, item.name, item.description)
-            for item in node_class.bl_rna.properties['type'].enum_items
-            if item.identifier != 'GROUP']
-
-
-# Generate items for node group types
-# Filter by the given tree_type
-# Node group trees don't have a description property yet
-# (could add this as a custom property though)
-def node_group_items(tree_type):
-    return [(node_group_prefix + group.name, group.name, '')
-            for group in bpy.data.node_groups if group.type == tree_type]
+def node_classes_iter(base=bpy.types.Node):
+    """
+    Yields all true node classes by checking for the is_registered_node_type classmethod.
+    Node types can use specialized subtypes of bpy.types.Node, which are not usable
+    nodes themselves (e.g. CompositorNode).
+    """
+    if base.is_registered_node_type():
+        yield base
+    for subclass in base.__subclasses__():
+        for node_class in node_classes_iter(subclass):
+            yield node_class
+
+
+def node_class_items_iter(node_class, context):
+    identifier = node_class.bl_rna.identifier
+    # XXX Checking for explicit group node types is stupid.
+    # This should be replaced by a generic system of generating
+    # node items via callback.
+    # Group node_tree pointer should also use a poll function to filter the library list,
+    # but cannot do that without a node instance here. A node callback could just use the internal poll function.
+    if identifier in {'ShaderNodeGroup', 'CompositorNodeGroup', 'TextureNodeGroup'}:
+        tree_idname = context.space_data.edit_tree.bl_idname
+        for group in bpy.data.node_groups:
+            if group.bl_idname == tree_idname:
+                yield (group.name, "", {"node_tree":group}) # XXX empty string should be replaced by description from tree
+    else:
+        yield (node_class.bl_rna.name, node_class.bl_rna.description, {})
 
 
-# Returns the enum item list for the edited tree in the context
-def node_type_items_cb(self, context):
+def node_items_iter(context):
     snode = context.space_data
     if not snode:
-        return ()
+        return
     tree = snode.edit_tree
     if not tree:
-        return ()
-
-    # Lists of basic node types for each
-    if not node_type_items_dict:
-        node_type_items_dict.update({
-            'SHADER': node_type_items(bpy.types.ShaderNode),
-            'COMPOSITING': node_type_items(bpy.types.CompositorNode),
-            'TEXTURE': node_type_items(bpy.types.TextureNode),
-            })
-
-    # XXX Does not work correctly, see comment above
-    '''
-    return [(item.identifier, item.name, item.description, item.value)
-            for item in
-            tree.nodes.bl_rna.functions['new'].parameters['type'].enum_items]
-    '''
-
-    if tree.type in node_type_items_dict:
-        return node_type_items_dict[tree.type] + node_group_items(tree.type)
-    else:
-        return ()
+        return
+
+    for node_class in node_classes_iter():
+        if node_class.poll(tree):
+            for item in node_class_items_iter(node_class, context):
+                yield (node_class,) + item
+
+
+# Create an enum list from node class items
+def node_type_items_cb(self, context):
+    return [(str(index), item[1], item[2]) for index, item in enumerate(node_items_iter(context))]
 
 
-class NODE_OT_add_search(Operator):
+class NODE_OT_add_search(NodeAddOperator, Operator):
     '''Add a node to the active tree'''
     bl_idname = "node.add_search"
     bl_label = "Search and Add Node"
@@ -182,55 +162,48 @@ class NODE_OT_add_search(Operator):
             items=node_type_items_cb,
             )
 
-    _node_type_items_dict = None
+    def execute(self, context):
+        for index, item in enumerate(node_items_iter(context)):
+            if str(index) == self.type:
+                node = self.create_node(context, item[0].bl_rna.identifier)
+                for prop,value in item[3].items():
+                    setattr(node, prop, value)
+                break
+        return {'FINISHED'}
 
-    def create_node(self, context):
-        space = context.space_data
-        tree = space.edit_tree
+    def invoke(self, context, event):
+        self.store_mouse_cursor(context, event)
+        # Delayed execution in the search popup
+        context.window_manager.invoke_search_popup(self)
+        return {'CANCELLED'}
 
-        # Enum item identifier has an additional prefix to
-        # distinguish base node types from node groups
-        item = self.type
-        if item.startswith(node_type_prefix):
-            # item means base node type
-            node = tree.nodes.new(type=item[len(node_type_prefix):])
-        elif item.startswith(node_group_prefix):
-            # item means node group type
-            node = tree.nodes.new(
-                    type='GROUP',
-                    group=bpy.data.node_groups[item[len(node_group_prefix):]])
-        else:
-            return None
 
-        for n in tree.nodes:
-            if n == node:
-                node.select = True
-                tree.nodes.active = node
-            else:
-                node.select = False
-        node.location = space.cursor_location
-        return node
+# Simple basic operator for adding a node without further initialization
+class NODE_OT_add_node(NodeAddOperator, bpy.types.Operator):
+    '''Add a node to the active tree'''
+    bl_idname = "node.add_node"
+    bl_label = "Add Node"
 
-    @classmethod
-    def poll(cls, context):
-        space = context.space_data
-        # needs active node editor and a tree to add nodes to
-        return (space.type == 'NODE_EDITOR' and space.edit_tree)
+    type = StringProperty(name="Node Type", description="Node type")
 
     def execute(self, context):
-        self.create_node(context)
+        node = self.create_node(context, self.type)
         return {'FINISHED'}
 
-    def invoke(self, context, event):
-        space = context.space_data
-        v2d = context.region.view2d
 
-        # convert mouse position to the View2D for later node placement
-        space.cursor_location = v2d.region_to_view(event.mouse_region_x,
-                                                   event.mouse_region_y)
+class NODE_OT_add_group_node(NodeAddOperator, bpy.types.Operator):
+    '''Add a group node to the active tree'''
+    bl_idname = "node.add_group_node"
+    bl_label = "Add Group Node"
 
-        context.window_manager.invoke_search_popup(self)
-        return {'CANCELLED'}
+    type = StringProperty(name="Node Type", description="Node type")
+    grouptree = StringProperty(name="Group tree", description="Group node tree name")
+
+    def execute(self, context):
+        node = self.create_node(context, self.type)
+        node.node_tree = bpy.data.node_groups[self.grouptree]
+
+        return {'FINISHED'}
 
 
 class NODE_OT_collapse_hide_unused_toggle(Operator):
@@ -261,3 +234,24 @@ class NODE_OT_collapse_hide_unused_toggle(Operator):
                     socket.hide = hide
 
         return {'FINISHED'}
+
+
+class NODE_OT_tree_path_parent(Operator):
+    '''Go to parent node tree'''
+    bl_idname = "node.tree_path_parent"
+    bl_label = "Parent Node Tree"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    @classmethod
+    def poll(cls, context):
+        space = context.space_data
+        # needs active node editor and a tree
+        return (space.type == 'NODE_EDITOR' and len(space.path) > 1)
+
+    def execute(self, context):
+        space = context.space_data
+
+        space.path.pop()
+
+        return {'FINISHED'}
+
index 1865b049a03c70965d8260f3ab39df2cc7bd1c73..e739c5ea5d486834298a82cc15cec5d7b1224878 100644 (file)
@@ -44,8 +44,8 @@ class NODE_HT_header(Header):
             row.menu("NODE_MT_node")
 
         layout.prop(snode, "tree_type", text="", expand=True)
-
-        if snode.tree_type == 'SHADER':
+        
+        if snode.tree_type == 'ShaderNodeTree':
             if scene.render.use_shading_nodes:
                 layout.prop(snode, "shader_type", text="", expand=True)
 
@@ -65,7 +65,7 @@ class NODE_HT_header(Header):
                 if snode_id:
                     layout.prop(snode_id, "use_nodes")
 
-        elif snode.tree_type == 'TEXTURE':
+        elif snode.tree_type == 'TextureNodeTree':
             layout.prop(snode, "texture_type", text="", expand=True)
 
             if id_from:
@@ -76,7 +76,7 @@ class NODE_HT_header(Header):
             if snode_id:
                 layout.prop(snode_id, "use_nodes")
 
-        elif snode.tree_type == 'COMPOSITING':
+        elif snode.tree_type == 'CompositorNodeTree':
             layout.prop(snode_id, "use_nodes")
             layout.prop(snode_id.render, "use_free_unused_nodes", text="Free Unused")
             layout.prop(snode, "show_backdrop")
@@ -84,6 +84,13 @@ class NODE_HT_header(Header):
                 row = layout.row(align=True)
                 row.prop(snode, "backdrop_channels", text="", expand=True)
             layout.prop(snode, "use_auto_render")
+        
+        else:
+            # Custom node tree is edited as independent ID block
+            layout.template_ID(snode, "node_tree", new="node.new_node_tree")
+
+        layout.prop(snode, "pin", text="")
+        layout.operator("node.tree_path_parent", text="", icon='FILE_PARENT')
 
         layout.separator()
 
@@ -182,6 +189,7 @@ class NODE_MT_node(Menu):
         layout.operator("node.group_edit")
         layout.operator("node.group_ungroup")
         layout.operator("node.group_make")
+        layout.operator("node.group_insert")
 
         layout.separator()
 
@@ -208,7 +216,7 @@ class NODE_PT_properties(Panel):
     @classmethod
     def poll(cls, context):
         snode = context.space_data
-        return snode.tree_type == 'COMPOSITING'
+        return snode.tree_type == 'CompositorNodeTree'
 
     def draw_header(self, context):
         snode = context.space_data
@@ -237,7 +245,7 @@ class NODE_PT_quality(bpy.types.Panel):
     @classmethod
     def poll(cls, context):
         snode = context.space_data
-        return snode.tree_type == 'COMPOSITING' and snode.node_tree is not None
+        return snode.tree_type == 'CompositorNodeTree' and snode.node_tree is not None
 
     def draw(self, context):
         layout = self.layout
@@ -276,5 +284,28 @@ class NODE_MT_node_color_specials(Menu):
         layout.operator("node.node_copy_color", icon='COPY_ID')
 
 
+class NODE_UL_interface_sockets(bpy.types.UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        socket = item
+        color = socket.draw_color(context)
+
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            row = layout.row(align=True)
+
+           # inputs get icon on the left
+            if socket.in_out == 'IN':
+                row.template_node_socket(color)
+
+            row.label(text=socket.name, icon_value=icon)
+
+            # outputs get icon on the right
+            if socket.in_out == 'OUT':
+                row.template_node_socket(color)
+
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.template_node_socket(color)
+
+
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)
diff --git a/release/scripts/templates_py/custom_nodes.py b/release/scripts/templates_py/custom_nodes.py
new file mode 100644 (file)
index 0000000..485ee0e
--- /dev/null
@@ -0,0 +1,159 @@
+import bpy
+# XXX these don't work yet ...
+#from bpy_types import NodeTree, Node, NodeSocket
+
+# Implementation of custom nodes from Python
+
+
+# Shortcut for node type menu
+def add_nodetype(layout, type):
+    layout.operator("node.add_node", text=type.bl_label).type = type.bl_rna.identifier
+
+# Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.
+class MyCustomTree(bpy.types.NodeTree):
+    # Description string
+    '''A custom node tree type that will show up in the node editor header'''
+    # Optional identifier string. If not explicitly defined, the python class name is used.
+    bl_idname = 'CustomTreeType'
+    # Label for nice name display
+    bl_label = 'Custom Node Tree'
+    # Icon identifier
+    # NOTE: If no icon is defined, the node tree will not show up in the editor header!
+    #       This can be used to make additional tree types for groups and similar nodes (see below)
+    #       Only one base tree class is needed in the editor for selecting the general category
+    bl_icon = 'NODETREE'
+
+    def draw_add_menu(self, context, layout):
+        layout.label("Hello World!")
+        add_nodetype(layout, bpy.types.CustomNodeType)
+        add_nodetype(layout, bpy.types.MyCustomGroup)
+
+
+# Custom socket type
+class MyCustomSocket(bpy.types.NodeSocket):
+    # Description string
+    '''Custom node socket type'''
+    # Optional identifier string. If not explicitly defined, the python class name is used.
+    bl_idname = 'CustomSocketType'
+    # Label for nice name display
+    bl_label = 'Custom Node Socket'
+    # Socket color
+    bl_color = (1.0, 0.4, 0.216, 0.5)
+
+    # Enum items list
+    my_items = [
+        ("DOWN", "Down", "Where your feet are"),
+        ("UP", "Up", "Where your head should be"),
+        ("LEFT", "Left", "Not right"),
+        ("RIGHT", "Right", "Not left")
+    ]
+
+    myEnumProperty = bpy.props.EnumProperty(name="Direction", description="Just an example", items=my_items, default='UP')
+
+    # Optional function for drawing the socket input value
+    def draw(self, context, layout, node):
+        layout.prop(self, "myEnumProperty", text=self.name)
+
+
+# Base class for all custom nodes in this tree type.
+# Defines a poll function to enable instantiation.
+class MyCustomTreeNode :
+    @classmethod
+    def poll(cls, ntree):
+        return ntree.bl_idname == 'CustomTreeType'
+
+# Derived from the Node base type.
+class MyCustomNode(bpy.types.Node, MyCustomTreeNode):
+    # === Basics ===
+    # Description string
+    '''A custom node'''
+    # Optional identifier string. If not explicitly defined, the python class name is used.
+    bl_idname = 'CustomNodeType'
+    # Label for nice name display
+    bl_label = 'Custom Node'
+    # Icon identifier
+    bl_icon = 'SOUND'
+
+    # === Custom Properties ===
+    # These work just like custom properties in ID data blocks
+    # Extensive information can be found under
+    # http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties
+    myStringProperty = bpy.props.StringProperty()
+    myFloatProperty = bpy.props.FloatProperty(default=3.1415926)
+
+    # === Optional Functions ===
+    # Initialization function, called when a new node is created.
+    # This is the most common place to create the sockets for a node, as shown below.
+    # NOTE: this is not the same as the standard __init__ function in Python, which is
+    #       a purely internal Python method and unknown to the node system!
+    def init(self, context):
+        self.inputs.new('CustomSocketType', "Hello")
+        self.inputs.new('NodeSocketFloat', "World")
+        self.inputs.new('NodeSocketVector', "!")
+
+        self.outputs.new('NodeSocketColor', "How")
+        self.outputs.new('NodeSocketColor', "are")
+        self.outputs.new('NodeSocketFloat', "you")
+
+    # Copy function to initialize a copied node from an existing one.
+    def copy(self, node):
+        print("Copying from node ", node)
+
+    # Free function to clean up on removal.
+    def free(self):
+        print("Removing node ", self, ", Goodbye!")
+
+    # Additional buttons displayed on the node.
+    def draw_buttons(self, context, layout):
+        layout.label("Node settings")
+        layout.prop(self, "myFloatProperty")
+
+    # Detail buttons in the sidebar.
+    # If this function is not defined, the draw_buttons function is used instead
+    def draw_buttons_ext(self, context, layout):
+        layout.prop(self, "myFloatProperty")
+        # myStringProperty button will only be visible in the sidebar
+        layout.prop(self, "myStringProperty")
+
+
+# A customized group-like node.
+class MyCustomGroup(bpy.types.NodeGroup, MyCustomTreeNode):
+    # === Basics ===
+    # Description string
+    '''A custom group node'''
+    # Label for nice name display
+    bl_label = 'Custom Group Node'
+    bl_group_tree_idname = 'CustomTreeType'
+
+    orks = bpy.props.IntProperty(default=3)
+    dwarfs = bpy.props.IntProperty(default=12)
+    wizards = bpy.props.IntProperty(default=1)
+
+    # Additional buttons displayed on the node.
+    def draw_buttons(self, context, layout):
+        col = layout.column(align=True)
+        col.prop(self, "orks")
+        col.prop(self, "dwarfs")
+        col.prop(self, "wizards")
+
+        layout.label("The Node Tree:")
+        layout.prop(self, "node_tree", text="")
+
+
+def register():
+    bpy.utils.register_class(MyCustomTree)
+    bpy.utils.register_class(MyCustomSocket)
+    bpy.utils.register_class(MyCustomNode)
+    bpy.utils.register_class(MyCustomGroup)
+
+
+def unregister():
+    bpy.utils.unregister_class(MyCustomTree)
+    bpy.utils.unregister_class(MyCustomSocket)
+    bpy.utils.unregister_class(MyCustomNode)
+    bpy.utils.unregister_class(MyCustomGroup)
+
+
+if __name__ == "__main__":
+    register()
+
index a53fc15714e7dcaff7a4d15cfa7b08de51c841fc..d03c631f7a1dd406bf510636066b46895de1d174 100644 (file)
@@ -42,7 +42,7 @@ extern "C" {
  * and keep comment above the defines.
  * Use STRINGIFY() rather than defining with quotes */
 #define BLENDER_VERSION         266
-#define BLENDER_SUBVERSION      1
+#define BLENDER_SUBVERSION      2
 
 /* 262 was the last editmesh release but it has compatibility code for bmesh data */
 #define BLENDER_MINVERSION      262
index 809557293262ea8deff1114f2dd77e10919bca92..513851ce18fe55f3b4cc4082ed7ace32fa161389 100644 (file)
  *  \ingroup bke
  */
 
+#include "BLI_ghash.h"
+#include "BLI_utildefines.h"
+
 #include "DNA_listBase.h"
 
+/* for FOREACH_NODETREE */
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "RNA_types.h"
+
 /* not very important, but the stack solver likes to know a maximum */
 #define MAX_SOCKET     64
 
@@ -43,7 +56,10 @@ struct bNodeLink;
 struct bNodeSocket;
 struct bNodeStack;
 struct bNodeTree;
+struct bNodeTreeType;
 struct bNodeTreeExec;
+struct bNodeExecContext;
+struct bNodeExecData;
 struct GPUMaterial;
 struct GPUNode;
 struct GPUNodeStack;
@@ -65,6 +81,7 @@ struct ARegion;
 struct Object;
 struct ColorManagedViewSettings;
 struct ColorManagedDisplaySettings;
+struct bNodeInstanceHash;
 
 /* ************** NODE TYPE DEFINITIONS ***** */
 
@@ -72,9 +89,9 @@ struct ColorManagedDisplaySettings;
  * Can be used to quickly define a list of static sockets for a node,
  * which are added to each new node of that type. 
  *
- * \deprecated New nodes should add default sockets in the initialization
- * function instead. This struct is mostly kept for old nodes and should
- * be removed some time.
+ * \deprecated This struct is used by C nodes to define templates as simple
+ * static struct lists. These are converted to the new template collections
+ * in RNA types automatically.
  */
 typedef struct bNodeSocketTemplate {
        int type, limit;
@@ -86,38 +103,38 @@ typedef struct bNodeSocketTemplate {
        
        /* after this line is used internal only */
        struct bNodeSocket *sock;               /* used to hold verified socket */
+       char identifier[64];                    /* generated from name */
 } bNodeSocketTemplate;
 
-typedef void (*NodeSocketButtonFunction)(const struct bContext *C, struct uiBlock *block, 
-                                         struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock,
-                                         const char *name, int x, int y, int width);
-
 /** Defines a socket type.
  * Defines the appearance and behavior of a socket in the UI.
  */
 typedef struct bNodeSocketType {
-       int type;
-       char ui_name[64];       /* MAX_NAME */
-       char ui_description[128];
-       int ui_icon;
-       char ui_color[4];
+       char idname[64];                                /* identifier name */
+       
+       void (*draw)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr, struct PointerRNA *node_ptr);
+       void (*draw_color)(struct bContext *C, struct PointerRNA *ptr, struct PointerRNA *node_ptr, float *r_color);
+       
+       void (*interface_draw)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr);
+       void (*interface_draw_color)(struct bContext *C, struct PointerRNA *ptr, float *r_color);
+       void (*interface_register_properties)(struct bNodeTree *ntree, struct bNodeSocket *stemp, struct StructRNA *data_srna);
+       void (*interface_init_socket)(struct bNodeTree *ntree, struct bNodeSocket *stemp, struct bNode *node, struct bNodeSocket *sock, const char *data_path);
+       void (*interface_from_socket)(struct bNodeTree *ntree, struct bNodeSocket *stemp, struct bNode *node, struct bNodeSocket *sock);
        
-       const char *value_structname;
-       int value_structsize;
+       /* RNA integration */
+       ExtensionRNA ext_socket;
+       ExtensionRNA ext_interface;
        
-       NodeSocketButtonFunction buttonfunc;
+       /* for standard socket types in C */
+       int type, subtype;
 } bNodeSocketType;
 
-/** Template for creating a node.
- * Stored required parameters to make a new node of a specific type.
- */
-typedef struct bNodeTemplate {
-       int type;
-       
-       struct Main *main;
-       struct Scene *scene;
-       struct bNodeTree *ngroup;       /* group tree */
-} bNodeTemplate;
+typedef void (*NodeSocketDrawFunction)(struct bContext *C, struct uiLayout *layout, struct PointerRNA *ptr, struct PointerRNA *node_ptr, int linked);
+
+typedef void *(*NodeInitExecFunction)(struct bNodeExecContext *context, struct bNode *node, bNodeInstanceKey key);
+typedef void (*NodeFreeExecFunction)(struct bNode *node, void *nodedata);
+typedef void (*NodeExecFunction)(void *data, int thread, struct bNode *, struct bNodeExecData *execdata, struct bNodeStack **in, struct bNodeStack **out);
+typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat, struct bNode *node, struct bNodeExecData *execdata, struct GPUNodeStack *in, struct GPUNodeStack *out);
 
 /** Defines a node type.
  * Initial attributes and constants for a node as well as callback functions
@@ -127,8 +144,13 @@ typedef struct bNodeType {
        void *next, *prev;
        short needs_free;               /* set for allocated types that need to be freed */
        
+       char idname[64];                                /* identifier name */
        int type;
-       char name[64];  /* MAX_NAME */
+
+       char ui_name[64];       /* MAX_NAME */
+       char ui_description[256];
+       int ui_icon;
+       
        float width, minwidth, maxwidth;
        float height, minheight, maxheight;
        short nclass, flag, compatibility;
@@ -139,7 +161,8 @@ typedef struct bNodeType {
        char storagename[64];                   /* struct name for DNA */
        
        /// Main draw function for the node.
-       void (*drawfunc)(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *node);
+       void (*drawfunc)(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode,
+                        struct bNodeTree *ntree, struct bNode *node, bNodeInstanceKey key);
        /// Updates the node geometry attributes according to internal state before actual drawing.
        void (*drawupdatefunc)(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
        /// Draw the option buttons on the node.
@@ -150,8 +173,11 @@ typedef struct bNodeType {
        void (*uibackdropfunc)(struct SpaceNode *snode, struct ImBuf *backdrop, struct bNode *node, int x, int y);
 
        /// Draw a node socket. Default draws the input value button.
-       NodeSocketButtonFunction drawinputfunc;
-       NodeSocketButtonFunction drawoutputfunc;
+       /* XXX deprecated, only used for the OutputFile node,
+        * should be removed at some point.
+        */
+       NodeSocketDrawFunction drawinputfunc;
+       NodeSocketDrawFunction drawoutputfunc;
 
        /// Optional custom label function for the node header.
        const char *(*labelfunc)(struct bNode *);
@@ -168,45 +194,42 @@ typedef struct bNodeType {
        void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id);
        
        /// Initialize a new node instance of this type after creation.
-       void (*initfunc)(struct bNodeTree *ntree, struct bNode *node, struct bNodeTemplate *ntemp);
-       /// Free the custom storage data.
-       void (*freestoragefunc)(struct bNode *node);
-       /// Make a copy of the custom storage data.
-       void (*copystoragefunc)(struct bNode *node, struct bNode *target);
+       void (*initfunc)(struct bNodeTree *ntree, struct bNode *node);
+       /// Free the node instance.
+       void (*freefunc)(struct bNode *node);
+       /// Make a copy of the node instance.
+       void (*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, struct bNode *src_node);
        
-       /// Create a template from an existing node.
-       struct bNodeTemplate (*templatefunc)(struct bNode *);
-       /** If a node can be made from the template in the given node tree.
-        * \note Node groups can not be created inside their own node tree.
-        */
-       int (*validfunc)(struct bNodeTree *ntree, struct bNodeTemplate *ntemp);
+       /* Registerable API callback versions, called in addition to C callbacks */
+       void (*initfunc_api)(const struct bContext *C, struct PointerRNA *ptr);
+       void (*freefunc_api)(struct PointerRNA *ptr);
+       void (*copyfunc_api)(struct PointerRNA *ptr, struct bNode *src_node);
        
-       /// Initialize a node tree associated to this node type.
-       void (*inittreefunc)(struct bNodeTree *ntree);
-       /// Update a node tree associated to this node type.
-       void (*updatetreefunc)(struct bNodeTree *ntree);
-       
-       /* group edit callbacks for operators */
-       /* XXX this is going to be changed as required by the UI */
-       struct bNodeTree *(*group_edit_get)(struct bNode *node);
-       struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit);
-       void (*group_edit_clear)(struct bNode *node);
+       /* can this node type be added to a node tree */
+       int (*poll)(struct bNodeType *ntype, struct bNodeTree *nodetree);
+       /* can this node be added to a node tree */
+       int (*poll_instance)(struct bNode *node, struct bNodeTree *nodetree);
        
        /* Update the internal links list, for muting and disconnect operators. */
        void (*update_internal_links)(struct bNodeTree *, struct bNode *node);
        
        /* **** execution callbacks **** */
-       void *(*initexecfunc)(struct bNode *node);
-       void (*freeexecfunc)(struct bNode *node, void *nodedata);
-       void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **);
-       /* XXX this alternative exec function has been added to avoid changing all node types.
-        * when a final generic version of execution code is defined, this will be changed anyway
-        */
-       void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata, struct bNodeStack **, struct bNodeStack **);
+       NodeInitExecFunction initexecfunc;
+       NodeFreeExecFunction freeexecfunc;
+       NodeExecFunction execfunc;
        /* gpu */
-       int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out);
-       /* extended gpu function */
-       int (*gpuextfunc)(struct GPUMaterial *mat, struct bNode *node, void *nodedata, struct GPUNodeStack *in, struct GPUNodeStack *out);
+       NodeGPUExecFunction gpufunc;
+       
+       /* Group type static info
+        * 
+        * XXX This data is needed by group operators. If these operators could be implemented completely in Python,
+        * the static data could instead be stored in Python classes and would need no special treatment.
+        * Due to the way group operators move nodes between data blocks this is currently not possible.
+        */
+       char group_tree_idname[64];             /* tree type associated to the group node type */
+       
+       /* RNA integration */
+       ExtensionRNA ext;
 } bNodeType;
 
 /* node->exec, now in use for composites (#define for break is same as ready yes) */
@@ -245,6 +268,7 @@ typedef struct bNodeType {
 #define NODE_CLASS_TRANSFORM           30
 #define NODE_CLASS_COMBINE                     31
 #define NODE_CLASS_SCRIPT                      32
+#define NODE_CLASS_INTERFACE           33
 #define NODE_CLASS_SHADER                      40
 #define NODE_CLASS_LAYOUT                      100
 
@@ -258,10 +282,6 @@ typedef struct bNodeType {
 #define NODE_RESIZE_RIGHT      4
 #define NODE_RESIZE_LEFT       8
 
-/* enum values for input/output */
-#define SOCK_IN                1
-#define SOCK_OUT       2
-
 typedef enum eNodeSizePreset {
        NODE_SIZE_DEFAULT,
        NODE_SIZE_SMALL,
@@ -270,19 +290,26 @@ typedef enum eNodeSizePreset {
 
 struct bNodeTreeExec;
 
-typedef void (*bNodeTreeCallback)(void *calldata, struct ID *owner_id, struct bNodeTree *ntree);
 typedef void (*bNodeClassCallback)(void *calldata, int nclass, const char *name);
 typedef struct bNodeTreeType {
        int type;                                               /* type identifier */
-       char idname[64];                                /* id name for RNA identification */
-       
-       ListBase node_types;                    /* type definitions */
+       char idname[64];                                /* identifier name */
+
+       char ui_name[64];
+       char ui_description[256];
+       int ui_icon;
        
        /* callbacks */
        void (*free_cache)(struct bNodeTree *ntree);
        void (*free_node_cache)(struct bNodeTree *ntree, struct bNode *node);
-       void (*foreach_nodetree)(struct Main *main, void *calldata, bNodeTreeCallback func);            /* iteration over all node trees */
        void (*foreach_nodeclass)(struct Scene *scene, void *calldata, bNodeClassCallback func);        /* iteration over all node classes */
+       /* Add menu for this node tree. */
+       void (*draw_add_menu)(const struct bContext *C, struct uiLayout *layout, struct bNodeTree *ntree);
+       /* Check visibility in the node editor */
+       int (*poll)(const struct bContext *C, struct bNodeTreeType *ntreetype);
+       /* Select a node tree from the context */
+       void (*get_from_context)(const struct bContext *C, struct bNodeTreeType *ntreetype,
+                                struct bNodeTree **r_ntree, struct ID **r_id, struct ID **r_from);
 
        /* calls allowing threaded composite */
        void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree);
@@ -291,23 +318,37 @@ typedef struct bNodeTreeType {
 
        /* Tree update. Overrides nodetype->updatetreefunc! */
        void (*update)(struct bNodeTree *ntree);
-       /* Node update. Overrides nodetype->updatefunc! */
-       void (*update_node)(struct bNodeTree *ntree, struct bNode *node);
        
        int (*validate_link)(struct bNodeTree *ntree, struct bNodeLink *link);
-
-       /* Default internal linking. */
-       void (*update_internal_links)(struct bNodeTree *, struct bNode *node);
+       
+       /* RNA integration */
+       ExtensionRNA ext;
 } bNodeTreeType;
 
+
 /* ************** GENERIC API, TREES *************** */
 
-struct bNodeTreeType *ntreeGetType(int type);
-struct bNodeType *ntreeGetNodeType(struct bNodeTree *ntree);
-struct bNodeSocketType *ntreeGetSocketType(int type);
+struct bNodeTreeType *ntreeTypeFind(const char *idname);
+void ntreeTypeAdd(struct bNodeTreeType* nt);
+void ntreeTypeFreeLink(struct bNodeTreeType* nt);
+struct GHashIterator *ntreeTypeGetIterator(void);
+
+/* helper macros for iterating over tree types */
+#define NODE_TREE_TYPES_BEGIN(ntype) \
+{ \
+       GHashIterator *__node_tree_type_iter__ = ntreeTypeGetIterator(); \
+       for (; BLI_ghashIterator_notDone(__node_tree_type_iter__); BLI_ghashIterator_step(__node_tree_type_iter__)) { \
+               bNodeTreeType *ntype = BLI_ghashIterator_getValue(__node_tree_type_iter__);
 
-struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, int type, int nodetype);
-void              ntreeInitTypes(struct bNodeTree *ntree);
+#define NODE_TREE_TYPES_END \
+       } \
+       BLI_ghashIterator_free(__node_tree_type_iter__); \
+}
+
+void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree);
+int ntreeIsValid(struct bNodeTree *ntree);
+
+struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
 
 /* copy/free funcs, need to manage ID users */
 void              ntreeFreeTree_ex(struct bNodeTree *ntree, const short do_id_user);
@@ -337,8 +378,6 @@ void              ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode *
  * new tree types have a per-output socket flag to indicate the final output to use explicitly.
  */
 void            ntreeSetOutput(struct bNodeTree *ntree);
-void            ntreeInitPreview(struct bNodeTree *, int xsize, int ysize);
-void            ntreeClearPreview(struct bNodeTree *ntree);
 
 void            ntreeFreeCache(struct bNodeTree *ntree);
 
@@ -348,29 +387,86 @@ struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
 void            ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
 void            ntreeLocalMerge(struct bNodeTree *localtree, struct bNodeTree *ntree);
 
+/* ************** NODE TREE INTERFACE *************** */
+
+struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree, int in_out, const char *identifier);
+struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree, int in_out, const char *idname, const char *name);
+struct bNodeSocket *ntreeInsertSocketInterface(struct bNodeTree *ntree, int in_out, const char *idname,
+                                               struct bNodeSocket *next_sock, const char *name);
+struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(struct bNodeTree *ntree, struct bNode *from_node, struct bNodeSocket *from_sock);
+struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(struct bNodeTree *ntree, struct bNodeSocket *next_sock,
+                                                         struct bNode *from_node, struct bNodeSocket *from_sock);
+void            ntreeRemoveSocketInterface(struct bNodeTree *ntree, struct bNodeSocket *sock);
+
+struct StructRNA *ntreeInterfaceTypeGet(struct bNodeTree *ntree, int create);
+void ntreeInterfaceTypeFree(struct bNodeTree *ntree);
+void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree);
+
 /* ************** GENERIC API, NODES *************** */
 
-struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *name, int type);
-struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, struct bNodeSocket *next_sock, const char *name, int type);
+struct bNodeType *nodeTypeFind(const char *idname);
+void                   nodeRegisterType(struct bNodeType* ntype);
+void                   nodeUnregisterType(struct bNodeType* ntype);
+struct GHashIterator *nodeTypeGetIterator(void);
+
+/* helper macros for iterating over node types */
+#define NODE_TYPES_BEGIN(ntype) \
+{ \
+       GHashIterator *__node_type_iter__ = nodeTypeGetIterator(); \
+       for (; BLI_ghashIterator_notDone(__node_type_iter__); BLI_ghashIterator_step(__node_type_iter__)) { \
+               bNodeType *ntype = BLI_ghashIterator_getValue(__node_type_iter__);
+
+#define NODE_TYPES_END \
+       } \
+       BLI_ghashIterator_free(__node_type_iter__); \
+}
+
+struct bNodeSocketType *nodeSocketTypeFind(const char *idname);
+void                   nodeRegisterSocketType(struct bNodeSocketType* stype);
+void                   nodeUnregisterSocketType(struct bNodeSocketType* stype);
+struct GHashIterator *nodeSocketTypeGetIterator(void);
+const char *   nodeStaticSocketType(int type, int subtype);
+const char *   nodeStaticSocketInterfaceType(int type, int subtype);
+
+/* helper macros for iterating over node types */
+#define NODE_SOCKET_TYPES_BEGIN(stype) \
+{ \
+       GHashIterator *__node_socket_type_iter__ = nodeSocketTypeGetIterator(); \
+       for (; BLI_ghashIterator_notDone(__node_socket_type_iter__); BLI_ghashIterator_step(__node_socket_type_iter__)) { \
+               bNodeSocketType *stype = BLI_ghashIterator_getValue(__node_socket_type_iter__);
+
+#define NODE_SOCKET_TYPES_END \
+       } \
+       BLI_ghashIterator_free(__node_socket_type_iter__); \
+}
+
+void                   nodeMakeDynamicType(struct bNode *node);
+int                            nodeDynamicUnlinkText(struct ID *txtid);
+
+struct bNodeSocket *nodeFindSocket(struct bNode *node, int in_out, const char *identifier);
+struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *idname,
+                                  const char *identifier, const char *name);
+struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *idname,
+                                     struct bNodeSocket *next_sock, const char *identifier, const char *name);
+struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, int type, int subtype,
+                                        const char *identifier, const char *name);
+struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, int type, int subtype,
+                                           struct bNodeSocket *next_sock, const char *identifier, const char *name);
 void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
 void nodeRemoveAllSockets(struct bNodeTree *ntree, struct bNode *node);
 
-void            nodeAddToPreview(struct bNode *node, const float col[4], int x, int y, int do_manage);
-
-struct bNode   *nodeAddNode(struct bNodeTree *ntree, struct bNodeTemplate *ntemp);
+struct bNode   *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname);
+struct bNode   *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type);
 void            nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
 void            nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
 
-void            nodeRegisterType(struct bNodeTreeType *ttype, struct bNodeType *ntype);
-void            nodeMakeDynamicType(struct bNode *node);
-int             nodeDynamicUnlinkText(struct ID *txtid);
-
 void            nodeFreeNode(struct bNodeTree *ntree, struct bNode *node);
 struct bNode   *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node);
 
 struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock);
 void            nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link);
 void            nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
+int             nodeLinkIsHidden(struct bNodeLink *link);
 void            nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node);
 
 void            nodeToView(struct bNode *node, float x, float y, float *rx, float *ry);
@@ -380,11 +476,12 @@ void            nodeAttachNode(struct bNode *node, struct bNode *parent);
 void            nodeDetachNode(struct bNode *node);
 
 struct bNode   *nodeFindNodebyName(struct bNodeTree *ntree, const char *name);
-int             nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **nodep, int *sockindex, int *in_out);
+int             nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **nodep, int *sockindex);
 
 struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, struct bNodeSocket *from, struct bNodeSocket *to);
 int             nodeCountSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
 
+void                   nodeSetSelected(struct bNode *node, int select);
 void            nodeSetActive(struct bNodeTree *ntree, struct bNode *node);
 struct bNode   *nodeGetActive(struct bNodeTree *ntree);
 struct bNode   *nodeGetActiveID(struct bNodeTree *ntree, short idtype);
@@ -396,11 +493,9 @@ struct bNode   *nodeGetActiveTexture(struct bNodeTree *ntree);
 void            nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
 int             nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
 void            nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-
-void            nodeFreePreview(struct bNode *node);
+void            nodeSynchronizeID(struct bNode *node, bool copy_to_id);
 
 int             nodeSocketIsHidden(struct bNodeSocket *sock);
-void            nodeSocketSetType(struct bNodeSocket *sock, int type);
 
 /* Node Clipboard */
 void                   BKE_node_clipboard_init(struct bNodeTree *ntree);
@@ -412,78 +507,189 @@ const struct ListBase *BKE_node_clipboard_get_nodes(void);
 const struct ListBase *BKE_node_clipboard_get_links(void);
 int                    BKE_node_clipboard_get_type(void);
 
+/* Node Instance Hash */
+typedef struct bNodeInstanceHash
+{
+        GHash *ghash;  /* XXX should be made a direct member, GHash allocation needs to support it */
+} bNodeInstanceHash;
+
+typedef void (*bNodeInstanceValueFP)(void *value);
+
+extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE;
+
+bNodeInstanceKey       BKE_node_instance_key(bNodeInstanceKey parent_key, struct bNodeTree *ntree, struct bNode *node);
+
+bNodeInstanceHash *    BKE_node_instance_hash_new(const char *info);
+void                   BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp);
+void                   BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value);
+void*                  BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key);
+int                    BKE_node_instance_hash_remove(bNodeInstanceHash *hash, bNodeInstanceKey key, bNodeInstanceValueFP valfreefp);
+void                   BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp);
+void*                  BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key);
+int                    BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key);
+int                    BKE_node_instance_hash_size(bNodeInstanceHash *hash);
+
+void                   BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash);
+void                   BKE_node_instance_hash_tag(bNodeInstanceHash *hash, void *value);
+int                    BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key);
+void                   BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp);
+
+typedef GHashIterator bNodeInstanceHashIterator;
+
+BLI_INLINE bNodeInstanceHashIterator *BKE_node_instance_hash_iterator_new(bNodeInstanceHash *hash) { return BLI_ghashIterator_new(hash->ghash); }
+BLI_INLINE void                       BKE_node_instance_hash_iterator_init(bNodeInstanceHashIterator *iter, bNodeInstanceHash *hash) { BLI_ghashIterator_init(iter, hash->ghash); }
+BLI_INLINE void                       BKE_node_instance_hash_iterator_free(bNodeInstanceHashIterator *iter) { BLI_ghashIterator_free(iter); }
+BLI_INLINE bNodeInstanceKey           BKE_node_instance_hash_iterator_get_key(bNodeInstanceHashIterator *iter) { return *(bNodeInstanceKey *)BLI_ghashIterator_getKey(iter); }
+BLI_INLINE void*                      BKE_node_instance_hash_iterator_get_value(bNodeInstanceHashIterator *iter) { return BLI_ghashIterator_getValue(iter); }
+BLI_INLINE void                       BKE_node_instance_hash_iterator_step(bNodeInstanceHashIterator *iter) { BLI_ghashIterator_step(iter); }
+BLI_INLINE bool                       BKE_node_instance_hash_iterator_not_done(bNodeInstanceHashIterator *iter) { return BLI_ghashIterator_notDone(iter); }
+
+#define NODE_INSTANCE_HASH_ITER(iter_, hash_) \
+       for (BKE_node_instance_hash_iterator_init(&iter_, hash_); \
+            BKE_node_instance_hash_iterator_not_done(&iter_); \
+            BKE_node_instance_hash_iterator_step(&iter_))
+
+
+/* Node Previews */
+
+int             BKE_node_preview_used(struct bNode *node);
+bNodePreview*   BKE_node_preview_verify(struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, int create);
+bNodePreview*   BKE_node_preview_copy(struct bNodePreview *preview);
+void            BKE_node_preview_free(struct bNodePreview *preview);
+void            BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize, int create_previews);
+void            BKE_node_preview_free_tree(struct bNodeTree *ntree);
+void            BKE_node_preview_remove_unused(struct bNodeTree *ntree);
+void            BKE_node_preview_clear(struct bNodePreview *preview);
+void            BKE_node_preview_clear_tree(struct bNodeTree *ntree);
+
+void            BKE_node_preview_sync_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree);
+void            BKE_node_preview_merge_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree);
+
+void            BKE_node_preview_set_pixel(struct bNodePreview *preview, const float col[4], int x, int y, int do_manage);
+
+
 /* ************** NODE TYPE ACCESS *************** */
 
-struct bNodeTemplate nodeMakeTemplate(struct bNode *node);
-int             nodeValid(struct bNodeTree *ntree, struct bNodeTemplate *ntemp);
 const char     *nodeLabel(struct bNode *node);
 struct bNodeTree *nodeGroupEditGet(struct bNode *node);
 struct bNodeTree *nodeGroupEditSet(struct bNode *node, int edit);
 void            nodeGroupEditClear(struct bNode *node);
 
+int                            nodeGroupPoll(struct bNodeTree *nodetree, struct bNodeTree *grouptree);
+
 /* Init a new node type struct with default values and callbacks */
-void            node_type_base(struct bNodeTreeType *ttype, struct bNodeType *ntype, int type,
-                               const char *name, short nclass, short flag);
+void            node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void            node_type_base_custom(struct bNodeType *ntype, const char *idname, const char *name, short nclass, short flag);
 void            node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs);
 void            node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth);
 void            node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size);
-void            node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node, struct bNodeTemplate *ntemp));
-void            node_type_valid(struct bNodeType *ntype, int (*validfunc)(struct bNodeTree *ntree, struct bNodeTemplate *ntemp));
+void            node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node));
 void            node_type_storage(struct bNodeType *ntype,
                                   const char *storagename,
-                                  void (*freestoragefunc)(struct bNode *),
-                                  void (*copystoragefunc)(struct bNode *, struct bNode *));
+                                  void (*freefunc)(struct bNode *node),
+                                  void (*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, struct bNode *src_node));
 void            node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bNode *));
-void            node_type_template(struct bNodeType *ntype, struct bNodeTemplate (*templatefunc)(struct bNode *));
 void            node_type_update(struct bNodeType *ntype,
                                  void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node),
                                  void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id));
-void            node_type_tree(struct bNodeType *ntype,
-                               void (*inittreefunc)(struct bNodeTree *),
-                               void (*updatetreefunc)(struct bNodeTree *));
-void            node_type_group_edit(struct bNodeType *ntype,
-                                     struct bNodeTree *(*group_edit_get)(struct bNode *node),
-                                     struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit),
-                                     void (*group_edit_clear)(struct bNode *node));
-
-void            node_type_exec(struct bNodeType *ntype, void (*execfunc)(void *data, struct bNode *, struct bNodeStack **,
-                                                                         struct bNodeStack **));
-void            node_type_exec_new(struct bNodeType *ntype,
-                                   void *(*initexecfunc)(struct bNode *node),
-                                   void (*freeexecfunc)(struct bNode *node, void *nodedata),
-                                   void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata,
-                                                       struct bNodeStack **, struct bNodeStack **));
+
+void            node_type_exec(struct bNodeType *ntype, NodeInitExecFunction initexecfunc, NodeFreeExecFunction freeexecfunc, NodeExecFunction execfunc);
+void            node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc);
 void            node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *));
-void            node_type_gpu(struct bNodeType *ntype, int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node,
-                                                                      struct GPUNodeStack *in, struct GPUNodeStack *out));
-void            node_type_gpu_ext(struct bNodeType *ntype, int (*gpuextfunc)(struct GPUMaterial *mat, struct bNode *node,
-                                                                             void *nodedata, struct GPUNodeStack *in,
-                                                                             struct GPUNodeStack *out));
 void            node_type_compatibility(struct bNodeType *ntype, short compatibility);
 
 /* ************** COMMON NODES *************** */
 
+#define NODE_UNDEFINED -2              /* node type is not registered */
+#define NODE_CUSTOM            -1              /* for dynamically registered custom types */
 #define NODE_GROUP             2
-#define __NODE_FORLOOP 3       /* deprecated */
+#define __NODE_FORLOOP 3               /* deprecated */
 #define __NODE_WHILELOOP       4       /* deprecated */
 #define NODE_FRAME             5
 #define NODE_REROUTE   6
+#define NODE_GROUP_INPUT       7
+#define NODE_GROUP_OUTPUT      8
 
-/* look up a socket on a group node by the internal group socket */
-struct bNodeSocket *node_group_find_input(struct bNode *gnode, struct bNodeSocket *gsock);
-struct bNodeSocket *node_group_find_output(struct bNode *gnode, struct bNodeSocket *gsock);
+void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree);
 
-struct bNodeSocket *node_group_add_socket(struct bNodeTree *ngroup, const char *name, int type, int in_out);
-struct bNodeSocket *node_group_expose_socket(struct bNodeTree *ngroup, struct bNodeSocket *sock, int in_out);
-void node_group_expose_all_sockets(struct bNodeTree *ngroup);
-void node_group_remove_socket(struct bNodeTree *ngroup, struct bNodeSocket *gsock, int in_out);
-struct bNodeSocket *node_group_add_extern_socket(struct bNodeTree *ntree, ListBase *lb, int in_out, struct bNodeSocket *gsock);
-
-/* in node_common.c */
-void register_node_type_frame(struct bNodeTreeType *ttype);
-void register_node_type_reroute(struct bNodeTreeType *ttype);
+/* Utility macro for visiting every node tree in the library data, including local bNodeTree blocks in other IDs.
+ * This avoids the need for callback functions and allows executing code in a single inner code block.
+ *
+ * Variables:
+ *
+ *   nodetree:  The actual bNodeTree data block.
+ *              Check nodetree->idname or nodetree->typeinfo to use only specific types.
+ *
+ *   id:        The owner of the bNodeTree data block.
+ *              Same as nodetree if it's a linkable node tree from the library.
+ *
+ * Examples:
+ *
+ * FOREACH_NODETREE(bmain, nodetree)
+ *     if (id == nodetree)
+ *         printf("This is a linkable node tree");
+ * FOREACH_NODETREE_END
+ *
+ * FOREACH_NODETREE(bmain, nodetree)
+ *     if (nodetree->idname == "ShaderNodeTree")
+ *         printf("This is a shader node tree);
+ *     if (GS(id) == ID_MA)
+ *         printf(" and it's owned by a material");
+ * FOREACH_NODETREE_END
+ */
 
-void BKE_node_tree_unlink_id_cb(void *calldata, struct ID *owner_id, struct bNodeTree *ntree);
+#define FOREACH_NODETREE(bmain, _nodetree, _id) \
+{ \
+       bNodeTree *_nodetree; \
+       ID *_id; \
+       bNodeTree *_ngroup = bmain->nodetree.first; \
+       Scene *_scene = bmain->scene.first; \
+       Material *_mat = bmain->mat.first; \
+       Tex *_tex = bmain->tex.first; \
+       Lamp *_lamp = bmain->lamp.first; \
+       World *_world = bmain->world.first; \
+       /* avoid compiler warning about unused variables */ \
+       (void)_id; \
+       (void)_nodetree; \
+       do { \
+               if (_ngroup) { \
+                       _nodetree = _ngroup; \
+                       _id = (ID *)_ngroup; \
+                       _ngroup = _ngroup->id.next; \
+               } \
+               else if (_scene) { \
+                       _nodetree = _scene->nodetree; \
+                       _id = (ID *)_scene; \
+                       _scene = _scene->id.next; \
+               } \
+               else if (_mat) { \
+                       _nodetree = _mat->nodetree; \
+                       _id = (ID *)_mat; \
+                       _mat = _mat->id.next; \
+               } \
+               else if (_tex) { \
+                       _nodetree = _tex->nodetree; \
+                       _id = (ID *)_tex; \
+                       _tex = _tex->id.next; \
+               } \
+               else if (_lamp) { \
+                       _nodetree = _lamp->nodetree; \
+                       _id = (ID *)_lamp; \
+                       _lamp = _lamp->id.next; \
+               } \
+               else if (_world) { \
+                       _nodetree = _world->nodetree; \
+                       _id = (ID *)_world; \
+                       _world = _world->id.next; \
+               } \
+               else \
+                       break; \
+               if (_nodetree) {
+
+#define FOREACH_NODETREE_END \
+               } \
+       } while (TRUE); \
+}
 
 /* ************** SHADER NODES *************** */
 
@@ -583,11 +789,10 @@ struct ShadeResult;
 
 /* API */
 
-struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree, int use_tree_data);
-void            ntreeShaderEndExecTree(struct bNodeTreeExec *exec, int use_tree_data);
+struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
+void            ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
 bool            ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr);
 void            ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode);
-void            nodeShaderSynchronizeID(struct bNode *node, int copyto);
 
 /* switch material render loop */
 extern void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
@@ -798,8 +1003,8 @@ struct TexResult;
 int  ntreeTexTagAnimated(struct bNodeTree *ntree);
 void ntreeTexCheckCyclics(struct bNodeTree *ntree);
 
-struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree, int use_tree_data);
-void ntreeTexEndExecTree(struct bNodeTreeExec *exec, int use_tree_data);
+struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
+void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
 int ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target,
                      float coord[3], float dxt[3], float dyt[3], int osatex, const short thread,
                      struct Tex *tex, short which_output, int cfra, int preview, struct ShadeInput *shi, struct MTex *mtex);
index c27f5e625206b175974f6d755677ab116637006b..355541557ea461da4e0a8259433916c42f3c6e83 100644 (file)
@@ -2171,7 +2171,7 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
                                }
                                else if (sa->spacetype == SPACE_NODE) {
                                        SpaceNode *snode = sa->spacedata.first;
-                                       if ((snode->treetype == NTREE_COMPOSIT) && (snode->nodetree)) {
+                                       if (snode->nodetree && snode->nodetree->type==NTREE_COMPOSIT) {
                                                bNode *node;
                                                for (node = snode->nodetree->nodes.first; node; node = node->next) {
                                                        if (node->id && node->type == CMP_NODE_IMAGE) {
index 87802ab8ee68e7ba9e47796088ecf87b12bd7caa..a5241684e3a19a0042b03e9a60b0259ba94c923c 100644 (file)
@@ -57,6 +57,8 @@
 #include "BKE_movieclip.h"
 #include "BKE_image.h"
 
+#include "NOD_composite.h"
+
 static MaskSplinePoint *mask_spline_point_next(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
 {
        if (point == &points_array[spline->tot_point - 1]) {
@@ -966,10 +968,9 @@ void BKE_mask_free(Main *bmain, Mask *mask)
                }
        }
 
-       {
-               bNodeTreeType *treetype = ntreeGetType(NTREE_COMPOSIT);
-               treetype->foreach_nodetree(bmain, (void *)mask, &BKE_node_tree_unlink_id_cb);
-       }
+       FOREACH_NODETREE(bmain, ntree, id) {
+               BKE_node_tree_unlink_id((ID *)mask, ntree);
+       } FOREACH_NODETREE_END
 
        /* free mask data */
        BKE_mask_layer_free_list(&mask->masklayers);
index ab425d8e5b91d00c5124a7bd9d93d568c4ed281e..c47eb7eac4575006aa062a06bf06b4b954363d41 100644 (file)
@@ -1012,7 +1012,7 @@ void init_render_material(Material *mat, int r_mode, float *amb)
                init_render_nodetree(mat->nodetree, mat, r_mode, amb);
                
                if (!mat->nodetree->execdata)
-                       mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree, 1);
+                       mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree);
        }
 }
 
@@ -1046,7 +1046,7 @@ void end_render_material(Material *mat)
 {
        if (mat && mat->nodetree && mat->use_nodes) {
                if (mat->nodetree->execdata)
-                       ntreeShaderEndExecTree(mat->nodetree->execdata, 1);
+                       ntreeShaderEndExecTree(mat->nodetree->execdata);
        }
 }
 
index e79754ca203b9e26f97cc5cf30d2a632e618ebd1..821c8fe3bdad3f16c1d3afea6167e93822188eb6 100644 (file)
@@ -86,6 +86,8 @@
 #include "intern/openexr/openexr_multi.h"
 #endif
 
+#include "NOD_composite.h"
+
 /*********************** movieclip buffer loaders *************************/
 
 static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen)
@@ -1401,10 +1403,9 @@ void BKE_movieclip_unlink(Main *bmain, MovieClip *clip)
                }
        }
 
-       {
-               bNodeTreeType *treetype = ntreeGetType(NTREE_COMPOSIT);
-               treetype->foreach_nodetree(bmain, (void *)clip, &BKE_node_tree_unlink_id_cb);
-       }
+       FOREACH_NODETREE(bmain, ntree, id) {
+               BKE_node_tree_unlink_id((ID *)clip, ntree);
+       } FOREACH_NODETREE_END
 
        clip->id.us = 0;
 }
index 974a564b9daf21a57bba3cf1924dca44f26e068b..0b63c4d8842446edeae8e0de2ce55b5817baec52 100644 (file)
 #include "BKE_action.h"
 #include "BKE_fcurve.h"
 #include "BKE_global.h"
+#include "BKE_idprop.h"
 #include "BKE_image.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_node.h"
 
+#include "BLI_ghash.h"
 #include "RNA_access.h"
+#include "RNA_define.h"
 
 #include "NOD_socket.h"
+#include "NOD_common.h"
 #include "NOD_composite.h"
 #include "NOD_shader.h"
 #include "NOD_texture.h"
 
 
-bNodeTreeType *ntreeGetType(int type)
+static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
 {
-       static bNodeTreeType *types[NUM_NTREE_TYPES];
-       static int types_init = 1;
-       if (types_init) {
-               types[NTREE_SHADER] = &ntreeType_Shader;
-               types[NTREE_COMPOSIT] = &ntreeType_Composite;
-               types[NTREE_TEXTURE] = &ntreeType_Texture;
-               types_init = 0;
+       bNodeSocketTemplate *sockdef;
+       /* bNodeSocket *sock; */ /* UNUSED */
+
+       if (ntype->inputs) {
+               sockdef = ntype->inputs;
+               while (sockdef->type != -1) {
+                       /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
+                       
+                       sockdef++;
+               }
        }
+       if (ntype->outputs) {
+               sockdef = ntype->outputs;
+               while (sockdef->type != -1) {
+                       /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
+                       
+                       sockdef++;
+               }
+       }
+}
+
+/* Note: This function is called to initialize node data based on the type.
+ * The bNodeType may not be registered at creation time of the node,
+ * so this can be delayed until the node type gets registered.
+ * The node->typeinfo must not be used in that case until it is defined!
+ */
+static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
+{
+       bNodeType *ntype = node->typeinfo;
+       if (!ntype)
+               return;
+       
+       /* only do this once */
+       if (node->flag & NODE_INIT)
+               return;
        
-       if (type >= 0 && type < NUM_NTREE_TYPES) {
-               return types[type];
+       node->flag = NODE_SELECT | ntype->flag;
+       node->width = ntype->width;
+       node->miniwidth = 42.0f;
+       node->height = ntype->height;
+       node->color[0] = node->color[1] = node->color[2] = 0.608;   /* default theme color */
+       
+       /* initialize the node name with the node label.
+        * note: do this after the initfunc so nodes get their data set which may be used in naming
+        * (node groups for example) */
+       /* XXX Do not use nodeLabel() here, it returns translated content, which should *only* be used
+        *     in UI, *never* in data...
+        *     This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler
+        *     than adding a "no translate" flag to this func (and labelfunc() as well). */
+       BLI_strncpy(node->name, ntype->ui_name, NODE_MAXSTR);
+       nodeUniqueName(ntree, node);
+       
+       node_add_sockets_from_type(ntree, node, ntype);
+       
+       if (ntype->initfunc != NULL)
+               ntype->initfunc(ntree, node);
+       
+       /* extra init callback */
+       if (ntype->initfunc_api) {
+               PointerRNA ptr;
+               RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
+               
+               /* XXX Warning: context can be NULL in case nodes are added in do_versions.
+                * Delayed init is not supported for nodes with context-based initfunc_api atm.
+                */
+               BLI_assert(C != NULL);
+               ntype->initfunc_api(C, &ptr);
+       }
+       
+       node->flag |= NODE_INIT;
+}
+
+static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
+{
+       ntree->typeinfo = typeinfo;
+       
+       if (typeinfo) {
+               /* deprecated integer type */
+               ntree->type = typeinfo->type;
        }
        else {
-               return NULL;
+               ntree->init &= ~NTREE_TYPE_INIT;
        }
 }
 
-static bNodeType *node_get_type(bNodeTree *ntree, int type)
+static void node_set_typeinfo(const struct bContext *C, bNodeTree *ntree, bNode *node, bNodeType *typeinfo)
 {
-       bNodeType *ntype = ntreeGetType(ntree->type)->node_types.first;
-       for (; ntype; ntype = ntype->next)
-               if (ntype->type == type)
-                       return ntype;
+       node->typeinfo = typeinfo;
        
+       if (typeinfo) {
+               /* deprecated integer type */
+               node->type = typeinfo->type;
+               
+               /* initialize the node if necessary */
+               node_init(C, ntree, node);
+       }
+       else {
+               ntree->init &= ~NTREE_TYPE_INIT;
+       }
+}
+
+static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeSocketType *typeinfo)
+{
+       sock->typeinfo = typeinfo;
+
+       if (typeinfo) {
+               if (sock->default_value == NULL) {
+                       /* initialize the default_value pointer used by standard socket types */
+                       node_socket_init_default_value(sock);
+               }
+       }
+       else {
+               ntree->init &= ~NTREE_TYPE_INIT;
+       }
+}
+
+/* Set specific typeinfo pointers in all node trees on register/unregister */
+static void update_typeinfo(Main *bmain, const struct bContext *C, bNodeTreeType *treetype, bNodeType *nodetype, bNodeSocketType *socktype, bool unregister)
+{
+       if (!bmain)
+               return;
+       
+       FOREACH_NODETREE(bmain, ntree, id) {
+               bNode *node;
+               bNodeSocket *sock;
+               
+               ntree->init |= NTREE_TYPE_INIT;
+               
+               if (treetype && strcmp(ntree->idname, treetype->idname)==0)
+                       ntree_set_typeinfo(ntree, unregister ? NULL : treetype);
+               
+               /* initialize nodes */
+               for (node=ntree->nodes.first; node; node=node->next) {
+                       if (nodetype && strcmp(node->idname, nodetype->idname)==0)
+                               node_set_typeinfo(C, ntree, node, unregister ? NULL : nodetype);
+                       
+                       /* initialize node sockets */
+                       for (sock=node->inputs.first; sock; sock=sock->next)
+                               if (socktype && strcmp(sock->idname, socktype->idname)==0)
+                                       node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+                       for (sock=node->outputs.first; sock; sock=sock->next)
+                               if (socktype && strcmp(sock->idname, socktype->idname)==0)
+                                       node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+               }
+               
+               /* initialize tree sockets */
+               for (sock=ntree->inputs.first; sock; sock=sock->next)
+                       if (socktype && strcmp(sock->idname, socktype->idname)==0)
+                               node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+               for (sock=ntree->outputs.first; sock; sock=sock->next)
+                       if (socktype && strcmp(sock->idname, socktype->idname)==0)
+                               node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+       }
+       FOREACH_NODETREE_END
+}
+
+/* Try to initialize all typeinfo in a node tree.
+ * NB: In general undefined typeinfo is a perfectly valid case, the type may just be registered later.
+ * In that case the update_typeinfo function will set typeinfo on registration
+ * and do necessary updates.
+ */
+void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree)
+{
+       bNode *node;
+       bNodeSocket *sock;
+       
+       ntree->init |= NTREE_TYPE_INIT;
+       
+       ntree_set_typeinfo(ntree, ntreeTypeFind(ntree->idname));
+       
+       for (node = ntree->nodes.first; node; node = node->next) {
+               node_set_typeinfo(C, ntree, node, nodeTypeFind(node->idname));
+               
+               for (sock=node->inputs.first; sock; sock=sock->next)
+                       node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+               for (sock=node->outputs.first; sock; sock=sock->next)
+                       node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+       }
+       
+       for (sock=ntree->inputs.first; sock; sock=sock->next)
+               node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+       for (sock=ntree->outputs.first; sock; sock=sock->next)
+               node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+}
+
+
+static GHash *nodetreetypes_hash= NULL;
+static GHash *nodetypes_hash= NULL;
+static GHash *nodesockettypes_hash= NULL;
+
+bNodeTreeType *ntreeTypeFind(const char *idname)
+{
+       bNodeTreeType* nt;
+
+       if (idname[0]) {
+               nt= BLI_ghash_lookup(nodetreetypes_hash, idname);
+               if(nt)
+                       return nt;
+       }
+
        return NULL;
 }
 
-bNodeType *ntreeGetNodeType(bNodeTree *ntree)
+void ntreeTypeAdd(bNodeTreeType* nt)
+{
+       BLI_ghash_insert(nodetreetypes_hash, (void *)nt->idname, nt);
+       /* XXX pass Main to register function? */
+       update_typeinfo(G.main, NULL, nt, NULL, NULL, false);
+}
+
+/* callback for hash value free function */
+static void ntree_free_type(void *treetype_v)
+{
+       bNodeTreeType *treetype = treetype_v;
+       /* XXX pass Main to unregister function? */
+       update_typeinfo(G.main, NULL, treetype, NULL, NULL, true);
+       MEM_freeN(treetype);
+}
+
+void ntreeTypeFreeLink(bNodeTreeType* nt)
+{
+       BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type);
+}
+
+GHashIterator *ntreeTypeGetIterator()
 {
-       return node_get_type(ntree, ntree->nodetype);
+       return BLI_ghashIterator_new(nodetreetypes_hash);
 }
 
-bNodeSocketType *ntreeGetSocketType(int type)
+int ntreeIsValid(bNodeTree *ntree)
 {
-       static bNodeSocketType *types[NUM_SOCKET_TYPES] = {NULL};
-       static int types_init = 1;
+       return (ntree && (ntree->init & NTREE_TYPE_INIT));
+}
 
-       if (types_init) {
-               node_socket_type_init(types);
-               types_init = 0;
+bNodeType *nodeTypeFind(const char *idname)
+{
+       bNodeType* nt;
+
+       if (idname[0]) {
+               nt= BLI_ghash_lookup(nodetypes_hash, idname);
+               if(nt)
+                       return nt;
        }
 
-       if (type < NUM_SOCKET_TYPES) {
-               return types[type];
+       return NULL;
+}
+
+static void free_dynamic_typeinfo(bNodeType *ntype)
+{
+       if(ntype->type==NODE_DYNAMIC) {
+               if(ntype->inputs) {
+                       MEM_freeN(ntype->inputs);
+               }
+               if(ntype->outputs) {
+                       MEM_freeN(ntype->outputs);
+               }
+               if(ntype->ui_name) {
+                       MEM_freeN((void *)ntype->ui_name);
+               }
        }
-       else {
-               return NULL;
+}
+
+/* callback for hash value free function */
+static void node_free_type(void *nodetype_v)
+{
+       bNodeType *nodetype = nodetype_v;
+       /* XXX pass Main to unregister function? */
+       update_typeinfo(G.main, NULL, NULL, nodetype, NULL, true);
+       
+       /* XXX deprecated */
+       if (nodetype->type==NODE_DYNAMIC)
+               free_dynamic_typeinfo(nodetype);
+       
+       if (nodetype->needs_free)
+               MEM_freeN(nodetype);
+}
+
+void nodeRegisterType(bNodeType *nt)
+{
+       /* debug only: basic verification of registered types */
+       BLI_assert(nt->idname[0] != '\0');
+       BLI_assert(nt->poll != NULL);
+       
+       BLI_ghash_insert(nodetypes_hash, (void *)nt->idname, nt);
+       /* XXX pass Main to register function? */
+       update_typeinfo(G.main, NULL, NULL, nt, NULL, false);
+}
+
+void nodeUnregisterType(bNodeType* nt)
+{
+       BLI_ghash_remove(nodetypes_hash, nt->idname, NULL, node_free_type);
+}
+
+GHashIterator *nodeTypeGetIterator()
+{
+       return BLI_ghashIterator_new(nodetypes_hash);
+}
+
+bNodeSocketType *nodeSocketTypeFind(const char *idname)
+{
+       bNodeSocketType* st;
+
+       if (idname[0]) {
+               st= BLI_ghash_lookup(nodesockettypes_hash, idname);
+               if(st)
+                       return st;
        }
+
+       return NULL;
 }
 
-void ntreeInitTypes(bNodeTree *ntree)
+/* callback for hash value free function */
+static void node_free_socket_type(void *socktype_v)
 {
-       bNode *node, *next;
+       bNodeSocketType *socktype = socktype_v;
+       /* XXX pass Main to unregister function? */
+       update_typeinfo(G.main, NULL, NULL, NULL, socktype, true);
        
-       for (node = ntree->nodes.first; node; node = next) {
-               next = node->next;
-               
-               node->typeinfo = node_get_type(ntree, node->type);
+       MEM_freeN(socktype);
+}
 
-               if (node->typeinfo == NULL) {
-                       printf("Error: Node type %s doesn't exist anymore, removed\n", node->name);
-                       nodeFreeNode(ntree, node);
-               }
+void nodeRegisterSocketType(bNodeSocketType* st)
+{
+       BLI_ghash_insert(nodesockettypes_hash, (void *)st->idname, st);
+       /* XXX pass Main to register function? */
+       update_typeinfo(G.main, NULL, NULL, NULL, st, false);
+}
+
+void nodeUnregisterSocketType(bNodeSocketType* st)
+{
+       BLI_ghash_remove(nodesockettypes_hash, st->idname, NULL, node_free_socket_type);
+}
+
+GHashIterator *nodeSocketTypeGetIterator(void)
+{
+       return BLI_ghashIterator_new(nodesockettypes_hash);
+}
+
+void nodeMakeDynamicType(bNode *UNUSED(node))
+{
+       #if 0   /* XXX deprecated */
+       /* find SH_DYNAMIC_NODE ntype */
+       bNodeType *ntype= ntreeType_Shader->node_types.first;
+       while(ntype) {
+               if(ntype->type==NODE_DYNAMIC)
+                       break;
+               ntype= ntype->next;
        }
-                       
-       ntree->init |= NTREE_TYPE_INIT;
+
+       /* make own type struct to fill */
+       if(ntype) {
+               /*node->typeinfo= MEM_dupallocN(ntype);*/
+               bNodeType *newtype= MEM_callocN(sizeof(bNodeType), "dynamic bNodeType");
+               *newtype= *ntype;
+               BLI_strncpy(newtype->name, ntype->name, sizeof(newtype->name));
+               node->typeinfo= newtype;
+       }
+       #endif
+}
+
+struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier)
+{
+       bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
+       for (; sock; sock=sock->next) {
+               if (strcmp(sock->identifier, identifier)==0)
+                       return sock;
+       }
+       return NULL;
+}
+
+/* find unique socket identifier */
+static bool unique_identifier_check(void *arg, const char *identifier)
+{
+       struct ListBase *lb = arg;
+       bNodeSocket *sock;
+       for (sock = lb->first; sock; sock = sock->next) {
+               if (strcmp(sock->identifier, identifier)==0)
+                       return true;
+       }
+       return false;
 }
 
-static bNodeSocket *make_socket(bNodeTree *UNUSED(ntree), int in_out, const char *name, int type)
+static bNodeSocket *make_socket(bNodeTree *ntree, bNode *UNUSED(node), int in_out, ListBase *lb,
+                                const char *idname, const char *identifier, const char *name)
 {
        bNodeSocket *sock;
+       char auto_identifier[MAX_NAME];
+       
+       if (identifier && identifier[0] != '\0') {
+               /* use explicit identifier */
+               BLI_strncpy(auto_identifier, identifier, sizeof(auto_identifier));
+       }
+       else {
+               /* if no explicit identifier is given, assign a unique identifier based on the name */
+               BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
+       }
+       /* make the identifier unique */
+       BLI_uniquename_cb(unique_identifier_check, lb, NULL, '.', auto_identifier, sizeof(auto_identifier));
        
        sock = MEM_callocN(sizeof(bNodeSocket), "sock");
+       sock->in_out = in_out;
        
-       BLI_strncpy(sock->name, name, NODE_MAXSTR);
+       BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
        sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
-       sock->type = type;
+       
+       BLI_strncpy(sock->name, name, NODE_MAXSTR);
        sock->storage = NULL;
        sock->flag |= SOCK_COLLAPSED;
+       sock->type = SOCK_CUSTOM;       /* int type undefined by default */
        
-       sock->default_value = node_socket_make_default_value(type);
-       node_socket_init_default_value(type, sock->default_value);
+       BLI_strncpy(sock->idname, idname, sizeof(sock->idname));
+       node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname));
        
        return sock;
 }
 
-bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *name, int type)
+bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname,
+                           const char *identifier, const char *name)
 {
-       bNodeSocket *sock = make_socket(ntree, in_out, name, type);
-       if (in_out == SOCK_IN)
-               BLI_addtail(&node->inputs, sock);
-       else if (in_out == SOCK_OUT)
-               BLI_addtail(&node->outputs, sock);
+       ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
+       bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
+       
+       BLI_remlink(lb, sock);  /* does nothing for new socket */
+       BLI_addtail(lb, sock);
        
        node->update |= NODE_UPDATE;
        
        return sock;
 }
 
-bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, int in_out, bNodeSocket *next_sock, const char *name, int type)
+bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname,
+                              bNodeSocket *next_sock, const char *identifier, const char *name)
 {
-       bNodeSocket *sock = make_socket(ntree, in_out, name, type);
-       if (in_out == SOCK_IN)
-               BLI_insertlinkbefore(&node->inputs, next_sock, sock);
-       else if (in_out == SOCK_OUT)
-               BLI_insertlinkbefore(&node->outputs, next_sock, sock);
+       ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
+       bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
+       
+       BLI_remlink(lb, sock);  /* does nothing for new socket */
+       BLI_insertlinkbefore(lb, next_sock, sock);
        
        node->update |= NODE_UPDATE;
        
        return sock;
 }
 
+const char *nodeStaticSocketType(int type, int subtype)
+{
+       switch (type) {
+       case SOCK_FLOAT:
+               switch (subtype) {
+               case PROP_UNSIGNED:
+                       return "NodeSocketFloatUnsigned";
+               case PROP_PERCENTAGE:
+                       return "NodeSocketFloatPercentage";
+               case PROP_FACTOR:
+                       return "NodeSocketFloatFactor";
+               case PROP_ANGLE:
+                       return "NodeSocketFloatAngle";
+               case PROP_TIME:
+                       return "NodeSocketFloatTime";
+               case PROP_NONE:
+               default:
+                       return "NodeSocketFloat";
+               }
+       case SOCK_INT:
+               switch (subtype) {
+               case PROP_UNSIGNED:
+                       return "NodeSocketIntUnsigned";
+               case PROP_PERCENTAGE:
+                       return "NodeSocketIntPercentage";
+               case PROP_FACTOR:
+                       return "NodeSocketIntFactor";
+               case PROP_NONE:
+               default:
+                       return "NodeSocketInt";
+               }
+       case SOCK_BOOLEAN:
+               return "NodeSocketBool";
+       case SOCK_VECTOR:
+               switch (subtype) {
+               case PROP_TRANSLATION:
+                       return "NodeSocketVectorTranslation";
+               case PROP_DIRECTION:
+                       return "NodeSocketVectorDirection";
+               case PROP_VELOCITY:
+                       return "NodeSocketVectorVelocity";
+               case PROP_ACCELERATION:
+                       return "NodeSocketVectorAcceleration";
+               case PROP_EULER:
+                       return "NodeSocketVectorEuler";
+               case PROP_XYZ:
+                       return "NodeSocketVectorXYZ";
+               case PROP_NONE:
+               default:
+                       return "NodeSocketVector";
+               }
+       case SOCK_RGBA:
+               return "NodeSocketColor";
+       case SOCK_STRING:
+               return "NodeSocketString";
+       case SOCK_SHADER:
+               return "NodeSocketShader";
+       }
+       return NULL;
+}
+
+const char *nodeStaticSocketInterfaceType(int type, int subtype)
+{
+       switch (type) {
+       case SOCK_FLOAT:
+               switch (subtype) {
+               case PROP_UNSIGNED:
+                       return "NodeSocketInterfaceFloatUnsigned";
+               case PROP_PERCENTAGE:
+                       return "NodeSocketInterfaceFloatPercentage";
+               case PROP_FACTOR:
+                       return "NodeSocketInterfaceFloatFactor";
+               case PROP_ANGLE:
+                       return "NodeSocketInterfaceFloatAngle";
+               case PROP_TIME:
+                       return "NodeSocketInterfaceFloatTime";
+               case PROP_NONE:
+               default:
+                       return "NodeSocketInterfaceFloat";
+               }
+       case SOCK_INT:
+               switch (subtype) {
+               case PROP_UNSIGNED:
+                       return "NodeSocketInterfaceIntUnsigned";
+               case PROP_PERCENTAGE:
+                       return "NodeSocketInterfaceIntPercentage";
+               case PROP_FACTOR:
+                       return "NodeSocketInterfaceIntFactor";
+               case PROP_NONE:
+               default:
+                       return "NodeSocketInterfaceInt";
+               }
+       case SOCK_BOOLEAN:
+               return "NodeSocketInterfaceBool";
+       case SOCK_VECTOR:
+               switch (subtype) {
+               case PROP_TRANSLATION:
+                       return "NodeSocketInterfaceVectorTranslation";
+               case PROP_DIRECTION:
+                       return "NodeSocketInterfaceVectorDirection";
+               case PROP_VELOCITY:
+                       return "NodeSocketInterfaceVectorVelocity";
+               case PROP_ACCELERATION:
+                       return "NodeSocketInterfaceVectorAcceleration";
+               case PROP_EULER:
+                       return "NodeSocketInterfaceVectorEuler";
+               case PROP_XYZ:
+                       return "NodeSocketInterfaceVectorXYZ";
+               case PROP_NONE:
+               default:
+                       return "NodeSocketInterfaceVector";
+               }
+       case SOCK_RGBA:
+               return "NodeSocketInterfaceColor";
+       case SOCK_STRING:
+               return "NodeSocketInterfaceString";
+       case SOCK_SHADER:
+               return "NodeSocketInterfaceShader";
+       }
+       return NULL;
+}
+
+bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, bNode *node, int in_out, int type, int subtype,
+                                 const char *identifier, const char *name)
+{
+       const char *idname = nodeStaticSocketType(type, subtype);
+       bNodeSocket *sock;
+       
+       if (!idname) {
+               printf("Error: static node socket type %d undefined\n", type);
+               return NULL;
+       }
+       
+       sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name);
+       sock->type = type;
+       return sock;
+}
+
+bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, bNode *node, int in_out, int type, int subtype,
+                                    bNodeSocket *next_sock, const char *identifier, const char *name)
+{
+       const char *idname = nodeStaticSocketType(type, subtype);
+       bNodeSocket *sock;
+       
+       if (!idname) {
+               printf("Error: static node socket type %d undefined\n", type);
+               return NULL;
+       }
+       
+       sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name);
+       sock->type = type;
+       return sock;
+}
+
+static void node_socket_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bNode *UNUSED(node))
+{
+       if (sock->prop) {
+               IDP_FreeProperty(sock->prop);
+               MEM_freeN(sock->prop);
+       }
+       
+       if (sock->default_value)
+               MEM_freeN(sock->default_value);
+}
+
 void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
 {
        bNodeLink *link, *next;
@@ -200,7 +701,7 @@ void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
        BLI_remlink(&node->inputs, sock);
        BLI_remlink(&node->outputs, sock);
        
-       node_socket_free_default_value(sock->type, sock->default_value);
+       node_socket_free(ntree, sock, node);
        MEM_freeN(sock);
        
        node->update |= NODE_UPDATE;
@@ -208,7 +709,7 @@ void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
 
 void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
 {
-       bNodeSocket *sock;
+       bNodeSocket *sock, *sock_next;
        bNodeLink *link, *next;
        
        for (link = ntree->links.first; link; link = next) {
@@ -218,12 +719,16 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
                }
        }
        
-       for (sock = node->inputs.first; sock; sock = sock->next)
-               node_socket_free_default_value(sock->type, sock->default_value);
-       BLI_freelistN(&node->inputs);
-       for (sock = node->outputs.first; sock; sock = sock->next)
-               node_socket_free_default_value(sock->type, sock->default_value);
-       BLI_freelistN(&node->outputs);
+       for (sock = node->inputs.first; sock; sock = sock_next) {
+               sock_next = sock->next;
+               node_socket_free(ntree, sock, node);
+               MEM_freeN(sock);
+       }
+       for (sock = node->outputs.first; sock; sock = sock_next) {
+               sock_next = sock->next;
+               node_socket_free(ntree, sock, node);
+               MEM_freeN(sock);
+       }
        
        node->update |= NODE_UPDATE;
 }
@@ -235,26 +740,18 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
 }
 
 /* finds a node based on given socket */
-int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex, int *in_out)
+int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex)
 {
+       int in_out = sock->in_out;
        bNode *node;
        bNodeSocket *tsock;
        int index = 0;
        
        for (node = ntree->nodes.first; node; node = node->next) {
-               for (index = 0, tsock = node->inputs.first; tsock; tsock = tsock->next, index++) {
-                       if (tsock == sock) {
-                               if (in_out) *in_out = SOCK_IN;
+               tsock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
+               for (index = 0; tsock; tsock = tsock->next, index++) {
+                       if (tsock == sock)
                                break;
-                       }
-               }
-               if (tsock)
-                       break;
-               for (index = 0, tsock = node->outputs.first; tsock; tsock = tsock->next, index++) {
-                       if (tsock == sock) {
-                               if (in_out) *in_out = SOCK_OUT;
-                               break;
-                       }
                }
                if (tsock)
                        break;
@@ -271,28 +768,6 @@ int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockin
 }
 
 /* ************** Add stuff ********** */
-static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
-{
-       bNodeSocketTemplate *sockdef;
-       /* bNodeSocket *sock; */ /* UNUSED */
-
-       if (ntype->inputs) {
-               sockdef = ntype->inputs;
-               while (sockdef->type != -1) {
-                       /* sock = */ node_add_input_from_template(ntree, node, sockdef);
-                       
-                       sockdef++;
-               }
-       }
-       if (ntype->outputs) {
-               sockdef = ntype->outputs;
-               while (sockdef->type != -1) {
-                       /* sock = */ node_add_output_from_template(ntree, node, sockdef);
-                       
-                       sockdef++;
-               }
-       }
-}
 
 /* Find the first available, non-duplicate name for a given node */
 void nodeUniqueName(bNodeTree *ntree, bNode *node)
@@ -300,51 +775,55 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node)
        BLI_uniquename(&ntree->nodes, node, "Node", '.', offsetof(bNode, name), sizeof(node->name));
 }
 
-bNode *nodeAddNode(bNodeTree *ntree, struct bNodeTemplate *ntemp)
+bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname)
 {
        bNode *node;
-       bNodeType *ntype;
-       
-       ntype = node_get_type(ntree, ntemp->type);
-       if (ntype == NULL) {
-               printf("nodeAddNodeType() error: '%d' type invalid\n", ntemp->type);
-               return NULL;
-       }
-       /* validity check */
-       if (!nodeValid(ntree, ntemp))
-               return NULL;
        
        node = MEM_callocN(sizeof(bNode), "new node");
-       node->type = ntype->type;
-       node->typeinfo = ntype;
-       node->flag = NODE_SELECT | ntype->flag;
-       node->width = ntype->width;
-       node->miniwidth = 42.0f;
-       node->height = ntype->height;
-       node->color[0] = node->color[1] = node->color[2] = 0.608;   /* default theme color */
-       
-       node_add_sockets_from_type(ntree, node, ntype);
-
        BLI_addtail(&ntree->nodes, node);
        
-       if (ntype->initfunc != NULL)
-               ntype->initfunc(ntree, node, ntemp);
-
-       /* initialize the node name with the node label.
-        * note: do this after the initfunc so nodes get their data set which may be used in naming
-        * (node groups for example) */
-       /* XXX Do not use nodeLabel() here, it returns translated content, which should *only* be used
-        *     in UI, *never* in data...
-        *     This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler
-        *     than adding a "no translate" flag to this func (and labelfunc() as well). */
-       BLI_strncpy(node->name, node->typeinfo->name, NODE_MAXSTR);
-       nodeUniqueName(ntree, node);
+       BLI_strncpy(node->idname, idname, sizeof(node->idname));
+       node_set_typeinfo(C, ntree, node, nodeTypeFind(idname));
        
        ntree->update |= NTREE_UPDATE_NODES;
        
        return node;
 }
 
+bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
+{
+       const char *idname=NULL;
+       
+       NODE_TYPES_BEGIN(ntype)
+               if(ntype->type==type) {
+                       idname = ntype->idname;
+                       break;
+               }
+       NODE_TYPES_END
+       if (!idname) {
+               printf("Error: static node type %d undefined\n", type);
+               return NULL;
+       }
+       return nodeAddNode(C, ntree, idname);
+}
+
+static void node_socket_copy(bNodeSocket *dst, bNodeSocket *src)
+{
+       src->new_sock = dst;
+       
+       if (src->prop)
+               dst->prop = IDP_CopyProperty(src->prop);
+       
+       if (src->default_value)
+               dst->default_value = MEM_dupallocN(src->default_value);
+       
+       dst->stack_index = 0;
+       /* XXX some compositor node (e.g. image, render layers) still store
+        * some persistent buffer data here, need to clear this to avoid dangling pointers.
+        */
+       dst->cache = NULL;
+}
+
 /* keep socket listorder identical, for copying links */
 /* ntree is the target tree */
 bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
@@ -363,33 +842,16 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
 
        BLI_duplicatelist(&nnode->inputs, &node->inputs);
        oldsock = node->inputs.first;
-       for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) {
-               oldsock->new_sock = sock;
-               sock->stack_index = 0;
-               
-               sock->default_value = node_socket_make_default_value(oldsock->type);
-               node_socket_copy_default_value(oldsock->type, sock->default_value, oldsock->default_value);
-               
-               /* XXX some compositor node (e.g. image, render layers) still store
-                * some persistent buffer data here, need to clear this to avoid dangling pointers.
-                */
-               sock->cache = NULL;
-       }
+       for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next)
+               node_socket_copy(sock, oldsock);
        
        BLI_duplicatelist(&nnode->outputs, &node->outputs);
        oldsock = node->outputs.first;
-       for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) {
-               oldsock->new_sock = sock;
-               sock->stack_index = 0;
-               
-               sock->default_value = node_socket_make_default_value(oldsock->type);
-               node_socket_copy_default_value(oldsock->type, sock->default_value, oldsock->default_value);
-               
-               /* XXX some compositor node (e.g. image, render layers) still store
-                * some persistent buffer data here, need to clear this to avoid dangling pointers.
-                */
-               sock->cache = NULL;
-       }
+       for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next)
+               node_socket_copy(sock, oldsock);
+       
+       if (node->prop)
+               nnode->prop = IDP_CopyProperty(node->prop);
        
        BLI_duplicatelist(&nnode->internal_links, &node->internal_links);
        oldlink = node->internal_links.first;
@@ -402,22 +864,17 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
        
        /* don't increase node->id users, freenode doesn't decrement either */
        
-       if (node->typeinfo->copystoragefunc)
-               node->typeinfo->copystoragefunc(node, nnode);
+       if (node->typeinfo->copyfunc)
+               node->typeinfo->copyfunc(ntree, nnode, node);
        
        node->new_node = nnode;
        nnode->new_node = NULL;
        
-       /* only shader nodes get pleasant preview updating this way, compo uses own system */
-       if (node->preview) {
-               if (ntree && (ntree->type == NTREE_SHADER)) {
-                       nnode->preview = MEM_dupallocN(node->preview);
-                       if (node->preview->rect)
-                               nnode->preview->rect = MEM_dupallocN(node->preview->rect);
-               }
-               else {
-                       nnode->preview = NULL;
-               }
+       if (nnode->typeinfo->copyfunc_api) {
+               PointerRNA ptr;
+               RNA_pointer_create((ID *)ntree, &RNA_Node, nnode, &ptr);
+               
+               nnode->typeinfo->copyfunc_api(&ptr, node);
        }
        
        if (ntree)
@@ -429,71 +886,13 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
 /* also used via rna api, so we check for proper input output direction */
 bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
 {
-       bNodeSocket *sock;
        bNodeLink *link = NULL;
-       int from = 0, to = 0;
        
-       if (fromnode) {
-               /* test valid input */
-               for (sock = fromnode->outputs.first; sock; sock = sock->next)
-                       if (sock == fromsock)
-                               break;
-               if (sock)
-                       from = 1;  /* OK */
-               else {
-                       for (sock = fromnode->inputs.first; sock; sock = sock->next)
-                               if (sock == fromsock)
-                                       break;
-                       if (sock)
-                               from = -1;  /* OK but flip */
-               }
-       }
-       else if (ntree) {
-               /* check tree sockets */
-               for (sock = ntree->inputs.first; sock; sock = sock->next)
-                       if (sock == fromsock)
-                               break;
-               if (sock)
-                       from = 1;  /* OK */
-               else {
-                       for (sock = ntree->outputs.first; sock; sock = sock->next)
-                               if (sock == fromsock)
-                                       break;
-                       if (sock)
-                               from = -1;  /* OK but flip */
-               }
-       }
-       if (tonode) {
-               for (sock = tonode->inputs.first; sock; sock = sock->next)
-                       if (sock == tosock)
-                               break;
-               if (sock)
-                       to = 1;  /* OK */
-               else {
-                       for (sock = tonode->outputs.first; sock; sock = sock->next)
-                               if (sock == tosock)
-                                       break;
-                       if (sock)
-                               to = -1;  /* OK but flip */
-               }
-       }
-       else if (ntree) {
-               /* check tree sockets */
-               for (sock = ntree->outputs.first; sock; sock = sock->next)
-                       if (sock == tosock)
-                               break;
-               if (sock)
-                       to = 1;  /* OK */
-               else {
-                       for (sock = ntree->inputs.first; sock; sock = sock->next)
-                               if (sock == tosock)
-                                       break;
-                       if (sock)
-                               to = -1;  /* OK but flip */
-               }
-       }
+       /* test valid input */
+       BLI_assert(fromnode);
+       BLI_assert(tonode);
        
-       if (from >= 0 && to >= 0) {
+       if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) {
                link = MEM_callocN(sizeof(bNodeLink), "link");
                if (ntree)
                        BLI_addtail(&ntree->links, link);
@@ -502,7 +901,8 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock,
                link->tonode = tonode;
                link->tosock = tosock;
        }
-       else if (from <= 0 && to <= 0) {
+       else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) {
+               /* OK but flip */
                link = MEM_callocN(sizeof(bNodeLink), "link");
                if (ntree)
                        BLI_addtail(&ntree->links, link);
@@ -546,6 +946,11 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
        ntree->update |= NTREE_UPDATE_LINKS;
 }
 
+int nodeLinkIsHidden(bNodeLink *link)
+{
+       return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock);
+}
+
 void nodeInternalRelink(bNodeTree *ntree, bNode *node)
 {
        bNodeLink *link, *link_next;
@@ -662,30 +1067,29 @@ void nodeDetachNode(struct bNode *node)
        }
 }
 
-bNodeTree *ntreeAddTree(Main *bmain, const char *name, int type, int nodetype)
+bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
 {
        bNodeTree *ntree;
-       bNodeType *ntype;
        
-       /* trees are created as local trees if they of compositor, material or texture type,
+       /* trees are created as local trees for compositor, material or texture nodes,
         * node groups and other tree types are created as library data.
         */
-       if (ELEM3(type, NTREE_COMPOSIT, NTREE_SHADER, NTREE_TEXTURE) && nodetype == 0) {
+       if (bmain) {
+               ntree= BKE_libblock_alloc(&bmain->nodetree, ID_NT, name);
+       }
+       else {
                ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
-               *( (short *)ntree->id.name) = ID_NT; /* not "type", as that is ntree->type */
+               *( (short *)ntree->id.name ) = ID_NT;
                BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name));
        }
-       else
-               ntree = BKE_libblock_alloc(&bmain->nodetree, ID_NT, name);
        
-       ntree->type = type;
-       ntree->nodetype = nodetype;
-       
-       ntreeInitTypes(ntree);
+       /* Types are fully initialized at this point,
+        * if an undefined node is added later this will be reset.
+        */
+       ntree->init |= NTREE_TYPE_INIT;
        
-       ntype = node_get_type(ntree, ntree->nodetype);
-       if (ntype && ntype->inittreefunc)
-               ntype->inittreefunc(ntree);
+       BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname));
+       ntree_set_typeinfo(ntree, ntreeTypeFind(idname));
        
        return ntree;
 }
@@ -699,12 +1103,12 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, int type, int nodetype)
  * copying for internal use (threads for eg), where you wont want it to modify the
  * scene data.
  */
-static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_user, const short do_make_extern)
+static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_user, const short do_make_extern, const short copy_previews)
 {
        bNodeTree *newtree;
        bNode *node /*, *nnode */ /* UNUSED */, *last;
+       bNodeSocket *sock, *oldsock;
        bNodeLink *link;
-       bNodeSocket *gsock, *oldgsock;
        
        if (ntree == NULL) return NULL;
        
@@ -747,22 +1151,6 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_use
                        break;
        }
        
-       /* socket definition for group usage */
-       BLI_duplicatelist(&newtree->inputs, &ntree->inputs);
-       for (gsock = newtree->inputs.first, oldgsock = ntree->inputs.first; gsock; gsock = gsock->next, oldgsock = oldgsock->next) {
-               oldgsock->new_sock = gsock;
-               gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL);
-               gsock->default_value = node_socket_make_default_value(oldgsock->type);
-               node_socket_copy_default_value(oldgsock->type, gsock->default_value, oldgsock->default_value);
-       }
-       BLI_duplicatelist(&newtree->outputs, &ntree->outputs);
-       for (gsock = newtree->outputs.first, oldgsock = ntree->outputs.first; gsock; gsock = gsock->next, oldgsock = oldgsock->next) {
-               oldgsock->new_sock = gsock;
-               gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL);
-               gsock->default_value = node_socket_make_default_value(oldgsock->type);
-               node_socket_copy_default_value(oldgsock->type, gsock->default_value, oldgsock->default_value);
-       }
-       
        /* copy links */
        BLI_duplicatelist(&newtree->links, &ntree->links);
        for (link = newtree->links.first; link; link = link->next) {
@@ -775,18 +1163,47 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_use
                        link->tosock->link = link;
        }
        
+       /* copy interface sockets */
+       BLI_duplicatelist(&newtree->inputs, &ntree->inputs);
+       oldsock = ntree->inputs.first;
+       for (sock = newtree->inputs.first; sock; sock = sock->next, oldsock = oldsock->next)
+               node_socket_copy(sock, oldsock);
+       
+       BLI_duplicatelist(&newtree->outputs, &ntree->outputs);
+       oldsock = ntree->outputs.first;
+       for (sock = newtree->outputs.first; sock; sock = sock->next, oldsock = oldsock->next)
+               node_socket_copy(sock, oldsock);
+       
+       /* copy preview hash */
+       if (ntree->previews && copy_previews) {
+               bNodeInstanceHashIterator iter;
+               
+               newtree->previews = BKE_node_instance_hash_new("node previews");
+               
+               NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
+                       bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+                       bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+                       BKE_node_instance_hash_insert(newtree->previews, key, BKE_node_preview_copy(preview));
+               }
+       }
+       else
+               newtree->previews = NULL;
+       
        /* update node->parent pointers */
        for (node = newtree->nodes.first; node; node = node->next) {
                if (node->parent)
                        node->parent = node->parent->new_node;
        }
        
+       /* node tree will generate its own interface type */
+       ntree->interface_type = NULL;
+       
        return newtree;
 }
 
 bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, const short do_id_user)
 {
-       return ntreeCopyTree_internal(ntree, do_id_user, TRUE);
+       return ntreeCopyTree_internal(ntree, do_id_user, TRUE, TRUE);
 }
 bNodeTree *ntreeCopyTree(bNodeTree *ntree)
 {
@@ -835,62 +1252,225 @@ void ntreeUserDecrefID(bNodeTree *ntree)
        }
 }
 
-/* *************** preview *********** */
-/* if node->preview, then we assume the rect to exist */
+/* *************** Node Preview *********** */
 
-void nodeFreePreview(bNode *node)
+/* XXX this should be removed eventually ...
+ * Currently BKE functions are modelled closely on previous code,
+ * using BKE_node_preview_init_tree to set up previews for a whole node tree in advance.
+ * This should be left more to the individual node tree implementations.
+ */
+int BKE_node_preview_used(bNode *node)
 {
-       if (node->preview) {
-               if (node->preview->rect)
-                       MEM_freeN(node->preview->rect);
-               MEM_freeN(node->preview);
-               node->preview = NULL;
-       }
+       /* XXX check for closed nodes? */
+       return (node->typeinfo->flag & NODE_PREVIEW) != 0;
 }
 
-static void node_init_preview(bNode *node, int xsize, int ysize)
+bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, int create)
 {
+       bNodePreview *preview;
        
-       if (node->preview == NULL) {
-               node->preview = MEM_callocN(sizeof(bNodePreview), "node preview");
-               //              printf("added preview %s\n", node->name);
+       preview = BKE_node_instance_hash_lookup(previews, key);
+       if (!preview) {
+               if (create) {
+                       preview = MEM_callocN(sizeof(bNodePreview), "node preview");
+                       BKE_node_instance_hash_insert(previews, key, preview);
+               }
+               else
+                       return NULL;
        }
        
        /* node previews can get added with variable size this way */
        if (xsize == 0 || ysize == 0)
-               return;
+               return preview;
        
        /* sanity checks & initialize */
-       if (node->preview->rect) {
-               if (node->preview->xsize != xsize && node->preview->ysize != ysize) {
-                       MEM_freeN(node->preview->rect);
-                       node->preview->rect = NULL;
+       if (preview->rect) {
+               if (preview->xsize != xsize || preview->ysize != ysize) {
+                       MEM_freeN(preview->rect);
+                       preview->rect = NULL;
                }
        }
        
-       if (node->preview->rect == NULL) {
-               node->preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char) * 4, "node preview rect");
-               node->preview->xsize = xsize;
-               node->preview->ysize = ysize;
+       if (preview->rect == NULL) {
+               preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char) * 4, "node preview rect");
+               preview->xsize = xsize;
+               preview->ysize = ysize;
        }
        /* no clear, makes nicer previews */
+       
+       return preview;
+}
+
+bNodePreview *BKE_node_preview_copy(bNodePreview *preview)
+{
+       bNodePreview *new_preview = MEM_dupallocN(preview);
+       if (preview->rect)
+               new_preview->rect = MEM_dupallocN(preview->rect);
+       return new_preview;
+}
+
+void BKE_node_preview_free(bNodePreview *preview)
+{
+       if (preview->rect)
+               MEM_freeN(preview->rect);
+       MEM_freeN(preview);
+}
+
+static void node_preview_init_tree_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key, int xsize, int ysize, int create)
+{
+       bNode *node;
+       for (node = ntree->nodes.first; node; node = node->next) {
+               bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
+               
+               if (BKE_node_preview_used(node)) {
+                       node->preview_xsize = xsize;
+                       node->preview_ysize = ysize;
+                       
+                       BKE_node_preview_verify(previews, key, xsize, ysize, create);
+               }
+               
+               if (node->type == NODE_GROUP)
+                       node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize, create);
+       }
 }
 
-void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize)
+void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, int create_previews)
+{
+       if (!ntree)
+               return;
+       
+       if (!ntree->previews)
+               ntree->previews = BKE_node_instance_hash_new("node previews");
+       
+       node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
+}
+
+static void node_preview_tag_used_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key)
 {
        bNode *node;
+       for (node = ntree->nodes.first; node; node = node->next) {
+               bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
+               
+               if (BKE_node_preview_used(node))
+                       BKE_node_instance_hash_tag_key(previews, key);
+               
+               if (node->type == NODE_GROUP)
+                       node_preview_tag_used_recursive(previews, (bNodeTree *)node->id, key);
+       }
+}
+
+void BKE_node_preview_remove_unused(bNodeTree *ntree)
+{
+       if (!ntree || !ntree->previews)
+               return;
        
-       if (ntree == NULL)
+       /* use the instance hash functions for tagging and removing unused previews */
+       BKE_node_instance_hash_clear_tags(ntree->previews);
+       node_preview_tag_used_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE);
+       
+       BKE_node_instance_hash_remove_untagged(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+}
+
+void BKE_node_preview_free_tree(bNodeTree *ntree)
+{
+       if (!ntree)
+               return;
+       
+       if (ntree->previews) {
+               BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+               ntree->previews = NULL;
+       }
+}
+
+void BKE_node_preview_clear(bNodePreview *preview)
+{
+       if (preview && preview->rect)
+               memset(preview->rect, 0, MEM_allocN_len(preview->rect));
+}
+
+void BKE_node_preview_clear_tree(bNodeTree *ntree)
+{
+       bNodeInstanceHashIterator iter;
+       
+       if (!ntree || !ntree->previews)
+               return;
+       
+       NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
+               bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+               BKE_node_preview_clear(preview);
+       }
+}
+
+static void node_preview_sync(bNodePreview *to, bNodePreview *from)
+{
+       /* sizes should have been initialized by BKE_node_preview_init_tree */
+       BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize);
+       
+       /* copy over contents of previews */
+       if (to->rect && from->rect) {
+               int xsize = to->xsize;
+               int ysize = to->ysize;
+               memcpy(to->rect, from->rect, 4 * xsize + xsize * ysize * sizeof(char) * 4);
+       }
+}
+
+void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree)
+{
+       bNodeInstanceHash *from_previews = from_ntree->previews;
+       bNodeInstanceHash *to_previews = to_ntree->previews;
+       bNodeInstanceHashIterator iter;
+       
+       if (!from_previews || !to_previews)
                return;
        
-       for (node = ntree->nodes.first; node; node = node->next) {
-               if (node->typeinfo->flag & NODE_PREVIEW)    /* hrms, check for closed nodes? */
-                       node_init_preview(node, xsize, ysize);
-               if (node->type == NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
-                       ntreeInitPreview((bNodeTree *)node->id, xsize, ysize);
+       NODE_INSTANCE_HASH_ITER(iter, from_previews) {
+               bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+               bNodePreview *from = BKE_node_instance_hash_iterator_get_value(&iter);
+               bNodePreview *to = BKE_node_instance_hash_lookup(to_previews, key);
+               
+               if (from && to)
+                       node_preview_sync(to, from);
+       }
+}
+
+void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree)
+{
+       /* free old previews */
+       if (to_ntree->previews)
+               BKE_node_instance_hash_free(to_ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+       
+       /* transfer previews */
+       to_ntree->previews = from_ntree->previews;
+       from_ntree->previews = NULL;
+       
+       /* clean up, in case any to_ntree nodes have been removed */
+       BKE_node_preview_remove_unused(to_ntree);
+}
+
+/* hack warning! this function is only used for shader previews, and 
+ * since it gets called multiple times per pixel for Ztransp we only
+ * add the color once. Preview gets cleared before it starts render though */
+void BKE_node_preview_set_pixel(bNodePreview *preview, const float col[4], int x, int y, int do_manage)
+{
+       if (preview) {
+               if (x >= 0 && y >= 0) {
+                       if (x < preview->xsize && y < preview->ysize) {
+                               unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
+                               
+                               if (do_manage) {
+                                       linearrgb_to_srgb_uchar4(tar, col);
+                               }
+                               else {
+                                       rgba_float_to_uchar(tar, col);
+                               }
+                       }
+                       //else printf("prv out bound x y %d %d\n", x, y);
+               }
+               //else printf("prv out bound x y %d %d\n", x, y);
        }
 }
 
+#if 0
 static void nodeClearPreview(bNode *node)
 {
        if (node->preview && node->preview->rect)
@@ -908,7 +1488,7 @@ void ntreeClearPreview(bNodeTree *ntree)
        for (node = ntree->nodes.first; node; node = node->next) {
                if (node->typeinfo->flag & NODE_PREVIEW)
                        nodeClearPreview(node);
-               if (node->type == NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
+               if (node->type == NODE_GROUP)
                        ntreeClearPreview((bNodeTree *)node->id);
        }
 }
@@ -936,6 +1516,7 @@ void nodeAddToPreview(bNode *node, const float col[4], int x, int y, int do_mana
                //else printf("prv out bound x y %d %d\n", x, y);
        }
 }
+#endif
 
 /* ************** Free stuff ********** */
 
@@ -985,45 +1566,54 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
 {
        bNodeSocket *sock, *nextsock;
        
+       /* extra free callback */
+       if (node->typeinfo && node->typeinfo->freefunc_api) {
+               PointerRNA ptr;
+               RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
+               
+               node->typeinfo->freefunc_api(&ptr);
+       }
+       
+       /* since it is called while free database, node->id is undefined */
+       
        /* can be called for nodes outside a node tree (e.g. clipboard) */
        if (ntree) {
-               bNodeTreeType *treetype = ntreeGetType(ntree->type);
-
                /* remove all references to this node */
                nodeUnlinkNode(ntree, node);
                node_unlink_attached(ntree, node);
-
+               
                BLI_remlink(&ntree->nodes, node);
-
-               if (treetype->free_node_cache)
-                       treetype->free_node_cache(ntree, node);
+               
+               if (ntree->typeinfo && ntree->typeinfo->free_node_cache)
+                       ntree->typeinfo->free_node_cache(ntree, node);
                
                /* texture node has bad habit of keeping exec data around */
                if (ntree->type == NTREE_TEXTURE && ntree->execdata) {
-                       ntreeTexEndExecTree(ntree->execdata, 1);
+                       ntreeTexEndExecTree(ntree->execdata);
                        ntree->execdata = NULL;
                }
+               
+               if(node->typeinfo && node->typeinfo->freefunc)
+                       node->typeinfo->freefunc(node);
        }
        
-       /* since it is called while free database, node->id is undefined */
-       
-       if (node->typeinfo && node->typeinfo->freestoragefunc)
-               node->typeinfo->freestoragefunc(node);
-       
        for (sock = node->inputs.first; sock; sock = nextsock) {
                nextsock = sock->next;
-               node_socket_free_default_value(sock->type, sock->default_value);
+               node_socket_free(ntree, sock, node);
                MEM_freeN(sock);
        }
        for (sock = node->outputs.first; sock; sock = nextsock) {
                nextsock = sock->next;
-               node_socket_free_default_value(sock->type, sock->default_value);
+               node_socket_free(ntree, sock, node);
                MEM_freeN(sock);
        }
 
        BLI_freelistN(&node->internal_links);
 
-       nodeFreePreview(node);
+       if (node->prop) {
+               IDP_FreeProperty(node->prop);
+               MEM_freeN(node->prop);
+       }
 
        MEM_freeN(node);
        
@@ -1031,12 +1621,24 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
                ntree->update |= NTREE_UPDATE_NODES;
 }
 
+static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock)
+{
+       if (sock->prop) {
+               IDP_FreeProperty(sock->prop);
+               MEM_freeN(sock->prop);
+       }
+       
+       /* can be left over from old files */
+       if (sock->default_value)
+               MEM_freeN(sock->default_value);
+}
+
 /* do not free ntree itself here, BKE_libblock_free calls this function too */
 void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user)
 {
        bNodeTree *tntree;
        bNode *node, *next;
-       bNodeSocket *sock;
+       bNodeSocket *sock, *nextsock;
        
        if (ntree == NULL) return;
        
@@ -1048,15 +1650,18 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user)
        if (ntree->execdata) {
                switch (ntree->type) {
                        case NTREE_SHADER:
-                               ntreeShaderEndExecTree(ntree->execdata, 1);
+                               ntreeShaderEndExecTree(ntree->execdata);
                                break;
                        case NTREE_TEXTURE:
-                               ntreeTexEndExecTree(ntree->execdata, 1);
+                               ntreeTexEndExecTree(ntree->execdata);
                                ntree->execdata = NULL;
                                break;
                }
        }
        
+       /* unregister associated RNA types */
+       ntreeInterfaceTypeFree(ntree);
+       
        BKE_free_animdata((ID *)ntree);
        
        id_us_min((ID *)ntree->gpd);
@@ -1082,13 +1687,23 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user)
 
                nodeFreeNode(ntree, node);
        }
+
+       /* free interface sockets */
+       for (sock = ntree->inputs.first; sock; sock = nextsock) {
+               nextsock = sock->next;
+               node_socket_interface_free(ntree, sock);
+               MEM_freeN(sock);
+       }
+       for (sock = ntree->outputs.first; sock; sock = nextsock) {
+               nextsock = sock->next;
+               node_socket_interface_free(ntree, sock);
+               MEM_freeN(sock);
+       }
        
-       for (sock = ntree->inputs.first; sock; sock = sock->next)
-               node_socket_free_default_value(sock->type, sock->default_value);
-       BLI_freelistN(&ntree->inputs);
-       for (sock = ntree->outputs.first; sock; sock = sock->next)
-               node_socket_free_default_value(sock->type, sock->default_value);
-       BLI_freelistN(&ntree->outputs);
+       /* free preview hash */
+       if (ntree->previews) {
+               BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+       }
        
        /* if ntree is not part of library, free the libblock data explicitly */
        for (tntree = G.main->nodetree.first; tntree; tntree = tntree->id.next)
@@ -1106,13 +1721,10 @@ void ntreeFreeTree(bNodeTree *ntree)
 
 void ntreeFreeCache(bNodeTree *ntree)
 {
-       bNodeTreeType *treetype;
-       
        if (ntree == NULL) return;
        
-       treetype = ntreeGetType(ntree->type);
-       if (treetype->free_cache)
-               treetype->free_cache(ntree);
+       if (ntree->typeinfo->free_cache)
+               ntree->typeinfo->free_cache(ntree);
 }
 
 void ntreeSetOutput(bNodeTree *ntree)
@@ -1162,6 +1774,24 @@ void ntreeSetOutput(bNodeTree *ntree)
                        if (output == 0)
                                node->flag |= NODE_DO_OUTPUT;
                }
+               
+               /* group node outputs use this flag too */
+               if (node->type == NODE_GROUP_OUTPUT) {
+                       bNode *tnode;
+                       int output = 0;
+                       
+                       for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+                               if (tnode->type == NODE_GROUP_OUTPUT) {
+                                       if (tnode->flag & NODE_DO_OUTPUT) {
+                                               output++;
+                                               if (output > 1)
+                                                       tnode->flag &= ~NODE_DO_OUTPUT;
+                                       }
+                               }
+                       }
+                       if (output == 0)
+                               node->flag |= NODE_DO_OUTPUT;
+               }
        }
        
        /* here we could recursively set which nodes have to be done,
@@ -1180,52 +1810,10 @@ bNodeTree *ntreeFromID(ID *id)
        }
 }
 
-typedef struct MakeLocalCallData {
-       ID *group_id;
-       ID *new_id;
-       int lib, local;
-} MakeLocalCallData;
-
-static void ntreeMakeLocal_CheckLocal(void *calldata, ID *owner_id, bNodeTree *ntree)
-{
-       MakeLocalCallData *cd = (MakeLocalCallData *)calldata;
-       bNode *node;
-       
-       /* find if group is in tree */
-       for (node = ntree->nodes.first; node; node = node->next) {
-               if (node->id == cd->group_id) {
-                       if (owner_id->lib) {
-                               cd->lib = TRUE;
-                       }
-                       else {
-                               cd->local = TRUE;
-                       }
-               }
-       }
-}
-
-static void ntreeMakeLocal_LinkNew(void *calldata, ID *owner_id, bNodeTree *ntree)
-{
-       MakeLocalCallData *cd = (MakeLocalCallData *)calldata;
-       bNode *node;
-       
-       /* find if group is in tree */
-       for (node = ntree->nodes.first; node; node = node->next) {
-               if (node->id == cd->group_id) {
-                       if (owner_id->lib == NULL) {
-                               node->id = cd->new_id;
-                               cd->new_id->us++;
-                               cd->group_id->us--;
-                       }
-               }
-       }
-}
-
 void ntreeMakeLocal(bNodeTree *ntree)
 {
        Main *bmain = G.main;
-       bNodeTreeType *treetype = ntreeGetType(ntree->type);
-       MakeLocalCallData cd;
+       int lib = FALSE, local = FALSE;
        
        /* - only lib users: do nothing
         * - only local users: set flag
@@ -1239,26 +1827,42 @@ void ntreeMakeLocal(bNodeTree *ntree)
        }
        
        /* now check users of groups... again typedepending, callback... */
-       cd.group_id = &ntree->id;
-       cd.new_id = NULL;
-       cd.local = 0;
-       cd.lib = 0;
-       
-       treetype->foreach_nodetree(G.main, &cd, &ntreeMakeLocal_CheckLocal);
+       FOREACH_NODETREE(G.main, tntree, owner_id) {
+               bNode *node;
+               /* find if group is in tree */
+               for (node = tntree->nodes.first; node; node = node->next) {
+                       if (node->id == (ID *)ntree) {
+                               if (owner_id->lib)
+                                       lib = TRUE;
+                               else
+                                       local = TRUE;
+                       }
+               }
+       } FOREACH_NODETREE_END
        
        /* if all users are local, we simply make tree local */
-       if (cd.local && cd.lib == 0) {
+       if (local && !lib) {
                id_clear_lib_data(bmain, (ID *)ntree);
        }
-       else if (cd.local && cd.lib) {
+       else if (local && lib) {
                /* this is the mixed case, we copy the tree and assign it to local users */
                bNodeTree *newtree = ntreeCopyTree(ntree);
                
                newtree->id.us = 0;
                
-
-               cd.new_id = &newtree->id;
-               treetype->foreach_nodetree(G.main, &cd, &ntreeMakeLocal_LinkNew);
+               FOREACH_NODETREE(G.main, tntree, owner_id) {
+                       bNode *node;
+                       /* find if group is in tree */
+                       for (node = tntree->nodes.first; node; node = node->next) {
+                               if (node->id == (ID *)ntree) {
+                                       if (owner_id->lib == NULL) {
+                                               node->id = (ID *)newtree;
+                                               newtree->id.us++;
+                                               ntree->id.us--;
+                                       }
+                               }
+                       }
+               } FOREACH_NODETREE_END
        }
 }
 
@@ -1283,90 +1887,326 @@ int ntreeOutputExists(bNode *node, bNodeSocket *testsock)
 /* returns localized tree for execution in threads */
 bNodeTree *ntreeLocalize(bNodeTree *ntree)
 {
-       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
-
-       bNodeTree *ltree;
-       bNode *node;
+       if (ntreeIsValid(ntree)) {
+               bNodeTree *ltree;
+               bNode *node;
+               
+               bAction *action_backup = NULL, *tmpact_backup = NULL;
+               
+               /* Workaround for copying an action on each render!
+                * set action to NULL so animdata actions don't get copied */
+               AnimData *adt = BKE_animdata_from_id(&ntree->id);
+       
+               if (adt) {
+                       action_backup = adt->action;
+                       tmpact_backup = adt->tmpact;
+       
+                       adt->action = NULL;
+                       adt->tmpact = NULL;
+               }
+       
+               /* Make full copy.
+                * Note: previews are not copied here.
+                */
+               ltree = ntreeCopyTree_internal(ntree, FALSE, FALSE, FALSE);
+       
+               if (adt) {
+                       AnimData *ladt = BKE_animdata_from_id(&ltree->id);
+       
+                       adt->action = ladt->action = action_backup;
+                       adt->tmpact = ladt->tmpact = tmpact_backup;
+       
+                       if (action_backup) action_backup->id.us++;
+                       if (tmpact_backup) tmpact_backup->id.us++;
+                       
+               }
+               /* end animdata uglyness */
+       
+               /* ensures only a single output node is enabled */
+               ntreeSetOutput(ntree);
        
-       bAction *action_backup = NULL, *tmpact_backup = NULL;
+               for (node = ntree->nodes.first; node; node = node->next) {
+                       /* store new_node pointer to original */
+                       node->new_node->new_node = node;
+               }
        
-       /* Workaround for copying an action on each render!
-        * set action to NULL so animdata actions don't get copied */
-       AnimData *adt = BKE_animdata_from_id(&ntree->id);
+               if (ntree->typeinfo->localize)
+                       ntree->typeinfo->localize(ltree, ntree);
+       
+               return ltree;
+       }
+       else
+               return NULL;
+}
 
-       if (adt) {
-               action_backup = adt->action;
-               tmpact_backup = adt->tmpact;
+/* sync local composite with real tree */
+/* local tree is supposed to be running, be careful moving previews! */
+/* is called by jobs manager, outside threads, so it doesnt happen during draw */
+void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
+{
+       if (localtree && ntreeIsValid(ntree)) {
+               /* XXX syncing was disabled for compositor nodes.
+                * It has to be ensured that there is no concurrent read/write access!
+                * Possibly needs a mutex lock or a flag to disable for certain tree types ...
+                */
+               BKE_node_preview_sync_tree(ntree, localtree);
+               
+               if (ntree->typeinfo->local_sync)
+                       ntree->typeinfo->local_sync(localtree, ntree);
+       }
+}
 
-               adt->action = NULL;
-               adt->tmpact = NULL;
+/* merge local tree results back, and free local tree */
+/* we have to assume the editor already changed completely */
+void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
+{
+       if (localtree && ntreeIsValid(ntree)) {
+               BKE_node_preview_merge_tree(ntree, localtree);
+               
+               if (ntree->typeinfo->local_merge)
+                       ntree->typeinfo->local_merge(localtree, ntree);
+               
+               ntreeFreeTree_ex(localtree, FALSE);
+               MEM_freeN(localtree);
        }
+}
+
 
-       /* node copy func */
-       ltree = ntreeCopyTree_internal(ntree, FALSE, FALSE);
+/* ************ NODE TREE INTERFACE *************** */
 
-       if (adt) {
-               AnimData *ladt = BKE_animdata_from_id(&ltree->id);
+static bNodeSocket *make_socket_template(bNodeTree *ntree, int in_out,
+                                         const char *idname, const char *name)
+{
+       bNodeSocketType *stype = nodeSocketTypeFind(idname);
+       bNodeSocket *sock;
+       int own_index = ntree->cur_index++;
+       
+       if (stype == NULL) {
+               printf("Error: node socket type '%s' undefined\n", idname);
+               return NULL;
+       }
+       
+       sock = MEM_callocN(sizeof(bNodeSocket), "socket template");
+       sock->typeinfo= stype;
+       BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
+       sock->in_out = in_out;
+       sock->type = SOCK_CUSTOM;       /* int type undefined by default */
+       
+       /* assign new unique index */
+       own_index = ntree->cur_index++;
+       /* use the own_index as socket identifier */
+       if (in_out == SOCK_IN)
+               BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index);
+       else
+               BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index);
+#ifdef USE_NODE_COMPAT_CUSTOMNODES
+       /* XXX forward compatibility:
+        * own_index is deprecated, but needs to be set here.
+        * Node sockets generally use the identifier string instead now,
+        * but reconstructing own_index in writefile.c would require parsing the identifier string.
+        */
+       sock->own_index = own_index;
+#endif
+       
+       sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
+       
+       BLI_strncpy(sock->name, name, NODE_MAXSTR);
+       sock->storage = NULL;
+       sock->flag |= SOCK_COLLAPSED;
+       
+       return sock;
+}
 
-               adt->action = ladt->action = action_backup;
-               adt->tmpact = ladt->tmpact = tmpact_backup;
+bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *identifier)
+{
+       bNodeSocket *iosock = (in_out == SOCK_IN ? ntree->inputs.first : ntree->outputs.first);
+       for (; iosock; iosock = iosock->next)
+               if (strcmp(iosock->identifier, identifier)==0)
+                       return iosock;
+       return NULL;
+}
 
-               if (action_backup) action_backup->id.us++;
-               if (tmpact_backup) tmpact_backup->id.us++;
-               
+bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, int in_out, const char *idname, const char *name)
+{
+       bNodeSocket *iosock;
+       
+       iosock = make_socket_template(ntree, in_out, idname, name);
+       if (in_out == SOCK_IN) {
+               BLI_addtail(&ntree->inputs, iosock);
+               ntree->update |= NTREE_UPDATE_GROUP_IN;
        }
-       /* end animdata uglyness */
+       else if (in_out == SOCK_OUT) {
+               BLI_addtail(&ntree->outputs, iosock);
+               ntree->update |= NTREE_UPDATE_GROUP_OUT;
+       }
+       
+       return iosock;
+}
 
-       /* ensures only a single output node is enabled */
-       ntreeSetOutput(ntree);
+bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree, int in_out, const char *idname,
+                               bNodeSocket *next_sock, const char *name)
+{
+       bNodeSocket *iosock;
+       
+       iosock = make_socket_template(ntree, in_out, idname, name);
+       if (in_out == SOCK_IN) {
+               BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock);
+               ntree->update |= NTREE_UPDATE_GROUP_IN;
+       }
+       else if (in_out == SOCK_OUT) {
+               BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
+               ntree->update |= NTREE_UPDATE_GROUP_OUT;
+       }
+       
+       return iosock;
+}
 
-       for (node = ntree->nodes.first; node; node = node->next) {
-               /* store new_node pointer to original */
-               node->new_node->new_node = node;
+struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree, bNode *from_node, bNodeSocket *from_sock)
+{
+       bNodeSocket *iosock = ntreeAddSocketInterface(ntree, from_sock->in_out, from_sock->idname, from_sock->name);
+       if (iosock) {
+               if (iosock->typeinfo->interface_from_socket)
+                       iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
        }
+       return iosock;
+}
 
-       if (ntreetype->localize)
-               ntreetype->localize(ltree, ntree);
+struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(bNodeTree *ntree, bNodeSocket *next_sock, bNode *from_node, bNodeSocket *from_sock)
+{
+       bNodeSocket *iosock = ntreeInsertSocketInterface(ntree, from_sock->in_out, from_sock->idname, next_sock, from_sock->name);
+       if (iosock) {
+               if (iosock->typeinfo->interface_from_socket)
+                       iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
+       }
+       return iosock;
+}
 
-       return ltree;
+void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
+{
+       /* this is fast, this way we don't need an in_out argument */
+       BLI_remlink(&ntree->inputs, sock);
+       BLI_remlink(&ntree->outputs, sock);
+       
+       node_socket_interface_free(ntree, sock);
+       MEM_freeN(sock);
+       
+       ntree->update |= NTREE_UPDATE_GROUP;
 }
 
-/* sync local composite with real tree */
-/* local tree is supposed to be running, be careful moving previews! */
-/* is called by jobs manager, outside threads, so it doesnt happen during draw */
-void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
+/* generates a valid RNA identifier from the node tree name */
+static void ntree_interface_identifier_base(bNodeTree *ntree, char *base)
 {
-       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
+       /* generate a valid RNA identifier */
+       sprintf(base, "NodeTreeInterface_%s", ntree->id.name+2);
+       RNA_identifier_sanitize(base, FALSE);
+}
 
-       if (ntreetype->local_sync)
-               ntreetype->local_sync(localtree, ntree);
+/* check if the identifier is already in use */
+static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier)
+{
+       return (RNA_struct_find(identifier) != NULL);
 }
 
-/* merge local tree results back, and free local tree */
-/* we have to assume the editor already changed completely */
-void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
+/* generates the actual unique identifier and ui name and description */
+static void ntree_interface_identifier(bNodeTree *ntree, const char *base, char *identifier, int maxlen, char *name, char *description)
+{
+       /* There is a possibility that different node tree names get mapped to the same identifier
+        * after sanitization (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A").
+        * On top of the sanitized id string add a number suffix if necessary to avoid duplicates.
+        */
+       identifier[0] = '\0';
+       BLI_uniquename_cb(ntree_interface_unique_identifier_check, NULL, base, '_', identifier, maxlen);
+       
+       sprintf(name, "Node Tree %s Interface", ntree->id.name+2);
+       sprintf(description, "Interface properties of node group %s", ntree->id.name+2);
+}
+
+static void ntree_interface_type_create(bNodeTree *ntree)
 {
-       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
-       bNode *lnode;
+       StructRNA *srna;
+       bNodeSocket *sock;
+       /* strings are generated from base string + ID name, sizes are sufficient */
+       char base[MAX_ID_NAME+64], identifier[MAX_ID_NAME+64], name[MAX_ID_NAME+64], description[MAX_ID_NAME+64];
        
-       /* move over the compbufs and previews */
-       for (lnode = localtree->nodes.first; lnode; lnode = lnode->next) {
-               if (ntreeNodeExists(ntree, lnode->new_node)) {
-                       if (lnode->preview && lnode->preview->rect) {
-                               nodeFreePreview(lnode->new_node);
-                               lnode->new_node->preview = lnode->preview;
-                               lnode->preview = NULL;
-                       }
+       /* generate a valid RNA identifier */
+       ntree_interface_identifier_base(ntree, base);
+       ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description);
+       
+       /* register a subtype of PropertyGroup */
+       srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup);
+       RNA_def_struct_ui_text(srna, name, description);
+       RNA_def_struct_duplicate_pointers(srna);
+       
+       /* associate the RNA type with the node tree */
+       ntree->interface_type = srna;
+       RNA_struct_blender_type_set(srna, ntree);
+       
+       /* add socket properties */
+       for (sock = ntree->inputs.first; sock; sock = sock->next) {
+               bNodeSocketType *stype = sock->typeinfo;
+               if (stype && stype->interface_register_properties)
+                       stype->interface_register_properties(ntree, sock, srna);
+       }
+       for (sock = ntree->outputs.first; sock; sock = sock->next) {
+               bNodeSocketType *stype = sock->typeinfo;
+               if (stype && stype->interface_register_properties)
+                       stype->interface_register_properties(ntree, sock, srna);
+       }
+}
+
+StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create)
+{
+       if (ntree->interface_type) {
+               /* strings are generated from base string + ID name, sizes are sufficient */
+               char base[MAX_ID_NAME+64], identifier[MAX_ID_NAME+64], name[MAX_ID_NAME+64], description[MAX_ID_NAME+64];
+               
+               /* A bit of a hack: when changing the ID name, update the RNA type identifier too,
+                * so that&nb